/* ════════════════════════════════════════════════════════════════════════
   THE COUNCIL LINE — dogelord.com/chat — chat.css
   ────────────────────────────────────────────────────────────────────────
   Visual styling ONLY. Imports no JS. Consumes the :root HOLOTABLE token
   block defined in index.html <style> (§7). Styles every DOM id/class in
   the §3 contract and nothing else.

   Aesthetic = the dashboard HOLOTABLE world, reused verbatim:
     14px-chamfer glass panels · accent inner-stroke + corner tick · CRT
     scanlines · vignette · parallax starfield · corner reticles · per-agent
     accent theming via --d-ac (set by chat.js on #chat-room).

   The avatar #avatar-mount is the single Wan-Streamer slot: this file only
   SIZES that container; it never reaches inside it (canvas/video is owned by
   avatar.js). All HUD chrome is layered OVER the mount so the live-video swap
   needs zero CSS change here.
   ════════════════════════════════════════════════════════════════════════ */

*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%;background:var(--void);color:var(--ink-1);
  font-family:var(--mono);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
body{overflow-x:hidden}

/* ════════════════ ROOT STAGE ════════════════
   Clone of dashboard #detail drill-down: absolute inset 0 over a radial,
   normal flow + scroll body (NOT a transform-scaled fixed stage — input
   under transform:scale() feels cramped, per brief). --d-ac is set HERE by
   chat.js; everything below inherits the live accent through var(--d-ac). */
#chat-room{
  position:absolute;inset:0;
  background:var(--detail-radial);
  display:flex;flex-direction:column;align-items:center;
  gap:22px;
  padding:0 24px 64px;
  overflow-y:auto;overflow-x:hidden;
  /* --d-ac default mirrors the cyan SAARVIS token until chat.js sets it. */
}
#chat-room::-webkit-scrollbar{width:9px}
#chat-room::-webkit-scrollbar-track{background:rgba(255,255,255,.02)}
#chat-room::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--d-ac) 30%,#1a2433);border-radius:6px}
#chat-room::-webkit-scrollbar-thumb:hover{background:var(--d-ac)}

/* ════════════════ GLOBAL HUD OVERLAYS ════════════════ */

/* parallax starfield — canvas painted by chat.js (150 stars). */
#starfield{position:fixed;inset:0;z-index:1;pointer-events:none;width:100%;height:100%;display:block}

/* CRT scan drift — verbatim from dashboard. */
#scanlines{position:fixed;inset:0;z-index:60;pointer-events:none;
  background:repeating-linear-gradient(transparent 0 2px, rgba(57,211,255,0.03) 2px 3px);
  animation:scandrift 14s linear infinite;opacity:.7}
@keyframes scandrift{from{transform:translateY(0)}to{transform:translateY(3px)}}

/* vignette — verbatim. */
#vig{position:fixed;inset:0;z-index:61;pointer-events:none;
  box-shadow:inset 0 0 340px 40px rgba(2,4,9,.9)}

/* corner reticles — 26×26 L-shapes at the 4 corners. */
.bracket{position:fixed;width:26px;height:26px;border:2px solid var(--reticle-live);z-index:62;pointer-events:none}
.bracket.tl{left:14px;top:12px;border-right:0;border-bottom:0}
/* TR shifts inboard so the 26px reticle clears the fixed #sfxMute circle
   (sfx.js injects it at right:12px, 36px wide). Only TR moves. */
.bracket.tr{right:52px;top:12px;border-left:0;border-bottom:0}
.bracket.bl{left:14px;bottom:12px;border-right:0;border-top:0}
.bracket.br{right:14px;bottom:12px;border-left:0;border-top:0}

/* every interactive surface keeps a visible focus ring (a11y §8). */
button:focus-visible,
input:focus-visible,
.agent-card:focus-visible,
.pill:focus-visible,
.patch-plate:focus-visible{
  outline:2px solid color-mix(in srgb,var(--d-ac) 70%,transparent);
  outline-offset:2px}

/* ════════════════ HEADER (#d-head clone) ════════════════ */
#d-head{
  position:sticky;top:0;z-index:40;
  width:100%;max-width:1180px;
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  gap:18px;padding:20px 8px 16px;
  background:linear-gradient(180deg,rgba(7,12,22,.96) 60%,rgba(7,12,22,0));
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
#d-head .head-l{display:flex;justify-content:flex-start}
#d-head .head-c{display:flex;flex-direction:column;align-items:center;text-align:center}
/* reserve a right gutter so #mode-badge / #session-clock never sit under the
   floating #sfxMute circle (sfx.js injects it at fixed top:12px;right:12px,
   36px wide → ~48px occupied). This file must not edit sfx.js. */
#d-head .head-r{display:flex;align-items:center;justify-content:flex-end;gap:16px;
  padding-right:48px}

#agent-name{font-family:var(--display);font-weight:900;font-size:32px;letter-spacing:.16em;
  color:var(--d-ac);line-height:1;
  text-shadow:0 0 3px var(--d-ac),0 0 30px color-mix(in srgb,var(--d-ac) 30%,transparent)}
#agent-role{font-family:var(--micro);font-size:11px;letter-spacing:.30em;text-transform:uppercase;
  color:var(--ink-3);margin-top:6px}

/* BACK control — text swapped by chat.js across states ("DEMO" disabled on the
   landing roster, "⟵ ROSTER" in-call, "⟵ CALL" in CONVENE). */
#back-btn{font-family:var(--micro);font-size:11px;letter-spacing:.28em;text-transform:uppercase;
  color:var(--ink-3);border:1px solid var(--reticle-dim);background:rgba(10,16,26,.6);
  padding:9px 16px;cursor:pointer;transition:color .18s,border-color .18s,box-shadow .18s;
  clip-path:polygon(8px 0,100% 0,100% calc(100% - 8px),calc(100% - 8px) 100%,0 100%,0 8px)}
#back-btn:disabled{opacity:.55;cursor:default;box-shadow:none;
  color:var(--warn);border-color:color-mix(in srgb,var(--warn) 35%,transparent)}
#back-btn:disabled:hover{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 35%,transparent);box-shadow:none}
#back-btn:hover{color:var(--d-ac);border-color:var(--d-ac);
  box-shadow:0 0 22px -8px var(--d-ac)}

/* honesty badge — chat.js sets .live / .demo + text every turn. */
#mode-badge{display:inline-flex;align-items:center;gap:8px;
  font-family:var(--micro);font-size:11px;letter-spacing:.2em;text-transform:uppercase;
  padding:5px 12px;border:1px solid var(--reticle-dim);
  background:color-mix(in srgb,var(--d-ac) 6%,transparent);
  color:var(--ink-3);white-space:nowrap}
