/* ==========================================================================
   FORGE MOBILE 2.0 — HOLY GRAIL VISUAL LAW R1 — APPLICATION STYLES
   Consumes only tokens.css custom properties. Mobile-first; iPad and desktop
   adaptations layered on with min-width media queries per
   COORDINATES_AND_LAYOUT_LAW.md "Responsive law".
   ========================================================================== */

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--bg-void);
  color: var(--text-primary);
  font-family: var(--font-family);
  font-size: var(--fs-base);
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  /* Disables the browser's own double-tap-to-zoom gesture app-wide while
     still allowing pinch-zoom (manipulation = pan + pinch-zoom, per spec),
     so accessibility zoom keeps working. */
  touch-action: manipulation;
}
button, input, textarea, select { font-family: inherit; color: inherit; }
button {
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  text-align: inherit;
  font-size: inherit;
  appearance: none;
  -webkit-appearance: none;
}
a { color: inherit; text-decoration: none; }
::selection { background: var(--violet-glow-soft); }

/* Baseline icon size for every inline SVG glyph in the app. Specific
   contexts (icon-btn, dock-item, cap-icon, etc.) override this with a
   higher-specificity class rule further down; hero visuals (the EnForce
   crystal, the Certified Passage shield) size themselves via inline style
   so they are unaffected by this default. Without this baseline, an SVG
   with only a viewBox and no surrounding size rule can inflate to its
   browser default box inside any flex container with room to give it. */
svg { width: 20px; height: 20px; flex-shrink: 0; display: block; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* -- App atmosphere ------------------------------------------------------- */
#app-root {
  min-height: 100vh;
  /* dvh tracks the real visible viewport (shrinks for the on-screen
     keyboard / browser chrome) where supported; 100vh above is the
     fallback for browsers without dvh support. Same unit already relied
     on elsewhere in this product (vivian-first-use-card, the preauth
     shell) -- applied here too so the bottom dock (a flex child of this
     column) never ends up hidden behind the keyboard or a shrinking
     browser chrome bar. */
  min-height: 100dvh;
  display: flex;
  justify-content: center;
  background:
    radial-gradient(560px 420px at 50% -6%, rgba(242, 163, 92, 0.16), transparent 60%),
    radial-gradient(640px 520px at 84% 18%, rgba(139, 124, 245, 0.12), transparent 62%),
    radial-gradient(700px 600px at 8% 82%, rgba(139, 124, 245, 0.08), transparent 60%),
    var(--bg-void);
}

.device-frame {
  width: 100%;
  max-width: var(--phone-max);
  /* R4-S2: a definite height, not min-height. A flex column's children
     only ever flex-shrink against a DEFINITE main size -- min-height is
     purely a floor applied after the fact, so a flex-shrink child (here,
     .screen-scroll) never actually compresses below its own content's
     natural size no matter how small the viewport gets, and the whole
     shell silently grows past the real viewport instead of scrolling
     internally. That's exactly what stranded the dock under a shrunk
     viewport (the keyboard-open case this law exists for): the frame
     just kept its content-driven height and pushed the dock down with
     it. height (with the same vh-then-dvh fallback pattern used
     elsewhere in this product) gives the column a real size to shrink
     its children against, so .screen-scroll's own min-height:0 can
     actually take effect and scroll internally instead. */
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  position: relative;
}

/* -- Status/utility strip -------------------------------------------------- */
.status-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Mirrors the existing bottom-dock/composer env(safe-area-inset-bottom)
     law: keeps the top status row clear of a notch/Dynamic Island instead
     of stacking a fixed 14px on top of whatever the device already insets. */
  padding: max(14px, env(safe-area-inset-top)) var(--safe-inset) 2px;
  font-size: var(--fs-xs);
  color: var(--text-tertiary);
  letter-spacing: 0.02em;
  flex-shrink: 0;
}
.status-strip .clock { color: var(--text-secondary); font-weight: 600; }
.status-strip .glyphs { display: flex; gap: 6px; align-items: center; opacity: 0.8; }

.chrome-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px var(--safe-inset) 4px;
  flex-shrink: 0;
  gap: var(--space-3);
}
.chrome-left, .chrome-right { display: flex; align-items: center; gap: var(--space-2); }
.brandmark {
  display: flex; align-items: center; gap: 8px;
  font-size: var(--fs-xs); letter-spacing: 0.12em; color: var(--text-tertiary);
  text-transform: uppercase; font-weight: 600;
}
.brandmark strong { color: var(--text-primary); font-weight: 700; }
.live-dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--status-ready);
  box-shadow: 0 0 8px var(--status-ready); display: inline-block;
}

.icon-btn {
  width: var(--touch-min); height: var(--touch-min);
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius-pill);
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  color: var(--text-secondary);
  transition: background var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.icon-btn svg { width: 18px; height: 18px; }
.icon-btn:hover { background: var(--surface-card-hover); color: var(--text-primary); }
.icon-btn:active { transform: scale(0.94); }
.icon-btn:focus-visible, button:focus-visible, input:focus-visible,
textarea:focus-visible, select:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--violet-400);
  outline-offset: 2px;
}
.icon-btn.has-dot::after {
  content: ""; position: absolute; width: 7px; height: 7px; border-radius: 50%;
  background: var(--amber-500); box-shadow: 0 0 6px var(--amber-glow);
  transform: translate(11px, -11px);
}
.icon-btn { position: relative; }

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 10px; border-radius: var(--radius-pill);
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; border: 1px solid transparent; white-space: nowrap;
}
.badge-owner { color: var(--role-owner); background: var(--role-owner-bg); border-color: var(--border-amber-soft); }
.badge-tester { color: var(--role-tester); background: var(--role-tester-bg); border-color: var(--border-violet-soft); }
.badge-analyst { color: var(--role-analyst); background: rgba(124,199,242,0.14); border-color: rgba(124,199,242,0.3); }
.badge-shared { color: var(--violet-200); background: var(--violet-glow-soft); border-color: var(--border-violet-soft); }
.badge-owner-only { color: var(--amber-300); background: rgba(242,163,92,0.1); border-color: var(--border-amber-soft); }
.badge-dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; }

/* -- Status pill (capability truth) ---------------------------------------- */
.status-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: var(--radius-pill);
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
}
.status-pill .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; box-shadow: 0 0 6px currentColor; }
.status-ready-pill { color: var(--status-ready); background: var(--status-ready-bg); }
.status-active-pill { color: var(--status-active); background: var(--status-active-bg); }
.status-pending-pill { color: var(--status-pending); background: var(--status-pending-bg); }
.status-unavailable-pill { color: var(--status-unavailable); background: var(--status-unavailable-bg); }
.status-restricted-pill { color: var(--status-restricted); background: var(--status-restricted-bg); }
.status-failed-pill { color: var(--status-failed); background: var(--status-failed-bg); }
.status-sealed-pill { color: var(--status-sealed); background: var(--status-sealed-bg); }

/* -- Screen root shell (flex column so inner content scrolls, not page) --- */
.screen-root-shell { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }

/* -- Main scroll area ------------------------------------------------------ */
.screen-scroll {
  flex: 1 1 auto;
  /* R4-S2: .screen-root-shell (this element's parent) already sets
     min-height:0 to opt itself out of a flex item's default min-height:
     auto, but that only clears the parent's own refusal to shrink -- this
     element is itself an independent flex item one level deeper (in
     .screen-root-shell's own column) and needs the identical override, or
     its own content's natural height silently wins again at exactly this
     level: past a certain point (the on-screen keyboard opening, a short
     browser window) the whole shell grows taller than the page instead of
     scrolling internally, stranding the dock below the visible viewport. */
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 0 var(--safe-inset) var(--space-9);
  -webkit-overflow-scrolling: touch;
  /* App-like scroll surfaces stay scrollable but never show the host
     browser's own scrollbar chrome. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.screen-scroll::-webkit-scrollbar { display: none; width: 0; height: 0; }
.screen-scroll.no-pad-x { padding-left: 0; padding-right: 0; }
.section-gap { margin-top: var(--space-7); }
.section-gap-sm { margin-top: var(--space-5); }

/* -- Cards ------------------------------------------------------------------ */
/* Glass pass: real backdrop blur (previously the "glass" cards were only a
   flat tinted rgba fill — no actual glass material). The inset top highlight
   is the classic frosted-pane cue: a hairline of light catching the upper
   edge, same trick real glass/ice UI references use. Additive only — same
   tokens, same radius/spacing/colors, so no layout or identity drift. */
.card {
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-card), inset 0 1px 0 rgba(255, 246, 235, 0.05);
  backdrop-filter: blur(20px) saturate(1.3);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
}
.card-strong { background: var(--surface-card-strong); }
.card-amber { border-color: var(--border-amber-soft); }
.card-violet { border-color: var(--border-violet-soft); }
.card-sm { border-radius: var(--radius-md); padding: var(--space-4); }
.card-interactive {
  transition: background var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard);
}
.card-interactive:hover { background: var(--surface-card-hover); border-color: var(--border-hairline-strong); }
.card-interactive:active { transform: scale(0.99); }

.eyebrow {
  font-size: var(--fs-2xs); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--amber-300); font-weight: 700; margin: 0 0 6px;
}
.eyebrow.violet { color: var(--violet-400); }
.eyebrow.muted { color: var(--text-tertiary); }

