/* ═══════════════════════════════════════════════════════════════════════════
   ATTENTION LABS — live demo surface
   Design system, 2026-07-15 revamp.

   Concept: ONE INSTRUMENT. The orb is the constant center of gravity across
   every stage — it never moves, never swaps. Idle, warmup, and live are states
   of the same composition, so the page reads as a single listening instrument
   rather than a sequence of screens (which is the product's own story).

   Type carries the split personality on purpose: the machine speaks in small
   engineered mono labels; the verdict — the product's one human sentence —
   is set large and light in a serif. Perception in, language out.

   JS contract (do not rename): body.state-* / .connected / .debug /
   .audio-only / .mode-native; stage-* ids; .visible .changing .settling
   .switching .is-active .active .warming .done .live .ticking .stage-anim.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Fonts (self-hosted, latin variable subsets) ─────────────────────────── */
@font-face {
  font-family: "Fraunces";
  src: url("./fonts/Fraunces-normal.woff2") format("woff2");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("./fonts/Fraunces-italic.woff2") format("woff2");
  font-weight: 300;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("./fonts/JetBrainsMono-normal.woff2") format("woff2");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

/* ── Tokens ──────────────────────────────────────────────────────────────── */
:root {
  --bg: #0c1615;
  --bg-lift: #0e1a1b;
  --ink: #f2f0ea;
  --muted: #96a69c;
  --faint: #5f6d64;
  --hairline: rgba(234, 241, 218, 0.13);
  --hairline-soft: rgba(234, 241, 218, 0.075);
  --neon: #d6f20f;
  --neon-ink: #131a00;
  --violet: #8f89e8;
  --surface: rgba(234, 241, 218, 0.045);
  --surface-up: rgba(234, 241, 218, 0.075);

  --serif: "Fraunces", "Iowan Old Style", Georgia, serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", sans-serif;

  --track: 0.18em;          /* mono label letterspacing */
  --track-wide: 0.26em;     /* brand + eyebrow tier */
  --ease: cubic-bezier(0.23, 1, 0.32, 1);

  /* verdict + legend share ONE state color vocabulary (panel finding m1) */
  --verdict: var(--muted);
}
body.state-device     { --verdict: #e6f3b8; }
body.state-device .con-pred { text-shadow: 0 0 36px rgba(214, 242, 15, 0.22); }
body.state-responding { --verdict: var(--ink); }
body.state-talking    { --verdict: var(--ink); }
body.state-thinking   { --verdict: var(--ink); }
body.state-human      { --verdict: #b9b5f2; }
body.state-silent     { --verdict: var(--muted); }

/* ── Base ────────────────────────────────────────────────────────────────── */
* { box-sizing: border-box; }
html, body { height: 100%; overflow-x: clip; }
body {
  margin: 0;
  /* one warm key light where the orb lives, one violet floor glow: the two
     state colors exist in the room, so every element sits in the same light */
  background:
    radial-gradient(900px 640px at 50% 26%, rgba(214, 242, 15, 0.05), transparent 62%),
    radial-gradient(1500px 900px at 50% 112%, rgba(86, 80, 200, 0.055), transparent 62%),
    var(--bg);
  background-attachment: fixed;
  color: var(--ink);
  font: 15px/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
  /* clip, not hidden: decorative overflow (orb vignette) must never create
     scrollable width — clip removes the scroll mechanism entirely */
  overflow-x: clip;
}
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
[hidden] { display: none !important; }  /* author display rules must never resurrect hidden stages */
:focus-visible { outline: 2px solid var(--neon); outline-offset: 3px; border-radius: 4px; }

.mono-tiny {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--faint);
}
.eyebrow {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 16px;
}

/* ── Top bar ─────────────────────────────────────────────────────────────── */
.topbar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 32px;
  pointer-events: none;             /* children re-enable */
}
.topbar > * { pointer-events: auto; }
.brandmark {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: var(--track-wide);
  color: var(--muted);
  user-select: none;
}
.brand-mark { width: 17px; height: 15px; fill: var(--neon); }
.float-setup { display: flex; gap: 8px; align-items: center; }
.pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;              /* a pill never wraps — it shortens (mobile hides the switch label) */
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--muted);
  background: var(--surface);
  border: 1px solid var(--hairline-soft);
  border-radius: 999px;
  padding: 7px 13px;
  backdrop-filter: blur(6px);
  box-shadow: inset 0 1px 0 rgba(244, 248, 226, 0.055);
}
.pill .dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--faint);
  transition: background 0.3s;
}
body.connected .pill .dot { background: var(--neon); }
.pill-btn { transition: border-color 0.2s, color 0.2s; }
/* Modality truth chip: whenever the session runs without camera, say so
   loudly and persistently — a silent camera fallback once cost a whole
   operator test pass (2026-07-15). Hidden entirely in camera mode. */