#mode-badge.live{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 55%,transparent);
  background:color-mix(in srgb,var(--ok) 10%,transparent)}
#mode-badge.live::before{content:"";width:7px;height:7px;border-radius:50%;
  background:var(--ok);box-shadow:0 0 10px var(--ok);animation:hb 1.7s ease-in-out infinite}
#mode-badge.demo{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 45%,transparent);
  background:color-mix(in srgb,var(--warn) 8%,transparent)}

#session-clock{font-family:var(--mono);font-size:12px;letter-spacing:.06em;color:var(--ink-2)}

@keyframes hb{0%,100%{opacity:.35}50%{opacity:1}}

/* ════════════════ STATE SELECT — CHARACTER SELECT (landing) ════════════════
   Centered roster of living glass cards (the .dp chamfer idiom). Each card
   carries its own --card-ac accent (mirrors the .caller-chip / .patch-plate
   per-data-agent accent pattern). Resting cards are dim; hover/focus/.is-awake
   "wakes" them (drop the dim, add an accent glow). chat.js mounts a cheap idle
   avatar canvas into each .card-avatar via AgentAvatar.mountCard(). */
#select-screen{position:relative;z-index:5;
  width:100%;max-width:1040px;margin-top:0;
  min-height:calc(100dvh - 132px);            /* header ~76px + room bottom gap; dvh survives iOS URL-bar */
  display:flex;flex-direction:column;align-items:center;
  justify-content:center;                     /* vertical hero centering */
  gap:clamp(20px,3.2vh,34px);
  padding-block:32px;}                         /* never kisses the sticky header when it scrolls */
#select-screen[hidden]{display:none}

/* ── SELECT hero keyframes ── */
@keyframes titlePowerOn{
  0%  {opacity:0;clip-path:inset(0 100% 0 0);
       text-shadow:0 0 0 var(--d-ac)}
  55% {opacity:1;clip-path:inset(0 0 0 0);
       text-shadow:0 0 4px var(--d-ac),0 0 60px var(--d-ac)}
  100%{opacity:1;clip-path:inset(0 0 0 0);
       text-shadow:0 0 3px var(--d-ac),0 0 30px color-mix(in srgb,var(--d-ac) 28%,transparent)}
}
@keyframes cardRise{
  0%  {opacity:0;transform:translateY(26px) scale(.90)}
  70% {opacity:1;transform:translateY(-3px) scale(1.02)}   /* springy overshoot (arcade pop) */
  100%{opacity:1;transform:translateY(0)    scale(1)}
}
@keyframes cardSweep{
  0%  {transform:translateY(-120%);opacity:0}
  15% {opacity:.9}
  85% {opacity:.9}
  100%{transform:translateY(320%);opacity:0}
}
@keyframes reactorPulse{
  0%,100%{opacity:.55;transform:scale(1)}
  50%    {opacity:1;  transform:scale(1.06)}
}
@keyframes conveneHues{
  0%{color:var(--saarvis)}25%{color:var(--hh)}50%{color:var(--nyx)}
  75%{color:var(--minidoge)}100%{color:var(--saarvis)}
}

/* AMBIENT REACTOR PULSE — sits behind the cards, re-tints live via --d-ac. */
#select-screen::before{
  content:"";position:absolute;z-index:-1;inset:-10% 0 0 0;pointer-events:none;
  background:radial-gradient(60% 46% at 50% 42%,
    color-mix(in srgb,var(--d-ac) 12%,transparent) 0%,transparent 68%);
  transition:background .4s ease;
  animation:reactorPulse 6.5s ease-in-out infinite;
  will-change:opacity,transform}

/* ── ENTRANCE choreography — driven by .entering on #select-screen ── */
#select-screen.entering #select-title{
  animation:titlePowerOn .9s cubic-bezier(.2,.9,.15,1) both}
#select-screen.entering #select-sub{
  animation:cardRise .5s ease-out both;animation-delay:.30s}
#select-screen.entering #select-demo-tag{
  animation:cardRise .45s ease-out both;animation-delay:.42s}
#select-screen.entering .agent-card{
  opacity:0;
  animation:cardRise .52s cubic-bezier(.34,1.4,.5,1) both;
  animation-delay:calc(.5s + var(--i) * .09s)}
#select-screen.entering #select-tell{
  animation:cardRise .5s ease-out both;animation-delay:1.0s}
#select-screen.entering #select-foot{
  animation:cardRise .45s ease-out both;animation-delay:1.05s}

#select-head{display:flex;flex-direction:column;align-items:center;text-align:center;gap:9px}
#select-title{font-family:var(--display);font-weight:900;font-size:30px;letter-spacing:.18em;
  color:var(--d-ac);line-height:1;
  text-shadow:0 0 3px var(--d-ac),0 0 30px color-mix(in srgb,var(--d-ac) 28%,transparent)}
#select-sub{font-family:var(--mono);font-size:13px;line-height:1.5;color:var(--ink-2);max-width:440px}
#select-demo-tag{font-family:var(--micro);font-size:10px;letter-spacing:.26em;text-transform:uppercase;
  color:var(--warn);padding:5px 13px;
  border:1px solid color-mix(in srgb,var(--warn) 40%,transparent);
  background:color-mix(in srgb,var(--warn) 8%,transparent)}

/* the roster grid — five equal portrait tracks (4 agents + Peter), centered under
   the hero title. CONVENE drops to a full-width banner on the row below (§convene). */
#agent-roster{width:100%;
  display:grid;grid-template-columns:repeat(5,1fr);gap:14px;
  align-items:stretch;}

/* CONVENE = full-width horizontal banner below the 5 face-cards (keeps the faces
   centered under the title instead of a lone wide tile pulling the row left). */
#convene-tile{grid-column:1 / -1;flex-direction:row;justify-content:center;
  align-items:center;gap:16px;padding:14px 18px}
#convene-tile .convene-avatar{width:52px;height:52px;aspect-ratio:1/1;font-size:24px}
#convene-tile .card-status,#convene-tile .card-tag,#convene-tile .card-tagline{position:static;order:3}

.agent-card{position:relative;display:flex;flex-direction:column;align-items:center;gap:10px;
  padding:18px 10px 14px;cursor:pointer;
  --card-ac:var(--d-ac);
  background:var(--glass-fill);border:0;
  -webkit-backdrop-filter:blur(14px) saturate(116%);backdrop-filter:blur(14px) saturate(116%);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--card-ac) 14%,transparent),var(--glass-litedge);
  filter:saturate(.72) brightness(.92);
  transform-style:preserve-3d;
  transition:transform .18s ease, box-shadow .22s, filter .22s;
  --rx:0deg;--ry:0deg;
  clip-path:polygon(14px 0,100% 0,100% calc(100% - 14px),calc(100% - 14px) 100%,0 100%,0 14px)}