h1, h2, h3, h4, p { margin: 0; }
.h-display { font-size: var(--fs-display); font-weight: 700; letter-spacing: -0.01em; line-height: var(--lh-tight); }
.h-xl { font-size: var(--fs-xl); font-weight: 700; letter-spacing: -0.01em; line-height: var(--lh-tight); }
.h-lg { font-size: var(--fs-lg); font-weight: 700; line-height: var(--lh-tight); }
.h-md { font-size: var(--fs-md); font-weight: 600; line-height: var(--lh-tight); }
.t-base { font-size: var(--fs-base); color: var(--text-secondary); line-height: var(--lh-normal); }
.t-sm { font-size: var(--fs-sm); color: var(--text-tertiary); line-height: var(--lh-normal); }
.t-xs { font-size: var(--fs-xs); color: var(--text-tertiary); }
.t-primary { color: var(--text-primary); }

.divider { height: 1px; background: var(--border-hairline); border: none; margin: var(--space-5) 0; }

/* -- Buttons ------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: var(--touch-min);
  padding: 0 22px;
  border-radius: var(--radius-md);
  font-size: var(--fs-base); font-weight: 700;
  border: 1px solid transparent;
  transition: transform var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard),
              background var(--dur-fast) var(--ease-standard),
              opacity var(--dur-fast) var(--ease-standard);
  width: 100%;
}
.btn:active { transform: scale(0.98); }
.btn-primary {
  background: linear-gradient(135deg, var(--amber-500), var(--amber-600));
  color: var(--text-on-amber);
  box-shadow: var(--glow-amber-sm);
}
.btn-primary:hover { box-shadow: var(--glow-amber-lg); }
.btn-outline {
  background: transparent; border-color: var(--border-amber);
  color: var(--amber-300);
}
.btn-outline:hover { background: rgba(242,163,92,0.08); }
.btn-violet {
  background: linear-gradient(135deg, var(--violet-500), var(--violet-700));
  color: #fff; box-shadow: var(--glow-violet-sm);
}
.btn-violet:hover { box-shadow: var(--glow-violet-lg); }
.btn-ghost {
  background: var(--surface-card); border-color: var(--border-hairline); color: var(--text-secondary);
}
.btn-ghost:hover { background: var(--surface-card-hover); color: var(--text-primary); }
.btn-danger {
  background: transparent; border-color: rgba(242,104,95,0.4); color: var(--status-failed);
}
.btn-danger:hover { background: rgba(242,104,95,0.1); }
.btn-block { width: 100%; }
.btn-auto { width: auto; }
.btn-sm { min-height: 38px; padding: 0 14px; font-size: var(--fs-sm); border-radius: var(--radius-sm); }
.btn:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; }
.btn-row { display: flex; gap: var(--space-3); }

/* -- Bottom dock ------------------------------------------------------------ */
.bottom-dock {
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px var(--safe-inset) calc(env(safe-area-inset-bottom, 0px) + 12px);
  gap: var(--space-2);
}
.dock-item {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;
  min-height: var(--touch-min);
  background: none; border: none; color: var(--text-tertiary);
  padding: 6px 2px; border-radius: var(--radius-md);
  transition: color var(--dur-fast) var(--ease-standard);
}
.dock-item svg { width: 22px; height: 22px; }
.dock-item span { font-size: 10px; font-weight: 600; letter-spacing: 0.02em; }
.dock-item:hover { color: var(--text-secondary); }
.dock-item.active { color: var(--amber-300); }
.dock-item.center {
  position: relative;
}
.dock-orb {
  width: 46px; height: 46px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 35% 30%, var(--amber-300), var(--amber-600) 70%);
  box-shadow: 0 0 22px var(--amber-glow), inset 0 0 10px rgba(255,255,255,0.25);
  color: var(--text-on-amber);
  transition: box-shadow var(--dur-base) var(--ease-standard), transform var(--dur-fast) var(--ease-standard);
}
.dock-item.center:active .dock-orb { transform: scale(0.92); }
.dock-item.center.active .dock-orb { box-shadow: 0 0 30px var(--amber-glow), inset 0 0 12px rgba(255,255,255,0.3); }
.dock-home-indicator {
  width: 120px; height: 4px; border-radius: var(--radius-pill);
  background: rgba(255,255,255,0.22); margin: 0 auto 6px;
}

/* -- Home screen ------------------------------------------------------------ */
.home-greeting { padding-top: var(--space-6); }
.enforce-hero { display: flex; flex-direction: column; align-items: center; padding: var(--space-6) 0 var(--space-4); position: relative; }

/* -- Ambient atmosphere behind the EnForce presence ----------------------
   A deep layered glow field + slow-drifting dust motes, sitting behind the
   crystal-wrap. Figma/OpenArt reference exploration (surreal, living,
   materializing atmosphere) translated into real CSS: cheap, GPU-friendly
   (opacity/transform only), and shared by both the SVG and WebGL crystal
   paths since it lives on the hero, not on .crystal itself. ------------- */
.hero-glow-field {
  position: absolute; top: 8px; left: 50%; transform: translateX(-50%);
  width: 340px; height: 340px; pointer-events: none; z-index: 0;
  background:
    radial-gradient(circle at 42% 40%, var(--amber-glow-soft) 0%, transparent 46%),
    radial-gradient(circle at 58% 62%, var(--violet-glow-soft) 0%, transparent 50%);
  filter: blur(4px);
  animation: glow-field-breathe 7.4s ease-in-out infinite;
}
@keyframes glow-field-breathe {
  0%, 100% { opacity: 0.65; transform: translateX(-50%) scale(0.96); }
  50%      { opacity: 1;    transform: translateX(-50%) scale(1.05); }
}
.crystal-atmosphere {
  position: absolute; inset: 0; pointer-events: none; z-index: 1;
  overflow: visible;
}
.mote {
  position: absolute; border-radius: 50%;
  width: 4px; height: 4px;
  background: var(--amber-300);
  box-shadow: 0 0 6px 1px var(--amber-glow);
  opacity: 0;
  animation: mote-drift 6s ease-in-out infinite;
}
.mote-violet { background: var(--violet-400); box-shadow: 0 0 6px 1px var(--violet-glow); }
.mote-1 { top: 68%; left: 22%; animation-delay: 0s;    animation-duration: 6.2s; }
.mote-2 { top: 58%; left: 76%; animation-delay: 1.1s;  animation-duration: 7.1s; }
.mote-3 { top: 30%; left: 14%; animation-delay: 2.3s;  animation-duration: 5.6s; }
.mote-4 { top: 22%; left: 82%; animation-delay: 0.6s;  animation-duration: 6.8s; }
.mote-5 { top: 74%; left: 50%; animation-delay: 3.1s;  animation-duration: 6.4s; }
.mote-6 { top: 16%; left: 48%; animation-delay: 1.8s;  animation-duration: 7.6s; }
@keyframes mote-drift {
  0%   { opacity: 0;    transform: translateY(0) scale(0.7); }
  15%  { opacity: 0.85; }
  50%  { opacity: 0.55; transform: translateY(-22px) scale(1); }
  85%  { opacity: 0.2;  }
  100% { opacity: 0;    transform: translateY(-40px) scale(0.6); }
}

.crystal-wrap {
  position: relative; z-index: 2; width: 178px; height: 178px;
  display: flex; align-items: center; justify-content: center;
  opacity: 1;
  animation: crystal-materialize 1s var(--ease-out) both;
}
/* One-shot on mount (screens re-render fresh innerHTML per navigation, so
   this naturally replays every time Home is entered): the presence
   condenses out of soft light rather than simply appearing. */
@keyframes crystal-materialize {
  0%   { opacity: 0; filter: blur(16px); transform: scale(0.68) rotateY(-30deg); }
  55%  { opacity: 1; filter: blur(2px);  transform: scale(1.05) rotateY(4deg); }
  100% { opacity: 1; filter: blur(0);    transform: scale(1) rotateY(-7deg); }
}
.crystal-wrap::before {
  content: ""; position: absolute; inset: -30px; border-radius: 50%;
  background: radial-gradient(circle, var(--amber-glow) 0%, var(--violet-glow-soft) 45%, transparent 72%);
  opacity: 0; z-index: -1;
  animation: materialize-flash 1s var(--ease-out) both;
}
@keyframes materialize-flash {
  0%   { opacity: 0; transform: scale(0.4); }
  38%  { opacity: 0.9; transform: scale(1.15); }
  100% { opacity: 0; transform: scale(1.5); }
}
.crystal-ring {
  position: absolute; inset: 0; border-radius: 50%;
  border: 1px solid var(--border-violet-soft);
  animation: spin-slow var(--dur-ambient) linear infinite;
}
/* Compact inline crystals (Chat welcome, Persona, Forge Execution — see
   crystalRinged() in js/ui.js): same ring/spin as the Home hero, but no
   one-shot materialize-flash-in on every render of a screen you may
   revisit often, and no forced hero footprint — width/height come from
   the inline style crystalRinged() sets per call site. */