.audio-only-pill { display: none; }
body.audio-only .audio-only-pill {
  display: inline-flex;
  color: var(--amber, #e8b23f);
  border-color: color-mix(in srgb, var(--amber, #e8b23f) 55%, transparent);
}
.pill-btn:hover { border-color: var(--hairline); color: var(--ink); }
#modeSwitchBtn { display: none; align-items: center; gap: 7px; }
body.connected #modeSwitchBtn { display: inline-flex; }  /* session-only: idle uses the segmented control */
#modeSwitchBtn.switching { pointer-events: none; opacity: 0.75; }
#modeSwitchBtn.switching #modeSwitchIco { animation: mode-spin 0.9s linear infinite; }
@keyframes mode-spin { to { transform: rotate(360deg); } }

.pill-icon { padding: 7px 9px; }

/* ── Device panel ────────────────────────────────────────────────────────── */
.dev-panel {
  position: fixed;
  top: 58px;
  right: 32px;
  z-index: 45;
  width: min(300px, calc(100vw - 32px));
  background: var(--bg-lift);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  padding: 16px;
  display: none;
  flex-direction: column;
  gap: 12px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(244, 248, 226, 0.06);
}
.dev-panel.visible { display: flex; }
.dev-row { display: flex; flex-direction: column; gap: 5px; }
.dev-label {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--faint);
}
/* Native dropdown popups paint their own (often white) background while
   inheriting our light ink — options were invisible (operator find). Paint
   both explicitly. */
.dev-panel select option { background: var(--bg-lift); color: var(--ink); }
.dev-panel select {
  font: 12.5px/1.4 var(--sans);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 8px 10px;
  width: 100%;
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%2396a69c' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
}
.dev-level {
  height: 3px;
  border-radius: 2px;
  background: var(--hairline-soft);
  overflow: hidden;
}
.dev-level-fill {
  height: 100%;
  width: 0%;
  background: var(--neon);
  border-radius: 2px;
  transition: width 0.12s linear;
}
.dev-restart {
  margin-top: 2px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 9px 0;
  transition: color 0.2s, border-color 0.2s;
}
.dev-restart:hover { color: var(--ink); border-color: var(--muted); }

/* ── The single-axis stage ───────────────────────────────────────────────── */
.var-console {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow-x: clip;   /* the orb vignette may exceed narrow viewports; clip it here so the document never gains width */
}
.var-stage {
  flex: 1;
  display: grid;
  grid-template-rows: minmax(0, auto) auto;
  grid-template-areas: "orb" "panel";
  justify-items: center;
  align-content: center;
  gap: 24px;
  padding: 80px 24px 120px;         /* clears topbar + instrument bar */
}
.con-right { grid-area: orb; display: grid; place-items: center; }
.con-left  { grid-area: panel; width: min(1020px, 94vw); text-align: center; }

/* Stage content crossfade — the orb never participates. */
.stage-anim > .con-left { animation: stage-in 0.42s var(--ease); }
/* Page entrance: the orb leads (immediate fade-in), the copy follows a beat
   later. The canvas is blank until the module boots, so ::after paints a
   placeholder disc matching the idle orb; orb.js adds .orb-live and the
   placeholder dissolves into the live render. */
.orb-wrap { animation: orb-in 0.55s ease-out both; }
/* The orb holds the stage ALONE for a beat (~0.7s), then everything else —
   header, copy, legend — fades in around it. Landing-page load only:
   these one-shot animations run at element insertion; mid-session stage
   switches keep the immediate 0.42s crossfade above. */
.brandmark, .float-setup, .legend {
  animation: stage-in 0.6s 0.7s var(--ease) both;
}
.stage-anim > .con-left:has(#stage-idle:not([hidden])) { animation: stage-in 0.6s 0.7s var(--ease) both; }
@keyframes orb-in {
  from { opacity: 0; transform: scale(0.965); }
  to   { opacity: 1; transform: none; }
}
.orb-wrap::after {
  content: "";
  position: absolute;
  inset: 6%;
  border-radius: 50%;
  /* Whisper-quiet placeholder: barely-there glow, soft edges, and its own
     fast fade-in (pure CSS at first paint — adds zero latency; the canvas
     boots underneath regardless and dissolves it via .orb-live). */
  background:
    radial-gradient(circle at 40% 36%, rgba(214, 242, 15, 0.055), transparent 60%),
    radial-gradient(circle at 50% 55%, rgba(120, 190, 200, 0.04), transparent 72%);
  filter: blur(6px);
  animation: orb-ghost-in 0.35s ease-out both;
  transition: opacity 0.5s ease;
  pointer-events: none;
}
@keyframes orb-ghost-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.orb-wrap.orb-live::after { opacity: 0; animation: none; }
@keyframes stage-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ── Orb ─────────────────────────────────────────────────────────────────── */
.orb-wrap {
  position: relative;
  width: clamp(220px, 36vh, 420px);
  aspect-ratio: 1;
}
.orb-wrap::before {                  /* quiet ambient vignette, no hard glow */
  content: "";
  position: absolute;
  inset: -22%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(214, 242, 15, 0.055), transparent 64%);
  pointer-events: none;
}
.orb-canvas { width: 100%; height: 100%; display: block; }
#orb, #soundBars { display: none; }  /* legacy stubs — state classes only */

/* ── Set-aside chip + session ledger (under the orb, SAA mode only) ──────── */
.aside-chip {
  position: absolute;
  left: 50%;
  bottom: 2%;
  transform: translate(-50%, 4px);
  opacity: 0;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: var(--track);
  color: var(--violet);
  background: var(--surface);
  border: 1px solid var(--hairline-soft);
  border-radius: 999px;
  padding: 7px 14px;
  pointer-events: none;
  white-space: nowrap;
  transition: opacity 0.18s var(--ease), transform 0.18s var(--ease);
}
.aside-chip.show { opacity: 1; transform: translate(-50%, 0); }
.turn-ledger {
  position: absolute;
  left: 50%;
  /* Tucked just under the wrap: the live verdict headline sits ~16px below
     the orb on small viewports, so the marks stay inside that band. */
  bottom: -0.75rem;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 7px;
  pointer-events: none;
}
/* Deliberately quiet: the ledger is a trace you notice when you look for it,
   not a element that competes with the orb. Shape carries the meaning (dot
   answered, dash held back), so presence can stay low: no glow, small marks,
   low opacity. */
.tl-mark {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--neon);
  opacity: 0.4;
  animation: markIn 0.22s var(--ease);
}
.tl-mark.aside {
  width: 11px;
  height: 2px;
  border-radius: 2px;
  background: var(--violet);
  opacity: 0.45;
}
@keyframes markIn {
  from { transform: scale(1.4); opacity: 0; }
}
/* Native mode shows none of this — the contrast is the demo. */
body.mode-native .aside-chip,
body.mode-native .turn-ledger { display: none; }
@media (prefers-reduced-motion: reduce) {
  .aside-chip { transform: translate(-50%, 0); }
  .tl-mark { animation: none; }
}

/* ── Idle ────────────────────────────────────────────────────────────────── */
.con-hero {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(22px, 2.6vw, 38px);
  line-height: 1.16;
  letter-spacing: -0.01em;
  margin: 0 0 32px;
  text-wrap: balance;
}
.con-sub {
  color: var(--muted);
  font-size: 15.5px;
  max-width: 52ch;
  margin: 0 auto 24px;
  text-wrap: balance;
}
.action-row {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 16px;
}
.action-row > * { height: 52px; }
.mode-seg {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--surface);
  box-shadow: inset 0 1px 0 rgba(244, 248, 226, 0.055);
}
.mode-opt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  border-radius: 999px;
  padding: 11px 24px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--muted);
  transition: background 0.25s, color 0.25s;
}
.mode-opt svg { width: 15px; height: 15px; flex: none; color: var(--faint); transition: color 0.25s; }
.mode-opt[aria-checked="true"] {
  background: var(--surface-up);
  color: var(--ink);
  box-shadow: inset 0 0 0 1px rgba(214, 242, 15, 0.35);
}
.mode-opt[aria-checked="true"] svg { color: var(--neon); }
.mode-opt:hover { color: var(--ink); }