.agent-card[data-agent="saarvis"]{--card-ac:var(--saarvis)}
.agent-card[data-agent="hh"]{--card-ac:var(--hh)}
.agent-card[data-agent="nyx"]{--card-ac:var(--nyx)}
.agent-card[data-agent="minidoge"]{--card-ac:var(--minidoge)}
.agent-card[data-agent="council"]{--card-ac:var(--saarvis)}
.agent-card[data-agent="peter"]{--card-ac:var(--peter,#fd6524)}
.agent-card::after{content:"";position:absolute;right:8px;top:8px;width:10px;height:10px;z-index:6;
  border-top:1px solid color-mix(in srgb,var(--card-ac) 40%,transparent);
  border-right:1px solid color-mix(in srgb,var(--card-ac) 40%,transparent)}

/* "wake" pose on hover / focus / chat.js .is-awake (preview the focused agent).
   Lift + parallax tilt (card-local --rx/--ry written by JS, default 0) + accent
   bloom. Compositor-only (transform/opacity). */
.agent-card:hover,.agent-card:focus-visible,.agent-card.is-awake{
  filter:none;
  transform:translateY(-6px) perspective(680px) rotateX(var(--ry)) rotateY(var(--rx));
  box-shadow:inset 0 0 0 1px var(--card-ac),var(--glass-litedge),
             0 18px 60px -20px var(--card-ac),
             0 0 70px -10px var(--card-ac)}
/* parallax pop: avatar sits forward in Z */
.agent-card:hover .card-avatar,
.agent-card:focus-visible .card-avatar,
.agent-card.is-awake .card-avatar{transform:translateZ(24px)}

/* reticle brackets: upgrade existing ::after (TR) + ADD ::before (BL) on wake. */
.agent-card::before,.agent-card::after{transition:border-color .25s,width .25s,height .25s}
.agent-card:hover::after,.agent-card:focus-visible::after,.agent-card.is-awake::after{
  border-color:var(--card-ac);width:16px;height:16px}
.agent-card:hover::before,.agent-card:focus-visible::before,.agent-card.is-awake::before{
  content:"";position:absolute;left:8px;bottom:8px;width:16px;height:16px;z-index:6;
  border-bottom:1px solid var(--card-ac);border-left:1px solid var(--card-ac)}

/* SCANLINE WHIP — the NEW .card-scan element (peer of .card-avatar), clipped to
   the portrait chamfer, sweeping the portrait region only on wake. */
.card-scan{position:absolute;left:10px;right:10px;
  top:34px;height:calc(100% - 96px);z-index:3;pointer-events:none;overflow:hidden;
  clip-path:polygon(10px 0,100% 0,100% calc(100% - 10px),calc(100% - 10px) 100%,0 100%,0 10px)}
.card-scan::after{content:"";position:absolute;left:0;right:0;height:40%;
  background:linear-gradient(180deg,transparent,
    color-mix(in srgb,var(--card-ac) 45%,transparent),transparent);
  transform:translateY(-120%);opacity:0}
.agent-card:hover .card-scan::after,
.agent-card:focus-visible .card-scan::after,
.agent-card.is-awake .card-scan::after{
  animation:cardSweep 1.1s ease-in-out}

/* ● ONLINE status — top-left, pulsing dot (reuses @keyframes hb). */
.card-status{position:absolute;left:10px;top:9px;z-index:6;
  display:inline-flex;align-items:center;gap:5px;
  font-family:var(--micro);font-size:8px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--ink-3)}
.card-status .status-dot{width:6px;height:6px;border-radius:50%;
  background:var(--card-ac);box-shadow:0 0 8px var(--card-ac);
  animation:hb 1.9s ease-in-out infinite}
.agent-card:hover .card-status,.agent-card:focus-visible .card-status,
.agent-card.is-awake .card-status{color:var(--card-ac)}

/* domain micro-tag under the role */
.card-tag{font-family:var(--micro);font-size:8px;letter-spacing:.22em;text-transform:uppercase;
  color:var(--ink-3);opacity:.72}

/* one-line tagline — space is ALWAYS reserved (in-flow at natural height); wake
   only fades opacity 0→1. Reserving the space is what stops the hover reflow:
   animating max-height grew the card and, via align-items:stretch, shifted the
   whole row. Opacity never affects layout, so nothing shifts on rollover. */
.card-tagline{opacity:0;overflow:hidden;text-align:center;
  font-family:var(--serif);font-style:italic;font-weight:300;font-size:12px;
  line-height:1.35;color:var(--ink-2);
  transition:opacity .25s ease}
.agent-card:hover .card-tagline,
.agent-card:focus-visible .card-tagline,
.agent-card:focus-within .card-tagline,
.agent-card.is-awake .card-tagline{opacity:1}

/* the card-avatar mount — sizes the AgentAvatar.mountCard() canvas. */
.agent-card .card-avatar{position:relative;width:100%;aspect-ratio:1/1;overflow:hidden;
  background:var(--well);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--card-ac) 30%,transparent);
  clip-path:polygon(10px 0,100% 0,100% calc(100% - 10px),calc(100% - 10px) 100%,0 100%,0 10px)}
.agent-card .card-avatar canvas{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;display:block}

.agent-card .card-name{font-family:var(--micro);font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-1)}
.agent-card .card-role{font-family:var(--micro);font-size:9px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3)}

/* CONVENE tile: no portrait canvas — a static accent glyph plate. */
.convene-tile{--card-ac:var(--saarvis)}
.convene-tile .convene-avatar{display:flex;align-items:center;justify-content:center;
  width:100%;aspect-ratio:1/1;font-size:40px;color:var(--card-ac);
  background:linear-gradient(180deg,color-mix(in srgb,var(--card-ac) 12%,transparent),var(--well));
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--card-ac) 30%,transparent);
  clip-path:polygon(10px 0,100% 0,100% calc(100% - 10px),calc(100% - 10px) 100%,0 100%,0 10px)}

/* ── CONVENE special styling: four-accent segmented stroke + heavier presence ── */
.convene-tile{
  background:
    linear-gradient(180deg,color-mix(in srgb,var(--saarvis) 8%,transparent),transparent),
    var(--glass-fill);
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb,var(--saarvis) 30%,transparent),
    inset 0 0 40px -20px var(--nyx),
    var(--glass-litedge)}