.crystal-wrap-inline { animation: none; }
.crystal-wrap-inline::before { display: none; }
.crystal-ring::after {
  content: ""; position: absolute; inset: 14px; border-radius: 50%;
  border: 1px solid var(--border-amber-soft);
}
@keyframes spin-slow { to { transform: rotate(360deg); } }
.crystal {
  /* sizing comes from an inline style set per-instance in ui.js so the
     same crystal can be reused at hero, chat-welcome and persona scale */
  filter: drop-shadow(0 0 30px var(--amber-glow)) drop-shadow(0 0 46px var(--violet-glow-soft));
  animation: crystal-breathe 4.2s ease-in-out infinite;
  transform-style: preserve-3d;
  perspective: 600px;
}
@keyframes crystal-breathe {
  /* combines the original gentle float/scale with a slow turntable tilt so
     the gem reads as one dimensional object catching light, not a flat
     sticker breathing in place */
  0%   { transform: translateY(0)   scale(1)     rotateY(-7deg) rotateX(1deg); }
  25%  { transform: translateY(-3px) scale(1.012) rotateY(0deg)  rotateX(0deg); }
  50%  { transform: translateY(-4px) scale(1.02)  rotateY(7deg)  rotateX(-1deg); }
  75%  { transform: translateY(-3px) scale(1.012) rotateY(0deg)  rotateX(0deg); }
  100% { transform: translateY(0)   scale(1)     rotateY(-7deg) rotateX(1deg); }
}
/* Individual facets shimmer on independent, staggered timers (delay is set
   per-polygon inline in ui.js) so the gem reads as internally alive rather
   than one flat surface pulsing in unison. */
.facet {
  animation: facet-shimmer 3.6s ease-in-out infinite;
  transform-origin: center;
}
@keyframes facet-shimmer {
  0%, 100% { filter: brightness(1); }
  50% { filter: brightness(1.22); }
}
.facet-pavilion { animation-duration: 4.4s; }
/* The two hand-placed specular glints sparkle independently — a real gem's
   sharpest highlight moves and catches, it doesn't hold static. */
.facet-glint { animation: glint-sparkle 2.4s ease-in-out infinite; transform-origin: center; }
.facet-glint-b { animation-duration: 3.1s; animation-delay: 0.9s; }
@keyframes glint-sparkle {
  0%, 100% { opacity: 0.15; transform: scale(0.85); }
  45% { opacity: 0.75; transform: scale(1.15); }
  60% { opacity: 0.35; transform: scale(0.95); }
}
/* -- Screen-entrance transition (transition-smoothness polish pass) -------
   Previously js/router.js swapped #screen-root's content with zero
   transition — an instant cut on every navigation. This plays a short,
   calm fade+rise on whichever content just landed there, replayed by JS
   removing/re-adding the class (see playScreenEnter in router.js). Same
   route table, same screens, same role guard — purely a swap-in animation
   layered on top of already-decided content. */
.screen-root-shell.screen-enter {
  animation: screen-fade-in var(--dur-slow) var(--ease-out);
}
@keyframes screen-fade-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .crystal, .crystal-ring, .glow-pulse, .listening-wave, .thinking-dots span,
  .facet, .facet-glint,
  .crystal-wrap, .crystal-wrap::before, .hero-glow-field, .mote,
  .screen-root-shell.screen-enter {
    animation: none !important;
  }
  /* Static resting state instead of the animated entrance/atmosphere: the
     glow field and crystal stay fully present, the transient flash and
     drifting motes (which rely on their keyframes to ever become visible)
     simply don't render rather than freezing on an invisible frame. */
  .crystal-wrap { opacity: 1; }
  .crystal-wrap::before { opacity: 0; }
  .hero-glow-field { opacity: 0.8; transform: translateX(-50%) scale(1); }
  .mote { opacity: 0; }
}
/* The real-time WebGL gem (Home hero only, js/crystal3d.js). It shares the
   flat SVG version's glow filter and box footprint via .crystal, but its
   rotation/bob/tilt are computed per-frame in JS against real lighting, not
   CSS keyframes — so the CSS breathe animation is switched off here and the
   canvas gets its own display rule instead of inheriting SVG defaults. */
.crystal-gl {
  display: block;
  animation: none !important;
}
.crystal-floor {
  position: relative; z-index: 2;
  width: 148px; height: 22px; margin-top: -6px; border-radius: 50%;
  background: radial-gradient(ellipse at center, var(--amber-glow) 0%, transparent 72%);
  filter: blur(2px);
}
.enforce-id-label {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  font-size: var(--fs-xs); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--amber-300); font-weight: 700; margin-top: var(--space-3);
}
.intent-line { text-align: center; margin-top: var(--space-2); }

.prism-tile {
  margin-top: var(--space-6);
  display: flex; align-items: center; gap: var(--space-4);
  min-height: 80px;
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-lg);
  background: linear-gradient(135deg, rgba(242,163,92,0.14), rgba(139,124,245,0.10));
  border: 1px solid var(--border-amber-soft);
  box-shadow: var(--glow-amber-sm), inset 0 1px 0 rgba(255, 246, 235, 0.06);
  backdrop-filter: blur(20px) saturate(1.3);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
  width: 100%;
  transition: box-shadow var(--dur-base) var(--ease-standard), transform var(--dur-fast) var(--ease-standard);
}
.prism-tile:hover { box-shadow: var(--glow-amber-lg); }
.prism-tile:active { transform: scale(0.99); }
.prism-glyph {
  width: 44px; height: 44px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-sm);
  background: rgba(0,0,0,0.2);
}
.prism-glyph svg { width: 26px; height: 26px; }
.prism-tile .tile-copy { flex: 1; text-align: left; }
.prism-tile .tile-title { font-weight: 700; font-size: var(--fs-base); color: var(--text-primary); }
.prism-tile .tile-sub { font-size: var(--fs-xs); color: var(--text-tertiary); margin-top: 2px; }
.prism-tile .chev { color: var(--amber-300); flex-shrink: 0; }

.context-chip-row { display: flex; gap: var(--space-2); overflow-x: auto; padding: 2px 0 4px; margin-top: var(--space-5); scrollbar-width: none; -ms-overflow-style: none; }
.context-chip-row::-webkit-scrollbar { display: none; width: 0; height: 0; }
.context-chip {
  flex-shrink: 0; display: flex; align-items: center; gap: 8px;
  padding: 8px 14px; border-radius: var(--radius-pill);
  background: var(--surface-card); border: 1px solid var(--border-hairline);
  font-size: var(--fs-xs); color: var(--text-secondary); white-space: nowrap;
}
.context-chip svg { width: 14px; height: 14px; color: var(--amber-300); }

/* -- Owner console entry (header utility, owner-only) ------------------- */
.owner-console-btn { position: relative; }
.owner-console-btn::before {
  content: ""; position: absolute; inset: -3px; border-radius: 50%;
  border: 1px solid var(--border-amber-soft);
}

/* -- EnForce shell header --------------------------------------------------- */
.enforce-header { display: flex; align-items: flex-start; justify-content: space-between; padding: var(--space-4) var(--safe-inset) var(--space-2); gap: var(--space-3); }
.enforce-id { display: flex; gap: var(--space-3); align-items: center; }
.enforce-avatar {
  width: 52px; height: 52px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 40% 30%, rgba(139,124,245,0.5), rgba(20,16,32,0.9) 68%);
  border: 1px solid var(--border-violet-soft);
  box-shadow: var(--glow-violet-sm);
}
.enforce-avatar svg { width: 26px; height: 26px; color: var(--violet-200); }
.enforce-id .name { font-size: var(--fs-lg); font-weight: 700; }
.enforce-id .role-line { font-size: var(--fs-xs); color: var(--text-tertiary); margin: 2px 0 6px; }
.enforce-actions { display: flex; gap: var(--space-2); flex-shrink: 0; }

/* -- Tabs ------------------------------------------------------------------- */
.tab-row {
  display: flex; flex-wrap: wrap; gap: var(--space-2);
  padding: var(--space-2) var(--safe-inset) var(--space-4);
}
.tab-btn {
  min-height: 40px; padding: 0 16px; border-radius: var(--radius-pill);
  background: var(--surface-card); border: 1px solid var(--border-hairline);
  color: var(--text-secondary); font-size: var(--fs-sm); font-weight: 600;
  display: inline-flex; align-items: center; gap: 6px;
  transition: all var(--dur-fast) var(--ease-standard);
}
.tab-btn:hover { color: var(--text-primary); background: var(--surface-card-hover); }
.tab-btn.active {
  color: var(--text-on-amber);
  background: linear-gradient(135deg, var(--amber-500), var(--amber-600));
  border-color: transparent;
  box-shadow: var(--glow-amber-sm);
}
.tab-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--amber-500); }

/* -- Chat ------------------------------------------------------------------- */
.chat-scroll { display: flex; flex-direction: column; gap: var(--space-4); padding-bottom: var(--space-4); }
.chat-welcome {
  display: flex; align-items: center; gap: var(--space-4);
  border-radius: var(--radius-lg); padding: var(--space-5);
  background: linear-gradient(135deg, rgba(242,163,92,0.10), rgba(139,124,245,0.08));
  border: 1px solid var(--border-amber-soft);
}
/* C2-006: minimum functional default (screens-core.js sets data-engaged
   once real conversation content exists) -- a presentation pass may
   replace this with an actual recede/collapse transition; this is not a
   claim on that final motion design. */