.cta-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--neon-ink);
  background: var(--neon);
  border-radius: 999px;
  padding: 15px 34px;
  box-shadow: 0 0 26px rgba(214, 242, 15, 0.13), inset 0 1px 0 rgba(255, 255, 246, 0.28);
  transition: transform 0.18s var(--ease), box-shadow 0.18s;
}
.cta-primary:hover { transform: translateY(-1px); box-shadow: 0 0 34px rgba(214, 242, 15, 0.24), 0 6px 24px rgba(214, 242, 15, 0.18), inset 0 1px 0 rgba(255, 255, 246, 0.28); }
.cta-primary:active { transform: none; }
.cta-primary .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }

/* ── Permissions / reconnecting ──────────────────────────────────────────── */
#stage-permissions .con-hero,
#stage-reconnecting .con-hero { font-size: clamp(22px, 2.6vw, 34px); margin-bottom: 12px; }
#stage-permissions .con-sub,
#stage-reconnecting .con-sub { margin-bottom: 0; }

/* ── Warmup ──────────────────────────────────────────────────────────────── */
/* Same serif voice and near-verdict scale as the live state word, so the
   stage change reads as the same slot updating, never a shrunk headline
   (panel blocker: warmup title rendered ~half the verdict size). */
.con-hero-mid {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(27px, 3.8vw, 44px);
  margin: 0 0 24px;
}
.warm-steps {
  list-style: none;
  margin: 0 auto 24px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: min(420px, 86vw);
}
.warm-steps li {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--faint);
  transition: color 0.3s;
}
.warm-steps li .glyph {
  width: 6px; height: 6px; flex: none;
  border-radius: 50%;
  background: var(--hairline);
  transition: background 0.3s;
}
.warm-steps li.active { color: var(--ink); }
.warm-steps li.active .glyph { background: var(--neon); animation: pulse-dot 1.1s ease-in-out infinite; }
.warm-steps li.done { color: var(--muted); }
.warm-steps li.done .glyph { background: var(--muted); }
.warm-steps li .pct { display: none; margin-left: auto; font-variant-numeric: tabular-nums; }
body.debug .warm-steps li .pct { display: inline; }
@keyframes pulse-dot { 50% { opacity: 0.35; } }
.warmup-bar {
  width: min(420px, 86vw);
  height: 2px;
  margin: 0 auto 8px;
  background: var(--hairline-soft);
  border-radius: 1px;
  overflow: hidden;
}
.warmup-bar .bar-fill {
  height: 100%;
  width: 0%;
  background: var(--neon);
  box-shadow: 0 0 12px rgba(214, 242, 15, 0.4);
  transition: width 0.5s var(--ease);
}
.warmup-pct {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: var(--track);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* ── Live: the verdict ───────────────────────────────────────────────────── */
.con-live { display: flex; flex-direction: column; align-items: center; }
.native-eyebrow {
  display: none;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: var(--track);
  color: var(--faint);
  margin-bottom: 10px;
}
body.mode-native .native-eyebrow { display: inline-block; }
.con-pred {
  max-width: 820px;
  margin-inline: auto;
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(32px, 5vw, 56px);
  line-height: 1.08;
  letter-spacing: -0.01em;
  margin: 0;
  min-height: 1.2em;                /* desktop: every verdict is one line; mobile overrides to 2 lines */
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--verdict);
  transition: color 0.45s var(--ease), opacity 0.3s;
  text-wrap: balance;
}
.con-pred.settling { opacity: 0.4; }
#verdictTick { margin-top: 6px; }