.convene-tile:hover,.convene-tile:focus-visible,.convene-tile.is-awake{
  box-shadow:inset 0 0 0 1px var(--saarvis),0 0 70px -12px var(--nyx),var(--glass-litedge)}

/* four-accent gradient plate under the glyph */
.convene-tile .convene-avatar{
  background:
    conic-gradient(from 0deg,
      color-mix(in srgb,var(--saarvis) 22%,transparent),
      color-mix(in srgb,var(--hh) 22%,transparent),
      color-mix(in srgb,var(--nyx) 22%,transparent),
      color-mix(in srgb,var(--minidoge) 22%,transparent),
      color-mix(in srgb,var(--saarvis) 22%,transparent)),
    var(--well)}

/* glyph cycles the four accents on wake — the ONE arcade shimmer we keep (cheap: color only) */
.convene-tile:hover .convene-avatar,
.convene-tile:focus-visible .convene-avatar,
.convene-tile.is-awake .convene-avatar{
  animation:conveneHues 4s linear infinite}

.convene-status .status-dot{background:var(--saarvis);box-shadow:0 0 8px var(--saarvis)}
.convene-tag{color:var(--saarvis);opacity:.9}

/* card recede during the FOCUS transition (chat.js adds .is-receding). */
.agent-card.is-receding{opacity:0;transform:scale(.92);filter:blur(2px);
  transition:opacity .32s ease,transform .32s ease,filter .32s ease;pointer-events:none}

/* personality TELL + voice hint (chat.js fills on hover/focus). */
#select-tell{min-height:48px;width:100%;max-width:620px;text-align:center;
  display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:12px 18px;
  background:color-mix(in srgb,var(--well) 70%,transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--d-ac) 10%,transparent);
  clip-path:polygon(12px 0,100% 0,100% calc(100% - 12px),calc(100% - 12px) 100%,0 100%,0 12px)}
#select-tell-line{font-family:var(--serif);font-style:italic;font-weight:300;
  font-size:18px;line-height:1.4;color:var(--serif-ink)}
#select-tell-voice{font-family:var(--micro);font-size:9px;letter-spacing:.24em;
  text-transform:uppercase;color:var(--d-ac)}

/* SELECT footer — control hint + honesty line. */
#select-foot{font-family:var(--micro);font-size:10px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--ink-3);text-align:center;max-width:560px}

/* the FOCUS-transition flyer — a single positioned element the JS reuses.
   Carries the chosen agent's cached portrait as a background-image; FLIP-style
   transform from the card rect into the #avatar-mount rect (§7). */
#focus-flyer{position:fixed;z-index:50;pointer-events:none;
  background-position:center;background-size:cover;background-repeat:no-repeat;
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--d-ac) 30%,transparent),
    0 0 60px -14px var(--d-ac);
  transform-origin:top left;will-change:transform,opacity;
  transition:transform .52s cubic-bezier(.2,.8,.2,1),opacity .12s ease}
#focus-flyer[hidden]{display:none}
@media (prefers-reduced-motion: reduce){
  #focus-flyer{transition:none}
}

/* ════════════════ GLASS PANEL BASE (.dp) ════════════════
   14px chamfer · backdrop blur · accent inner stroke + corner tick. */
.dp{position:relative;
  background:var(--glass-fill);
  -webkit-backdrop-filter:blur(14px) saturate(116%);backdrop-filter:blur(14px) saturate(116%);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--d-ac) 12%,transparent),var(--glass-litedge);
  clip-path:polygon(14px 0,100% 0,100% calc(100% - 14px),calc(100% - 14px) 100%,0 100%,0 14px)}
.dp::after{content:"";position:absolute;right:8px;top:8px;width:10px;height:10px;z-index:6;
  border-top:1px solid color-mix(in srgb,var(--d-ac) 40%,transparent);
  border-right:1px solid color-mix(in srgb,var(--d-ac) 40%,transparent)}

/* ════════════════ STATE B — IN-CALL TWO-SECTION LAYOUT ════════════════
   #call-layout is the row wrapper (STAGE | COMMS). It's a full-width child of
   #chat-room, sized to fill the viewport height below the sticky header so the
   avatar STAGE gets a large area. chat.js shows/hides #call-layout as the
   master IN-CALL container.

     ┌── #call-layout (flex row) ─────────────────────────────────────┐
     │  #call-stage (~60%)          │  #call-comms (~40%, own scroll)   │
     │  ┌────────────────────────┐  │  #caption                        │
     │  │      #call-frame       │  │  #transcript  (flex:1, scrolls)  │
     │  │      (avatar, fills)   │  │  #composer                       │
     │  │                        │  │  #pills-bar                      │
     │  └────────────────────────┘  │  #patch-bar                      │
     └──────────────────────────────┴──────────────────────────────────┘

   Below ~900px it becomes a column (STAGE on top, COMMS below). */
#call-layout{
  position:relative;z-index:4;
  width:100%;max-width:1180px;
  /* fill the space under the sticky header; header is ~76px + #chat-room's own
     top gap. Keep a floor so short viewports still show both panels. */
  height:min(760px,calc(100vh - 132px));min-height:480px;
  display:flex;align-items:stretch;gap:22px}
#call-layout[hidden]{display:none}

/* LEFT — STAGE: the enlarged avatar panel (the larger share). */
#call-stage{position:relative;
  flex:1 1 60%;min-width:0;
  display:flex;align-items:stretch;justify-content:center}

/* RIGHT — COMMS: caption → transcript → composer → pills → patch, stacked,
   with the transcript flexing to fill the middle and its own internal scroll. */
#call-comms{position:relative;
  flex:1 1 40%;min-width:0;
  display:flex;flex-direction:column;gap:14px;
  min-height:0;overflow:hidden}

/* ════════════════ STATE B — CALL FRAME (the avatar mount) ════════════════
   Dominant glass panel. In the two-section layout it FILLS #call-stage (its
   height comes from the flex row), so a bigger stage = a bigger avatar. We ONLY
   size the mount; avatar.js owns what's inside it (ResizeObserver + cover-fit).
   HUD chrome (badge, scan sweep, glow) layers OVER. */
#call-frame{
  position:relative;z-index:4;
  /* fill the STAGE panel; cap the width so head-and-shoulders framing doesn't
     stretch too wide in an ultra-wide stage. */
  width:100%;max-width:640px;height:100%;
  overflow:hidden;background:#05080f;
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--d-ac) 14%,transparent),var(--glass-litedge),
    0 0 60px -18px var(--d-ac);
  animation:livethrob 3.4s ease-in-out infinite}