.chat-welcome[data-engaged="true"] { display: none; }
.chat-welcome .crystal { flex-shrink: 0; }
.msg-row { display: flex; }
.msg-row.from-user { justify-content: flex-end; }
.msg-row.from-enforce { justify-content: flex-start; }
.msg-bubble {
  max-width: 82%; padding: 12px 16px; border-radius: var(--radius-md);
  font-size: var(--fs-base); line-height: var(--lh-normal);
}
.from-enforce .msg-bubble {
  background: var(--surface-card-strong); border: 1px solid var(--border-hairline);
  border-bottom-left-radius: 6px;
}
.from-user .msg-bubble {
  background: linear-gradient(135deg, rgba(242,163,92,0.22), rgba(242,163,92,0.12));
  border: 1px solid var(--border-amber-soft);
  border-bottom-right-radius: 6px;
}
.msg-meta { font-size: 10px; color: var(--text-tertiary); margin-top: 5px; display: flex; gap: 4px; align-items: center; }
.from-user .msg-meta { justify-content: flex-end; }
/* C3-012, SHARED: quiet visual weight, integrated into the metadata row
   rather than floating over the bubble -- present but never competing
   with message content. */
.msg-copy {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; padding: 0; margin-left: 2px;
  background: none; border: none; color: var(--text-tertiary);
  opacity: 0.55; cursor: pointer; border-radius: 4px;
  transition: opacity var(--dur-fast) var(--ease-standard);
}
.msg-copy:hover, .msg-copy:focus-visible { opacity: 1; }
.msg-copy svg { width: 12px; height: 12px; }
.msg-row-wrap { display: flex; flex-direction: column; max-width: 82%; }
.from-user .msg-row-wrap { margin-left: auto; align-items: flex-end; }
.thinking-row { display: flex; align-items: center; gap: 8px; padding: 10px 16px; }
.thinking-dots { display: flex; gap: 4px; }
.thinking-dots span {
  width: 6px; height: 6px; border-radius: 50%; background: var(--violet-400);
  animation: dot-bounce 1.2s ease-in-out infinite;
}
.thinking-dots span:nth-child(2) { animation-delay: 0.15s; }
.thinking-dots span:nth-child(3) { animation-delay: 0.3s; }
@keyframes dot-bounce { 0%, 60%, 100% { opacity: 0.35; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-3px); } }

.quick-actions { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-2); margin: var(--space-4) 0; }
.quick-action {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 12px 4px; min-height: var(--touch-min);
  border-radius: var(--radius-md);
  background: var(--surface-card); border: 1px solid var(--border-hairline);
  box-shadow: inset 0 1px 0 rgba(255, 246, 235, 0.05);
  backdrop-filter: blur(20px) saturate(1.3);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
  text-align: center;
  transition: background var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard);
}
.quick-action svg { width: 18px; height: 18px; color: var(--violet-400); }
.quick-action .qa-title { font-size: 11px; font-weight: 700; color: var(--text-primary); }
.quick-action .qa-sub { font-size: 10px; color: var(--text-tertiary); }
.quick-action:hover { background: var(--surface-card-hover); border-color: var(--border-violet-soft); }
.quick-action:active { transform: scale(0.96); }
.quick-action.selected { border-color: var(--border-violet); box-shadow: var(--glow-violet-sm); }

.composer-wrap { flex-shrink: 0; padding: var(--space-3) var(--safe-inset) calc(env(safe-area-inset-bottom, 0px) + var(--space-3)); }
.composer-field {
  display: flex; align-items: center; gap: var(--space-2);
  background: var(--surface-input); border: 1px solid var(--border-hairline-strong);
  border-radius: var(--radius-lg); padding: 6px 6px 6px 14px;
}
.composer-field input {
  flex: 1; background: none; border: none; color: var(--text-primary);
  /* iOS Safari auto-zooms the viewport on focus for any input under 16px;
     kept as its own literal (not --fs-base) so this stays pinned at the
     zoom-safe floor even if the base type scale changes later. */
  font-size: 16px; min-height: var(--touch-min);
}
.composer-field input::placeholder { color: var(--text-tertiary); }
.composer-field input:focus { outline: none; }
.send-btn {
  width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--amber-500), var(--amber-600));
  color: var(--text-on-amber); border: none;
  box-shadow: var(--glow-amber-sm);
}
.send-btn:disabled { opacity: 0.35; box-shadow: none; }
.attach-btn {
  width: 36px; height: 36px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: none; color: var(--text-tertiary);
}
/* -- C2-007: voice inline with composer -------------------------------------- */
.mic-btn {
  width: 36px; height: 36px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: none; color: var(--text-tertiary);
  transition: background var(--dur-fast) var(--ease-standard), color var(--dur-fast) var(--ease-standard);
}
.mic-btn svg { width: 18px; height: 18px; }
.mic-btn.unavailable { opacity: 0.35; }
.mic-btn.listening {
  color: #fff;
  background: radial-gradient(circle at 35% 30%, var(--violet-400), var(--violet-700) 75%);
  box-shadow: var(--glow-violet-sm);
}
/* -- C2-009: one trigger reveals Quick actions + Create image together --- */
.tray-single { margin-bottom: var(--space-2); text-align: right; }
.tray-single > .qa-trigger {
  width: auto; display: inline-flex; margin: 0; gap: 6px;
  min-height: 34px; padding: 0 var(--space-4); border-radius: var(--radius-pill);
  background: var(--surface-card); border: 1px solid var(--border-violet-soft);
  font-size: var(--fs-xs);
}
.tray-single > .qa-trigger:hover { background: var(--violet-glow-soft); border-color: var(--border-violet); }
.tray-single .collapsible-panel {
  transition: max-height var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-standard);
}
.tray-single .collapsible-panel .quick-actions { margin: var(--space-3) 0 0; }
.create-image-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  margin-top: var(--space-2); padding: 0 var(--space-4); min-height: 44px;
  border-radius: var(--radius-md);
  background: var(--surface-card); border: 1px solid var(--border-violet-soft);
  color: var(--text-primary); font-size: var(--fs-sm); font-weight: 700;
  transition: background var(--dur-fast) var(--ease-standard), border-color var(--dur-fast) var(--ease-standard);
}
.create-image-row:hover { background: var(--surface-card-hover); border-color: var(--border-violet); }
.create-image-row svg { width: 16px; height: 16px; color: var(--violet-400); flex-shrink: 0; }
.create-image-hint { margin-left: auto; font-size: var(--fs-2xs); font-weight: 600; color: var(--text-tertiary); text-transform: none; letter-spacing: normal; }
/* -- Voice status: only present while actively listening/transcribing -------- */
.voice-status[hidden] { display: none; }
.voice-status {
  display: flex; align-items: center; gap: var(--space-2);
  margin-bottom: var(--space-2); padding: 8px 14px;
  border-radius: var(--radius-pill);
  background: var(--surface-card); border: 1px solid var(--border-hairline);
  font-size: var(--fs-xs); font-weight: 700; color: var(--text-secondary);
}
.voice-status.listening { color: var(--status-ready); border-color: var(--border-violet); }
.listening-wave { display: flex; align-items: center; gap: 2px; height: 16px; }
.listening-wave span { width: 2px; background: var(--violet-400); border-radius: 2px; animation: wave 1s ease-in-out infinite; }
.listening-wave span:nth-child(1){height:6px;animation-delay:0s;}
.listening-wave span:nth-child(2){height:12px;animation-delay:.1s;}
.listening-wave span:nth-child(3){height:16px;animation-delay:.2s;}
.listening-wave span:nth-child(4){height:10px;animation-delay:.3s;}
.listening-wave span:nth-child(5){height:14px;animation-delay:.4s;}
@keyframes wave { 0%,100%{transform:scaleY(.5);} 50%{transform:scaleY(1);} }

/* -- Threads ---------------------------------------------------------------- */
/* C2-004: New Thread + Search + filter chips read as one compact cluster
   instead of three separately-spaced blocks. */
.thread-toolbar { display: flex; flex-direction: column; gap: var(--space-2); }
.new-thread-btn {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; min-height: 52px; padding: 0 var(--space-4);
  border-radius: var(--radius-lg);
  background: linear-gradient(135deg, rgba(242,163,92,0.18), rgba(242,163,92,0.08));
  border: 1px solid var(--border-amber);
  color: var(--amber-100); font-weight: 700; font-size: var(--fs-base);
  box-shadow: var(--glow-amber-sm);
}
.new-thread-btn .plus-wrap { display: flex; align-items: center; gap: 10px; }
.search-row { display: flex; gap: var(--space-2); }
.search-field {
  flex: 1; display: flex; align-items: center; gap: 8px;
  background: var(--surface-input); border: 1px solid var(--border-hairline);
  border-radius: var(--radius-md); padding: 0 14px; min-height: var(--touch-min);
}
.search-field svg { width: 16px; height: 16px; color: var(--text-tertiary); flex-shrink: 0; }
.search-field input { flex: 1; background: none; border: none; color: var(--text-primary); font-size: 16px; min-height: var(--touch-min); }
.search-field input:focus { outline: none; }
.filter-chip-row { display: flex; gap: var(--space-2); overflow-x: auto; padding: var(--space-1) 0; scrollbar-width: none; -ms-overflow-style: none; }
.filter-chip-row::-webkit-scrollbar { display: none; width: 0; height: 0; }
.filter-chip {
  flex-shrink: 0; padding: 7px 14px; border-radius: var(--radius-pill);
  background: var(--surface-card); border: 1px solid var(--border-hairline);
  font-size: var(--fs-xs); color: var(--text-secondary); font-weight: 600;
}
.filter-chip.active { background: var(--violet-glow-soft); border-color: var(--border-violet); color: var(--violet-200); }

