/* LANDING — Foundry chassis. docs/SITE_REDESIGN.md.
   No figure is written here. Anything numeric on this page is rendered from
   model-registry.ts at runtime or it is absent, so adding a model updates the
   page by itself and a stale number cannot be committed. */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--body);
  font-size: var(--step-0);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hi); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--rad-s); }

.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }

/* ── eyebrow ───────────────────────────────────────────────────────── */
.eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--mono); font-size: var(--step--1);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--dim);
}
.pulse {
  width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 0 var(--accent-dim); animation: pulse 2.4s ease-out infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 #f0a86066; }
  70%  { box-shadow: 0 0 0 9px #f0a86000; }
  100% { box-shadow: 0 0 0 0 #f0a86000; }
}
@media (prefers-reduced-motion: reduce) { .pulse { animation: none; } }

/* ── nav ───────────────────────────────────────────────────────────── */
.nav {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
.nav-in { display: flex; align-items: center; gap: 28px; height: 60px; }
.nav-logo {
  font-family: var(--mono); font-weight: 500; color: var(--text);
  letter-spacing: -0.02em; margin-right: auto;
}
.nav-logo span { color: var(--accent); }
.nav a:not(.nav-logo):not(.nav-cta) { color: var(--muted); font-size: var(--step--1); }
.nav a:not(.nav-logo):not(.nav-cta):hover { color: var(--text); }
.nav-cta {
  font-size: var(--step--1); padding: 7px 15px; border-radius: var(--rad-s);
  border: 1px solid var(--accent); color: var(--accent);
}
.nav-cta:hover { background: var(--accent); color: var(--bg); }
.nav-links { display: flex; gap: 22px; align-items: center; }
/* On phones the nav used to collapse to ONLY "Open chat" — the single action
   that costs gigabytes — while Docs and everything explanatory vanished. Docs
   stays; the heavyweight links are the ones that can go. */
@media (max-width: 720px) { .nav-links a:not(.nav-cta):not([href="docs.html"]) { display: none; } }

/* ── hero ──────────────────────────────────────────────────────────── */
.hero { padding: 84px 0 64px; }
.hero h1 {
  font-family: var(--display);
  font-size: var(--step-3);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.02em;
  margin: 20px 0 0;
  text-wrap: balance;
}
.hero h1 em { font-style: italic; color: var(--accent); }
.hero p {
  color: var(--muted); max-width: 62ch; margin: 20px 0 0; font-size: var(--step-1);
  line-height: 1.6;
}
.hero-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 28px; }
.btn {
  font-family: var(--body); font-size: var(--step-0);
  padding: 11px 20px; border-radius: var(--rad-s); border: 1px solid var(--border-hi);
  color: var(--text); background: transparent; cursor: pointer;
}
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #1a1206; font-weight: 500; }
.btn-primary:hover { background: var(--accent-hi); border-color: var(--accent-hi); color: #1a1206; }

/* ── kernel window ─────────────────────────────────────────────────── */
.kw {
  margin-top: 44px; border: 1px solid var(--border); border-radius: var(--rad);
  background: var(--surface); overflow: hidden;
}
.kw-bar {
  display: flex; align-items: center; gap: 10px;
  padding: 0 14px; height: 40px; border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.kw-dots { display: flex; gap: 6px; margin-right: 6px; }
.kw-dots i { width: 10px; height: 10px; border-radius: 50%; background: var(--border-hi); }
.kw-tabs { display: flex; gap: 2px; overflow-x: auto; scrollbar-width: none; }
.kw-tabs::-webkit-scrollbar { display: none; }
.kw-tab {
  font-family: var(--mono); font-size: var(--step--1); color: var(--dim);
  background: none; border: 0; padding: 6px 11px; border-radius: var(--rad-s);
  cursor: pointer; white-space: nowrap;
}
.kw-tab:hover { color: var(--muted); }
.kw-tab[aria-selected="true"] { color: var(--accent); background: var(--accent-dim); }
.kw-body { overflow-x: auto; }
.kw-body pre {
  margin: 0; padding: 20px 22px;
  font-family: var(--mono); font-size: var(--step--1); line-height: 1.7;
  color: var(--muted);
}
.kw-body pre[hidden] { display: none; }
.kw-foot {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  padding: 10px 16px; border-top: 1px solid var(--border);
  font-family: var(--mono); font-size: var(--step--1); color: var(--dim);
  flex-wrap: wrap;
}

/* WGSL syntax — one hue family, so the code reads as material rather than
   as a rainbow. Comments recede; the accent is spent on identifiers. */
.t-key  { color: #c58bff; }
.t-fn   { color: var(--accent-hi); }
.t-num  { color: var(--ok); }
.t-str  { color: #9fd3ff; }
.t-com  { color: var(--dim); font-style: italic; }
.t-attr { color: #7e8aa0; }
.t-type { color: #8fd0ff; }

/* ── capability band ───────────────────────────────────────────────── */
.band { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--border);
        border: 1px solid var(--border); border-radius: var(--rad); overflow: hidden; }
@media (max-width: 840px) { .band { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .band { grid-template-columns: 1fr; } }
.band a { background: var(--surface); padding: 22px; display: block; color: inherit; }
.band a:hover { background: var(--surface-2); }
.band h3 {
  font-family: var(--mono); font-size: var(--step--1); text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--accent); margin: 0 0 8px; font-weight: 500;
}
.band p { margin: 0; color: var(--muted); font-size: var(--step--1); line-height: 1.6; }

/* ── sections ──────────────────────────────────────────────────────── */
section { padding: 72px 0; }
.sec-head { margin-bottom: 32px; }
.sec-head h2 {
  font-family: var(--display); font-weight: 400; font-size: var(--step-2);
  margin: 12px 0 0; letter-spacing: -0.01em;
}
.sec-head p { color: var(--muted); margin: 12px 0 0; max-width: 66ch; }

/* ── model browser ─────────────────────────────────────────────────── */
/* The container IS the keyboard interface — index.html tells the reader the
   arrow keys move between models, and this is the element that must be
   focused for that to work. Removing its ring left no way to tell. */
#model-browser:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.mb-stage { display: flex; align-items: center; gap: 8px; }
.mb-arrow {
  flex: 0 0 auto; width: 42px; height: 42px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--border); color: var(--muted);
  font-size: 22px; line-height: 1; cursor: pointer; font-family: var(--body);
}
.mb-arrow:hover { border-color: var(--accent); color: var(--accent); }
.mb-slide {
  flex: 1 1 auto; display: grid; grid-template-columns: 1fr 1fr; gap: 32px;
  align-items: center; min-height: 380px;
  border: 1px solid var(--border); border-radius: var(--rad);
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  padding: 28px 32px;
}
@media (max-width: 780px) {
  .mb-slide { grid-template-columns: 1fr; text-align: center; min-height: 0; }
  .mb-stats { justify-items: center; }
  .mb-variants, .mb-info { justify-content: center; align-items: center; }
}
.mb-art { position: relative; padding-bottom: 66px; }
.mb-mascot { display: block; width: 100%; height: 320px; position: relative; z-index: 1; }
@media (max-width: 780px) { .mb-mascot { height: 220px; } }
/* The pedestal: a class-coloured light pool under the figure — the character
   stands ON something, which is most of what makes a select screen read as a
   stage rather than a card. */
.mb-pedestal {
  position: absolute; left: 50%; bottom: 46px; transform: translateX(-50%);
  width: 78%; height: 64px; border-radius: 50%;
  background: radial-gradient(ellipse at center,
    color-mix(in srgb, var(--cs-accent, var(--accent)) 34%, transparent) 0%,
    color-mix(in srgb, var(--cs-accent, var(--accent)) 10%, transparent) 55%,
    transparent 72%);
  filter: blur(2px);
}
/* Nameplate under the stage, class-coloured keyline. */
.mb-plate {
  position: absolute; left: 50%; bottom: 0; transform: translateX(-50%);
  text-align: center; padding: 8px 22px 10px; min-width: 60%;
  border: 1px solid color-mix(in srgb, var(--cs-accent, var(--accent)) 45%, var(--border));
  border-radius: 10px;
  background: color-mix(in srgb, var(--cs-accent, var(--accent)) 7%, var(--surface));
}
.mb-panel {
  border: 1px solid var(--border); border-radius: 12px;
  background: linear-gradient(180deg, var(--surface-2), transparent);
  padding: 16px 18px 14px;
}
.mb-row-label {
  font-family: var(--mono); font-size: var(--step--1); color: var(--dim);
  text-transform: uppercase; letter-spacing: 0.09em; margin: 10px 0 6px;
}
.mb-row-label:first-child { margin-top: 0; }

.mb-info { display: flex; flex-direction: column; gap: 14px; }
.mb-name { font-family: var(--display); font-size: var(--step-2); line-height: 1.1; }
.mb-params { font-family: var(--mono); font-size: var(--step--1); color: var(--dim); margin-top: 2px; }

.mb-variants { display: flex; gap: 6px; flex-wrap: wrap; }
/* Memory builds — the character screen's loadout row. Same pill grammar as
   the quantisation picker: a build is a choice about THIS character, and the
   selected one re-poses the figure (leaner, streamed experts drifting out). */
.mb-modes { display: flex; gap: 6px; flex-wrap: wrap; }
.mb-variant {
  font-family: var(--mono); font-size: var(--step--1); cursor: pointer;
  padding: 5px 12px; border-radius: 99px;
  border: 1px solid var(--border-hi); background: transparent; color: var(--muted);
}
.mb-variant:hover { color: var(--text); border-color: var(--accent); }
.mb-variant[aria-selected="true"] { border-color: var(--accent); color: var(--accent); background: var(--accent-dim); }

.mb-stats { display: grid; grid-template-columns: repeat(3, auto); gap: 22px; margin: 14px 0 4px; justify-content: start; }
@media (max-width: 780px) { .mb-stats { justify-content: center; } }
/* At 390px the three-column stats row set a ~204px min-content floor which,
   plus slide padding and the two 42px arrows, needed ~368px of a 342px
   viewport — the body scrolled sideways. Flex-wrap has no min-content floor:
   each stat drops to the next line instead of pushing the page. min-width: 0
   on the grid/flex items is what lets the slide actually shrink. */
@media (max-width: 480px) {
  .mb-stats { display: flex; flex-wrap: wrap; gap: 10px 20px; }
  .mb-slide { min-width: 0; padding: 20px 18px; }
  .mb-art, .mb-info { min-width: 0; }
  .mb-arrow { width: 34px; height: 34px; font-size: 18px; }
}
.mb-stats dt {
  font-family: var(--mono); font-size: var(--step--1); color: var(--dim);
  text-transform: uppercase; letter-spacing: 0.07em;
}
.mb-stats dd { margin: 4px 0 0; font-family: var(--mono); font-size: var(--step-0); color: var(--text); }
.mb-hw { color: var(--dim); font-size: var(--step--1); }
.mb-cached { color: var(--ok); font-size: var(--step--1); margin: 14px 0 0; }
.mb-ram { color: var(--warn); font-size: var(--step--1); margin: 14px 0 0; }
.mb-cta {
  align-self: stretch; text-align: center; font-size: var(--step-0);
  padding: 0.85rem 1.2rem;
  background: var(--cs-accent, var(--accent));
  border-color: var(--cs-accent, var(--accent));
}
.mb-cta:hover { filter: brightness(1.12); }
@media (max-width: 780px) { .mb-cta { align-self: center; } }

/* The roster rail — party lineup instead of dots. Each slot carries the
   character's own snapshotted face (--thumb, painted async); cached models
   were snapshotted lit, which is the visual for "unlocked". */
.mb-dots { display: flex; gap: 10px; justify-content: center; margin-top: 22px; flex-wrap: wrap; }
.mb-dot {
  width: 64px; height: 76px; padding: 0 0 4px; cursor: pointer;
  border: 1px solid var(--border-hi); border-radius: 10px;
  background:
    var(--thumb, radial-gradient(circle at 50% 40%, var(--border-hi) 0%, transparent 60%))
    center 2px / 58px 58px no-repeat,
    var(--surface);
  display: flex; align-items: flex-end; justify-content: center;
  transition: border-color 0.15s, transform 0.15s;
}
.mb-dot:hover { border-color: var(--muted); transform: translateY(-2px); }
.mb-dot[aria-selected="true"] {
  border-color: var(--cs-accent, var(--accent));
  box-shadow: 0 0 0 1px var(--cs-accent, var(--accent)),
              0 6px 18px color-mix(in srgb, var(--cs-accent, var(--accent)) 25%, transparent);
}
.mb-dot-name {
  font-family: var(--mono); font-size: 9px; color: var(--dim);
  max-width: 60px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mb-dot[aria-selected="true"] .mb-dot-name { color: var(--text); }
@media (max-width: 480px) { .mb-dot { width: 52px; height: 64px; } .mb-dot-name { font-size: 8px; } }
.note { color: var(--muted); font-size: var(--step--1); margin-top: 16px; }

/* ── kernel wall ───────────────────────────────────────────────────── */
/* Five columns so the ten tiles fill exactly two rows — auto-fill left a
   half-empty third row that read as a rendering fault. */
.wall { display: grid; grid-template-columns: repeat(5, 1fr); gap: 1px;
        background: var(--border); border: 1px solid var(--border); border-radius: var(--rad);
        overflow: hidden; }
@media (max-width: 900px) { .wall { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 560px) { .wall { grid-template-columns: repeat(2, 1fr); } }
.wall a {
  background: var(--surface); padding: 16px 14px; color: var(--muted);
  font-family: var(--mono); font-size: var(--step--1); display: block;
}
.wall a:hover { background: var(--surface-2); color: var(--accent); }
.wall b { display: block; color: var(--text); font-weight: 500; margin-bottom: 4px; }
.wall a:hover b { color: var(--accent); }
.wall span { color: var(--dim); }

/* ── proof strip ───────────────────────────────────────────────────── */
.proof {
  border: 1px solid var(--border); border-left: 2px solid var(--accent);
  border-radius: var(--rad); background: var(--surface); padding: 26px 28px;
}
.proof h2 { font-family: var(--display); font-weight: 400; font-size: var(--step-1); margin: 0; }
.proof p { color: var(--muted); margin: 10px 0 0; max-width: 70ch; }

/* ── footer ────────────────────────────────────────────────────────── */
footer { border-top: 1px solid var(--border); padding: 56px 0 72px; }
.foot-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: 40px; }
@media (max-width: 780px) { .foot-grid { grid-template-columns: 1fr; gap: 28px; } }
footer h4 {
  font-family: var(--mono); font-size: var(--step--1); text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--dim); margin: 0 0 12px; font-weight: 500;
}
footer ul { list-style: none; padding: 0; margin: 0; display: grid; gap: 8px; }
footer li a { color: var(--muted); font-size: var(--step--1); }
footer li a:hover { color: var(--accent); }
.foot-about { color: var(--muted); font-size: var(--step--1); max-width: 44ch; }
.foot-bottom {
  margin-top: 44px; padding-top: 22px; border-top: 1px solid var(--border);
  display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  font-family: var(--mono); font-size: var(--step--1); color: var(--dim);
}


/* ══ THE GAME ENTRANCE ═════════════════════════════════════════════════════
   #models is the site: a full-viewport character select. The chrome is the
   circuit-rune asset set in /entrance (bg painting, pedestal ring, corner
   brackets, divider) — monochrome SVGs applied through CSS masks so every
   ornament tints to the class accent of the model on stage. Data unchanged:
   every value is the registry row. */
#models { padding: 0; }
#models .cs-root {
  position: relative;
  min-height: 100dvh;
  display: grid;
  grid-template-columns: minmax(270px, 350px) 1fr minmax(250px, 320px);
  grid-template-rows: auto 1fr auto auto;
  grid-template-areas:
    'plate plate  roster'
    'sheet stage  roster'
    'enter enter  roster'
    'note  note   note';
  gap: 10px 24px;
  padding: calc(var(--nav-h, 64px) + 14px) 30px 24px;
  background:
    radial-gradient(ellipse at 50% 92%,
      color-mix(in srgb, var(--cs-accent, var(--accent)) 13%, transparent) 0%,
      transparent 52%),
    url('/entrance/bg.svg') center / cover no-repeat,
    var(--bg);
  overflow: hidden;
}

/* Atmosphere: two fog bands drifting opposite ways, and a dust field. All
   accent-neutral; the accent lives in the radial wash above. */
.cs-fog { position: absolute; inset: 0; pointer-events: none; z-index: 0; }
.cs-fog i {
  position: absolute; width: 90vw; height: 34vh; border-radius: 50%;
  background: radial-gradient(ellipse at center, #18223a55 0%, transparent 65%);
  filter: blur(30px);
}
.cs-fog i:nth-child(1) { left: -20vw; bottom: 4vh; animation: fogA 46s ease-in-out infinite alternate; }
.cs-fog i:nth-child(2) { right: -25vw; bottom: 12vh; animation: fogB 58s ease-in-out infinite alternate; }
@keyframes fogA { from { transform: translateX(0); } to { transform: translateX(9vw); } }
@keyframes fogB { from { transform: translateX(0); } to { transform: translateX(-11vw); } }
.cs-dust {
  position: absolute; inset: -10% 0 0 0; pointer-events: none; z-index: 0; opacity: 0.5;
  background-image:
    radial-gradient(1.2px 1.2px at 12% 30%, #cfe0ff88 50%, transparent 51%),
    radial-gradient(1px 1px at 34% 68%, #cfe0ff66 50%, transparent 51%),
    radial-gradient(1.4px 1.4px at 58% 22%, #cfe0ff77 50%, transparent 51%),
    radial-gradient(1px 1px at 71% 55%, #cfe0ff55 50%, transparent 51%),
    radial-gradient(1.2px 1.2px at 86% 34%, #cfe0ff77 50%, transparent 51%),
    radial-gradient(1px 1px at 45% 84%, #cfe0ff44 50%, transparent 51%);
  background-size: 900px 700px;
  animation: dust 90s linear infinite;
}
@keyframes dust { from { background-position: 0 0; } to { background-position: -900px 350px; } }

/* Nameplate: display face over an ornamental divider. */
#models .mb-plate {
  grid-area: plate; position: relative; z-index: 1; justify-self: center;
  text-align: center; margin-top: 4px; padding: 0 26px 14px;
  border: 0; background: none;
}
#models .mb-name {
  font-family: var(--display); font-size: clamp(1.9rem, 3.6vw, 2.9rem);
  line-height: 1.05; text-shadow: 0 2px 24px #000c;
}
#models .mb-params {
  font-family: var(--mono); font-size: var(--step--1); letter-spacing: 0.14em;
  text-transform: uppercase; margin-top: 6px;
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 75%, var(--text));
}
#models .mb-plate::after {
  content: ''; display: block; height: 16px; margin: 10px auto 0; width: min(360px, 80%);
  background: color-mix(in srgb, var(--cs-accent, var(--accent)) 80%, #fff);
  -webkit-mask: url('/entrance/divider.svg') center / contain no-repeat;
  mask: url('/entrance/divider.svg') center / contain no-repeat;
}

/* The stage. */
#models .mb-stage { grid-area: stage; display: flex; align-items: stretch; gap: 4px; min-height: 0; position: relative; z-index: 1; }
#models .mb-art { flex: 1; padding: 0; display: flex; align-items: center; justify-content: center; position: relative; }
#models .mb-mascot { height: min(54dvh, 500px); max-width: 100%; position: relative; z-index: 2; }
#models .mb-pedestal {
  position: absolute; left: 50%; bottom: 2%; transform: translateX(-50%);
  width: min(560px, 86%); height: 150px; border-radius: 0; filter: none;
  background: radial-gradient(ellipse at center,
    color-mix(in srgb, var(--cs-accent, var(--accent)) 30%, transparent) 0%,
    color-mix(in srgb, var(--cs-accent, var(--accent)) 8%, transparent) 52%,
    transparent 70%);
}
#models .mb-pedestal::after {
  content: ''; position: absolute; inset: 0;
  background: color-mix(in srgb, var(--cs-accent, var(--accent)) 85%, #fff);
  -webkit-mask: url('/entrance/ring.svg') center bottom / 100% auto no-repeat;
  mask: url('/entrance/ring.svg') center bottom / 100% auto no-repeat;
  animation: ringPulse 5s ease-in-out infinite;
}
@keyframes ringPulse { 0%, 100% { opacity: 0.85; } 50% { opacity: 0.5; } }
#models .mb-arrow {
  align-self: center; width: 52px; height: 76px; border-radius: 12px;
  background: transparent; border: 1px solid transparent; font-size: 34px;
  color: var(--dim); z-index: 2;
}
#models .mb-arrow:hover { color: var(--cs-accent, var(--accent)); border-color: var(--border); background: #0b101cbb; }

/* The sheet: glass plate with rune corners. */
#models .mb-info { grid-area: sheet; align-self: center; z-index: 1; }
#models .mb-panel {
  position: relative; border: 1px solid color-mix(in srgb, var(--cs-accent, var(--accent)) 22%, var(--border));
  border-radius: 4px; padding: 20px 20px 16px;
  background: linear-gradient(180deg, #0c1220ee, #090e18e6);
  box-shadow: inset 0 1px 0 #ffffff0a, 0 18px 50px #0009;
  backdrop-filter: blur(4px);
}
#models .mb-panel::before, #models .mb-panel::after {
  content: ''; position: absolute; width: 40px; height: 40px;
  background: color-mix(in srgb, var(--cs-accent, var(--accent)) 85%, #fff);
  -webkit-mask: url('/entrance/corner.svg') 0 0 / contain no-repeat;
  mask: url('/entrance/corner.svg') 0 0 / contain no-repeat;
}
#models .mb-panel::before { top: -5px; left: -5px; }
#models .mb-panel::after { bottom: -5px; right: -5px; transform: rotate(180deg); }
#models .mb-row-label {
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.16em;
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 55%, var(--dim));
  text-transform: uppercase; margin: 14px 0 7px;
}
#models .mb-row-label:first-child { margin-top: 0; }
#models .mb-stats { display: block; margin: 12px 0 2px; }
#models .mb-stats > div {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 6px 2px; border-bottom: 1px solid #ffffff0d;
}
#models .mb-stats dt {
  font-family: var(--mono); font-size: 0.66rem; letter-spacing: 0.12em; color: var(--dim);
}
#models .mb-stats dd {
  margin: 0; font-family: var(--mono); font-size: var(--step-0);
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 45%, var(--text));
}
#models .mb-variant {
  border-radius: 3px; border-color: #ffffff1c; background: #ffffff07;
}
#models .mb-variant[aria-selected="true"] {
  border-color: var(--cs-accent, var(--accent));
  background: color-mix(in srgb, var(--cs-accent, var(--accent)) 18%, transparent);
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 70%, #fff);
}
#models .mb-cached { color: var(--ok); font-size: var(--step--1); margin: 10px 0 0; }
#models .mb-ram { font-size: var(--step--1); margin: 8px 0 0; }