@keyframes livethrob{
  0%,100%{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--d-ac) 14%,transparent),var(--glass-litedge),0 0 50px -22px var(--d-ac)}
  50%{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--d-ac) 22%,transparent),var(--glass-litedge),0 0 80px -16px var(--d-ac)}}

/* the WAN-STREAMER SLOT — size only; never reach inside. */
#avatar-mount{position:absolute;inset:0;z-index:1;background:#05080f}
#avatar-mount canvas,#avatar-mount video{position:absolute;inset:0;
  width:100%;height:100%;object-fit:cover;display:block}

/* holo scanlines + inner glow over the avatar (chrome, survives the swap). */
#call-frame::before{content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:repeating-linear-gradient(transparent 0 3px, rgba(57,211,255,0.04) 3px 4px);
  mix-blend-mode:screen;opacity:.5;
  box-shadow:inset 0 0 80px -20px var(--d-ac),
    inset 0 0 0 1px color-mix(in srgb,var(--d-ac) 18%,transparent)}
/* accent sweep line (livescan). */
#call-frame::after{content:"";position:absolute;left:0;right:0;top:0;height:2px;z-index:3;pointer-events:none;
  background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--d-ac) 75%,transparent),transparent);
  animation:livescan 3.6s linear infinite}
@keyframes livescan{0%{top:0;opacity:0}10%{opacity:.7}90%{opacity:.7}100%{top:100%;opacity:0}}

/* ● LIVE badge over the frame (livedot pulse). */
#live-badge{position:absolute;left:14px;top:14px;z-index:5;
  display:inline-flex;align-items:center;gap:7px;
  font-family:var(--micro);font-size:10px;letter-spacing:.22em;text-transform:uppercase;
  color:var(--d-ac);padding:5px 11px;
  background:rgba(4,7,13,.6);border:1px solid color-mix(in srgb,var(--d-ac) 35%,transparent);
  text-shadow:0 0 12px color-mix(in srgb,var(--d-ac) 60%,transparent);
  animation:hb 1.7s ease-in-out infinite}

/* ════════════════ CAPTION PLATE (spoken-line typewriter target) ════════════════ */
#caption{position:relative;z-index:4;
  width:100%;flex:0 0 auto;min-height:78px;
  display:flex;flex-direction:column;gap:9px;
  padding:18px 24px;
  background:color-mix(in srgb,var(--well) 80%,transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--d-ac) 10%,transparent);
  clip-path:polygon(12px 0,100% 0,100% calc(100% - 12px),calc(100% - 12px) 100%,0 100%,0 12px)}
#caption[hidden]{display:none}
#cap-who{font-family:var(--micro);font-size:10px;letter-spacing:.34em;text-transform:uppercase;
  color:var(--cap-ac,var(--saarvis))}
#caption .cap-line{font-family:var(--serif);font-style:italic;font-weight:300;
  font-size:25px;line-height:1.4;color:var(--serif-ink);
  text-shadow:0 2px 30px rgba(0,0,0,.7);min-height:1.4em}
/* block caret while the caption is the active spoken/typing target. */
#caption .cap-line .tcur{display:inline-block;width:9px;height:17px;margin-left:2px;
  vertical-align:-2px;background:var(--cap-ac,var(--d-ac));animation:caret 1.06s steps(1) infinite}
@keyframes caret{0%,49%{opacity:1}50%,100%{opacity:0}}

/* ════════════════ TRANSCRIPT (.dp-stream) ════════════════ */
#transcript{position:relative;z-index:4;
  width:100%;flex:1 1 0;min-height:0;overflow-y:auto;
  display:flex;flex-direction:column;gap:11px;padding:4px 6px;
  font-family:var(--mono);font-size:12px;line-height:1.7;
  -webkit-mask:linear-gradient(180deg,transparent,#000 8%,#000 90%,transparent);
  mask:linear-gradient(180deg,transparent,#000 8%,#000 90%,transparent)}
/* when empty it still holds its flex slot (a blank scroll well is fine); do NOT
   collapse to display:none, or the composer would jump up before the first turn. */
#transcript[hidden]{display:none}
#transcript::-webkit-scrollbar{width:6px}
#transcript::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--d-ac) 22%,#1a2433);border-radius:3px}

/* row grammar — chat.js builds [NAME] prefix from the fixed PERSONAS set only.
   Message rows carry .msg + (.agent | .you) and per-agent accent via --row-ac. */
.msg{display:flex;flex-direction:column;gap:3px;opacity:0;animation:feedin .4s forwards}
@keyframes feedin{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}
.msg .msg-meta{display:flex;gap:9px;font-family:var(--micro);font-size:9px;
  letter-spacing:.18em;text-transform:uppercase;color:var(--ink-3)}
.msg .msg-name{font-weight:700;color:var(--row-ac,var(--d-ac))}
.msg .msg-ts{color:var(--ink-3)}
/* agent turns: serif italic. */
.msg.agent .msg-text{font-family:var(--serif);font-style:italic;font-weight:300;
  font-size:15px;line-height:1.5;color:var(--serif-ink);max-width:92%}

/* ════════════════ RENDERED MARKDOWN (agent .msg-text.md) ════════════════
   chat.js sets .md and assigns SAFE HTML (escape-first + tag allowlist + href
   validation) via mdToSafeHtml(): <strong>/<em>/<ul>/<li>/<a>/<br> + a muted
   "Go Deeper" citations block. Keeps the HOLOTABLE serif look for the body.
   Inert for the four demo agents (they never receive .md); Peter only. */
.msg.agent .msg-text.md{display:block}
/* paragraph lines — tight spacing between blocks. */
.msg.agent .msg-text.md .md-line{margin:0 0 6px}
.msg.agent .msg-text.md .md-line:last-child{margin-bottom:0}
/* tight bullet list — hanging "•" in the active accent. */
.msg.agent .msg-text.md ul{list-style:none;margin:5px 0 6px;padding:0}
.msg.agent .msg-text.md li{position:relative;padding-left:16px;margin:0 0 3px;line-height:1.5}
.msg.agent .msg-text.md li::before{content:"•";position:absolute;left:2px;top:0;
  color:var(--d-ac);font-style:normal}
/* bold reads upright + slightly brighter so it separates from the serif italic. */
.msg.agent .msg-text.md strong{font-style:normal;font-weight:700;color:var(--ink-1)}
.msg.agent .msg-text.md em{font-style:italic}
/* links — active accent, underline-on-hover, break long URLs gracefully. */
.msg.agent .msg-text.md a{color:var(--d-ac);text-decoration:none;font-style:normal;
  word-break:break-word;transition:color .16s,text-shadow .16s}
.msg.agent .msg-text.md a:hover,
.msg.agent .msg-text.md a:focus-visible{text-decoration:underline;
  text-shadow:0 0 14px color-mix(in srgb,var(--d-ac) 55%,transparent)}
/* "Go Deeper" citations — smaller, muted, set off from the answer body. */
.msg.agent .msg-text.md .go-deeper{margin-top:9px;padding-top:8px;
  border-top:1px solid color-mix(in srgb,var(--d-ac) 16%,transparent);
  font-style:normal;font-family:var(--mono);font-size:11px;line-height:1.55;color:var(--ink-3)}
.msg.agent .msg-text.md .go-deeper-head{font-family:var(--micro);font-size:9px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--ink-3);margin-bottom:4px}
.msg.agent .msg-text.md .go-deeper .md-line{margin:0 0 3px}
.msg.agent .msg-text.md .go-deeper ul{margin:2px 0 0}
.msg.agent .msg-text.md .go-deeper a{color:var(--d-ac)}
/* user turns: mono, right-aligned, dimmer. */
.msg.you{align-items:flex-end;text-align:right}
.msg.you .msg-name{color:var(--ink-2)}
.msg.you .msg-text{font-family:var(--mono);font-size:13px;color:var(--ink-2);max-width:88%}
/* per-row accent: chat.js sets --row-ac inline via appendRow() (the persona's
   accent), which .msg-name consumes above — no data-agent attribute needed. */

/* the "thinking" / typing caret used inside a forming agent row. */
.tcur{display:inline-block;width:9px;height:17px;vertical-align:-2px;
  background:var(--row-ac,var(--d-ac));animation:caret 1.06s steps(1) infinite}
/* the big block input caret (composer / hero), per §7 recipe. */
#cursor{display:inline-block;width:15px;height:30px;background:var(--d-ac);
  animation:caret 1.06s steps(1) infinite}