.thread-list { display: flex; flex-direction: column; gap: var(--space-3); }
.thread-card { display: flex; align-items: center; gap: var(--space-3); width: 100%; text-align: left; }
.thread-glyph {
  width: 42px; height: 42px; border-radius: var(--radius-sm); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--violet-glow-soft); color: var(--violet-300, var(--violet-400));
}
.thread-body { flex: 1; min-width: 0; }
.thread-title-row { display: flex; align-items: center; gap: 6px; }
.thread-title { font-weight: 700; font-size: var(--fs-base); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thread-preview { font-size: var(--fs-xs); color: var(--text-tertiary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 2px; }
.thread-meta { flex-shrink: 0; text-align: right; }
.thread-time { font-size: 10px; color: var(--text-tertiary); }
.unread-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--amber-500); margin: 4px 0 0 auto; box-shadow: 0 0 6px var(--amber-glow); }

.empty-state { display: flex; flex-direction: column; align-items: center; text-align: center; padding: var(--space-8) var(--space-5); }
.empty-glyph {
  width: 88px; height: 88px; border-radius: 50%; margin-bottom: var(--space-4);
  display: flex; align-items: center; justify-content: center;
  background: var(--violet-glow-soft); border: 1px solid var(--border-violet-soft);
}
.empty-glyph svg { width: 34px; height: 34px; color: var(--violet-400); }

/* -- Persona sliders --------------------------------------------------------- */
.archetype-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
.archetype-btn {
  display: flex; align-items: center; gap: 10px; min-height: var(--touch-min);
  padding: 0 14px; border-radius: var(--radius-md);
  background: var(--surface-card); border: 1px solid var(--border-hairline);
  color: var(--text-secondary); font-size: var(--fs-sm); font-weight: 600;
}
.archetype-btn svg { width: 16px; height: 16px; }
.archetype-btn.active {
  background: var(--violet-glow-soft); border-color: var(--border-violet); color: var(--violet-200);
  box-shadow: var(--glow-violet-sm);
}
.slider-block { margin-top: var(--space-2); }
.slider-label-row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: var(--space-2); }
.slider-value { font-size: var(--fs-lg); font-weight: 700; color: var(--amber-300); }
input[type="range"] {
  -webkit-appearance: none; appearance: none; width: 100%; height: 6px;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--violet-600), var(--amber-500) var(--slider-pct, 50%), var(--border-hairline-strong) var(--slider-pct, 50%));
  min-height: var(--touch-min);
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 22px; height: 22px; border-radius: 50%;
  background: var(--text-primary); border: 3px solid var(--amber-500);
  box-shadow: var(--glow-amber-sm); cursor: pointer; margin-top: -8px;
}
input[type="range"]::-moz-range-thumb {
  width: 22px; height: 22px; border-radius: 50%; background: var(--text-primary);
  border: 3px solid var(--amber-500); box-shadow: var(--glow-amber-sm); cursor: pointer;
}
input[type="range"]::-moz-range-track { height: 6px; border-radius: var(--radius-pill); background: var(--border-hairline-strong); }
.slider-ends { display: flex; justify-content: space-between; font-size: var(--fs-2xs); color: var(--text-tertiary); margin-top: 4px; }

.field-block { margin-top: var(--space-4); }
.field-label { font-size: var(--fs-xs); letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-tertiary); font-weight: 700; margin-bottom: 8px; display: block; }
.text-input, .textarea-input, .select-input {
  width: 100%; background: var(--surface-input); border: 1px solid var(--border-hairline-strong);
  border-radius: var(--radius-md); padding: 0 14px; min-height: var(--touch-min);
  color: var(--text-primary);
  /* Zoom-safe floor -- see .composer-field input above. */
  font-size: 16px;
}
.textarea-input { padding: 12px 14px; min-height: 88px; resize: vertical; }
.text-input:focus, .textarea-input:focus, .select-input:focus { outline: none; border-color: var(--border-violet); }
.segmented { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-2); }
.segmented .archetype-btn { justify-content: center; padding: 0 6px; }

.notice-row {
  display: flex; gap: 10px; align-items: flex-start;
  padding: var(--space-4); border-radius: var(--radius-md);
  background: rgba(242,163,92,0.08); border: 1px solid var(--border-amber-soft);
}
.notice-row svg { width: 18px; height: 18px; color: var(--amber-300); flex-shrink: 0; margin-top: 1px; }
.notice-row.violet { background: var(--violet-glow-soft); border-color: var(--border-violet-soft); }
.notice-row.violet svg { color: var(--violet-400); }

/* -- Access / capability list ------------------------------------------------ */
.cap-list { display: flex; flex-direction: column; gap: var(--space-2); }
.cap-row {
  display: flex; align-items: center; gap: var(--space-3);
  min-height: 60px; padding: var(--space-2) var(--space-1); width: 100%; text-align: left;
  border-radius: var(--radius-md);
}
.cap-row:hover { background: var(--surface-card); }
.cap-icon {
  width: 40px; height: 40px; border-radius: var(--radius-sm); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-card-strong); color: var(--text-secondary);
}
.cap-icon svg { width: 18px; height: 18px; }
.cap-icon.ready { color: var(--status-ready); }
.cap-body { flex: 1; min-width: 0; }
.cap-title { font-weight: 700; font-size: var(--fs-base); }
.cap-sub { font-size: var(--fs-xs); margin-top: 2px; }
.cap-sub.ready { color: var(--status-ready); }
.cap-sub.unavailable { color: var(--status-unavailable); }
.cap-sub.sealed { color: var(--status-sealed); }
.cap-chev { color: var(--text-tertiary); flex-shrink: 0; }

/* -- Access directory --------------------------------------------------- */
.audited-banner {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-4); border-radius: var(--radius-lg);
  background: rgba(242,163,92,0.08); border: 1px solid var(--border-amber);
}
.audited-banner .shield { width: 38px; height: 38px; border-radius: 50%; flex-shrink: 0; display: flex; align-items: center; justify-content: center; background: rgba(242,163,92,0.16); }
.audited-banner .shield svg { width: 18px; height: 18px; color: var(--amber-300); }
.dir-refresh-btn { margin-left: auto; flex-shrink: 0; align-self: center; }
.dir-refresh-btn:disabled { opacity: 0.55; cursor: not-allowed; }
.dir-refresh-btn:disabled:hover { background: var(--surface-card); color: var(--text-secondary); }
.dir-refresh-btn.is-refreshing svg { animation: spin-slow 0.8s linear infinite; }
.summary-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2); }
.summary-cell { text-align: center; padding: var(--space-4) var(--space-2); }
.summary-num { font-size: var(--fs-xl); font-weight: 800; }
.summary-label { font-size: var(--fs-2xs); color: var(--text-tertiary); text-transform: uppercase; letter-spacing: 0.06em; margin-top: 4px; }
.lifecycle-row { display: flex; align-items: center; justify-content: space-between; }
.access-card { display: flex; align-items: flex-start; gap: var(--space-3); }
.access-avatar {
  width: 44px; height: 44px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: var(--fs-base);
  background: var(--violet-glow-soft); color: var(--violet-200); border: 1px solid var(--border-violet-soft);
}
.access-body { flex: 1; min-width: 0; }
.access-top-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; row-gap: 6px; }
.access-name { font-weight: 700; font-size: var(--fs-base); }
.access-sub { font-size: var(--fs-xs); color: var(--text-tertiary); margin-top: 2px; }
.access-actions { display: flex; gap: var(--space-2); margin-top: var(--space-3); }
.footer-note { text-align: center; padding: var(--space-4) 0 var(--space-2); }
.footer-note .lock-line { display: flex; align-items: center; justify-content: center; gap: 6px; font-size: var(--fs-xs); color: var(--text-tertiary); }

/* -- Access Ledger (Enrollment History) ----------------------------------
   The Directory/History toggle and "Open Directory" link are navigation
   between two permanently separate sibling screens -- neither ever
   inlines the other's data. Filter chips reuse .tab-row/.tab-btn (the
   existing active-chip treatment) verbatim rather than a parallel style. */