/* live meters: one quiet mono strip under the verdict */
.stats {
  max-width: 440px;
  margin-inline: auto;
  display: flex;
  gap: 40px;
  justify-content: center;
  border-top: 1px solid var(--hairline-soft);
  margin-top: 24px;
  padding-top: 16px;
}
.stat { text-align: center; }
.stat-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 5px;
}
.stat-val {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
body.audio-only .stat:first-child { display: none; }  /* faces: camera sessions only */

/* SAA toggle — a labeled switch, not a form checkbox */
#saaRow {
  margin-top: 16px !important;
  color: var(--muted);
  letter-spacing: 0.12em;
}
#saaRow input {
  appearance: none;
  width: 30px !important;
  height: 17px !important;
  border-radius: 999px;
  border: 1px solid var(--hairline);
  background: var(--surface);
  position: relative;
  transition: background 0.25s, border-color 0.25s;
  flex: none;
  margin: 0;
}
#saaRow input::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--muted);
  transition: transform 0.25s var(--ease), background 0.25s;
}
#saaRow input:checked { background: rgba(214, 242, 15, 0.16); border-color: rgba(214, 242, 15, 0.4); }
#saaRow input:checked::after { transform: translateX(13px); background: var(--neon); }

/* fabricated-counter theater — permanently off the public surface */
.tokens-block { display: none !important; }