/* ════════════════ COMPOSER (glass input bar) ════════════════ */
#composer{position:relative;z-index:4;
  width:100%;flex:0 0 auto;
  display:flex;align-items:stretch;gap:9px;padding:11px 12px}
#composer[hidden]{display:none}

/* shared button grammar (back/send/ptt/convene): micro uppercase, accent on hover. */
#ptt-btn,#send-btn,#convene-btn{font-family:var(--micro);font-size:11px;letter-spacing:.28em;
  text-transform:uppercase;color:var(--ink-3);
  background:rgba(6,11,20,.6);border:1px solid var(--reticle-dim);
  padding:0 18px;cursor:pointer;white-space:nowrap;transition:all .16s;
  clip-path:polygon(10px 0,100% 0,100% calc(100% - 10px),calc(100% - 10px) 100%,0 100%,0 10px)}
#ptt-btn:hover,#send-btn:hover,#convene-btn:hover{
  color:var(--d-ac);border-color:var(--d-ac);box-shadow:0 0 22px -8px var(--d-ac)}
#ptt-btn:disabled,#send-btn:disabled,#convene-btn:disabled{opacity:.4;cursor:default;box-shadow:none}

/* HOLD TO TALK — primary mic affordance; chat.js sets aria-pressed + .hot. */
#ptt-btn{flex:0 0 auto;font-weight:700;letter-spacing:.2em}
#ptt-btn[aria-pressed="true"],#ptt-btn.hot{color:var(--fail);border-color:var(--fail);
  background:color-mix(in srgb,var(--fail) 10%,transparent);
  box-shadow:0 0 26px -6px var(--fail);animation:hb 1s ease-in-out infinite}

/* mono text field. */
#text-input{flex:1;min-width:0;height:46px;
  background:rgba(4,7,13,.6);border:1px solid var(--reticle-dim);
  color:var(--ink-1);font-family:var(--mono);font-size:14px;padding:0 14px;outline:none;
  clip-path:polygon(10px 0,100% 0,100% calc(100% - 10px),calc(100% - 10px) 100%,0 100%,0 10px)}
#text-input:focus{border-color:color-mix(in srgb,var(--d-ac) 50%,transparent);
  box-shadow:0 0 0 1px color-mix(in srgb,var(--d-ac) 30%,transparent)}
#text-input::placeholder{color:var(--ink-3)}
#ptt-btn,#send-btn,#convene-btn{height:46px}

#convene-btn{color:var(--saarvis);border-color:color-mix(in srgb,var(--saarvis) 30%,transparent)}
#convene-btn:hover{color:var(--saarvis);border-color:var(--saarvis);box-shadow:0 0 22px -8px var(--saarvis)}

/* mic-unsupported fallback line (chat.js un-hides; hides #ptt-btn). */
#mic-hint{width:100%;flex:0 0 auto;text-align:center;
  font-family:var(--micro);font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3)}
#mic-hint[hidden]{display:none}

/* ════════════════ PILLS BAR (curated quick-start, in-call) ════════════════
   Sits directly beneath #composer; both inputs are visible together at all
   times (demo AND live). chat.js rebuilds .pill buttons per active agent. The
   static "TRY ASKING…" label is the honesty signal that these are curated. */
#pills-bar{position:relative;z-index:4;
  width:100%;flex:0 0 auto;
  display:flex;align-items:center;flex-wrap:wrap;gap:9px;padding:2px 12px}
#pills-bar[hidden]{display:none}
#pills-label{font-family:var(--micro);font-size:9px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--ink-3);flex:0 0 auto}
#pills-row{display:flex;flex-wrap:wrap;gap:8px}

/* per-question button: reuses the composer button grammar (micro uppercase,
   chamfer, accent-on-hover). Label is the pill's q via textContent. */
.pill{font-family:var(--micro);font-size:10px;letter-spacing:.1em;
  text-transform:none;color:var(--ink-2);
  background:rgba(6,11,20,.6);border:1px solid var(--reticle-dim);
  padding:7px 13px;cursor:pointer;white-space:nowrap;max-width:100%;
  overflow:hidden;text-overflow:ellipsis;transition:all .16s;
  clip-path:polygon(8px 0,100% 0,100% calc(100% - 8px),calc(100% - 8px) 100%,0 100%,0 8px)}
.pill:hover{color:var(--d-ac);border-color:var(--d-ac);
  box-shadow:0 0 22px -8px var(--d-ac)}
.pill:disabled{opacity:.4;cursor:default;box-shadow:none}

/* ════════════════ FACET-LENS (Peter-only lens strip) ════════════════
   Sits between #composer and #pills-bar; PETER only (chat.js toggles [hidden]).
   Reuses the pill/patch chamfer grammar. Each .lens-btn carries an inline
   --lens-ac (set in index.html per lens) that drives its hover/active tint —
   the only place a non-accent color enters, per the frozen spec. */