.ledger-hero {
  position: relative; overflow: hidden; display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-5); border-radius: var(--radius-xl);
  background: linear-gradient(135deg, rgba(139,124,245,0.14), rgba(242,163,92,0.06));
  border: 1px solid var(--border-violet); box-shadow: var(--glow-violet-sm);
}
.ledger-hero .shield {
  width: 52px; height: 52px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(242,163,92,0.16); border: 1px solid var(--border-amber-soft);
}
.ledger-hero .shield svg { width: 24px; height: 24px; color: var(--amber-300); }
.ledger-hero .eyebrow { color: var(--amber-300); }
.ledger-hero-corner {
  position: absolute; top: var(--space-4); right: var(--space-4); text-align: right;
  font-size: 9px; line-height: 1.5; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-tertiary);
}
.ledger-control-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.ledger-control-row .field-label { margin: 0; }
.ledger-toggle { display: flex; gap: var(--space-2); }
.ledger-toggle-btn {
  flex: 1; min-height: var(--touch-min); border-radius: var(--radius-pill); padding: 0 var(--space-4);
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  background: var(--surface-card); border: 1px solid var(--border-hairline);
  color: var(--text-secondary); font-size: var(--fs-sm); font-weight: 600;
  transition: all var(--dur-fast) var(--ease-standard);
}
.ledger-toggle-btn svg { width: 15px; height: 15px; }
.ledger-toggle-btn.active { color: var(--amber-300); border-color: var(--border-amber); box-shadow: var(--glow-amber-sm); }
.ledger-date-label {
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-tertiary); margin: var(--space-5) 0 var(--space-3) 0;
}
.ledger-timeline { display: flex; flex-direction: column; gap: var(--space-4); }
.ledger-row { display: flex; align-items: stretch; gap: var(--space-2); }
.ledger-time { flex-shrink: 0; width: 56px; padding-top: 3px; text-align: right; font-size: var(--fs-2xs); color: var(--text-tertiary); }
.ledger-rail { position: relative; flex-shrink: 0; width: 14px; display: flex; justify-content: center; }
.ledger-rail::before {
  content: ""; position: absolute; top: 0; bottom: calc(var(--space-4) * -1); left: 50%;
  width: 2px; background: var(--border-hairline-strong); transform: translateX(-50%);
}
.ledger-row:last-child .ledger-rail::before { bottom: 0; }
.ledger-dot { position: relative; z-index: 1; margin-top: 5px; width: 10px; height: 10px; border-radius: 50%; box-shadow: 0 0 0 4px var(--bg-deep); }
.ledger-dot.ready { background: var(--status-ready); }
.ledger-dot.failed { background: var(--status-failed); }
.ledger-dot.restricted { background: var(--status-restricted); }
.ledger-dot.pending { background: var(--status-pending); }
.ledger-dot.unavailable { background: var(--status-unavailable); }
.ledger-card { flex: 1; min-width: 0; display: flex; align-items: flex-start; gap: var(--space-3); }
.ledger-card .access-avatar { width: 40px; height: 40px; font-size: var(--fs-sm); }
.ledger-card .access-name { font-size: var(--fs-sm); }
.ledger-card .access-sub { font-family: ui-monospace, monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ledger-role-col { flex-shrink: 0; text-align: right; }
.ledger-filter-row { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* -- Usage & Capacity ------------------------------------------------------ */
.ring-row { display: flex; align-items: center; gap: var(--space-5); }
.usage-ring { flex-shrink: 0; }
.ring-copy { flex: 1; }
.ring-state { font-size: var(--fs-lg); font-weight: 800; letter-spacing: -0.01em; }
.ring-meta-row { display: flex; justify-content: space-between; margin-top: 4px; }
.stat-card-row { display: flex; flex-direction: column; gap: var(--space-2); }
.stat-card { display: flex; align-items: center; gap: var(--space-3); }
.stat-icon {
  width: 40px; height: 40px; border-radius: var(--radius-sm); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; background: var(--surface-card-strong); color: var(--violet-400);
}
.stat-body { flex: 1; }
.stat-value { font-size: var(--fs-lg); font-weight: 800; }
.stat-note { font-size: var(--fs-2xs); color: var(--text-tertiary); }

/* -- Certified Passage ------------------------------------------------------ */
.authority-hero { display: flex; flex-direction: column; align-items: center; text-align: center; padding-top: var(--space-4); }
.shield-wrap { width: 168px; height: 168px; display: flex; align-items: center; justify-content: center; margin: var(--space-5) 0; position: relative; }
.shield-wrap svg { width: 100%; height: 100%; filter: drop-shadow(0 0 34px var(--violet-glow)) drop-shadow(0 0 20px var(--amber-glow-soft)); }
.step-list { display: flex; flex-direction: column; }
.step-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-4) 0; border-bottom: 1px solid var(--border-hairline); width: 100%; text-align: left; }
.step-row:last-child { border-bottom: none; }
.step-num {
  width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--violet-glow-soft); border: 1px solid var(--border-violet-soft); color: var(--violet-200);
}
.step-num svg { width: 18px; height: 18px; }
.step-title { font-weight: 700; font-size: var(--fs-base); }
.step-sub { font-size: var(--fs-xs); color: var(--text-tertiary); margin-top: 2px; }

/* -- Forge Execution --------------------------------------------------------- */
.mission-chip-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2); }
.mission-chip { text-align: center; padding: var(--space-3) var(--space-2); border-radius: var(--radius-md); background: var(--surface-sunken); }
.mission-chip .mc-label { font-size: 9px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-tertiary); }
.mission-chip .mc-value { font-size: var(--fs-xs); font-weight: 800; margin-top: 4px; }
.progress-track { width: 100%; height: 8px; border-radius: var(--radius-pill); background: var(--surface-sunken); overflow: hidden; margin-top: var(--space-3); }
.progress-fill { height: 100%; border-radius: var(--radius-pill); background: linear-gradient(90deg, var(--amber-600), var(--amber-300)); box-shadow: var(--glow-amber-sm); transition: width var(--dur-slow) var(--ease-out); }
.progress-pct { font-size: var(--fs-2xl); font-weight: 800; }
.mission-log-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) 0; border-top: 1px solid var(--border-hairline); }
.mission-log-tag { font-size: 9px; font-weight: 800; letter-spacing: 0.06em; color: var(--amber-300); flex-shrink: 0; width: 44px; }

/* -- Tasks / Memory ----------------------------------------------------------- */
.task-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--border-hairline); }
.task-row:last-child { border-bottom: none; }
.task-check {
  width: 26px; height: 26px; border-radius: 8px; flex-shrink: 0;
  border: 1.5px solid var(--border-hairline-strong); display: flex; align-items: center; justify-content: center;
  background: var(--surface-sunken);
}
.task-check.done { background: var(--status-ready); border-color: var(--status-ready); }
.task-check.done svg { width: 14px; height: 14px; color: #06210f; }
.task-title { font-size: var(--fs-base); font-weight: 600; }
.task-title.done { color: var(--text-tertiary); text-decoration: line-through; }
.task-sub { font-size: var(--fs-2xs); color: var(--text-tertiary); margin-top: 2px; }

.memory-card { display: flex; align-items: flex-start; gap: var(--space-3); }
.memory-icon {
  width: 38px; height: 38px; border-radius: var(--radius-sm); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; background: rgba(242,163,92,0.12); color: var(--amber-300);
}
.memory-icon svg { width: 17px; height: 17px; }

/* -- PRISM placeholder --------------------------------------------------- */
.prism-hero { display: flex; flex-direction: column; align-items: center; text-align: center; padding-top: var(--space-6); }

/* -- Restricted (fail-closed) state --------------------------------------- */
.restricted-wrap { display: flex; flex-direction: column; align-items: center; text-align: center; padding: var(--space-9) var(--space-5); }
.restricted-glyph {
  width: 92px; height: 92px; border-radius: 50%; margin-bottom: var(--space-5);
  display: flex; align-items: center; justify-content: center;
  background: var(--status-restricted-bg); border: 1px solid rgba(240,149,92,0.35);
}
.restricted-glyph svg { width: 36px; height: 36px; color: var(--status-restricted); }

/* -- Owner console list ----------------------------------------------------- */
.console-grid { display: flex; flex-direction: column; gap: var(--space-3); }
.console-item { display: flex; align-items: center; gap: var(--space-4); width: 100%; text-align: left; }
.console-icon {
  width: 46px; height: 46px; border-radius: var(--radius-md); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, rgba(242,163,92,0.16), rgba(139,124,245,0.1));
  border: 1px solid var(--border-amber-soft);
}
.console-icon svg { width: 20px; height: 20px; color: var(--amber-300); }

/* -- Owner Access Completion R2, Track A: Owner root entry rows --------- */
/* Access and History as dedicated, always-present Owner rows (never grid
   tiles alongside Usage/Passage/Forge — see screens-owner.js's own note
   on why "Access Ledger" was retired from OWNER_CONSOLE_ITEMS). */
.owner-entry-rows { display: flex; flex-direction: column; gap: var(--space-3); }
.owner-entry-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  width: 100%; text-align: left; min-height: 64px;
}
.owner-entry-main { display: flex; align-items: center; gap: var(--space-3); flex: 1; min-width: 0; }
.owner-entry-label { font-weight: 700; font-size: var(--fs-base); color: var(--text-primary); }
.owner-entry-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 26px; height: 26px; padding: 0 8px; border-radius: var(--radius-pill);
  background: var(--amber-500); color: var(--text-on-amber);
  font-size: var(--fs-xs); font-weight: 800; font-variant-numeric: tabular-nums;
}
.tester-preview-row { border-color: var(--border-violet-soft); }
.tester-preview-row .owner-entry-label { color: var(--violet-400); }

/* -- Owner Access Completion R2, Track G: Tester Preview banner --------- */
.preview-banner {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: 10px var(--space-4);
  background: var(--role-tester-bg); border-bottom: 1px solid var(--border-violet-soft);
}
.preview-banner-label {
  display: flex; align-items: center; gap: 6px;
  font-size: var(--fs-2xs); font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--role-tester);
}
.preview-banner-label svg { width: 14px; height: 14px; }
.preview-banner-exit {
  flex-shrink: 0; padding: 6px 14px; border-radius: var(--radius-pill);
  background: transparent; border: 1px solid var(--border-violet);
  color: var(--role-tester); font-size: var(--fs-xs); font-weight: 700; cursor: pointer;
}
.preview-banner-exit:hover { background: var(--violet-glow-soft); }