/* Redundancy discipline: surfaces never repeat each other. The verdict owns
   the conversational moment — the whole meters strip is a debug instrument
   (operator 2026-07-15: the public page needs no metrics). */
.stats { display: none; }
body.debug .stats { display: flex; }
.stats .stat:last-child { display: none; }
body.debug .stats .stat:last-child { display: block; }
.warmup-pct { display: none; }
body.debug .warmup-pct { display: inline; }

/* ── Suggestion cue (director's card, above the instrument bar) ─────────── */
/* Instruction PILL (testers liked the pill affordance — 2026-07-16 feedback):
   a single rounded surface, readable size, the prompt legible at a glance. */
.suggestion {
  position: fixed;
  left: 50%;
  bottom: 148px;
  transform: translate(-50%, 14px);
  z-index: 30;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
  text-align: center;
  width: max-content;
  max-width: min(620px, 92vw);
}
.suggestion.visible { opacity: 1; transform: translate(-50%, 0); }
.suggestion-body {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 14px 26px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--bg-lift) 88%, transparent);
  border: 1px solid var(--hairline);
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.32), inset 0 1px 0 rgba(244, 248, 226, 0.06);
  backdrop-filter: blur(10px);
}
.suggestion-text {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--muted);
  transition: opacity 0.3s;
}
.suggestion-text.changing { opacity: 0; }
.suggestion-quote {
  display: block;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 22px;
  line-height: 1.25;
  color: var(--ink);
}

/* Directive callout — the pivotal "look/turn away" step (operator feedback
   2026-07-19): testers were missing the small caption and reading the quote
   below it as their own line, so this step needs to read as a clear
   instruction, not fine print. Bigger/weightier caption in lime, a small
   pulsing cue dot (mirrors .warm-steps li.active .glyph), and a lime-tinted
   ring on the pill. Text still wraps inside the existing pill, so this can't
   overlap neighboring chrome — only the pill's own size grows. */
.suggestion--directive .suggestion-body {
  box-shadow:
    0 10px 34px rgba(0, 0, 0, 0.32),
    inset 0 1px 0 rgba(244, 248, 226, 0.06),
    0 0 0 1px rgba(214, 242, 15, 0.30),
    0 0 22px rgba(214, 242, 15, 0.10);
}
.suggestion--directive .suggestion-text {
  font-size: 16px;
  font-weight: 700;
  color: var(--neon);
  letter-spacing: 0.03em;
}
.suggestion--directive .suggestion-text::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 8px;
  vertical-align: middle;
  border-radius: 50%;
  background: var(--neon);
  animation: pulse-dot 1.1s ease-in-out infinite;
}

/* ── Instrument bar (bottom, session-only) ───────────────────────────────── */
.bottom-controls {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 35;
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 32px;
  border-top: 1px solid var(--hairline-soft);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(10px);
}
body.connected .bottom-controls { display: flex; }
.legend { display: flex; gap: 22px; }
.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: var(--track);
  text-transform: uppercase;
  /* The legend is the only key to the demo's colour language, so it has to
     survive a projector and an off-axis laptop screen. --faint measured 3.38:1
     against the bottom bar at 10px (sampled from a live screenshot 2026-07-24),
     under the 4.5:1 small-text floor; --muted measures 7.21:1 and keeps the
     inactive/active contrast step intact (--ink stays ~16:1). */
  color: var(--muted);
  transition: color 0.3s;
}
.legend-swatch { width: 7px; height: 7px; border-radius: 50%; background: var(--faint); transition: background 0.3s, box-shadow 0.3s; }
.legend-item[data-state="human"] .legend-swatch { background: color-mix(in srgb, var(--violet) 45%, var(--bg)); }
.legend-item[data-state="device"] .legend-swatch { background: color-mix(in srgb, var(--neon) 40%, var(--bg)); }
.legend-item.is-active { color: var(--ink); }
.legend-item.is-active .legend-swatch { box-shadow: 0 0 0 3px rgba(226, 240, 234, 0.10); }
.legend-item.is-active[data-state="human"] .legend-swatch { background: var(--violet); }
.legend-item.is-active[data-state="device"] .legend-swatch { background: var(--neon); }
.legend-item.is-active[data-state="silent"] .legend-swatch { background: var(--muted); }
/* One-shot swatch pulse on the first set-aside dismissal of a session. */
.legend-item.flash .legend-swatch { animation: swatchPulse 0.9s var(--ease); }
@keyframes swatchPulse {
  30% { box-shadow: 0 0 10px var(--violet); background: var(--violet); }
}
@media (prefers-reduced-motion: reduce) {
  .legend-item.flash .legend-swatch { animation: none; }
}