#facet-lens{position:relative;z-index:4;width:100%;flex:0 0 auto;
  display:flex;align-items:center;flex-wrap:wrap;gap:8px;padding:2px 12px}
#facet-lens[hidden]{display:none}
#lens-label{font-family:var(--micro);font-size:9px;letter-spacing:.24em;text-transform:uppercase;
  color:var(--ink-3);flex:0 0 auto}
.lens-btn{--lens-ac:var(--d-ac);
  font-family:var(--micro);font-size:10px;letter-spacing:.1em;color:var(--ink-2);
  background:rgba(6,11,20,.6);border:1px solid var(--reticle-dim);
  padding:7px 13px;cursor:pointer;white-space:nowrap;transition:all .16s;
  clip-path:polygon(8px 0,100% 0,100% calc(100% - 8px),calc(100% - 8px) 100%,0 100%,0 8px)}
.lens-btn:hover{color:var(--lens-ac);border-color:var(--lens-ac);
  box-shadow:0 0 22px -8px var(--lens-ac)}
.lens-btn.active{color:var(--lens-ac);border-color:var(--lens-ac);
  background:color-mix(in srgb,var(--lens-ac) 12%,transparent);
  box-shadow:inset 0 0 0 1px var(--lens-ac),0 0 26px -10px var(--lens-ac)}

/* ════════════════ COLD-START / RECONNECTING NOTE (#cold-note) ════════════════
   One-time cold-start hint (Render dyno wake); chat.js reuses it for the subtle
   "reconnecting…" note via .reconnecting. Below #pills-bar in the COMMS column. */
#cold-note{width:100%;flex:0 0 auto;text-align:center;
  font-family:var(--micro);font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3);padding:2px 12px}
#cold-note[hidden]{display:none}
#cold-note.reconnecting{color:var(--warn)}

/* ════════════════ PATCH-BAR (mid-call agent switch) ════════════════
   Reuses the .plate state grammar: .dormant / .muted / .live / .shown. */
#patch-bar{position:relative;z-index:4;
  width:100%;flex:0 0 auto;
  display:grid;grid-template-columns:repeat(5,1fr);gap:9px}
#patch-bar[hidden]{display:none}

.patch-plate{position:relative;display:flex;align-items:center;gap:9px;justify-content:center;
  padding:11px 10px;cursor:pointer;
  --ac:var(--d-ac);
  background:var(--glass-fill);border:0;
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ac) 16%,transparent),var(--glass-litedge);
  filter:saturate(.5) brightness(.62);transition:filter .25s,box-shadow .25s;
  clip-path:polygon(9px 0,100% 0,100% calc(100% - 9px),calc(100% - 9px) 100%,0 100%,0 9px)}
.patch-plate[data-agent="saarvis"]{--ac:var(--saarvis)}
.patch-plate[data-agent="hh"]{--ac:var(--hh)}
.patch-plate[data-agent="nyx"]{--ac:var(--nyx)}
.patch-plate[data-agent="minidoge"]{--ac:var(--minidoge)}
.patch-plate[data-agent="peter"]{--ac:var(--peter,#fd6524)}
.patch-plate:hover{filter:saturate(.85) brightness(.9)}

/* state classes set by chat.js. */
.patch-plate.dormant{filter:saturate(.5) brightness(.62)}
.patch-plate.muted{filter:brightness(.55) saturate(.7)}
.patch-plate.live{filter:none;
  box-shadow:inset 0 0 0 1px var(--ac),var(--glass-litedge),0 0 46px -12px var(--ac)}

/* border-draw race on reveal. */
.patch-plate.shown{animation:bordrace 1.1s ease-out}
@keyframes bordrace{0%{clip-path:polygon(9px 0,9px 0,9px 0,9px 0,0 9px,0 9px)}
  100%{clip-path:polygon(9px 0,100% 0,100% calc(100% - 9px),calc(100% - 9px) 100%,0 100%,0 9px)}}

.patch-plate .patch-dot{flex:0 0 auto;width:8px;height:8px;border-radius:50%;
  background:var(--ac);box-shadow:0 0 9px var(--ac)}
.patch-plate.muted .patch-dot{background:var(--ink-3);box-shadow:none}
.patch-plate.live .patch-dot{animation:hb 1.6s ease-in-out infinite}
.patch-plate .patch-label{font-family:var(--micro);font-size:9.5px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-2)}
.patch-plate.live .patch-label{color:var(--ac)}

/* ════════════════ STATE C — CONVENE GRID (2×2) ════════════════ */
#convene-grid{position:relative;z-index:4;
  width:100%;max-width:900px;
  display:flex;flex-direction:column;gap:16px;margin-top:6px}
#convene-grid[hidden]{display:none}

#convene-question{font-family:var(--serif);font-style:italic;font-weight:300;font-size:21px;
  line-height:1.4;color:var(--serif-ink);text-align:center;
  padding:6px 18px 14px;border-bottom:1px solid rgba(120,160,200,.1);
  text-shadow:0 2px 24px rgba(0,0,0,.6)}

.convene-plates{display:grid;grid-template-columns:1fr 1fr;gap:14px}

.convene-plate{position:relative;
  --ac:var(--d-ac);
  min-height:150px;padding:16px 18px;
  display:flex;flex-direction:column;gap:10px;
  background:var(--glass-fill);
  -webkit-backdrop-filter:blur(14px) saturate(116%);backdrop-filter:blur(14px) saturate(116%);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ac) 16%,transparent),var(--glass-litedge);
  filter:saturate(.5) brightness(.62);opacity:.85;transition:filter .3s,opacity .3s,box-shadow .3s;
  clip-path:polygon(12px 0,100% 0,100% calc(100% - 12px),calc(100% - 12px) 100%,0 100%,0 12px)}
.convene-plate[data-agent="saarvis"]{--ac:var(--saarvis)}
.convene-plate[data-agent="hh"]{--ac:var(--hh)}
.convene-plate[data-agent="nyx"]{--ac:var(--nyx)}
.convene-plate[data-agent="minidoge"]{--ac:var(--minidoge)}
.convene-plate::after{content:"";position:absolute;right:8px;top:8px;width:10px;height:10px;
  border-top:1px solid color-mix(in srgb,var(--ac) 40%,transparent);
  border-right:1px solid color-mix(in srgb,var(--ac) 40%,transparent)}

/* lit when its reply lands (chat.js sets .live + .shown). */
.convene-plate.live{filter:none;opacity:1;
  box-shadow:inset 0 0 0 1px var(--ac),var(--glass-litedge),0 0 46px -12px var(--ac)}