/* -- Role switcher (demo convenience — clearly not part of real product) - */
.demo-strip {
  margin: var(--space-3) var(--safe-inset) 0;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: repeating-linear-gradient(135deg, rgba(168,151,247,0.08), rgba(168,151,247,0.08) 8px, rgba(168,151,247,0.03) 8px, rgba(168,151,247,0.03) 16px);
  border: 1px dashed var(--border-violet);
  flex-shrink: 0;
}
.demo-strip .demo-label { font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--violet-400); font-weight: 800; }
.demo-row { display: flex; align-items: center; justify-content: space-between; margin-top: 6px; gap: var(--space-3); }
.role-toggle { display: flex; background: var(--surface-sunken); border-radius: var(--radius-pill); padding: 3px; gap: 3px; }
.role-toggle button {
  border: none; background: none; padding: 7px 14px; border-radius: var(--radius-pill);
  font-size: var(--fs-xs); font-weight: 700; color: var(--text-tertiary);
  min-height: 34px;
}
.role-toggle button.active { background: var(--violet-600); color: #fff; }
.demo-strip .demo-desc { font-size: 10px; color: var(--text-tertiary); }

/* -- Collapsible group: consolidates a row of standalone controls into one
   compact trigger, expanding to the full set on demand. Shared by the
   identity strip, the section tab row, and Chat's quick actions. -------- */
.collapsible-trigger {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  background: none; border: none; padding: 0; margin: 0; width: 100%;
  color: inherit; font: inherit; text-align: left; cursor: pointer;
  transition: opacity var(--dur-fast) var(--ease-standard);
}
.collapsible-trigger:active { opacity: 0.7; }
.collapsible-chevron { display: inline-flex; flex-shrink: 0; color: var(--text-tertiary); transition: transform var(--dur-base) var(--ease-out); }
.collapsible-chevron svg { width: 14px; height: 14px; }
.collapsible.open .collapsible-chevron { transform: rotate(90deg); }
.collapsible-panel { max-height: 0; opacity: 0; overflow: hidden; transition: max-height var(--dur-base) var(--ease-out), opacity var(--dur-fast) var(--ease-standard); }
.collapsible.open .collapsible-panel { opacity: 1; }

/* Identity strip: collapsed to its label only; expands in place. */
.demo-strip .collapsible-panel.open,
.demo-strip.open .collapsible-panel { margin-top: var(--space-2); }

/* Section tab row: one active-styled trigger replaces the full pill row;
   the remaining sections expand beneath it. */
.tab-row-collapsible { padding: var(--space-2) var(--safe-inset) var(--space-4); }
.tab-row-collapsible .collapsible-trigger {
  width: auto; display: inline-flex; gap: 8px;
  min-height: 40px; padding: 0 16px; border-radius: var(--radius-pill);
  color: var(--text-on-amber);
  background: linear-gradient(135deg, var(--amber-500), var(--amber-600));
}
.tab-row-options { display: flex; flex-wrap: wrap; gap: var(--space-2); padding-top: var(--space-2); }

/* Chat quick actions: one trigger replaces the 4-tile row; the tiles expand
   beneath it, still individually tappable exactly as before. */
.qa-trigger {
  margin-top: var(--space-4);
  min-height: 44px; padding: 0 var(--space-4); border-radius: var(--radius-md);
  background: var(--surface-card); border: 1px solid var(--border-hairline);
  color: var(--text-secondary); font-size: var(--fs-sm); font-weight: 700;
}
.qa-trigger:hover { background: var(--surface-card-hover); color: var(--text-primary); }
.qa-trigger-label { display: inline-flex; align-items: center; gap: 8px; }
.qa-trigger-label svg { width: 16px; height: 16px; color: var(--violet-400); }
.quick-actions-collapsible .collapsible-panel .quick-actions { margin: var(--space-3) 0 0; }

/* -- Toast ------------------------------------------------------------------- */
#toast-root { position: fixed; bottom: 100px; left: 50%; transform: translateX(-50%); z-index: 999; display: flex; flex-direction: column; gap: 8px; align-items: center; width: 100%; max-width: var(--phone-max); padding: 0 var(--space-5); pointer-events: none; }
.toast {
  pointer-events: auto;
  padding: 12px 18px; border-radius: var(--radius-md);
  background: rgba(18,15,26,0.95); border: 1px solid var(--border-amber-soft);
  color: var(--text-primary); font-size: var(--fs-sm); box-shadow: var(--shadow-elevated);
  animation: toast-in var(--dur-base) var(--ease-out);
}
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }

/* -- Skeleton / loading -------------------------------------------------- */
.skeleton { background: linear-gradient(90deg, var(--surface-card) 25%, var(--surface-card-hover) 50%, var(--surface-card) 75%); background-size: 200% 100%; animation: shimmer 1.6s ease-in-out infinite; border-radius: var(--radius-sm); }
@keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }

/* ==========================================================================
   RESPONSIVE — IPAD (~760-920 content width, two-column admin allowed)
   ========================================================================== */
@media (min-width: 720px) {
  .device-frame { max-width: var(--tablet-max); }
  .status-strip { display: none; }
  .chrome-row { padding-top: 22px; }
  :root { --safe-inset: 32px; }
  .two-col { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: var(--space-6); align-items: start; }
  .quick-actions { grid-template-columns: repeat(4, 1fr); }
  .home-greeting { padding-top: var(--space-8); }
  .crystal-wrap { width: 210px; height: 210px; }
  .crystal { width: 128px; height: 128px; }
  .summary-grid { grid-template-columns: repeat(3, 1fr); }
  .bottom-dock { max-width: 420px; margin: 0 auto; }
}

/* ==========================================================================
   RESPONSIVE — DESKTOP
   --------------------------------------------------------------------------
   The Golden UI shell is capped and centered rather than stretched edge to
   edge; the bottom dock remains the single consistent navigation surface
   across breakpoints (Gate 5: "iPad/desktop adaptation does not become a
   stretched phone"). Owner admin/detail screens gain a two-column layout.

   R4-S1: gated on (hover: hover) and (pointer: fine) -- a real mouse/
   trackpad, not a touchscreen -- in addition to min-width. iPad landscape
   (e.g. 1180x820) legitimately overlaps common desktop browser widths in
   raw pixels, so width alone can never reliably tell a tablet held
   sideways apart from a desktop window of the same width; a viewport
   width threshold with no pointer/hover check was catching iPad landscape
   and forcing it into this floating boxed desktop-card treatment instead
   of the plain full-bleed tablet composition the >=720px block already
   gives iPad portrait. A touch-primary device at this width now falls
   through to that same tablet block unchanged; a real desktop is
   unaffected. */
@media (min-width: 1024px) and (hover: hover) and (pointer: fine) {
  #app-root { align-items: center; padding: var(--space-8) 0; }
  .device-frame {
    max-width: 1040px;
    height: calc(100vh - 64px);
    height: calc(100dvh - 64px);
    border-radius: var(--radius-xl);
    border: 1px solid var(--border-hairline);
    box-shadow: var(--shadow-elevated);
    overflow: hidden;
  }
  .two-col { grid-template-columns: 1.3fr 1fr; }
  .bottom-dock { max-width: 460px; margin: 0 auto; }
}

/* -- Small phone safety (never below 360 in practice, but guard anyway) --- */
@media (max-width: 359px) {
  :root { --safe-inset: 14px; }
  .quick-actions { grid-template-columns: repeat(2, 1fr); }
}
/* Authenticated first-use choreography. Uses Golden materials and type tokens. */
.vivian-first-use{position:fixed;inset:0;z-index:1000;display:grid;place-items:center;padding:max(22px,env(safe-area-inset-top)) 18px max(22px,env(safe-area-inset-bottom));background:rgba(5,4,10,.88);backdrop-filter:blur(22px)}
.vivian-first-use[hidden]{display:none}.vivian-first-use-card{width:min(100%,520px);max-height:calc(100dvh - 44px);overflow:auto;padding:28px;border:1px solid var(--line-soft);border-radius:28px;background:linear-gradient(145deg,rgba(37,28,49,.96),rgba(13,11,22,.98));box-shadow:var(--shadow-lg);scrollbar-width:none;-ms-overflow-style:none}.vivian-first-use-card::-webkit-scrollbar{display:none;width:0;height:0}
.vivian-first-use-card h1{margin-top:8px}.vivian-first-use-card form{display:grid;gap:12px;margin-top:20px}.vivian-first-use-card label{display:grid;gap:6px;color:var(--text-secondary);font-size:.78rem}.vivian-first-use-card input,.vivian-first-use-card select,.vivian-first-use-card textarea{width:100%;border:1px solid var(--line-soft);border-radius:14px;padding:12px;background:rgba(255,255,255,.055);color:var(--text-primary);font:inherit}.vivian-first-use-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:20px}.vivian-first-use-status{min-height:1.4em;margin-top:12px;color:var(--text-secondary)}

/* -- Confirmation / notification overlay (J-004) -------------------------
   .vivian-overlay/.vivian-dialog (js/ui.js confirmInSurface, js/main.js
   notifications) had no rules at all: an unstyled div appended to
   #screen-root rendered as a plain block at the end of the screen's
   content instead of a modal, which is what "confirmations stack
   down-page" actually was. Modeled on the existing .vivian-first-use
   full-screen-overlay pattern immediately above, using this file's own
   design tokens instead of that block's undefined --line-soft/--shadow-lg. */