.stop-btn {
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--hairline);
  padding: 10px 20px;
  font-size: 10.5px;
}
.stop-btn:hover { color: var(--ink); border-color: var(--muted); box-shadow: none; transform: none; }

/* ── Camera thumb (docked above the bar, quiet chrome) ───────────────────── */
.cam-wrap {
  position: fixed;
  right: 32px;
  bottom: 92px;
  z-index: 34;
  width: 132px;
  aspect-ratio: 4 / 3;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--hairline);
  background: var(--bg-lift);
  display: none;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(244, 248, 226, 0.06);
}
body.connected .cam-wrap.live { display: block; }
body.audio-only .cam-wrap { display: none !important; }
.cam-wrap video { width: 100%; height: 100%; object-fit: cover; display: block; transform: scaleX(-1); }
.cam-placeholder { position: absolute; inset: 0; display: grid; place-items: center; color: var(--faint); }
.cam-tag {
  position: absolute;
  left: 7px; bottom: 6px;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: var(--track);
  color: var(--ink);
  background: rgba(12, 22, 21, 0.62);
  border-radius: 5px;
  padding: 2px 7px;
  backdrop-filter: blur(4px);
}

/* ── Toast ───────────────────────────────────────────────────────────────── */
.toast {
  position: fixed;
  left: 50%;
  top: 80px;
  transform: translate(-50%, -8px);
  z-index: 60;
  max-width: min(480px, 88vw);
  font-size: 13.5px;
  color: var(--ink);
  background: var(--bg-lift);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  padding: 11px 18px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s, transform 0.3s var(--ease);
  text-align: center;
}
.toast.visible { opacity: 1; transform: translate(-50%, 0); }

/* ── Turn-cap modal ──────────────────────────────────────────────────────── */
.turn-cap-modal { position: fixed; inset: 0; z-index: 80; display: none; }
.turn-cap-modal.visible { display: block; }
.turn-cap-modal__backdrop { position: absolute; inset: 0; background: rgba(8, 14, 13, 0.72); backdrop-filter: blur(4px); }
.turn-cap-modal__card {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: min(400px, 88vw);
  text-align: center;
  background: var(--bg-lift);
  border: 1px solid var(--hairline);
  border-radius: 18px;
  padding: 38px 32px 32px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(244, 248, 226, 0.06);
}
.turn-cap-modal__title {
  font-family: var(--serif);
  font-weight: 300;
  font-size: 28px;
  margin: 0 0 8px;
}
.turn-cap-modal__body { color: var(--muted); font-size: 15.5px; margin: 0 0 24px; }
/* Secondary step under the restart button: quiet by design so [Restart Demo]
   stays the primary action, but always visible and always a real link. */