.convene-plate.shown{animation:bordrace 1.1s ease-out,feedin .4s forwards}

.convene-who{font-family:var(--micro);font-size:11px;letter-spacing:.26em;text-transform:uppercase;
  color:var(--ac)}
.convene-reply{font-family:var(--serif);font-style:italic;font-weight:300;
  font-size:16px;line-height:1.5;color:var(--serif-ink)}
.convene-reply .tcur{background:var(--ac)}

/* ════════════════ TABULAR NUMS (verbatim §7) ════════════════ */
.tnum{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}

/* ════════════════════════════════════════════════════════════════════════
   RESPONSIVE STACK — below ~900px the two IN-CALL sections stack vertically
   (avatar STAGE on top, COMMS below), returning to a fluid normal-flow column
   like the original single-stack. Above 900px they sit side-by-side with the
   avatar as the larger panel (the rules above).
   ════════════════════════════════════════════════════════════════════════ */
@media (max-width:900px){
  #call-layout{
    flex-direction:column;align-items:center;
    height:auto;min-height:0;gap:18px;max-width:820px}
  /* STAGE: avatar goes near-fullwidth with a tall portrait height. */
  #call-stage{flex:0 0 auto;width:100%}
  #call-frame{width:100%;max-width:100%;height:min(520px,64vh)}
  /* COMMS flows in document height again (no internal clipping / fixed height);
     the transcript gets a bounded scroll well instead of flexing to fill. */
  #call-comms{flex:0 0 auto;width:100%;overflow:visible;min-height:0}
  #transcript{flex:0 0 auto;max-height:240px}
}

/* ════════════════════════════════════════════════════════════════════════
   MOBILE — portrait, fluid normal-flow stack (NOT a fixed-stage transform).
   Header compresses, portrait near-fullwidth, giant HOLD TO TALK as primary
   input, text fallback below, patch-bar shrinks to a 4-dot strip, CONVENE
   becomes a single-column stack of full-width accent-bordered cards.
   ════════════════════════════════════════════════════════════════════════ */
@media (max-width:720px){
  #chat-room{gap:16px;padding:0 14px 56px}

  #d-head{grid-template-columns:auto 1fr auto;gap:10px;padding:14px 4px 12px}
  #d-head .head-c{align-items:flex-start;text-align:left}
  /* the badge shrinks + clock drops here, but still reserve room for #sfxMute. */
  #d-head .head-r{padding-right:42px;gap:8px}
  #agent-name{font-size:22px;letter-spacing:.12em}
  #agent-role{font-size:9px;letter-spacing:.22em;margin-top:3px}
  #session-clock{display:none}            /* role→chip compression: drop the clock first */
  #mode-badge{font-size:9px;padding:4px 8px;letter-spacing:.14em}
  #back-btn{padding:8px 11px;font-size:9px;letter-spacing:.18em}

  /* SELECT screen: roster collapses to a 2-column grid that wraps. */
  #select-screen{gap:16px;margin-top:0;min-height:calc(100dvh - 108px);padding-block:20px;
    justify-content:center;}
  #select-title{font-size:22px;letter-spacing:.14em}
  #select-sub{font-size:12px}
  #agent-roster{grid-template-columns:repeat(2,1fr);gap:10px}
  /* CONVENE tile spans the full row at the bottom of the 2-col grid. */
  #convene-tile{grid-column:1 / -1;flex-direction:row;justify-content:center;gap:14px}
  #convene-tile .convene-avatar{width:54px;aspect-ratio:1/1;font-size:26px}
  #convene-tile .card-status,#convene-tile .card-tag,#convene-tile .card-tagline{position:static;order:3}
  #select-tell-line{font-size:16px}
  #select-foot{font-size:9px}

  /* pills wrap below the composer; both inputs stay visible. */
  #pills-bar{padding:2px 10px;gap:7px}
  .pill{font-size:9.5px;padding:6px 11px}

  /* portrait near-fullwidth ~55vh */
  #call-frame{width:100%;height:55vh;max-height:480px}

  #caption{padding:14px 16px;min-height:60px}
  #caption .cap-line{font-size:19px;line-height:1.35}

  #transcript{max-height:170px;font-size:11px}

  /* giant HOLD TO TALK as the primary input; text fallback below it. */
  #composer{flex-wrap:wrap;padding:10px}
  #ptt-btn{order:1;flex:1 1 100%;height:60px;font-size:14px;letter-spacing:.22em}
  #text-input{order:2;flex:1 1 100%;height:44px}
  #send-btn{order:3;flex:1 1 calc(50% - 5px)}
  #convene-btn{order:4;flex:1 1 calc(50% - 5px)}

  /* patch-bar collapses to a compact dot strip (Peter + the four agents). */
  #patch-bar{gap:6px}
  .patch-plate{flex-direction:column;gap:6px;padding:9px 4px}
  .patch-plate .patch-label{font-size:8px;letter-spacing:.1em}

  /* CONVENE → vertical single-column stack of full-width cards. */
  .convene-plates{grid-template-columns:1fr}
  #convene-question{font-size:17px}
}

/* very small phones: hide patch-bar text entirely, dots only. */
@media (max-width:420px){
  .patch-plate .patch-label{display:none}
  .patch-plate{padding:11px 4px}
}

/* ════════════════════════════════════════════════════════════════════════
   REDUCED MOTION (verbatim §7 guard) — kills livescan/scandrift/breathing/
   ring-pulse/caret; snaps to a static, fully usable answerable card.
   ════════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce){
  /* fully STOP the infinite loops (livethrob/livescan/scandrift/hb/caret) —
     .001s durations re-fire continuously and can read as flicker.
     NB: the universal selector does NOT match pseudo-elements, so ::before/
     ::after animations (livescan on #call-frame::after, hb on
     #mode-badge.live::before) need the explicit *::before,*::after reset — the
     bare * alone would leave them looping under reduced-motion. */
  *,*::before,*::after{animation:none !important;transition-duration:.001s !important}

  /* SELECT safety — guarantee nothing sticks mid-animation and the static
     tagline/status read cleanly (the global * kills the keyframes above). */
  #select-screen .agent-card{opacity:1 !important;transform:none !important}
  #select-screen #select-title{opacity:1 !important;clip-path:none !important}
  #select-screen #select-sub,#select-screen #select-demo-tag,
  #select-screen #select-tell,#select-screen #select-foot{opacity:1 !important;transform:none !important}
  #select-screen::before{animation:none !important;opacity:.5 !important}
  .card-scan{display:none !important}
  .card-tagline{max-height:none !important;opacity:1 !important}   /* just show it, statically */
  .card-status .status-dot{animation:none !important}
}