.vivian-overlay {
  position: fixed; inset: 0; z-index: 1001;
  display: grid; place-items: center;
  padding: max(var(--space-5), env(safe-area-inset-top)) var(--space-5)
    max(var(--space-5), env(safe-area-inset-bottom));
  background: rgba(5, 4, 10, 0.72);
  backdrop-filter: blur(12px);
}
.vivian-dialog {
  width: min(100%, 420px);
  max-height: calc(100dvh - 88px);
  overflow: auto;
  padding: var(--space-6);
  border: 1px solid var(--border-hairline-strong);
  border-radius: var(--radius-lg);
  background: var(--bg-deep-2);
  box-shadow: var(--shadow-elevated);
  /* Native-feeling modal: scrolls when content is long, never shows the
     host browser's own scrollbar chrome. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.vivian-dialog::-webkit-scrollbar { display: none; width: 0; height: 0; }
.vivian-dialog .dialog-actions { display: flex; gap: var(--space-3); justify-content: flex-end; }
.vivian-dialog .dialog-actions .btn { width: auto; flex: 0 0 auto; }

/* -- Cold-start materialization sequence ----------------------------------
   Witness directive: a cold-start-only launch ceremony (darkness -> emergence
   -> full crystal presence) that plays before boot()'s existing await chain
   resolves (js/main.js), then cross-dissolves into whatever boot() already
   renders next (router.js's playScreenEnter() already fades the next screen
   in on every render -- this overlay only needs to fade itself OUT, the
   reveal-not-swap feel comes from those two fades overlapping). Modeled on
   the existing .vivian-overlay full-screen pattern above (fixed inset,
   backdrop scrim) and .crystal-wrap's materialize/flash language, using only
   this file's own tokens -- no new color values invented. Sits above
   .vivian-overlay (1001) and .vivian-first-use (1000) since it is the very
   first thing a cold start can show. */
.vivian-launch {
  position: fixed; inset: 0; z-index: 1200;
  overflow: hidden;
  cursor: default;
  opacity: 1;
  /* Full-bleed law: the screen IS the viewport -- no inner padding, no
     content box, no "fit inside a rectangle" treatment. A radial violet-to-
     near-black backdrop sits under everything so first paint is never flat
     dead black and never a seam before the poster/video appear. */
  background: radial-gradient(circle at 50% 46%, var(--violet-glow-soft) 0%, rgba(5,4,10,0.96) 75%);
  transition: opacity var(--dur-slow) var(--ease-out);
}
.vivian-launch[data-dismissing] { opacity: 0; }
.vivian-launch-poster,
.vivian-launch-video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  /* Cover, not contain: scales until both screen dimensions are covered,
     cropping the sides as needed -- the same square master already covers
     any device viewport correctly without a per-device export. 48% keeps
     the crystal's focal point clear of the top safe area / Dynamic Island. */
  object-position: 50% 48%;
}
.vivian-launch-poster { z-index: 1; }
.vivian-launch-video {
  z-index: 2;
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-out);
}
.vivian-launch-video[data-visible] { opacity: 1; }
.vivian-launch-hint {
  position: absolute; left: 0; right: 0; bottom: max(var(--space-7), env(safe-area-inset-bottom));
  display: flex; justify-content: center;
  font-size: 0.78rem; letter-spacing: 0.04em; color: var(--text-secondary);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-standard);
  pointer-events: none;
}
.vivian-launch-hint[data-visible] { opacity: 0.8; }
@media (prefers-reduced-motion: reduce) {
  .vivian-launch,
  .vivian-launch-video { transition: none; }
}

/* CUT3-C: compact, native disclosures. Geometry never gates authority. */
.composer-field input { min-width: 0; }
.send-btn { width: 48px; height: 48px; transition: opacity 180ms ease, background 180ms ease; }
.attach-btn, .mic-btn { width: 44px; height: 44px; }
.access-console, .ledger-console, .claim-console { margin: 12px 0; padding: 16px; border-radius: 22px; min-width: 0; }
.access-console > summary, .ledger-console > summary, .claim-console > summary { cursor: pointer; min-height: 56px; overflow-wrap: anywhere; }
.access-console > summary { min-height: 64px; }
summary .t-xs, .ledger-select-row .t-xs { display: block; margin-top: 6px; }
.ledger-select-row { display: flex; align-items: center; gap: 12px; min-height: 64px; overflow-wrap: anywhere; }
.ledger-select-row input { width: 24px; height: 24px; margin: 10px; flex-shrink: 0; }
.ledger-console .access-actions { flex-wrap: wrap; }
.ledger-console button { min-height: 44px; white-space: normal; }
.claim-console .access-card { margin-top: 8px; padding: 10px; border-radius: 16px; }
.claim-console .access-avatar { width: 36px; height: 36px; flex-shrink: 0; }
.claim-console .access-actions:empty { display: none; }
.access-body, .access-name, .access-sub { min-width: 0; overflow-wrap: anywhere; }
.access-top-row { flex-wrap: wrap; }
.from-system .msg-meta { color: var(--text-secondary); }
.ledger-console[open] > :not(summary), .claim-console[open] > :not(summary), .access-console[open] > :not(summary) { animation: corrective-reveal 180ms ease-out; }
@keyframes corrective-reveal { from { opacity: .4; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .send-btn { transition: none; }
  .ledger-console[open] > :not(summary), .claim-console[open] > :not(summary), .access-console[open] > :not(summary) { animation: none; }
}
.send-status:empty { display: none; }
.send-status { margin: 6px 14px 0; overflow-wrap: anywhere; }

/* ==========================================================================
   OWNER ACCESS FINAL CORRECTIVE R3
   --------------------------------------------------------------------------
   Deliberately appended last: several rules below intentionally override
   same-specificity R2 rules (.access-console/.claim-console padding and
   radius), and CSS resolves equal specificity by source order.
   ========================================================================== */

/* FIX-001: the HTML hidden attribute must win visually. R2 declared
   display:inline-flex unconditionally, which beats the UA's
   [hidden]{display:none} rule -- so a pending count of 0 was still
   painted as a literal "0" beside Access while el.hidden read true. */
.owner-entry-badge {
  display: none;
  align-items: center;
  justify-content: center;
  min-width: 26px;
  height: 26px;
  padding: 0 8px;
  border-radius: var(--radius-pill);
  background: var(--amber-500);
  color: var(--text-on-amber);
  font-size: var(--fs-xs);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.owner-entry-badge:not([hidden]) { display: inline-flex; }

/* FIX-002/003/004: canonical collapsible Access sections. */
.access-section {
  margin: 12px 0;
  padding: 0;
  overflow: hidden;
  border-radius: var(--radius-lg);
}
.access-section > summary {
  list-style: none;
  min-height: 56px;
  padding: 10px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  cursor: pointer;
}
.access-section > summary::-webkit-details-marker { display: none; }
.access-section.active-access-section > summary { min-height: 64px; }

.access-section-title {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.access-section-title strong {
  color: var(--text-primary);
  font-size: var(--fs-base);
}
.access-section-meta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  flex-shrink: 0;
}
.access-section-chevron {
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
  transition: transform var(--dur-fast) var(--ease-standard);
}
.access-section[open] > summary .access-section-chevron {
  transform: rotate(90deg);
}
.access-section-body {
  padding: 0 14px 14px;
}
/* CLOSED MUST MEAN CLOSED. The UA hides a closed <details>'s content, but an
   author `display:` declaration on that content overrides the UA rule, so the
   rows below kept painting while the section reported open === false -- the
   same "declaration defeats the state-based hiding mechanism" defect as the
   R2 badge (FIX-001), caught by measuring client rects instead of trusting
   the .open flag. Both collapsibles are guarded explicitly. */
.access-section:not([open]) > .access-section-body { display: none; }

/* FIX-005: member -> Devices [N] nested expansion. */
.member-devices {
  margin-top: var(--space-3);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface-sunken);
}
.member-devices > summary {
  list-style: none;
  min-height: 44px;
  padding: 0 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  cursor: pointer;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  font-weight: 700;
}
.member-devices > summary::-webkit-details-marker { display: none; }
.member-devices-chevron {
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform var(--dur-fast) var(--ease-standard);
}
.member-devices[open] > summary .member-devices-chevron {
  transform: rotate(90deg);
}
.member-devices .access-device-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: 0 10px 10px;
}
.member-devices:not([open]) > .access-device-list { display: none; }
.access-device-row {
  min-height: 88px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "name state"
    "action action";
  align-items: center;
  gap: 8px 12px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-hairline);
  background: var(--surface-card);
}
.access-device-name {
  grid-area: name;
  min-width: 0;
  overflow-wrap: anywhere;
  font-weight: 700;
}
.access-device-row > .t-xs { grid-area: state; }
.access-device-row > button {
  grid-area: action;
  justify-self: end;
  min-height: 44px;
}

/* FIX-011/012: route-scoped compact width. Only the Owner Access
   completion surfaces and Tester Preview get the narrow mobile-native
   frame -- unrelated Vivian routes keep their existing tablet layout.
   The .device-frame.owner-access-compact pair outranks the plain
   .device-frame rules in the tablet/desktop media blocks above. */
@media (min-width: 720px) and (max-width: 899px) {
  .device-frame.owner-access-compact { max-width: 560px; }
}
@media (min-width: 900px) {
  .device-frame.owner-access-compact { max-width: 600px; }
}