.turn-cap-modal__next {
  /* own row: the CTA above is inline-flex, so an inline-block link lands
     beside it and overruns the card (caught in screenshot review) */
  display: block;
  width: fit-content;
  margin: 20px auto 0;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  border-bottom: 1px solid var(--hairline);
  padding-bottom: 3px;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.turn-cap-modal__next:hover,
.turn-cap-modal__next:focus-visible { color: var(--neon); border-color: var(--neon); }

/* ── Debug instruments (?debug only) ─────────────────────────────────────── */
.con-slider, #confCaption { display: none; }
body.debug .con-slider { display: block; width: min(460px, 88vw); margin: 22px auto 0; }
body.debug #confCaption { display: block; margin-top: 10px; }
.csl-labels { display: flex; justify-content: space-between; margin-bottom: 8px; }
.lbl-left, .lbl-right { display: flex; gap: 8px; align-items: baseline; }
.lbl-val { font-family: var(--mono); font-size: 12px; color: var(--ink); font-variant-numeric: tabular-nums; }
.solid-track { position: relative; height: 4px; border-radius: 2px; background: var(--hairline-soft); }
.solid-fill { position: absolute; inset: 0 auto 0 0; border-radius: 2px; background: var(--neon); opacity: 0.85; }
.solid-thumb {
  position: absolute;
  top: 50%;
  width: 14px; height: 14px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--ink);
  border: 2px solid var(--bg);
  cursor: ew-resize;
}
.thumb-val {
  position: absolute;
  top: -24px; left: 50%;
  transform: translateX(-50%);
  font-family: var(--mono);
  font-size: 10px;
  color: var(--muted);
}
/* debug select stage */
.select-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-bottom: 18px; }
.provider-card {
  border: 1px solid var(--hairline);
  border-radius: 14px;
  background: var(--surface);
  padding: 14px;
  text-align: left;
  display: grid;
  gap: 3px;
}
.provider-card.is-active { border-color: var(--neon); background: var(--surface-up); }
.pc-label { font-weight: 600; }
.pc-sub, .pc-model, .pc-tag { font-family: var(--mono); font-size: 10px; color: var(--faint); }
.select-config { display: grid; gap: 12px; text-align: left; margin-bottom: 18px; }
.cfg-row { display: flex; align-items: center; gap: 12px; }
.cfg-label { font-family: var(--mono); font-size: 10px; letter-spacing: var(--track); text-transform: uppercase; color: var(--faint); min-width: 84px; }
.seg { display: inline-flex; border: 1px solid var(--hairline); border-radius: 10px; overflow: hidden; }
.seg button { padding: 8px 14px; font-size: 12.5px; color: var(--muted); }
.seg button.is-active { background: var(--surface-up); color: var(--ink); }
.cfg-field { display: grid; gap: 6px; }
.cfg-keys { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.select-config input, .select-config textarea, .select-config select {
  font: 13px/1.4 var(--mono);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 9px 11px;
}
.req { color: var(--neon); }

/* ── Mobile ──────────────────────────────────────────────────────────────── */
@media (max-width: 760px) {
  /* bottom padding reserves the fixed cue-card band (see .suggestion below) */
  .var-stage { padding: 72px 16px 250px; gap: 16px; }
  /* header: icon-only mode switch — three chips can never fight for the row */
  #modeSwitchLbl { display: none; }
  #modeSwitchBtn { padding: 7px 10px; }
  /* bottom band: cue card left + camera right, side by side, never overlapping */
  .suggestion {
    left: 16px;
    transform: translateY(14px);
    width: calc(100vw - 148px);
    text-align: left;
  }
  .suggestion.visible { transform: translateY(0); }
  body.audio-only .suggestion { left: 50%; transform: translate(-50%, 14px); width: min(560px, 90vw); text-align: center; }
  body.audio-only .suggestion.visible { transform: translate(-50%, 0); }
  .orb-wrap { width: clamp(190px, 34vh, 300px); }
  .con-hero { font-size: clamp(21px, 5.6vw, 26px); margin-bottom: 24px; }
  .con-pred { font-size: clamp(27px, 8vw, 40px); min-height: 2.35em; }
  .mode-opt { padding: 10px 16px; }
  .action-row { gap: 12px; }
  .action-row .cta-primary { width: 100%; }
  .cta-primary.connect-big { width: 100%; }
  .stats { gap: 26px; }
  /* The cue card is position:fixed while the verdict column is in flow, so on
     a short phone (<=844px tall) the card climbed over the SAA toggle row and
     the headline's baseline. Measured 2026-07-24 at 390x844: card 555-674px,
     #saaRow 572-589px, fully covered. Sit the card in the same bottom band as
     the camera thumb (bottom:120px) and reserve that band in the stage's
     padding so flow content can never reach it. */
  .suggestion { bottom: 118px; }
  .suggestion-quote { font-size: 16.5px; }
  .suggestion--directive .suggestion-text { font-size: 13.5px; }
  .bottom-controls { flex-wrap: wrap; padding: 12px 16px; gap: 10px; }
  .legend { gap: 14px; }
  .cam-wrap { width: 96px; bottom: 120px; right: 14px; }
  .topbar { padding: 14px 16px; }
  .dev-panel { right: 16px; top: 54px; }
  .cfg-keys { grid-template-columns: 1fr; }
}

/* ── Short viewports (small laptops): keep every state inside the fold ───── */
@media (min-width: 761px) and (max-height: 780px) {
  .var-stage { gap: 16px; padding: 72px 24px 108px; }
  .orb-wrap { width: clamp(180px, 30vh, 330px); }
  .con-hero { font-size: clamp(25px, 3.2vw, 36px); }
  .con-pred { font-size: clamp(28px, 4.4vw, 48px); }
  .con-hero-mid { font-size: clamp(25px, 3.2vw, 36px); }
  .con-sub { margin-bottom: 20px; }
  .suggestion { bottom: 132px; }
}

/* ── Landscape (short + wide): the instrument rotates — orb left, panel right ── */
@media (max-height: 560px) and (min-width: 600px) {
  .var-stage {
    grid-template-areas: "orb panel";
    grid-template-columns: minmax(0, 42%) minmax(0, 58%);
    grid-template-rows: 1fr;
    align-items: center;
    justify-items: stretch;
    gap: 4vw;
    padding: 60px 5vw 76px;
  }
  .con-right { justify-self: end; }
  .orb-wrap { width: clamp(130px, 50vh, 300px); }
  .con-left { width: 100%; text-align: left; }
  .con-live { align-items: flex-start; }
  .con-pred { justify-content: flex-start; text-align: left; font-size: clamp(22px, 8vh, 40px); min-height: 1.2em; }
  .con-hero { font-size: clamp(17px, 6vh, 28px); margin-bottom: 14px; }
  .eyebrow { margin-bottom: 10px; }
  .action-row { justify-content: flex-start; }
  .action-row .cta-primary { width: auto; }
  .stats { margin-inline: 0; justify-content: flex-start; margin-top: 14px; padding-top: 12px; gap: 32px; }
  #saaRow { margin-top: 12px !important; }
  .warm-steps { margin: 0 0 14px; width: min(420px, 100%); gap: 6px; }
  .warmup-bar { margin: 0 0 8px; width: min(420px, 100%); }
  .con-hero-mid { font-size: clamp(18px, 6vh, 28px); margin-bottom: 12px; }
  .suggestion { left: 5vw; transform: translateY(10px); width: min(46vw, 420px); text-align: left; bottom: 76px; }
  .suggestion.visible { transform: translateY(0); }
  .suggestion-quote { font-size: 14.5px; }
  .suggestion--directive .suggestion-text { font-size: 12.5px; }
  .cam-wrap { width: 88px; bottom: 76px; right: 20px; }
  .bottom-controls { padding: 10px 20px; }
  .topbar { padding: 10px 20px; }
}
/* barely any height at all: the cue card yields to the instruments */
@media (max-height: 400px) {
  .suggestion { display: none; }
}

/* ── Micro viewports (<=360px wide): compact pills, full fit ─────────────── */
@media (max-width: 360px) {
  .mode-opt { padding: 9px 12px; font-size: 10px; gap: 6px; }
  .cta-primary { padding: 13px 22px; font-size: 10.5px; }
  .brandmark { font-size: 10px; letter-spacing: 0.22em; }
  .stats { gap: 20px; }
  .legend { gap: 10px; }
  .legend-item { font-size: 9px; }
}

/* ── Device safe areas (notches, home indicators) ────────────────────────── */
@supports (padding: env(safe-area-inset-left)) {
  .topbar {
    padding-left: max(32px, env(safe-area-inset-left));
    padding-right: max(32px, env(safe-area-inset-right));
    padding-top: max(16px, env(safe-area-inset-top));
  }
  .bottom-controls {
    padding-left: max(32px, env(safe-area-inset-left));
    padding-right: max(32px, env(safe-area-inset-right));
    padding-bottom: max(16px, env(safe-area-inset-bottom));
  }
  .cam-wrap { right: max(32px, env(safe-area-inset-right)); }
  @media (max-height: 560px) and (min-width: 600px) {
    .cam-wrap { right: max(20px, env(safe-area-inset-right)); }
  }
}

/* ── Motion preferences ──────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}


/* operator-request-2026-07-31: hide aside marks */
/* The timeline dots and dashes render the gate's per-utterance aside
   decisions. The operator asked for them removed: they were reading as
   noise (two dashes appearing where one was expected) and competing with
   the answer itself for attention. This hides the MARKS only - the gate
   still runs and still suppresses asides; we simply stop drawing its
   working out. Delete this block to bring them back. */
.tl-mark { display: none !important; }

/* operator-request-2026-07-31: hide the aside chip.
   It popped up to announce that an utterance was addressed to someone
   else. With the timeline marks already removed this was redundant, and
   a floating status pill competing with the answer reads as clutter.
   Display-only: the gate still classifies and still suppresses. */
/* Hidden again 2026-07-31. It was un-hidden on the theory that it was the
   instruction bubble; it is not. The bubble is .suggestion, which was never
   hidden — it appeared to be missing because the guided flow is blocked while
   a response is pending, and a stuck pending flag froze it on step 0. This
   chip is the redundant "talking to someone else" pill the operator asked to
   remove in the first place. */
.aside-chip { display: none !important; }