/* Roster rail. */
#models .cs-roster-head {
  grid-area: roster; align-self: start; z-index: 1;
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--dim);
  padding: 2px 0 0 16px; height: 20px;
}
#models .mb-roster {
  grid-area: roster; z-index: 1; margin: 26px 0 0; padding: 0 4px 4px 14px;
  display: flex; flex-direction: column; gap: 8px; justify-content: flex-start;
  overflow-y: auto; border-left: 1px solid #ffffff12;
  scrollbar-width: thin; scrollbar-color: var(--border-hi) transparent;
}
#models .mb-dot {
  width: 100%; height: auto; min-height: 64px; padding: 7px 10px;
  display: flex; flex-direction: row; align-items: center; gap: 11px;
  text-align: left; border-radius: 4px; cursor: pointer;
  border: 1px solid #ffffff14;
  background: linear-gradient(180deg, #ffffff08, transparent 60%), #0a0f1acc;
  transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
  position: relative;
}
#models .mb-dot:hover { border-color: var(--muted); transform: translateX(-2px); }
#models .mb-dot[aria-selected="true"] {
  border-color: var(--cs-accent, var(--accent));
  box-shadow: inset 0 0 0 1px var(--cs-accent, var(--accent)),
              0 0 22px color-mix(in srgb, var(--cs-accent, var(--accent)) 30%, transparent);
}
#models .mb-dot[data-cached]::after {
  content: 'READY'; position: absolute; top: 5px; right: 7px;
  font-family: var(--mono); font-size: 0.5rem; letter-spacing: 0.12em;
  color: var(--ok); border: 1px solid color-mix(in srgb, var(--ok) 55%, transparent);
  border-radius: 3px; padding: 1px 4px;
}
.mb-dot-face {
  flex: 0 0 46px; height: 46px; border-radius: 4px;
  background: var(--thumb, radial-gradient(circle at 50% 40%, var(--border-hi) 0%, transparent 60%))
    center / cover no-repeat, #0d1322;
  border: 1px solid #ffffff10;
}
.mb-dot-text { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.mb-dot-text b { font-size: 0.8rem; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mb-dot-text i { font-style: normal; font-family: var(--mono); font-size: 0.6rem;
  color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ENTER. */
#models .cs-enter { grid-area: enter; display: flex; justify-content: center; padding: 4px 0 2px; z-index: 1; }
#models .cs-enter .mb-cta {
  min-width: 340px; text-align: center; letter-spacing: 0.14em; text-transform: uppercase;
  font-weight: 700; font-size: var(--step-0); padding: 0.95rem 1.4rem;
  border-radius: 4px; position: relative; overflow: hidden;
  color: #0b0d10;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--cs-accent, var(--accent)) 80%, #fff) 0%,
    var(--cs-accent, var(--accent)) 55%,
    color-mix(in srgb, var(--cs-accent, var(--accent)) 70%, #000) 100%);
  border: 1px solid color-mix(in srgb, var(--cs-accent, var(--accent)) 60%, #fff);
  box-shadow: 0 10px 34px color-mix(in srgb, var(--cs-accent, var(--accent)) 40%, transparent),
              inset 0 1px 0 #ffffff66;
}
#models .cs-enter .mb-cta:hover { filter: brightness(1.1); }
#models .cs-enter .mb-cta::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 40%;
  left: -60%; transform: skewX(-20deg);
  background: linear-gradient(90deg, transparent, #ffffff55, transparent);
  transition: left 0.5s ease;
}
#models .cs-enter .mb-cta:hover::after { left: 130%; }
#models .cs-note { grid-area: note; text-align: center; z-index: 1; }

/* The logo opening. */
.cs-splash {
  position: absolute; inset: 0; z-index: 30;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px;
  background: radial-gradient(ellipse at 50% 42%, #0d1424 0%, var(--bg) 70%);
  animation: csSplashOut 2.6s ease forwards;
}
.cs-emblem {
  width: 84px; height: 84px; color: var(--accent);
  animation: csEmblem 1.4s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.cs-logo {
  font-family: var(--display); font-size: clamp(3rem, 9vw, 6.5rem); color: var(--text);
  animation: csLogoIn 1.6s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.cs-logo b { color: var(--accent); }
.cs-sub {
  font-family: var(--mono); font-size: 0.78rem; letter-spacing: 0.22em;
  text-transform: uppercase; color: var(--dim);
  animation: csSub 1s ease 0.7s both;
}
@keyframes csEmblem {
  0% { opacity: 0; transform: rotate(-90deg) scale(0.6); }
  100% { opacity: 1; transform: rotate(0deg) scale(1); }
}
@keyframes csLogoIn {
  0% { opacity: 0; transform: scale(1.22); letter-spacing: 0.16em; filter: blur(12px); }
  55% { opacity: 1; filter: blur(0); }
  100% { opacity: 1; transform: scale(1); letter-spacing: 0.01em; }
}
@keyframes csSub { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes csSplashOut { 0%, 78% { opacity: 1; } 100% { opacity: 0; visibility: hidden; } }

@media (prefers-reduced-motion: reduce) {
  .cs-fog i, .cs-dust, #models .mb-pedestal::after { animation: none; }
}

/* Phones: stage first, roster as a strip, sheet, enter. */
@media (max-width: 900px) {
  #models .cs-root {
    grid-template-columns: 1fr;
    grid-template-areas: 'plate' 'stage' 'roster' 'sheet' 'enter' 'note';
    padding: calc(var(--nav-h, 64px) + 8px) 14px 18px;
    gap: 8px;
  }
  #models .mb-mascot { height: min(36dvh, 300px); }
  #models .cs-roster-head { display: none; }
  #models .mb-roster {
    flex-direction: row; overflow-x: auto; overflow-y: hidden; margin-top: 0;
    border-left: 0; border-top: 1px solid #ffffff12; padding: 10px 2px 4px;
  }
  #models .mb-dot { width: auto; min-width: 168px; flex: 0 0 auto; }
  #models .cs-enter .mb-cta { min-width: 0; width: 100%; }
}


/* ══ ROUND TWO: depth, transitions, identity ═══════════════════════════════ */

/* The floor reflection — Chromium's box-reflect, which is the browser class
   the engine requires anyway. Elsewhere it simply does not draw. */
#models .mb-mascot {
  -webkit-box-reflect: below -6px linear-gradient(transparent 62%, rgba(255,255,255,0.10));
}

/* Selection transition. go() re-arms .cs-in, so switching characters flashes
   the pedestal and walks the plate and sheet back in — selection FEELS like
   selection. Names are transform/opacity only; nothing relayouts. */
#models .mb-art.cs-in .mb-pedestal::after { animation: ringFlash 0.7s ease-out, ringPulse 5s ease-in-out 0.7s infinite; }
@keyframes ringFlash {
  0% { opacity: 1; transform: scale(0.92); filter: brightness(2.2); }
  100% { opacity: 0.85; transform: scale(1); filter: brightness(1); }
}
#models .mb-art.cs-in .mb-mascot { animation: charIn 0.5s cubic-bezier(0.2, 1.4, 0.4, 1); }
@keyframes charIn {
  0% { opacity: 0; transform: translateY(14px) scale(0.965); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
#models .mb-plate.cs-in .mb-name { animation: plateIn 0.45s ease both; }
#models .mb-plate.cs-in .mb-params { animation: plateIn 0.45s ease 0.08s both; }
@keyframes plateIn {
  0% { opacity: 0; transform: translateY(-8px); letter-spacing: 0.08em; }
  100% { opacity: 1; transform: translateY(0); }
}
#models .mb-panel.cs-in > * { animation: rowIn 0.4s ease both; }
#models .mb-panel.cs-in > *:nth-child(2) { animation-delay: 0.05s; }
#models .mb-panel.cs-in > *:nth-child(3) { animation-delay: 0.10s; }
#models .mb-panel.cs-in > *:nth-child(4) { animation-delay: 0.15s; }
#models .mb-panel.cs-in > *:nth-child(5) { animation-delay: 0.20s; }
#models .mb-panel.cs-in > *:nth-child(n+6) { animation-delay: 0.25s; }
@keyframes rowIn {
  0% { opacity: 0; transform: translateX(-10px); }
  100% { opacity: 1; transform: translateX(0); }
}

/* Class sigil beside the class line. */
#models .mb-params { display: inline-flex; align-items: center; gap: 8px; justify-content: center; }
.mb-sigil { display: inline-flex; width: 16px; height: 16px; }
.mb-sigil svg { width: 100%; height: 100%; }

/* Realm corners: tiny mono statements, both literally true. */
.cs-corner {
  position: absolute; bottom: 10px; z-index: 1;
  font-family: var(--mono); font-size: 0.58rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: color-mix(in srgb, var(--dim) 70%, transparent);
  pointer-events: none;
}
.cs-corner-l { left: 16px; }
.cs-corner-r { right: 16px; }

/* READY glint: a light pass over the tag every few seconds — unlocked should
   glimmer. Masked to the tag only. */
#models .mb-dot[data-cached]::after { overflow: hidden; }
#models .mb-dot[data-cached] { isolation: isolate; }
#models .mb-dot[data-cached]::before {
  content: ''; position: absolute; top: 3px; right: 5px; width: 44px; height: 14px;
  background: linear-gradient(110deg, transparent 30%, #ffffff2e 50%, transparent 70%) no-repeat;
  background-size: 200% 100%;
  animation: readyGlint 4.5s ease-in-out infinite;
  pointer-events: none; z-index: 1;
}
@keyframes readyGlint {
  0%, 72% { background-position: 180% 0; }
  92%, 100% { background-position: -80% 0; }
}

/* Enter: charge on hover, visible keyboard focus. */
#models .cs-enter .mb-cta { transition: transform 0.18s ease, filter 0.18s ease, box-shadow 0.18s ease; }
#models .cs-enter .mb-cta:hover {
  transform: translateY(-1px) scale(1.015);
  box-shadow: 0 14px 44px color-mix(in srgb, var(--cs-accent, var(--accent)) 55%, transparent),
              inset 0 1px 0 #ffffff77;
}
#models .cs-enter .mb-cta:focus-visible {
  outline: 2px solid #fff; outline-offset: 3px;
}

/* Parallax layers move on transform — give them will-change and keep the
   fog's own drift composed with the pointer offset via nesting (the <i>
   children animate, the container translates). */
.cs-fog, .cs-dust, #models .mb-art { will-change: transform; transition: transform 0.3s ease-out; }

@media (prefers-reduced-motion: reduce) {
  #models .mb-art.cs-in .mb-mascot,
  #models .mb-plate.cs-in .mb-name, #models .mb-plate.cs-in .mb-params,
  #models .mb-panel.cs-in > *, #models .mb-dot[data-cached]::before { animation: none; }
}


/* ══ ROUNDS 3-6: the aura, the juice, the frame ════════════════════════════ */

/* The aura: motes of the class light rising off the pedestal, their pace set
   by the model's measured rate (--cs-tempo — the same number the mascot's
   idle clock reads). A fast little model boils; a 35B smoulders. */
.cs-aura { position: absolute; left: 50%; bottom: 8%; width: min(480px, 70%); height: 60%;
  transform: translateX(-50%); pointer-events: none; z-index: 1; }
.cs-aura i {
  position: absolute; bottom: 0; width: 4px; height: 4px; border-radius: 50%;
  background: color-mix(in srgb, var(--cs-accent, var(--accent)) 85%, #fff);
  opacity: 0;
  animation: mote calc(5.2s / var(--cs-tempo, 1)) ease-in infinite;
}
.cs-aura i:nth-child(1)  { left: 6%;  animation-delay: 0.0s; }
.cs-aura i:nth-child(2)  { left: 16%; animation-delay: 1.1s; width: 3px; height: 3px; }
.cs-aura i:nth-child(3)  { left: 27%; animation-delay: 2.3s; }
.cs-aura i:nth-child(4)  { left: 38%; animation-delay: 0.6s; width: 5px; height: 5px; }
.cs-aura i:nth-child(5)  { left: 50%; animation-delay: 1.7s; width: 3px; height: 3px; }
.cs-aura i:nth-child(6)  { left: 61%; animation-delay: 2.9s; }
.cs-aura i:nth-child(7)  { left: 70%; animation-delay: 0.3s; }
.cs-aura i:nth-child(8)  { left: 80%; animation-delay: 1.9s; width: 3px; height: 3px; }
.cs-aura i:nth-child(9)  { left: 89%; animation-delay: 2.6s; }
.cs-aura i:nth-child(10) { left: 95%; animation-delay: 1.3s; width: 5px; height: 5px; }
@keyframes mote {
  0% { opacity: 0; transform: translateY(0) scale(1); }
  12% { opacity: 0.9; }
  100% { opacity: 0; transform: translateY(-46vh) scale(0.4); }
}

/* ARMED: a cached character's circle runs a rotating highlight — the same
   OPFS truth as the READY tag, drawn as ceremony. Conic light clipped by the
   very ring mask. */
#models .mb-art[data-armed] .mb-pedestal::before {
  content: ''; position: absolute; inset: 0;
  background: conic-gradient(from 0deg,
    transparent 0deg, transparent 290deg,
    color-mix(in srgb, var(--cs-accent, var(--accent)) 90%, #fff) 330deg,
    transparent 360deg);
  -webkit-mask: url('/entrance/ring.svg') center bottom / 100% auto no-repeat;
  mask: url('/entrance/ring.svg') center bottom / 100% auto no-repeat;
  animation: armedSpin 6s linear infinite;
}
@keyframes armedSpin { to { transform: rotate(360deg); } }

/* Lore under the nameplate: computed from the spec, styled as inscription. */
.cs-lore {
  margin-top: 8px; font-size: 0.8rem; font-style: italic;
  color: color-mix(in srgb, var(--text) 62%, transparent);
  letter-spacing: 0.02em;
}

/* Juice: chips stamp when chosen, roster cards press, ENTER presses. */
#models .mb-variant[aria-selected="true"] { animation: stamp 0.22s ease; }
@keyframes stamp { 0% { transform: scale(1.08); } 100% { transform: scale(1); } }
#models .mb-dot:active { transform: translateX(-2px) scale(0.98); }
#models .cs-enter .mb-cta:active { transform: translateY(1px) scale(0.995); box-shadow: 0 6px 20px color-mix(in srgb, var(--cs-accent, var(--accent)) 35%, transparent); }

/* The cinematic frame: a breath of dark at the top and bottom edges, so the
   scene reads composed rather than cropped. */
#models .cs-root::before, #models .cs-root::after {
  content: ''; position: absolute; left: 0; right: 0; height: 90px;
  pointer-events: none; z-index: 2;
}
#models .cs-root::before { top: 0; background: linear-gradient(180deg, #05070dcc, transparent); }
#models .cs-root::after { bottom: 0; background: linear-gradient(0deg, #05070d99, transparent); }

/* Screen-reader announcer. */
.cs-live { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

@media (prefers-reduced-motion: reduce) {
  .cs-aura i, #models .mb-art[data-armed] .mb-pedestal::before,
  #models .mb-variant[aria-selected="true"] { animation: none; }
  .cs-aura i { opacity: 0.35; transform: translateY(-8vh); }
}


/* ══ ROUND 7: THE ENVIRONMENT ══════════════════════════════════════════════
   The realm gains architecture. Silhouette layers between backdrop and
   stage, each on its own parallax rate: obelisk skyline far, rune columns
   near, the character floating between them under an aerial ring. */
.cs-spires {
  position: absolute; left: -3%; right: -3%; bottom: 0; height: 42vh;
  background: url('/entrance/spires.svg') bottom center / cover no-repeat;
  opacity: 0.85; pointer-events: none; z-index: 0;
}
.cs-col {
  position: absolute; bottom: -2vh; width: min(240px, 16vw); height: 92vh;
  background: url('/entrance/column.svg') bottom / contain no-repeat;
  pointer-events: none; z-index: 1; opacity: 0.9;
}
.cs-col-l { left: max(6px, 2vw); }
.cs-col-r { right: max(6px, 2vw); transform: scaleX(-1); }

/* The aerial ring: a great slow wheel behind the character, in the class
   light at whisper opacity. The armed floor ring is ceremony; this is
   architecture. */
.cs-backring {
  position: absolute; left: 50%; top: 46%; width: min(64dvh, 620px); aspect-ratio: 1;
  translate: -50% -50%;
  background: color-mix(in srgb, var(--cs-accent, var(--accent)) 70%, #fff);
  -webkit-mask: url('/entrance/backring.svg') center / contain no-repeat;
  mask: url('/entrance/backring.svg') center / contain no-repeat;
  opacity: 0.14; z-index: 0;
  animation: backringSpin 80s linear infinite;
}
@keyframes backringSpin { to { rotate: 360deg; } }

/* Nameplate banner wings behind the name. */
#models .mb-plate { padding-top: 10px; }
.cs-banner {
  position: absolute; left: 50%; top: 16px; transform: translateX(-50%);
  width: min(640px, 92vw); height: 80px; pointer-events: none;
  background: color-mix(in srgb, var(--cs-accent, var(--accent)) 65%, #fff);
  -webkit-mask: url('/entrance/banner.svg') center / contain no-repeat;
  mask: url('/entrance/banner.svg') center / contain no-repeat;
  opacity: 0.5; z-index: -1;
}

/* Portrait frames on the roster faces. */
.mb-dot-face { position: relative; }
.mb-dot-face::after {
  content: ''; position: absolute; inset: -3px;
  background: color-mix(in srgb, var(--cs-accent, var(--accent)) 55%, #9fb4d8);
  -webkit-mask: url('/entrance/pframe.svg') center / contain no-repeat;
  mask: url('/entrance/pframe.svg') center / contain no-repeat;
  opacity: 0.35; transition: opacity 0.15s;
}
#models .mb-dot[aria-selected="true"] .mb-dot-face::after,
#models .mb-dot:hover .mb-dot-face::after { opacity: 0.9; }

/* The cinematic edges upgraded: the dark breath now carries the rune border
   strip along its inner line. */
#models .cs-root::before {
  background:
    linear-gradient(180deg, #05070dcc, transparent),
    linear-gradient(180deg, transparent 76px, transparent 76px);
}
#models .cs-root > .cs-edge-t, #models .cs-root > .cs-edge-b { display: none; }
#models .cs-root::after {
  background: linear-gradient(0deg, #05070d99, transparent);
}
.cs-borderline-t, .cs-borderline-b {
  position: absolute; left: 8%; right: 8%; height: 12px; z-index: 2; pointer-events: none;
  background: color-mix(in srgb, var(--cs-accent, var(--accent)) 40%, #6c7f9f);
  -webkit-mask: url('/entrance/border.svg') center / auto 100% repeat-x;
  mask: url('/entrance/border.svg') center / auto 100% repeat-x;
  opacity: 0.4;
}
.cs-borderline-t { top: calc(var(--nav-h, 64px) + 2px); }
.cs-borderline-b { bottom: 8px; }

/* The splash's ring burst: the aerial ring blooming open behind the emblem. */
.cs-splash { position: absolute; }
.cs-splash-ring {
  position: absolute; width: 420px; aspect-ratio: 1;
  background: var(--accent);
  -webkit-mask: url('/entrance/backring.svg') center / contain no-repeat;
  mask: url('/entrance/backring.svg') center / contain no-repeat;
  animation: splashRing 2.2s cubic-bezier(0.16, 1, 0.3, 1) both;
  opacity: 0.22;
}
@keyframes splashRing {
  0% { transform: scale(0.4) rotate(-40deg); opacity: 0; }
  40% { opacity: 0.3; }
  100% { transform: scale(1.05) rotate(8deg); opacity: 0.18; }
}

/* The realm's cursor: a small trace-diamond. Entrance only. */
#models .cs-root, #models .cs-root a, #models .cs-root button {
  cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 22 22"><path d="M11 1 L21 11 L11 21 L1 11 Z" fill="none" stroke="white" stroke-width="2"/><path d="M11 7 L15 11 L11 15 L7 11 Z" fill="white"/></svg>') 11 11, auto;
}

@media (prefers-reduced-motion: reduce) {
  .cs-backring, .cs-splash-ring { animation: none; }
}
@media (max-width: 900px) {
  .cs-col { display: none; }
  .cs-spires { height: 26vh; opacity: 0.6; }
  .cs-backring { width: min(78vw, 380px); top: 40%; }
  .cs-banner { height: 56px; opacity: 0.4; }
  .cs-borderline-t, .cs-borderline-b { display: none; }
}


/* ══ ROUND 8: THE ALIGNMENT PASS ═══════════════════════════════════════════
   One rhythm: an 8px gutter system, a hard max-width so ultrawide screens
   frame the scene instead of stretching it, the sheet and roster hung from
   the same top line, and the enter slab locked to the stage's centre line. */
#models .cs-root {
  --cs-gutter: 24px;
  max-width: 1720px; margin: 0 auto;
  grid-template-columns: minmax(280px, 340px) minmax(0, 1fr) minmax(260px, 310px);
  gap: 8px var(--cs-gutter);
  padding: calc(var(--nav-h, 64px) + 12px) max(28px, 4vw) 22px;
}
/* Sheet and roster share a top line: both start where the stage starts. */
#models .mb-info { align-self: start; padding-top: 34px; }
#models .cs-roster-head { padding-top: 8px; height: 26px; }
#models .mb-roster { margin-top: 34px; }
/* The plate is the one centred element; give it a fixed rhythm below. */
#models .mb-plate { margin: 2px 0 0; padding-bottom: 6px; }
/* Enter hangs centred under the stage column only, not the whole row —
   optically aligned with the character above it. */
#models .cs-enter { grid-column: 2; justify-self: center; }
#models .cs-corner-l { left: max(28px, 4vw); }
#models .cs-corner-r { right: max(28px, 4vw); }
/* Border strips share the content inset. */
.cs-borderline-t, .cs-borderline-b { left: max(28px, 4vw); right: max(28px, 4vw); }
/* Stat rows: value column right-aligned on a shared edge, tabular digits. */
#models .mb-stats dd { font-variant-numeric: tabular-nums; text-align: right; }
#models .mb-stats dt { padding-right: 12px; }
/* Chips wrap on the same 8px rhythm. */
#models .mb-variants, #models .mb-modes { gap: 8px; }
@media (max-width: 900px) {
  #models .cs-enter { grid-column: 1; justify-self: stretch; }
  #models .mb-info { padding-top: 0; }
  #models .mb-roster { margin-top: 0; }
}

/* ══ ROUND 15: THE PARTY READS AS CLASSES ══ */
#models .mb-dot { padding-right: 26px; }
.mb-dot-sigil {
  position: absolute; right: 7px; bottom: 6px; width: 13px; height: 13px; opacity: 0.75;
}
.mb-dot-sigil svg { width: 100%; height: 100%; }

/* ══ ROUND 17: THE SPLASH YIELDS ══ */
.cs-splash { cursor: pointer; }


/* ══ ROUND 9: ATTENTION ══ */
#models .mb-art { transition: rotate 0.4s ease, transform 0.3s ease-out; perspective: 900px; }

/* ══ ROUND 11: THE SELECTION WIPE ══ A sheet of the class light crossing the
   stage on every selection — the cut between characters reads as a cut. */
.cs-wipe {
  position: absolute; inset: 0; z-index: 3; pointer-events: none; opacity: 0;
  background: linear-gradient(100deg, transparent 30%,
    color-mix(in srgb, var(--cs-accent, var(--accent)) 26%, transparent) 50%,
    transparent 70%);
  transform: translateX(-100%);
}
.cs-wipe.cs-go { animation: csWipe 0.55s ease-out; }
@keyframes csWipe {
  0% { opacity: 1; transform: translateX(-100%); }
  100% { opacity: 1; transform: translateX(100%); }
}

/* ══ ROUND 16: THE ENGAGE ══ Clicking ENTER flashes the realm in the class
   light and falls to black before the chat page takes over — an exit that
   answers the entrance. Reduced motion (and modified clicks) skip it. */
.cs-engage {
  position: absolute; inset: 0; z-index: 40; pointer-events: none; opacity: 0;
  background:
    radial-gradient(ellipse at 50% 60%,
      color-mix(in srgb, var(--cs-accent, var(--accent)) 45%, transparent) 0%, transparent 60%),
    #05070d;
}
.cs-engage.cs-go { animation: csEngage 0.34s ease-in forwards; }
@keyframes csEngage {
  0% { opacity: 0; }
  45% { opacity: 0.65; }
  100% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .cs-wipe.cs-go, .cs-engage.cs-go { animation: none; } }


/* ══ ROUND 10: STAT ICONOGRAPHY + HONEST BARS ══ Icons name the stat; the
   bars are within-character fractions only (context: shipped ceiling over
   the checkpoint's own max; memory: the build's residency) — never a
   cross-model ranking. */
.mb-stat-ico { display: inline-flex; width: 12px; height: 12px; margin-right: 7px;
  vertical-align: -1px; color: color-mix(in srgb, var(--cs-accent, var(--accent)) 60%, var(--dim)); }
.mb-stat-ico svg { width: 100%; height: 100%; }
.mb-bar { display: block; height: 3px; margin-top: 5px; border-radius: 2px;
  background: #ffffff12; overflow: hidden; }
.mb-bar i { display: block; height: 100%; border-radius: 2px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--cs-accent, var(--accent)) 55%, transparent),
    var(--cs-accent, var(--accent)));
  transition: width 0.45s cubic-bezier(0.22, 1, 0.36, 1); }
#models .mb-stats dd { min-width: 128px; }

/* ══ ROUND 13: THE LOADOUT GAUGE ══ Filled diamonds for what the build
   keeps, hollow for what it streams — ordinal, not a measurement. */
.mb-gauge { font-size: 0.6rem; letter-spacing: 0.08em; margin-right: 7px;
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 70%, var(--dim)); }


/* ══ ROUND 12: IDLE LIFE ══ Left alone, the realm breathes: the stage sways
   a few pixels on a long period and the aura thickens slightly. Any input
   snaps the camera back to the hand. */
#models .cs-root.cs-idle .mb-art { animation: idleSway 14s ease-in-out infinite; }
@keyframes idleSway {
  0%, 100% { transform: translate(0, 0); }
  25% { transform: translate(6px, -3px); }
  75% { transform: translate(-6px, 2px); }
}
#models .cs-root.cs-idle .cs-aura i { animation-duration: calc(3.8s / var(--cs-tempo, 1)); }

/* ══ ROUND 14: REALM WEATHER ══ A falling trace crosses the high sky every
   ~16 s — thin, fast, gone. And the fog drinks a hint of the class light, so
   the weather itself changes when the character does. */
.cs-comet {
  position: absolute; top: 12%; left: -8%; width: 130px; height: 2px;
  background: linear-gradient(90deg, transparent, #cfe0ffbb 60%, #fff);
  border-radius: 2px; opacity: 0; pointer-events: none; z-index: 0;
  transform: rotate(9deg);
  animation: comet 16s linear infinite;
  animation-delay: 5s;
}
@keyframes comet {
  0%, 93% { opacity: 0; left: -8%; top: 12%; }
  94% { opacity: 0.9; }
  100% { opacity: 0; left: 108%; top: 26%; }
}
.cs-fog i {
  background: radial-gradient(ellipse at center,
    color-mix(in srgb, var(--cs-accent, var(--accent)) 12%, #18223a) 0%, transparent 65%);
  opacity: 0.36;
}
@media (prefers-reduced-motion: reduce) {
  .cs-comet, #models .cs-root.cs-idle .mb-art { animation: none; }
}


/* ══ CHAT MODE ══ ENTER pressed: the roster and the sheet step aside, the
   conversation takes the right column, and the character stays on stage —
   summoning heartbeat while the weights land, faster heartbeat while it
   thinks, one bounce per real token while it speaks. Requires chat-ui.css
   (linked by index.html) for the message bubbles and the composer; below is
   only the panel chrome and the stagecraft. */

#models .cs-root.cs-chatting {
  /* The nav is sticky IN FLOW (60px + border), so a flat 100dvh hangs the
     composer 61px below the fold. In chat mode the composer is the primary
     control — the chamber must end above it. The tightened padding-top gives
     the reclaimed room to the conversation. */
  height: calc(100dvh - 61px);
  min-height: 0;
  padding-top: 22px;
  grid-template-columns: 1fr minmax(420px, 600px);
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    'plate chat'
    'stage chat'
    'note  chat';
}
/* #models-prefixed: the base rules carry the #models id, and a bare class
   pair loses that specificity fight — the roster stayed visible and its
   orphaned grid-area spawned implicit tracks that crushed the real columns
   (caught by the first browser pass). */
#models .cs-chatting .mb-info, #models .cs-chatting .mb-roster,
#models .cs-chatting .cs-roster-head, #models .cs-chatting .cs-enter,
#models .cs-chatting .mb-arrow, #models .cs-chatting .cs-corner-r { display: none; }

/* The engage flash no longer hands off to another page — it lifts to reveal
   the chamber. Starts opaque (the .cs-go fade ran under it), holds long
   enough to cover the swap, then clears. */
#models .cs-root.cs-chatting .cs-engage.cs-go { animation: csEngageReveal 0.9s ease forwards; }
@keyframes csEngageReveal {
  0%, 30% { opacity: 1; }
  100% { opacity: 0; visibility: hidden; }
}

/* The panel: the sheet's glass and rune corners, grown into an instrument. */
#models .cs-chat {
  /* min-width 0: grid items default to min-content width, and the nowrap
     composer-hint line was wider than a phone — the panel overflowed the
     viewport instead of shrinking into its column. */
  grid-area: chat; z-index: 2; min-height: 0; min-width: 0; position: relative;
  /* It is a <section>, and the page's generic section rule pads 72px into
     the panel — zero it; the head/composer carry their own spacing. */
  padding: 0;
  display: flex; flex-direction: column;
  border: 1px solid color-mix(in srgb, var(--cs-accent, var(--accent)) 22%, var(--border));
  border-radius: 4px;
  background: linear-gradient(180deg, #0c1220ee, #090e18e6);
  box-shadow: inset 0 1px 0 #ffffff0a, 0 18px 50px #0009;
  backdrop-filter: blur(4px);
  animation: csChatIn 0.5s cubic-bezier(0.2, 1, 0.3, 1) 0.1s both;
}
@keyframes csChatIn {
  from { opacity: 0; transform: translateX(26px); }
  to { opacity: 1; transform: translateX(0); }
}
#models .cs-chat::before, #models .cs-chat::after {
  content: ''; position: absolute; width: 40px; height: 40px; z-index: 3; pointer-events: none;
  background: color-mix(in srgb, var(--cs-accent, var(--accent)) 85%, #fff);
  -webkit-mask: url('/entrance/corner.svg') 0 0 / contain no-repeat;
  mask: url('/entrance/corner.svg') 0 0 / contain no-repeat;
}
#models .cs-chat::before { top: -5px; left: -5px; }
#models .cs-chat::after { bottom: -5px; right: -5px; transform: rotate(180deg); }

/* Panel header: sigil, name, build, live badge, tools. */
.cs-chat-head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px; border-bottom: 1px solid #ffffff0f;
}
.cs-chat-sigil { flex: none; width: 22px; height: 22px;
  color: var(--cs-accent, var(--accent)); }
.cs-chat-sigil svg { width: 100%; height: 100%; }
.cs-chat-id { display: flex; flex-direction: column; gap: 1px; min-width: 0; margin-right: auto; }
.cs-chat-id b { font-family: var(--display); font-weight: 600; font-size: 1.02rem;
  line-height: 1.15; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-chat-id i { font-style: normal; font-family: var(--mono); font-size: 0.58rem;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 70%, var(--text));
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-chat-tool {
  flex: none; font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--dim); text-decoration: none;
  padding: 5px 9px; border: 1px solid #ffffff1c; border-radius: 3px; background: #ffffff07;
  cursor: pointer; transition: color 0.15s, border-color 0.15s;
}
.cs-chat-tool:hover { color: var(--text); border-color: var(--muted); }
.cs-chat-tool:disabled { opacity: 0.4; cursor: not-allowed; }

/* Live badge — written by loading-ui.ts (Summoning → % → Ready). */
.cs-chat .badge {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase;
  padding: 4px 9px; border: 1px solid #ffffff1c; border-radius: 999px; color: var(--dim);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.cs-chat .badge .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--muted); }
.cs-chat .badge.loading { color: #fbbf24; border-color: #fbbf2440; }
.cs-chat .badge.loading .dot { background: #fbbf24; animation: csBadgePulse 1.4s infinite; }
.cs-chat .badge.ready { color: var(--cs-accent, var(--accent));
  border-color: color-mix(in srgb, var(--cs-accent, var(--accent)) 40%, transparent); }
.cs-chat .badge.ready .dot { background: var(--cs-accent, var(--accent)); }
.cs-chat .badge.error { color: var(--err); border-color: color-mix(in srgb, var(--err) 45%, transparent); }
.cs-chat .badge.error .dot { background: var(--err); }
@keyframes csBadgePulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }

/* The rite card: download + compile progress, then it folds away. */
.cs-boot { padding: 16px 16px 14px; border-bottom: 1px solid #ffffff0f; }
.cs-boot.cs-done { display: none; }
.cs-boot-title { font-family: var(--display); font-size: 1.05rem; margin-bottom: 2px; }
.cs-boot-status { font-size: 0.78rem; color: var(--text-dim, #a9b3c6); min-height: 1.2em; margin-bottom: 10px; }
.cs-boot-track { height: 4px; border-radius: 2px; background: #ffffff12; overflow: hidden; }
.cs-boot-track i {
  display: block; height: 100%; width: 0; border-radius: 2px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--cs-accent, var(--accent)) 55%, transparent),
    var(--cs-accent, var(--accent)));
  transition: width 0.25s ease;
}
.cs-boot-detail { margin-top: 7px; font-family: var(--mono); font-size: 0.64rem;
  color: var(--dim); font-variant-numeric: tabular-nums; }
.cs-boot-note { margin-top: 7px; font-size: 0.72rem; color: var(--warn, #d9a441); }
.cs-boot-log { margin-top: 9px; }
.cs-boot-log summary {
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--dim); cursor: pointer; user-select: none;
}
.cs-boot-log summary:hover { color: var(--text-dim, #a9b3c6); }
.cs-boot-log pre {
  margin-top: 6px; max-height: 130px; overflow-y: auto;
  padding: 8px 10px; border: 1px solid #ffffff0f; border-radius: 3px; background: #070b13;
  font-family: var(--mono); font-size: 0.62rem; line-height: 1.5; color: var(--text-dim, #a9b3c6);
  white-space: pre-wrap;
}
.cs-boot-error { display: none; margin-top: 10px; padding: 9px 11px;
  border: 1px solid color-mix(in srgb, var(--err) 40%, transparent); border-radius: 3px;
  background: color-mix(in srgb, var(--err) 9%, transparent);
  font-size: 0.76rem; line-height: 1.5; color: color-mix(in srgb, var(--err) 60%, #fff); }
.cs-boot-error.visible { display: block; }

/* Conversation column: bubbles ride the panel glass, not their own ground. */
.cs-chat .chat-main { flex: 1; min-height: 0; }
.cs-chat .welcome.cs-wait, .cs-chat .welcome.hidden { display: none; }
.cs-chat .welcome { padding: 1.4rem 0.2rem 1rem; }
.cs-welcome-title { font-family: var(--display); font-size: 1.3rem; margin-bottom: 6px; }
.cs-welcome-lore { font-size: 0.8rem; font-style: italic; line-height: 1.55;
  color: color-mix(in srgb, var(--text) 62%, transparent); margin-bottom: 14px; }
.cs-sug-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.cs-chat .suggest {
  text-align: left; font-size: 0.76rem; line-height: 1.4; color: var(--text-dim, #a9b3c6);
  padding: 10px 12px; border: 1px solid #ffffff14; border-radius: 3px; background: #ffffff06;
  cursor: pointer; transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.cs-chat .suggest:hover {
  color: var(--text); background: color-mix(in srgb, var(--cs-accent, var(--accent)) 8%, transparent);
  border-color: color-mix(in srgb, var(--cs-accent, var(--accent)) 45%, transparent);
}

/* Composer, re-cut to the entrance's edge language (chat-ui.css carries the
   mechanics; only the chrome changes here). */
.cs-chat .composer-wrap { background: transparent; border-top: 1px solid #ffffff0f; padding: 11px 13px 10px; }
.cs-chat .composer { background: #0a101ccc; border-radius: 3px;
  border-color: color-mix(in srgb, var(--cs-accent, var(--accent)) 26%, var(--border)); }
.cs-chat .composer:focus-within { background: #0c1322; border-color: var(--cs-accent, var(--accent)); }
.cs-chat .composer-btn { border-radius: 3px; }
.cs-chat .composer-hint {
  display: flex; justify-content: space-between; gap: 4px 10px; flex-wrap: wrap; text-align: left;
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.06em; color: var(--dim);
  max-width: none;
}
.cs-chat-stats { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ── Stagecraft: what the realm does while the model works ──────────────── */

/* Summoning: the circle beats slowly and the ring runs the armed sweep — the
   character is being drawn through. */
#models .cs-summoning .mb-pedestal::after { animation: ringPulse 1.5s ease-in-out infinite; }
#models .cs-summoning .mb-pedestal::before {
  content: ''; position: absolute; inset: 0;
  background: conic-gradient(from 0deg,
    transparent 0deg, transparent 290deg,
    color-mix(in srgb, var(--cs-accent, var(--accent)) 90%, #fff) 330deg,
    transparent 360deg);
  -webkit-mask: url('/entrance/ring.svg') center bottom / 100% auto no-repeat;
  mask: url('/entrance/ring.svg') center bottom / 100% auto no-repeat;
  animation: armedSpin 2.6s linear infinite;
}
/* Thinking: prefill — the ring tightens to a fast shallow breath. */
#models .cs-thinking .mb-pedestal::after { animation: ringPulse 0.9s ease-in-out infinite; }
#models .cs-thinking .mb-pedestal { filter: brightness(1.18); }
/* Generating: the floor burns steady and bright; the bounce on stage is the
   token stream itself (mascot.pulse per emitted token). */
#models .cs-generating .mb-pedestal { filter: brightness(1.3); }
#models .cs-generating .mb-pedestal::after { animation: none; opacity: 1; }
#models .mb-pedestal { transition: filter 0.4s ease; }

/* Phones: the character folds to a small familiar above the conversation. */
@media (max-width: 900px) {
  #models .cs-root.cs-chatting {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto 1fr;
    grid-template-areas: 'plate' 'stage' 'chat';
  }
  #models .cs-chatting .mb-mascot { height: 110px; -webkit-box-reflect: none; }
  #models .cs-chatting .mb-pedestal { height: 60px; }
  #models .cs-chatting .cs-lore { display: none; }
  #models .cs-chatting .mb-plate { padding-bottom: 4px; }
  #models .cs-chatting .mb-name { font-size: 1.3rem; }
  .cs-sug-grid { grid-template-columns: 1fr; }
  .cs-chat-tool#new-chat-btn { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  #models .cs-chat, #models .cs-root.cs-chatting .cs-engage.cs-go { animation: none; }
  #models .cs-summoning .mb-pedestal::before { animation: none; }
}

/* ══ DOWNLOADED = READY ══ The READY tag gains a fill so it reads at roster
   distance, and a variant chip that is already on this device carries a dot —
   both from the same OPFS probe as everything else. */
#models .mb-dot[data-cached]::after {
  background: color-mix(in srgb, var(--ok) 16%, transparent);
}
#models .mb-variant[data-cached]::after {
  content: '●'; margin-left: 7px; font-size: 0.5rem; vertical-align: 2px;
  color: var(--ok);
}

/* ══ GAME ROUND: abilities, saves, listening, the token stream ═════════════ */

/* Abilities: the spec's mechanics as passives — rune bullet, name, clause. */
#models .mb-abilities { list-style: none; margin: 12px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px; }
#models .mb-abilities li { display: flex; align-items: baseline; gap: 8px;
  font-size: 0.74rem; line-height: 1.4; }
#models .mb-abilities li::before { content: '◆'; flex: none; font-size: 0.5rem;
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 80%, #fff); }
#models .mb-abilities b { flex: none; font-weight: 600; letter-spacing: 0.02em;
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 55%, var(--text)); }
#models .mb-abilities span { color: var(--dim); }

/* Save slot: a stored conversation marks its character — roster glyph +
   sheet line. Presence only, never a count. */
#models .mb-dot[data-save] .mb-dot-text b::after {
  content: ' ◈'; font-size: 0.7em; vertical-align: 1px;
  color: #cfe0ffaa;
}
#models .mb-save { font-size: var(--step--1); margin: 10px 0 0;
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 60%, var(--text)); }

/* LISTENING: keys are landing — the character turns toward the panel. The
   ears perk through the mascot's hover state; this is the body language. */
#models .cs-chatting.cs-listening .mb-art { rotate: y 9deg; }
#models .mb-art { transition: transform 0.3s ease-out, rotate 0.45s ease; }

/* THE TOKEN STREAM: while the model speaks, glyphs fly from the character's
   mouth into the conversation. Visible ONLY under cs-generating — the stream
   exists exactly when tokens do. */
.cs-stream { display: none; }
#models .cs-chatting.cs-generating .cs-stream { display: block;
  position: absolute; left: 26%; right: 0; top: 0; bottom: 0;
  pointer-events: none; z-index: 2; }
.cs-stream i {
  position: absolute; left: 0; top: 44%;
  font-style: normal; font-size: 11px;
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 85%, #fff);
  text-shadow: 0 0 6px color-mix(in srgb, var(--cs-accent, var(--accent)) 60%, transparent);
  opacity: 0;
  animation: tokFly 1.15s linear infinite;
}
.cs-stream i:nth-child(2) { animation-delay: 0.19s; font-size: 8px; top: 45.5%; }
.cs-stream i:nth-child(3) { animation-delay: 0.38s; top: 43%; }
.cs-stream i:nth-child(4) { animation-delay: 0.57s; font-size: 8px; top: 46%; }
.cs-stream i:nth-child(5) { animation-delay: 0.76s; top: 44.5%; }
.cs-stream i:nth-child(6) { animation-delay: 0.95s; font-size: 9px; top: 43.5%; }
@keyframes tokFly {
  0% { transform: translateX(0) translateY(0); opacity: 0; }
  12% { opacity: 0.9; }
  55% { transform: translateX(22vw) translateY(-1.2vh); opacity: 0.85; }
  92% { opacity: 0.5; }
  100% { transform: translateX(38vw) translateY(-0.6vh); opacity: 0; }
}

/* SUMMON FAILURE: the circle goes cold. The rite card carries the flavour
   line; the diagnostic stays in the error panel. */
#models .cs-boot-failed .mb-pedestal { filter: grayscale(0.7) brightness(0.55); }
#models .cs-boot-failed .mb-pedestal::after { animation: none; opacity: 0.3; }
#models .cs-boot-failed .mb-pedestal::before { display: none; }

@media (max-width: 900px) {
  /* The stream's geometry assumes stage-left/panel-right; stacked phones
     have neither, and the abilities pad the sheet. */
  .cs-stream { display: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  .cs-stream { display: none !important; }
  #models .cs-chatting.cs-listening .mb-art { rotate: none; }
}

/* ══ EXTENDED ROUND: sleep, the constellation, the deeds rail ══════════════ */

/* ASLEEP (50 s idle): the ring cools and slows with the character — the
   sleepy face itself is the mascot's mood, this is the room's light. */
#models .cs-asleep .mb-pedestal { filter: brightness(0.7) saturate(0.8); }
#models .cs-asleep .mb-pedestal::after { animation-duration: 10s; }
#models .cs-asleep .cs-fog i { opacity: 0.2; }

/* THE CONSTELLATION: the lane's sigil, huge and faint, behind the stage.
   Masked accent — it recolours with the character and drifts on parallax. */
.cs-sigilbg {
  position: absolute; z-index: 0; pointer-events: none;
  left: 50%; top: 50%;
  width: min(74vh, 58vw); height: min(74vh, 58vw);
  margin: calc(min(74vh, 58vw) / -2) 0 0 calc(min(74vh, 58vw) / -2);
  background: color-mix(in srgb, var(--cs-accent, var(--accent)) 80%, #fff);
  opacity: 0.05;
  -webkit-mask-size: contain; mask-size: contain;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
}
#models .cs-chatting .cs-sigilbg { left: 27%; }

/* THE DEEDS RAIL: things that happened on this device. Unearned = a dim rune
   with the trigger in its tooltip (a quest list, not decoration); earned =
   lit, named. No counts anywhere. */
#models .cs-deeds {
  grid-area: note; z-index: 1; justify-self: center;
  display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: center;
  padding: 2px 0;
}
.cs-deed {
  font-family: var(--mono); font-size: 0.56rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: color-mix(in srgb, var(--dim) 55%, transparent);
  cursor: default;
}
.cs-deed i { font-style: normal; display: none; margin-left: 5px; }
.cs-deed[data-on] {
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 75%, #fff);
  text-shadow: 0 0 8px color-mix(in srgb, var(--cs-accent, var(--accent)) 45%, transparent);
}
.cs-deed[data-on] i { display: inline; }
@media (max-width: 900px) { #models .cs-deeds { display: none; } }

/* ══ THE ROOM ══ Hosting from inside the game: the strip in the panel, and
   one small mascot per connected guest flanking the character. */
.cs-room { padding: 12px 14px; border-bottom: 1px solid #ffffff0f; }
.cs-room-consent p { font-size: 0.76rem; line-height: 1.55; color: var(--text-dim, #a9b3c6);
  margin: 0 0 10px; }
.cs-room-linkrow { display: flex; gap: 6px; align-items: center; }
.cs-room-linkrow input {
  flex: 1; min-width: 0; padding: 6px 9px; font-family: var(--mono); font-size: 0.66rem;
  color: var(--text); background: #0a101ccc; border-radius: 3px;
  border: 1px solid color-mix(in srgb, var(--cs-accent, var(--accent)) 30%, var(--border));
}
.cs-room-members { margin-top: 8px; font-family: var(--mono); font-size: 0.62rem;
  letter-spacing: 0.08em; color: var(--dim); }
.cs-room-log { list-style: none; margin: 8px 0 0; padding: 0; display: flex;
  flex-direction: column; gap: 4px; }
.cs-room-log li { display: flex; gap: 8px; align-items: baseline; font-size: 0.7rem;
  color: var(--text-dim, #a9b3c6); overflow: hidden; white-space: nowrap; }
.cs-room-log b { font-family: var(--mono); font-size: 0.6rem; font-weight: 400;
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 70%, var(--text)); flex: none; }
.cs-room-log span { overflow: hidden; text-overflow: ellipsis; }
.cs-room-log i { font-style: normal; font-family: var(--mono); font-size: 0.6rem;
  color: var(--dim); margin-left: auto; flex: none; }
.cs-tool-live { border-color: var(--cs-accent, var(--accent)) !important;
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 80%, #fff) !important; }

/* Guests on stage: small familiars on the ring's edge. */
.cs-guest-mascot { position: absolute; width: 90px; height: 90px; z-index: 1;
  pointer-events: none; animation: guestIn 0.5s ease both; }
.cs-guest-0 { left: 8%;  bottom: 10%; }
.cs-guest-1 { right: 8%; bottom: 10%; }
.cs-guest-2 { left: 2%;  bottom: 34%; }
.cs-guest-3 { right: 2%; bottom: 34%; }
.cs-guest-4 { left: 16%; bottom: 0; }
.cs-guest-5 { right: 16%; bottom: 0; }
@keyframes guestIn { from { opacity: 0; transform: translateY(10px) scale(0.8); }
  to { opacity: 1; transform: none; } }
@media (max-width: 900px) { .cs-guest-mascot { display: none; } }

/* The room path under ENTER: quiet sibling, same class light. */
#models .cs-enter { flex-direction: column; align-items: center; gap: 8px; }
#models .mb-cta-room {
  font-family: var(--mono); font-size: 0.64rem; letter-spacing: 0.1em;
  text-transform: uppercase; text-decoration: none; cursor: pointer;
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 65%, var(--dim));
  padding: 4px 10px; border: 1px solid transparent; border-radius: 3px;
  transition: color 0.15s, border-color 0.15s;
}
#models .mb-cta-room:hover {
  color: color-mix(in srgb, var(--cs-accent, var(--accent)) 85%, #fff);
  border-color: color-mix(in srgb, var(--cs-accent, var(--accent)) 40%, transparent);
}

/* ══ LENS ROUND 2026-08-17 FIXES ═══════════════════════════════════════════ */

/* The cinematic bottom fade must not wash the chat panel's composer — the
   panel IS the bottom of the screen in chat mode. */
#models .cs-root.cs-chatting::after { display: none; }

@media (prefers-reduced-motion: reduce) {
  /* The mood states re-armed the ring pulse that the base reduce block had
     disabled; and guests should simply appear. */
  #models .cs-summoning .mb-pedestal::after,
  #models .cs-thinking .mb-pedestal::after { animation: none; }
  .cs-guest-mascot { animation: none; }
}
