/* ============================================================
   LEARNING LAB · PLAYER SHELL  (ported from prototypes/course-lab)
   Studio theme: tokens come from static/css/theme/tokens.css via
   data-theme="build" on <html> — the prototype's :root token copy
   is deleted here, per LEARN_PLAN.md L1.8. Fonts are the site's
   self-hosted faces (static/css/fonts.css); no Google Fonts.
   Short-viewport overrides live at the END of this file and must
   stay there (source order decides when specificity ties, rule 10).
   ============================================================ */

/* The site names its font stacks per-theme (--font-*-studio); the lab's
   rules use the prototype's names. Alias, do not copy values. --font-mono
   is already global in tokens.css. */
[data-theme="build"]{
  --font-display:var(--font-display-studio);
  --font-body:var(--font-body-studio);
}

/* ---- Stage accents ------------------------------------------
   One accent per stage, all drawn from the studio palette.
   --stage      fills and bars
   --stage-ink  the same hue darkened for text on paper
   On the site these become --c-* primitives in tokens.css.
   ------------------------------------------------------------ */
.stage-1{ --stage:#6366f1; --stage-ink:#4f46e5; }  /* AI Core            indigo */
.stage-2{ --stage:#9b7cc4; --stage-ink:#7c5aa8; }  /* Build With AI      violet */
.stage-3{ --stage:#4db8a8; --stage-ink:#35907f; }  /* Self Hosting       teal   */
.stage-4{ --stage:#2d6a4f; --stage-ink:#1e4d38; }  /* Agentic Automation dark green (Hasan, AA 01 round 1) */
.stage-5{ --stage:#f5d76e; --stage-ink:#a8821a; }  /* Solo Business      gold   */

*{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; }
[hidden]{ display:none !important; }   /* beats the display rules below */

body{
  margin:0;
  background:var(--surface);
  color:var(--ink);
  font-family:var(--font-body);
  font-size:16px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
}

a{ color:inherit; }

/* ---- shared type roles --------------------------------------- */

.lw-display{
  font-family:var(--font-display);
  font-weight:700;
  letter-spacing:-0.02em;
  line-height:1.08;
  margin:0;
}

.lw-label{
  font-family:var(--font-mono);
  font-size:11.5px;
  font-weight:500;
  text-transform:uppercase;
  letter-spacing:0.12em;
  color:var(--muted);
}

.lw-num{ font-family:var(--font-mono); font-variant-numeric:tabular-nums; }

/* ---- buttons -------------------------------------------------- */

.lw-btn{
  font-family:var(--font-body);
  font-size:15px; font-weight:600;
  border-radius:var(--radius-pill);
  padding:11px 22px;
  border:1px solid var(--line);
  background:#fff;
  color:var(--ink);
  cursor:pointer;
  transition:background .16s ease, border-color .16s ease, transform .07s ease, box-shadow .16s ease;
  box-shadow:var(--shadow-sm);
}
.lw-btn:hover{ background:var(--surface-2); }
.lw-btn:active{ transform:translateY(1px); }
.lw-btn:focus-visible{ outline:2px solid var(--stage, var(--accent)); outline-offset:2px; }
.lw-btn[disabled]{ opacity:.38; cursor:not-allowed; box-shadow:none; }

.lw-btn--primary{
  background:var(--stage, var(--accent));
  border-color:transparent;
  color:#fff;
  box-shadow:0 1px 2px rgba(26,26,46,.10), 0 6px 18px -6px var(--stage, var(--accent));
}
.lw-btn--primary:hover{ background:var(--stage-ink, var(--accent-strong)); }

.lw-btn--ghost{ background:transparent; box-shadow:none; border-color:transparent; color:var(--muted); }
.lw-btn--ghost:hover{ background:var(--surface-2); color:var(--ink); }

.lw-btn--sm{ font-size:14px; padding:8px 15px; }

.lw-pill{
  display:inline-flex; align-items:center; gap:6px;
  font-family:var(--font-mono); font-size:10.5px; font-weight:500;
  text-transform:uppercase; letter-spacing:.1em;
  padding:5px 11px; border-radius:var(--radius-pill);
  border:1px solid var(--line); background:#fff; color:var(--muted);
}
.lw-pill--stage{ border-color:transparent; background:color-mix(in srgb, var(--stage) 16%, #fff); color:var(--stage-ink); }
.lw-pill--locked{ background:var(--surface-2); }

/* ============================================================
   LESSON SHELL — one focused screen, never scrolls
   ============================================================ */

.lab-shell{
  height:100dvh;
  display:flex;
  flex-direction:column;
  overflow:hidden;
}

/* ---- topbar: the unified path is always visible ---- */

.lab-topbar{
  flex:0 0 auto;
  display:flex; align-items:center; gap:16px;
  padding:0 clamp(14px, 2.4vw, 28px);
  height:56px;
  border-bottom:1px solid var(--line);
  background:var(--surface);
}

/* the site wordmark, matching .lw-nav__logo (chrome.css) at topbar scale */
.lab-logo{
  font-family:var(--font-display);
  font-weight:700; font-size:17px; letter-spacing:-0.02em;
  color:var(--ink); text-decoration:none; white-space:nowrap;
}
.lab-logo span{ color:var(--accent); }

.lab-back{
  display:inline-flex; align-items:center; gap:7px;
  font-size:13px; font-weight:500; color:var(--muted);
  text-decoration:none; white-space:nowrap;
  padding:6px 10px; border-radius:var(--radius-pill);
  transition:background .16s ease, color .16s ease;
}
.lab-back:hover{ background:var(--surface-2); color:var(--ink); }

/* five stage pips — the whole path, always in the corner of your eye */
.lab-pips{ display:flex; align-items:center; gap:5px; }
.lab-pip{
  width:22px; height:4px; border-radius:2px;
  background:var(--line);
}
.lab-pip.is-owned{ background:color-mix(in srgb, var(--ink) 26%, transparent); }
.lab-pip.is-here{ background:var(--stage); box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 18%, transparent); }

.lab-crumb{
  display:flex; align-items:baseline; gap:9px;
  min-width:0;
  font-size:13.5px; color:var(--muted);
}
.lab-crumb b{ color:var(--ink); font-weight:600; }
.lab-crumb .lab-crumb-title{
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}

.lab-topright{ margin-left:auto; display:flex; align-items:center; gap:14px; }

.lab-lamps{ display:flex; gap:6px; }
.lab-lamp{
  width:8px; height:8px; border-radius:50%;
  background:var(--line);
  transition:background .28s ease, box-shadow .28s ease, transform .28s ease;
}
.lab-lamp.is-done{ background:color-mix(in srgb, var(--stage) 55%, transparent); }
.lab-lamp.is-live{ background:var(--stage); transform:scale(1.25); box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 20%, transparent); }

.lab-topbtn{
  width:32px; height:32px; border-radius:9px;
  display:grid; place-items:center;
  border:1px solid var(--line); background:#fff; color:var(--muted);
  cursor:pointer; padding:0;
  transition:background .16s ease, color .16s ease;
}
.lab-topbtn:hover{ background:var(--surface-2); color:var(--ink); }
.lab-topbtn.is-on{ background:color-mix(in srgb, var(--stage) 14%, #fff); border-color:color-mix(in srgb, var(--stage) 40%, transparent); color:var(--stage-ink); }
.lab-topbtn:focus-visible{ outline:2px solid var(--stage); outline-offset:2px; }
.lab-topbtn--tools{ display:none; }   /* phone only — desktop has the rail */

/* ---- body: tool rail | stage | course pane ---- */

.lab-body{
  flex:1 1 auto; min-height:0;
  display:flex; position:relative;
}

.lab-rail{
  flex:0 0 auto; width:56px;
  display:flex; flex-direction:column; align-items:center; gap:6px;
  padding:12px 0;
  border-right:1px solid var(--line);
}
.lab-tool{
  width:38px; height:38px; border-radius:10px;
  display:grid; place-items:center;
  border:0; background:transparent; color:var(--muted);
  cursor:pointer; padding:0;
  transition:background .16s ease, color .16s ease;
}
.lab-tool:hover{ background:var(--surface-2); color:var(--ink); }
.lab-tool.is-on{ background:color-mix(in srgb, var(--stage) 14%, #fff); color:var(--stage-ink); }
.lab-tool:focus-visible{ outline:2px solid var(--stage); outline-offset:2px; }

/* the tool flyout overlays rather than squeezes, so opening a tool
   never reflows the interactive underneath it */
.lab-tools{
  position:absolute; left:56px; top:0; bottom:0; width:min(320px, 78vw);
  z-index:6;
  display:none; flex-direction:column;
  background:var(--surface);
  border-right:1px solid var(--line);
  box-shadow:var(--shadow);
}
.lab-tools.is-open{ display:flex; animation:lab-slide .22s cubic-bezier(.16,.9,.3,1) both; }
@keyframes lab-slide{ from{ opacity:0; transform:translateX(-12px); } to{ opacity:1; transform:none; } }

.lab-tools-head,
.lab-pane-head{
  flex:0 0 auto;
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:13px 16px; border-bottom:1px solid var(--line);
}
.lab-tools-body{ flex:1 1 auto; overflow-y:auto; padding:16px; }

/* the rail, relocated into the flyout for when there is no rail */
.lab-tools-tabs{ display:none; gap:2px; margin-left:auto; }
.lab-tab{
  width:32px; height:32px; border-radius:8px;
  display:grid; place-items:center; padding:0;
  border:0; background:transparent; color:var(--muted); cursor:pointer;
}
.lab-tab.is-on{ background:color-mix(in srgb, var(--stage) 15%, #fff); color:var(--stage-ink); }
.lab-tab:focus-visible{ outline:2px solid var(--stage); outline-offset:1px; }
.lab-tools-body .lab-textarea{ margin-top:0; max-width:none; min-height:150px; resize:vertical; }

.lab-empty{
  border:1px dashed var(--line); border-radius:var(--radius-sm);
  padding:16px; color:var(--muted); font-size:14px;
}
.lab-res{
  display:flex; align-items:center; gap:11px;
  padding:11px 13px; margin-bottom:8px;
  border:1px solid var(--line); border-radius:var(--radius-sm);
  background:#fff; font-size:14px;
}
.lab-res .lw-label{ display:block; }

/* ---- the course pane: the path IS the accordion ---- */

.lab-pane{
  flex:0 0 auto; width:328px;
  display:flex; flex-direction:column;
  border-left:1px solid var(--line);
  background:var(--surface-2);
  overflow:hidden;
  transition:width .26s cubic-bezier(.16,.9,.3,1);
}
.lab-shell.pane-closed .lab-pane{ width:0; border-left-width:0; }
.lab-pane-inner{ width:328px; display:flex; flex-direction:column; height:100%; }
.lab-pane-body{ flex:1 1 auto; overflow-y:auto; }

.pane-stage{ border-bottom:1px solid var(--line); }
.pane-stage-head{
  width:100%; display:flex; align-items:center; gap:11px;
  padding:13px 15px; background:transparent; border:0; cursor:pointer;
  text-align:left; font-family:inherit;
  transition:background .16s ease;
}
.pane-stage-head:hover{ background:rgba(26,26,46,.035); }
.pane-stage-head:focus-visible{ outline:2px solid var(--stage); outline-offset:-2px; }
.pane-dot{
  flex:0 0 auto; width:9px; height:9px; border-radius:50%;
  background:var(--stage);
}
.pane-stage.is-locked .pane-dot{ background:var(--line); }
.pane-stage-name{ flex:1 1 auto; min-width:0; font-size:14px; font-weight:600; }
.pane-stage.is-locked .pane-stage-name{ font-weight:500; color:var(--muted); }
.pane-stage-meta{ flex:0 0 auto; font-family:var(--font-mono); font-size:10px; color:var(--muted); }
.pane-caret{ flex:0 0 auto; color:var(--muted); transition:transform .2s ease; }
.pane-stage.is-open .pane-caret{ transform:rotate(90deg); }

.pane-lessons{ display:none; padding:0 0 8px; }
.pane-stage.is-open .pane-lessons{ display:block; }

.pane-lesson{
  width:100%; display:flex; align-items:center; gap:10px;
  padding:8px 15px 8px 35px;
  background:transparent; border:0; cursor:pointer; text-align:left;
  font-family:inherit; font-size:13.5px; color:var(--ink);
  text-decoration:none;
  transition:background .16s ease;
}
.pane-lesson:hover{ background:rgba(26,26,46,.045); }
.pane-lesson-n{ flex:0 0 auto; font-family:var(--font-mono); font-size:10px; color:var(--muted); width:2ch; }
.pane-lesson-t{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pane-lesson.is-here{ background:color-mix(in srgb, var(--stage) 12%, transparent); font-weight:600; }
.pane-lesson.is-here .pane-lesson-n{ color:var(--stage-ink); }
.pane-lesson.is-done .pane-lesson-n{ color:var(--stage-ink); }
.pane-lesson.is-locked{ color:var(--muted); cursor:default; }
.pane-lesson.is-locked:hover{ background:transparent; }
.pane-lesson-tag{
  flex:0 0 auto; font-family:var(--font-mono); font-size:9px;
  letter-spacing:.08em; text-transform:uppercase;
  color:var(--stage-ink);
}

.pane-foot{ flex:0 0 auto; padding:12px 15px; border-top:1px solid var(--line); }
.pane-bar{ height:5px; border-radius:3px; background:var(--line); overflow:hidden; margin-top:7px; }
.pane-bar i{ display:block; height:100%; background:var(--stage); border-radius:3px; }

/* ---- stage: split, fixed height, clipped ---- */

.lab-stage{
  flex:1 1 auto;
  min-height:0; min-width:0;
  overflow:hidden;
  display:grid;
  grid-template-columns:minmax(0, 5fr) minmax(0, 7fr);
  grid-template-rows:auto minmax(0, 1fr);
  grid-template-areas:"teach instr" "finding instr";
  gap:clamp(18px, 2.6vw, 40px);
  padding:clamp(18px, 2.6vw, 34px) clamp(14px, 2.4vw, 28px);
  align-content:start;
}

/* type sizes off the COLUMN, not the viewport — opening the course pane
   narrows this column and viewport units would not notice */
.lab-teach{ grid-area:teach; min-width:0; container-type:inline-size; }
.lab-finding-slot{ grid-area:finding; min-width:0; align-self:start; }
.lab-instr{ grid-area:instr; min-width:0; min-height:0; display:flex; flex-direction:column; }

/* step swap: a short cross-fade reads as moving to a new concept */
.lab-step{ display:none; }
.lab-step.is-live{ display:contents; }
.lab-swap{ animation:lab-enter .34s cubic-bezier(.16,.9,.3,1) both; }
@keyframes lab-enter{ from{ opacity:0; transform:translateY(10px); } to{ opacity:1; transform:none; } }
/* going BACK enters from above: direction you can feel, six lines of CSS */
.lab-stage[data-dir="back"] .lab-swap{ animation-name:lab-enter-back; }
@keyframes lab-enter-back{ from{ opacity:0; transform:translateY(-10px); } to{ opacity:1; transform:none; } }
/* a fresh set of options cascades in with its beat. Fade + scale, no
   translate: a translated child extends the scrollable overflow region
   mid-animation, and the no-scroll probe rightly catches it in flight */
.lab-swap .quiz-opts .opt{ animation:opt-in .32s ease both; }
@keyframes opt-in{ from{ opacity:0; transform:scale(.97); } to{ opacity:1; transform:none; } }
.lab-swap .quiz-opts .opt:nth-child(1){ animation-delay:.05s }
.lab-swap .quiz-opts .opt:nth-child(2){ animation-delay:.10s }
.lab-swap .quiz-opts .opt:nth-child(3){ animation-delay:.15s }
.lab-swap .quiz-opts .opt:nth-child(4){ animation-delay:.20s }

/* ---- teaching column ---- */

.lab-eyebrow{ display:flex; align-items:center; gap:8px; margin-bottom:12px; }
.lab-eyebrow b{ color:var(--stage-ink); font-weight:600; }

.lab-title{
  font-size:clamp(21px, 8.6cqi, 34px);
  max-width:18ch;
  margin-bottom:14px;
}

.lab-prose{
  color:var(--muted);
  font-size:clamp(15px, 4.3cqi, 17px);
  max-width:42ch;
  margin:0 0 14px;
}
.lab-prose strong{ color:var(--ink); font-weight:600; }
.lab-prose:last-child{ margin-bottom:0; }

.lab-field{
  display:flex; gap:9px; align-items:center; margin-top:16px; flex-wrap:wrap;
}
.lw-input{
  font-family:var(--font-mono); font-size:15px; color:var(--ink);
  padding:11px 14px; width:min(220px, 60vw);
  border:1px solid var(--line); border-radius:var(--radius-sm);
  background:#fff; outline:0;
  box-shadow:var(--shadow-sm);
}
.lw-input::placeholder{ color:var(--muted); opacity:.7; }
.lw-input:focus{ border-color:var(--stage); box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 20%, transparent); }

.lab-textarea{
  width:100%; max-width:42ch; margin-top:12px;
  font-family:var(--font-body); font-size:15px; line-height:1.55; color:var(--ink);
  padding:12px 14px; min-height:88px; resize:none;
  border:1px solid var(--line); border-radius:var(--radius-sm);
  background:#fff; outline:0; box-shadow:var(--shadow-sm);
}
.lab-textarea:focus{ border-color:var(--stage); box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 20%, transparent); }

/* ---- verdict + finding ---- */

.lab-verdict{
  display:none; margin-top:16px; max-width:42ch;
  padding-left:14px; border-left:3px solid var(--ink);
}
.lab-verdict.is-shown{ display:block; animation:lab-enter .38s ease both; }
.lab-finding-slot .lab-verdict{ margin-top:0; margin-bottom:16px; }
.lab-verdict-v{ font-size:15.5px; margin-top:3px; }
.lab-verdict-v b{ font-weight:600; }

.lab-finding{
  display:none;
  border-radius:var(--radius);
  border:1px solid var(--line);
  background:linear-gradient(180deg, #fff, var(--surface-2));
  box-shadow:var(--shadow-sm);
  padding:16px 18px;
  max-width:44ch;
}
.lab-finding.is-shown{ display:block; animation:lab-enter .42s ease both; }
.lab-finding p{
  margin:7px 0 0;
  font-family:var(--font-display); font-weight:600;
  font-size:clamp(16.5px, 1.4vw, 20px);
  line-height:1.32; letter-spacing:-.01em;
}
.lab-chips{ display:flex; gap:7px; flex-wrap:wrap; margin-top:14px; }

/* ============================================================
   INSTRUMENT — the machine speaking. Dark ink on the light page.
   ============================================================ */

.lab-readout{
  flex:1 1 auto;
  min-height:0;
  position:relative;
  display:flex; flex-direction:column;
  background:var(--c-ink-900);
  border-radius:var(--radius);
  box-shadow:var(--shadow);
  padding:clamp(14px, 1.8vw, 22px);
  overflow:hidden;
}
.lab-readout::before{
  content:''; position:absolute; inset:0; pointer-events:none;
  background-image:
    linear-gradient(rgba(201,209,217,.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(201,209,217,.045) 1px, transparent 1px);
  background-size:24px 24px;
}
.lab-readout > *{ position:relative; }

.lab-readout-head{
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  margin-bottom:12px;
}

/* steps without a dial would leave a lot of dead panel below the bars.
   The panel keeps its height (it is the same instrument every step) and
   the content sits optically centred inside it instead. */
.lab-readout-body{
  flex:1 1 auto; min-height:0;
  display:flex; flex-direction:column; justify-content:center;
}
.lab-readout-head .lw-label{ color:var(--c-ink-400); }

.lab-sentence{
  font-family:var(--font-display); font-weight:500;
  font-size:clamp(17px, 1.9vw, 24px);
  color:var(--c-ink-300); line-height:1.3; letter-spacing:-.01em;
  margin-bottom:14px;
}
.lab-blank{
  display:inline-block; min-width:2.2ch;
  border-bottom:2px solid var(--stage);
  color:var(--stage); padding:0 .1em;
}
.lab-caret{
  display:inline-block; width:.5ch; height:1em;
  background:var(--stage); vertical-align:-.14em;
  animation:lab-blink 1.05s steps(2,start) infinite;
}
@keyframes lab-blink{ 0%,50%{opacity:1} 50.01%,100%{opacity:0} }

/* ---- distribution ---- */

.lab-dist{ display:grid; gap:3px; }

.lab-row{
  display:grid;
  grid-template-columns:8.5ch minmax(0,1fr) 6ch;
  align-items:center; gap:10px;
  height:24px;
}
.lab-row-w{
  font-family:var(--font-mono); font-size:11.5px; color:var(--c-ink-300);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.lab-track{
  display:block; height:10px; border-radius:2px;
  background:rgba(201,209,217,.07); overflow:hidden;
}
.lab-fill{
  display:block; height:100%; width:0;
  background:var(--stage);
  transition:width .6s cubic-bezier(.16,.9,.3,1);
}
.lab-row-p{
  font-family:var(--font-mono); font-variant-numeric:tabular-nums;
  font-size:11px; color:var(--c-ink-300); text-align:right;
}
.lab-row-p i{ color:var(--c-ink-400); font-style:normal; }

/* your own mark is always paper-white, so it never collides with a stage accent */
.lab-row.is-you .lab-fill{ background:var(--c-paper); }
.lab-row.is-you .lab-row-w{ color:var(--c-paper); font-weight:500; }

.lab-row.is-tail .lab-row-w,
.lab-row.is-tail .lab-row-p{ color:var(--c-ink-400); }
.lab-row.is-tail .lab-fill{ background:rgba(201,209,217,.2); }

.lab-scale{ margin-top:9px; padding-left:calc(8.5ch + 10px); padding-right:calc(6ch + 10px); }
.lab-scale-ticks{
  display:flex; justify-content:space-between;
  border-top:1px solid rgba(201,209,217,.14); padding-top:4px;
}
.lab-scale-ticks span{ font-family:var(--font-mono); font-size:9px; letter-spacing:.06em; color:var(--c-ink-400); }

/* ---- dial ---- */

.lab-dial{ margin-top:auto; padding-top:14px; }
.lab-dial-top{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; margin-bottom:6px; }
.lab-dial-read{
  font-family:var(--font-mono); font-variant-numeric:tabular-nums;
  font-size:20px; font-weight:600; color:var(--c-ink-300); line-height:1;
}
.lab-zone{
  font-family:var(--font-mono); font-size:9.5px; letter-spacing:.12em; text-transform:uppercase;
  padding:3px 8px; border-radius:var(--radius-pill); border:1px solid currentColor;
}
.zone-locked{ color:var(--signal); }
.zone-natural{ color:var(--c-ink-400); }
.zone-unstable{ color:var(--danger); }

.lab-slider{
  -webkit-appearance:none; appearance:none;
  width:100%; height:22px; background:transparent; cursor:pointer; display:block;
}
.lab-slider:focus-visible{ outline:2px solid var(--stage); outline-offset:3px; }
.lab-slider::-webkit-slider-runnable-track{
  height:5px; border-radius:3px;
  background:linear-gradient(90deg, var(--signal) 0%, var(--c-ink-600) 48%, var(--warn) 76%, var(--danger) 100%);
}
.lab-slider::-moz-range-track{
  height:5px; border-radius:3px;
  background:linear-gradient(90deg, var(--signal) 0%, var(--c-ink-600) 48%, var(--warn) 76%, var(--danger) 100%);
}
.lab-slider::-webkit-slider-thumb{
  -webkit-appearance:none; width:14px; height:22px; margin-top:-8.5px;
  border-radius:4px; background:var(--c-ink-300);
  border:1px solid var(--c-ink-600); box-shadow:0 1px 3px rgba(0,0,0,.5);
}
.lab-slider::-moz-range-thumb{
  width:14px; height:22px; border-radius:4px; background:var(--c-ink-300);
  border:1px solid var(--c-ink-600); box-shadow:0 1px 3px rgba(0,0,0,.5);
}
.lab-ticks{ display:flex; justify-content:space-between; }
.lab-ticks span{ font-family:var(--font-mono); font-size:9px; color:var(--c-ink-400); }

.lab-instr-controls{ display:flex; gap:8px; margin-top:12px; flex-wrap:wrap; }
.lab-instr-controls .lw-btn{ box-shadow:none; }
.lab-instr-controls .lw-btn:not(.lw-btn--primary){
  background:var(--c-ink-700); border-color:var(--c-ink-600); color:var(--c-ink-300);
}
.lab-instr-controls .lw-btn:not(.lw-btn--primary):hover{ background:var(--c-ink-600); }

/* ---- generated output + log ---- */

.lab-gen{
  margin-top:12px; min-height:2.6em;
  font-family:var(--font-display); font-weight:500;
  font-size:clamp(15px, 1.5vw, 19px); color:var(--c-ink-300); line-height:1.35;
}
.lab-gen .lab-seed{ color:var(--c-ink-400); }
.lab-gen em{ font-style:normal; opacity:0; animation:lab-token .3s ease forwards; }
.lab-gen em.is-wild{ color:var(--warn); }
@keyframes lab-token{ from{opacity:0; filter:blur(3px)} to{opacity:1; filter:none} }

.lab-log{ margin-top:10px; display:grid; gap:5px; }
.lab-log-row{
  display:grid; grid-template-columns:6.5ch minmax(0,1fr); gap:10px; align-items:baseline;
  font-family:var(--font-mono); font-size:11px; color:var(--c-ink-400);
  animation:lab-enter .3s ease both;
}
.lab-log-row b{ color:var(--c-ink-300); font-weight:400; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* ---- tally ---- */

.lab-tally-strip{
  display:flex; gap:3px; flex-wrap:wrap; min-height:22px;
  padding:7px 9px; border-radius:var(--radius-sm);
  background:rgba(201,209,217,.05);
}
.lab-tick{ width:6px; height:14px; border-radius:1px; background:var(--stage); animation:lab-drop .2s ease both; }
.lab-tick.is-miss{ background:var(--danger); }
@keyframes lab-drop{ from{opacity:0; transform:translateY(-6px)} to{opacity:1; transform:none} }

.lab-counts{ display:flex; gap:22px; margin-top:11px; }
.lab-count-k{ font-family:var(--font-mono); font-size:9px; letter-spacing:.12em; text-transform:uppercase; color:var(--c-ink-400); display:block; }
.lab-count-v{ font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:19px; font-weight:600; color:var(--c-ink-300); line-height:1.2; }
.lab-count.is-miss .lab-count-v{ color:var(--danger); }

/* ---- reference card inside the readout ---- */

.lab-ref{ display:none; }
.lab-ref.is-shown{ display:block; animation:lab-enter .4s ease both; }
.lab-ref-block{ margin-bottom:14px; }
.lab-ref-block:last-child{ margin-bottom:0; }
.lab-ref-block p{ margin:6px 0 0; font-size:14.5px; color:var(--c-ink-300); line-height:1.55; }
.lab-ref-block.is-you{ border-left:3px solid var(--c-paper); padding-left:12px; }
.lab-ref-block.is-ref{ border-left:3px solid var(--stage); padding-left:12px; }

/* ---- footbar ---- */

.lab-footbar{
  flex:0 0 auto;
  display:flex; align-items:center; justify-content:space-between; gap:14px;
  padding:0 clamp(14px, 2.4vw, 28px);
  height:64px;
  border-top:1px solid var(--line);
  background:var(--surface);
}
.lab-footnote{ font-family:var(--font-mono); font-size:9.5px; letter-spacing:.05em; color:var(--muted); opacity:.75; max-width:52ch; }

/* the dock: the footbar's left slot, which a beat may borrow (a clip
   beat parks its transport here, so the stage is all picture). Any
   other beat leaves it empty; empty paper is breathing room. The
   promise -> payoff frame that used to sit here lives in About now. */
.lab-dock{ flex:1 1 auto; min-width:0; display:flex; align-items:center; gap:12px; }
.lab-dock > *{ min-width:0; }
.lab-est{ opacity:.7; }

/* ---- rail panels ---- */

.prob{ padding-bottom:13px; margin-bottom:13px; border-bottom:1px solid var(--line); }
.prob:last-of-type{ border-bottom:0; }
.prob-q{ margin:0 0 6px; font-weight:600; font-size:15.5px; }
.prob-a{ margin:0; font-size:15px; line-height:1.6; color:var(--muted); }
.prob-a b{ color:var(--ink); font-weight:600; }

.ask{ margin-top:6px; padding-top:14px; border-top:1px solid var(--line); }
.ask-note{ margin:6px 0 10px; font-size:14px; line-height:1.5; color:var(--muted); }
.ask-in{ width:100%; font-size:13.5px; }
.ask-in:disabled{ opacity:.55; cursor:not-allowed; }
.ask-off{ display:block; margin-top:7px; }

.about-row{ margin-bottom:15px; }
.about-row--obj.is-done .lw-label, .about-row--obj.is-done p{ color:var(--stage-ink); }
.about-row:last-child{ margin-bottom:0; }
.about-row p{ margin:6px 0 0; font-size:15px; line-height:1.6; }
.chlog{ margin-top:9px; padding-left:11px; border-left:2px solid var(--line); }
.chlog p{ margin:4px 0 0; font-size:14px; line-height:1.55; color:var(--muted); }
.chlog b{ color:var(--ink); font-weight:600; }

/* ---- completion, on the recap ---- */

/* the message must be ONE flex item. Loose text nodes beside an element
   become separate flex children, and the gap then lands inside the
   sentence — which is how a full stop ends up orphaned from its clause. */
.close-state{
  display:flex; align-items:center; gap:11px; flex-wrap:wrap; justify-content:center;
  font-size:15px; color:var(--muted);
}
.close-state b{ color:var(--stage-ink); font-weight:600; }
.close-state.is-open b{ color:var(--c-coral); }
.lab-footnav{ display:flex; gap:8px; margin-left:auto; }

/* resume notice — lives in the footbar because that bar is a fixed 64px
   and cannot push the stage into an overflow */
.lab-resume{
  display:inline-flex; align-items:center; gap:6px;
  font-size:12.5px; color:var(--stage-ink);
  padding:6px 12px; border-radius:var(--radius-pill);
  background:color-mix(in srgb, var(--stage) 12%, #fff);
  border:1px solid color-mix(in srgb, var(--stage) 32%, transparent);
  animation:lab-enter .4s ease both;
}
.lab-resume button{
  font:inherit; color:inherit; background:none; border:0; padding:0;
  text-decoration:underline; cursor:pointer;
}

/* When the stage itself is narrow — a small laptop with the course pane
   open leaves a 250px teaching column, which is worse than a phone — a
   split stops being a split. Keyed off the STAGE width, set by the shell,
   because the viewport does not know whether the pane is open. */
.lab-stage[data-narrow="1"][data-layout="split"]{
  grid-template-columns:minmax(0,1fr);
  grid-template-rows:auto auto auto;
  grid-template-areas:"teach" "instr" "finding";
}
/* full width stops the wrapping that caused the overflow; anything the
   beat marks as supplementary goes, and what is left is the response */
.lab-stage[data-narrow="1"] [data-narrow-drop]{ display:none; }

/* On a narrow stage the workbench stops being side-by-side. The picker
   and the comparison are one control, so nothing has to be dropped —
   only the hint goes, and the columns stack. */
.lab-stage[data-narrow="1"] .tok-bench{ grid-template-columns:minmax(0,1fr); }
.lab-stage[data-narrow="1"] .tok-hint{ display:none; }
.lab-stage[data-narrow="1"] .spec{ padding:4px 7px; }
.lab-stage[data-narrow="1"] .tok-list{ display:grid; grid-template-columns:1fr 1fr; gap:2px 8px; }
.lab-stage[data-narrow="1"] .tok-note{ display:none; }
.lab-stage[data-narrow="1"] .spec-cap{ display:none; }
.lab-stage[data-narrow="1"] .tokenlab{ gap:8px; }
.lab-stage[data-narrow="1"] .tok-readout{ padding:10px 12px; gap:8px; }
.lab-stage[data-narrow="1"] .tok-finding{ padding:9px 12px; }
.lab-stage[data-narrow="1"] .tok-finding p{ font-size:14px; }

/* ============================================================
   BEAT LAYOUTS
   A beat picks its own shape. Video usually wants the whole stage;
   a manipulable usually wants teaching beside it.
   ============================================================ */

.lab-stage[data-layout="full"]{
  grid-template-columns:minmax(0,1fr);
  grid-template-rows:minmax(0,1fr);
  grid-template-areas:"instr";
}

/* BLEED: the clip IS the stage. No padding, no frame; the picture's own
   paper runs into the page's paper. The stage carries the TSX Stage's
   resting light (same three blobs, same alphas) so the seam between
   page and picture is not there to see; the picture then moves it. */
.lab-stage[data-layout="bleed"]{
  grid-template-columns:minmax(0,1fr);
  grid-template-rows:minmax(0,1fr);
  grid-template-areas:"instr";
  padding:0; gap:0;
  background:
    radial-gradient(circle at 20% 27%, rgba(99,102,241,.15), transparent 48%),
    radial-gradient(circle at 82% 73%, rgba(155,124,196,.13), transparent 46%),
    radial-gradient(circle at 64% 14%, rgba(77,184,168,.08), transparent 40%);
}
.lab-stage[data-layout="bleed"] .lab-instr{ position:relative; }

/* ============================================================
   VIDEO BLOCK
   ============================================================ */

.vid-stack{ display:flex; flex-direction:column; height:100%; min-height:0; gap:10px; }

/* container-type:size lets the frame solve 16:9 against BOTH axes, so it
   never letterboxes wrong when the stage is short */
.vid-wrap{ flex:1 1 auto; min-height:0; container-type:size; display:grid; place-items:center; }
.vid-frame{
  position:relative;
  width:min(100cqw, 177.78cqh);
  aspect-ratio:16/9;
  container-type:inline-size;
  border-radius:var(--radius);
  background:var(--c-ink-900);
  box-shadow:var(--shadow);
  overflow:hidden;
}

.vid-scene{ position:absolute; inset:0; padding:5cqi 6cqi 4cqi; display:flex; flex-direction:column; }
.vid-lower{
  font-family:var(--font-display); font-weight:600;
  font-size:3.4cqi; color:var(--c-ink-300); letter-spacing:-.01em;
  margin-bottom:3cqi;
}
.vid-lower span{ display:block; font-family:var(--font-mono); font-weight:400; font-size:1.7cqi; letter-spacing:.12em; text-transform:uppercase; color:var(--c-ink-400); margin-bottom:.8cqi; }

/* the caption owns a real lane in the flex column rather than floating over
   the scene, so it can never land on top of the thing being taught */
.vid-cc{
  flex:0 0 auto; margin-top:auto; padding-top:2cqi;
  min-height:6.4cqi;
  text-align:center; font-size:2.3cqi; line-height:1.4;
  color:#fff; text-shadow:0 1px 6px rgba(0,0,0,.85);
  pointer-events:none;
}

.vid-play{
  position:absolute; inset:0; margin:auto;
  width:13cqi; height:13cqi; border-radius:50%;
  display:grid; place-items:center;
  border:0; cursor:pointer; padding:0;
  background:rgba(255,255,255,.92); color:var(--c-ink-900);
  box-shadow:0 6px 24px rgba(0,0,0,.4);
  transition:transform .16s ease, opacity .2s ease;
}
.vid-play:hover{ transform:scale(1.06); }
.vid-frame.is-playing .vid-play{ opacity:0; pointer-events:none; }

.vid-bar{ flex:0 0 auto; display:flex; align-items:center; gap:12px; }
.vid-btn{
  width:34px; height:34px; border-radius:50%;
  display:grid; place-items:center; padding:0;
  border:1px solid var(--line); background:#fff; color:var(--ink);
  cursor:pointer; flex:0 0 auto;
}
.vid-btn:hover{ background:var(--surface-2); }
.vid-btn:focus-visible{ outline:2px solid var(--stage); outline-offset:2px; }
.vid-time{ font-family:var(--font-mono); font-size:12.5px; color:var(--muted); flex:0 0 auto; font-variant-numeric:tabular-nums; }

.vid-seek{ flex:1 1 auto; position:relative; }
.vid-seek input{
  -webkit-appearance:none; appearance:none;
  width:100%; height:18px; background:transparent; display:block; cursor:pointer; margin:0;
}
.vid-seek input:focus-visible{ outline:2px solid var(--stage); outline-offset:2px; }
.vid-seek input::-webkit-slider-runnable-track{ height:5px; border-radius:3px; background:var(--line); }
.vid-seek input::-moz-range-track{ height:5px; border-radius:3px; background:var(--line); }
.vid-seek input::-webkit-slider-thumb{
  -webkit-appearance:none; width:13px; height:13px; margin-top:-4px; border-radius:50%;
  background:var(--stage); border:2px solid #fff; box-shadow:0 1px 3px rgba(26,26,46,.3);
}
.vid-seek input::-moz-range-thumb{
  width:13px; height:13px; border-radius:50%;
  background:var(--stage); border:2px solid #fff; box-shadow:0 1px 3px rgba(26,26,46,.3);
}
.vid-played{
  position:absolute; left:0; top:6.5px; height:5px; border-radius:3px;
  background:var(--stage); pointer-events:none;
}
.vid-ticks{ position:absolute; left:0; right:0; top:6.5px; height:5px; pointer-events:none; }
.vid-ticks i{ position:absolute; top:0; width:2px; height:5px; background:var(--surface); }

.vid-chapters{ flex:0 0 auto; display:flex; gap:7px; flex-wrap:wrap; }
.vid-chapter{
  font-size:13.5px; padding:7px 13px; border-radius:var(--radius-pill);
  border:1px solid var(--line); background:#fff; color:var(--muted);
  cursor:pointer; font-family:inherit;
  transition:border-color .16s ease, color .16s ease, background .16s ease;
}
.vid-chapter:hover{ color:var(--ink); border-color:var(--ink); }
.vid-chapter.is-on{ background:color-mix(in srgb, var(--stage) 12%, #fff); border-color:color-mix(in srgb, var(--stage) 45%, transparent); color:var(--stage-ink); font-weight:500; }
.vid-chapter b{ font-family:var(--font-mono); font-size:10px; font-weight:500; opacity:.7; margin-right:6px; }

/* ---- bleed: no frame, feathered edges, transport in the dock ---- */
.vid-stack--bleed{ gap:0; }
.vid-stack--bleed .vid-frame{
  border-radius:0; box-shadow:none; background:transparent;
}
/* the picture's edges dissolve into the page: a soft mask on both axes
   hides the last of the h264 white shift and the TSX grid's edge */
.vid-stack--bleed .vid-video{
  background:transparent;
  -webkit-mask-image:linear-gradient(90deg, transparent 0, #000 4.5%, #000 95.5%, transparent 100%), linear-gradient(180deg, transparent 0, #000 6%, #000 94%, transparent 100%);
  -webkit-mask-composite:source-in;
  mask-image:linear-gradient(90deg, transparent 0, #000 4.5%, #000 95.5%, transparent 100%), linear-gradient(180deg, transparent 0, #000 6%, #000 94%, transparent 100%);
  mask-composite:intersect;
}
/* captions: an ink pill near the bottom of the picture, never a dark band
   across paper */
.vid-stack--bleed .vid-frame > .vid-cc{
  background:none; padding:0 6cqi 2.6cqi; text-shadow:none; min-height:0;
  display:flex; justify-content:center;
}
.vid-stack--bleed .vid-cc span{
  display:inline-block; max-width:72%;
  background:rgba(26,26,46,.86); color:#fff;
  padding:.55cqi 1.5cqi; border-radius:.9cqi;
  font-size:2.25cqi; line-height:1.35; font-weight:500;
}
.vid-stack--bleed .vid-frame.is-placeholder{ background:transparent; border:0; box-shadow:none; }
.vid-stack--bleed .clip-ph{ background:transparent; }
.vid-stack--bleed .clip-ph-card{
  background:#fff; border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow);
  padding:clamp(18px, 3cqi, 34px) clamp(22px, 4cqi, 44px);
}
.vid-stack--bleed .vid-frame.is-ended .vid-play{ opacity:0; pointer-events:none; }

/* the transport, parked in the footbar dock */
.vid-dock{ display:flex; align-items:center; gap:14px; flex:1 1 auto; min-width:0; }
.vid-dock .vid-bar{ flex:1 1 auto; min-width:0; }
.vid-dock .vid-chapters{ flex:0 0 auto; flex-wrap:nowrap; }
.vid-btn--cc{
  width:auto; padding:0 8px; border-radius:var(--radius-sm);
  font-family:var(--font-mono); font-size:10.5px; font-weight:600; letter-spacing:.06em; color:var(--muted);
}
.vid-btn--cc.is-on{ background:var(--ink); color:#fff; border-color:var(--ink); }
@media (max-width:1180px){ .vid-dock .vid-chapters{ display:none; } }
@media (max-width:860px){
  /* a phone's footbar is Back + Continue + the seek bar, nothing else: the
     picture itself plays and pauses, and captions stay on */
  .vid-dock{ gap:8px; }
  .vid-dock .vid-watched, .vid-dock .vid-btn, .vid-dock .vid-time{ display:none; }
  .lab-footnav{ flex:0 0 auto; }
  .lab-footnav .lw-btn{ white-space:nowrap; }
}

/* a small supporting clip, for when video is not the spine */
.clip{
  margin-top:14px; border-radius:var(--radius-sm); overflow:hidden;
  border:1px solid var(--line); background:var(--c-ink-900);
  max-width:42ch;
}
.clip-frame{ position:relative; aspect-ratio:16/9; container-type:inline-size; }
.clip-label{
  display:flex; align-items:center; gap:8px;
  padding:9px 12px; background:#fff; border-top:1px solid var(--line);
  font-size:12.5px; color:var(--muted);
}
.clip-label b{ color:var(--ink); font-weight:600; }

/* ============================================================
   CONTEXT WINDOW WIDGET
   Same component in both places: time drives it inside the video,
   the student drives it on the next beat.
   ============================================================ */

.ctx{ display:flex; flex-direction:column; min-height:0; }
.ctx-head{
  display:flex; align-items:baseline; justify-content:space-between; gap:10px;
  font-family:var(--font-mono); font-size:2cqi; letter-spacing:.1em; text-transform:uppercase;
  color:var(--c-ink-400); margin-bottom:2cqi;
}
/* the grid FILLS the room it is given rather than dictating its own height.
   Square cells overflow a 16:9 frame, and a fixed row height only works at
   one frame size. Eight fr rows adapt to any. */
.ctx-grid{
  display:grid;
  grid-template-columns:repeat(16, 1fr);
  grid-template-rows:repeat(8, minmax(0, 1fr));
  gap:.55cqi;
  flex:1 1 auto; min-height:0;
  padding:1.6cqi; border-radius:1.4cqi;
  background:rgba(201,209,217,.05);
  box-shadow:inset 0 0 0 1px rgba(201,209,217,.1);
}
.ctx-cell{
  border-radius:.35cqi;
  background:rgba(201,209,217,.07);
  transition:background .3s ease, opacity .3s ease, transform .3s ease;
}
.ctx-cell.is-sys{ background:var(--stage); }
.ctx-cell.is-you{ background:var(--c-paper); }
.ctx-cell.is-ai{ background:color-mix(in srgb, var(--stage) 42%, transparent); }
.ctx-cell.is-gone{ opacity:0; transform:scale(.4); }
.ctx-cell.is-flush{ background:var(--danger) !important; }

.ctx-legend{ display:flex; gap:2.6cqi; margin-top:2cqi; font-family:var(--font-mono); font-size:1.7cqi; color:var(--c-ink-400); }
.ctx-legend span{ display:flex; align-items:center; gap:.8cqi; }
.ctx-legend i{ width:1.4cqi; height:1.4cqi; border-radius:.3cqi; display:block; }

/* the same widget on a normal (non cqi) surface inside the readout */
.ctx--live .ctx-head{ font-size:10.5px; letter-spacing:.12em; margin-bottom:10px; }
/* inside a readout the widget sizes to its own content instead */
.ctx--live .ctx-grid{
  gap:3px; padding:9px; border-radius:8px;
  flex:0 0 auto; grid-template-rows:none; grid-auto-rows:11px;
}
.ctx--live .ctx-cell{ border-radius:2px; }
.ctx--live .ctx-legend{ font-size:10px; gap:14px; margin-top:11px; }
.ctx--live .ctx-legend i{ width:8px; height:8px; border-radius:2px; }

.ctx-readouts{ display:flex; gap:22px; margin-top:14px; }
.ctx-k{ font-family:var(--font-mono); font-size:9px; letter-spacing:.12em; text-transform:uppercase; color:var(--c-ink-400); display:block; }
.ctx-v{ font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:19px; font-weight:600; color:var(--c-ink-300); line-height:1.2; }
.ctx-v.is-bad{ color:var(--danger); }

/* ---- chat consequence ---- */

.chat{ display:grid; gap:7px; margin-top:4px; }
.chat-line{
  display:grid; grid-template-columns:7ch minmax(0,1fr); gap:10px; align-items:baseline;
  font-size:12.5px; color:var(--c-ink-300);
  animation:lab-enter .28s ease both;
}
.chat-line .who{ font-family:var(--font-mono); font-size:10px; letter-spacing:.08em; text-transform:uppercase; color:var(--c-ink-400); }
.chat-line.is-pinned .who{ color:var(--stage); }
.chat-line.is-pinned .what{ color:var(--stage); }
.chat-line.is-lost{ opacity:.35; text-decoration:line-through; }
.chat-line.is-broken .what{ color:var(--danger); }

/* ---- transcript tool ---- */

.tr-line{
  display:grid; grid-template-columns:5.5ch minmax(0,1fr); gap:10px;
  width:100%; text-align:left; padding:8px 9px; border-radius:8px;
  background:transparent; border:0; cursor:pointer; font-family:inherit;
  font-size:15px; color:var(--ink); line-height:1.5;
}
.tr-line:hover{ background:rgba(26,26,46,.045); }
.tr-line .t{ font-family:var(--font-mono); font-size:11.5px; color:var(--muted); }
.tr-line.is-now{ background:color-mix(in srgb, var(--stage) 12%, transparent); font-weight:500; }
.tr-line.is-now .t{ color:var(--stage-ink); }

/* ============================================================
   DNS LAB — a full-stage interactive. No teaching column: the
   instruction is one line above the apparatus and the apparatus
   answers back, so the whole screen is the lesson.
   ============================================================ */

.dns{
  display:grid;
  grid-template-rows:auto auto auto minmax(0,1fr) auto;
  gap:clamp(9px, 1.5vh, 18px);
  height:100%; min-height:0;
}

.dns-head{ display:flex; align-items:baseline; gap:12px; flex-wrap:wrap; }
.dns-head h2{ font-size:clamp(18px, 2vw, 27px); margin:0; }
.dns-hint{ color:var(--muted); font-size:14px; flex:1 1 240px; min-width:0; }

/* ---- the chain ---- */

.dns-chain{ display:flex; align-items:stretch; }

.dns-node{
  flex:1 1 0; min-width:0;
  border:1px solid var(--line); border-radius:var(--radius);
  background:#fff; box-shadow:var(--shadow-sm);
  padding:10px 12px;
  transition:border-color .2s ease, box-shadow .2s ease, background .2s ease, opacity .2s ease;
}
.dns-node-k{ font-family:var(--font-mono); font-size:9px; letter-spacing:.12em; text-transform:uppercase; color:var(--muted); display:block; }
.dns-node-t{ font-weight:600; font-size:14px; margin-top:2px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.dns-node-s{ font-family:var(--font-mono); font-size:10.5px; color:var(--muted); margin-top:4px; min-height:1.4em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

.dns-node.is-asking{ border-color:var(--stage); box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 20%, transparent); }
.dns-node.is-done{ background:color-mix(in srgb, var(--stage) 9%, #fff); border-color:color-mix(in srgb, var(--stage) 45%, transparent); }
.dns-node.is-done .dns-node-s{ color:var(--stage-ink); }
.dns-node.is-skip{ opacity:.42; }
.dns-node.is-fail{ border-color:var(--danger); background:color-mix(in srgb, var(--danger) 8%, #fff); }
.dns-node.is-fail .dns-node-s{ color:var(--danger); }

.dns-link{ flex:0 0 auto; align-self:center; width:clamp(14px, 2.4vw, 40px); height:2px; background:var(--line); position:relative; }
.dns-link i{
  position:absolute; top:-3px; left:0; width:8px; height:8px; border-radius:50%;
  background:var(--stage); opacity:0;
}
.dns-link.is-live i{ animation:dns-fly .42s linear; }
@keyframes dns-fly{ from{ left:0; opacity:1; } to{ left:100%; opacity:1; } }

/* ---- answer banner ---- */

.dns-answer{
  display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  padding:11px 15px; border-radius:var(--radius);
  border:1px solid var(--line); background:var(--surface-2);
  min-height:46px;
}
.dns-answer.is-ok{ background:color-mix(in srgb, var(--stage) 11%, #fff); border-color:color-mix(in srgb, var(--stage) 40%, transparent); }
.dns-answer.is-bad{ background:color-mix(in srgb, var(--danger) 9%, #fff); border-color:color-mix(in srgb, var(--danger) 40%, transparent); }
.dns-ip{ font-family:var(--font-mono); font-size:19px; font-weight:600; letter-spacing:-.01em; }
.dns-answer.is-ok .dns-ip{ color:var(--stage-ink); }
.dns-answer.is-bad .dns-ip{ color:var(--danger); }
.dns-answer .lw-label{ margin-left:auto; }

/* ---- lower: log + controls ---- */

.dns-lower{ display:grid; grid-template-columns:minmax(0,1.1fr) minmax(0,1fr); gap:14px; min-height:0; }

.dns-log{
  min-height:0; overflow:hidden;
  border-radius:var(--radius); background:var(--c-ink-900);
  padding:13px 15px; box-shadow:var(--shadow);
  display:flex; flex-direction:column; gap:4px;
}
/* lines settle at the bottom like a terminal, label stays pinned up top */
.dns-log{ justify-content:flex-end; }
.dns-log .lw-label{ color:var(--c-ink-400); margin-bottom:auto; }
.dns-line{
  font-family:var(--font-mono); font-size:11.5px; line-height:1.5;
  color:var(--c-ink-300);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  animation:lab-enter .22s ease both;
}
.dns-line .q{ color:var(--c-ink-400); }
.dns-line .a{ color:var(--stage); }
.dns-line.is-bad .a{ color:var(--danger); }
.dns-line.is-cache .a{ color:var(--warn); }

.dns-panel{
  min-height:0; overflow:hidden;
  border-radius:var(--radius); border:1px solid var(--line);
  background:#fff; box-shadow:var(--shadow-sm);
  padding:13px 15px;
  display:flex; flex-direction:column; gap:10px;
}

.zone-row{
  display:grid; grid-template-columns:4.5ch 5.5ch minmax(0,1fr) auto;
  gap:8px; align-items:center;
  font-family:var(--font-mono); font-size:11.5px;
}
.zone-row.is-head{ color:var(--muted); font-size:9px; letter-spacing:.1em; text-transform:uppercase; }
.zone-in{
  font-family:var(--font-mono); font-size:11.5px; color:var(--ink);
  border:1px solid var(--line); border-radius:6px; background:var(--surface);
  padding:5px 8px; width:100%; outline:0; min-width:0;
}
.zone-in:focus{ border-color:var(--stage); box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 18%, transparent); }
.zone-in.is-dirty{ border-color:var(--warn); background:color-mix(in srgb, var(--warn) 14%, #fff); }
.zone-del{
  border:1px solid var(--line); background:#fff; color:var(--muted);
  border-radius:6px; width:24px; height:24px; cursor:pointer; padding:0;
  display:grid; place-items:center; font-size:13px; line-height:1;
}
.zone-del:hover{ border-color:var(--danger); color:var(--danger); }
.zone-row.is-off .zone-in{ opacity:.4; text-decoration:line-through; }
.zone-row.is-off .zone-del{ border-color:var(--danger); color:var(--danger); }

.dns-cache{ margin-top:auto; border-top:1px solid var(--line); padding-top:10px; }
.dns-cache-row{
  display:flex; align-items:center; gap:9px;
  font-family:var(--font-mono); font-size:11px; color:var(--muted);
  padding:3px 0;
}
.dns-cache-row b{ color:var(--ink); font-weight:500; }
.dns-ttl{
  margin-left:auto; font-variant-numeric:tabular-nums;
  padding:2px 7px; border-radius:var(--radius-pill);
  background:color-mix(in srgb, var(--warn) 26%, #fff); color:#7a5c00;
}

.dns-actions{ display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
.dns-actions .lw-label{ margin-left:auto; }

/* ---- the checkpoint ---- */

.dns-task{
  display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  padding:11px 15px; border-radius:var(--radius);
  border:1px dashed var(--line); background:var(--surface-2);
  font-size:14px;
}
.dns-task.is-pass{ border-style:solid; background:color-mix(in srgb, var(--stage) 12%, #fff); border-color:var(--stage); }
.dns-task-k{ font-family:var(--font-mono); font-size:9px; letter-spacing:.12em; text-transform:uppercase; color:var(--muted); }
.dns-check{ display:flex; gap:16px; flex-wrap:wrap; margin-left:auto; }
.dns-check span{ font-family:var(--font-mono); font-size:11px; color:var(--muted); }
.dns-check span::before{ content:'○ '; }
.dns-check span.is-ok{ color:var(--stage-ink); }
.dns-check span.is-ok::before{ content:'● '; }

/* ---- the lab compresses rather than scrolls on a phone ---- */

@media (max-width:860px){
  /* the chain turns vertical and each hop collapses to a single line:
     label, who, and what they answered */
  .dns-chain{ flex-direction:column; }
  .dns-node{
    display:grid; grid-template-columns:2.6ch minmax(0,1fr) minmax(0,1.15fr);
    align-items:baseline; gap:9px; padding:6px 11px;
  }
  .dns-node-t{ font-size:12.5px; }
  .dns-node-k{ font-size:8.5px; }
  .dns-node-s{ margin-top:0; font-size:10px; text-align:right; }
  .dns-link{ width:2px; height:clamp(5px, 1.1vh, 11px); align-self:center; }
  .dns-link i{ top:0; left:-3px; }
  .dns-link.is-live i{ animation:dns-fly-v .42s linear; }
  @keyframes dns-fly-v{ from{ top:0; opacity:1; } to{ top:100%; opacity:1; } }

  /* the log is the first thing cut: every hop already narrates itself
     on its own node, so nothing is actually lost */
  .dns-log{ display:none; }
  .dns-lower{ grid-template-columns:minmax(0,1fr); gap:10px; overflow:hidden; }

  .dns-head h2{ font-size:17px; }
  .dns-hint{ font-size:12.5px; }
  .dns-answer{ padding:8px 12px; min-height:auto; }
  .dns-ip{ font-size:16px; }
  .dns-actions{ gap:6px; }
  .dns-actions .lw-btn{ font-size:12px; padding:6px 11px; }
  .dns-task{ padding:9px 12px; font-size:13px; gap:8px; }
  .dns-check{ margin-left:0; gap:10px; }
}

/* ============================================================
   QUIZ — a full-stage checkpoint. One question on screen, three
   question shapes, and a celebration that is earned rather than
   automatic.
   ============================================================ */

.quiz{
  display:grid;
  grid-template-rows:auto auto minmax(0,1fr) auto auto;
  gap:clamp(9px, 1.8vh, 20px);
  height:100%; min-height:0;
}

.quiz-top{ display:flex; align-items:center; gap:14px; }
.quiz-dots{ display:flex; gap:6px; }
.quiz-dot{
  width:30px; height:5px; border-radius:3px; background:var(--line);
  transition:background .3s ease, box-shadow .3s ease;
}
.quiz-dot.is-ok{ background:var(--stage); }
.quiz-dot.is-no{ background:var(--danger); }
.quiz-dot.is-here{ box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 22%, transparent); }

.quiz-streak{
  margin-left:auto; display:flex; align-items:center; gap:8px;
  font-family:var(--font-mono); font-size:10.5px; letter-spacing:.1em;
  text-transform:uppercase; color:var(--muted);
}
.quiz-streak b{
  font-family:var(--font-display); font-size:19px; font-weight:700;
  letter-spacing:-.02em; color:var(--ink); line-height:1;
}
.quiz-streak.is-hot{ color:var(--stage-ink); }
.quiz-streak.is-hot b{ color:var(--stage-ink); }
.quiz-streak.is-pop{ animation:quiz-pop .45s cubic-bezier(.2,1.4,.4,1) both; }
@keyframes quiz-pop{ 0%{ transform:scale(1); } 38%{ transform:scale(1.28); } 100%{ transform:scale(1); } }

.quiz-q h2{ font-size:clamp(19px, 2.4vw, 31px); max-width:30ch; margin:0; }
.quiz-kind{ margin-bottom:7px; display:block; }

.quiz-opts{ display:grid; gap:9px; align-content:start; min-height:0; }
/* Clipping belongs ONLY to the quiz layout, where the opts row is squeezed
   by minmax(0,1fr). On the check/prediction beats the grid hugs its content,
   and a flush overflow:hidden eats the last card's shadow always and its
   bottom border at fractional browser zoom (AA 01 round 1). */
.quiz .quiz-opts{ overflow:hidden; }

.opt{
  display:flex; align-items:center; gap:13px;
  padding:13px 16px; width:100%;
  border:1px solid var(--line); border-radius:var(--radius);
  background:#fff; box-shadow:var(--shadow-sm);
  cursor:pointer; text-align:left; font-family:inherit; font-size:15px; color:var(--ink);
  transition:border-color .18s ease, background .18s ease, box-shadow .18s ease, transform .12s ease;
}
.opt:hover:not(:disabled){ border-color:color-mix(in srgb, var(--stage) 55%, transparent); }
.opt:focus-visible{ outline:2px solid var(--stage); outline-offset:2px; }
.opt:disabled{ cursor:default; }

.opt-mark{
  flex:0 0 auto; width:26px; height:26px; border-radius:50%;
  border:1.5px solid var(--line); background:var(--surface);
  display:grid; place-items:center;
  font-family:var(--font-mono); font-size:11px; color:var(--muted);
  transition:background .18s ease, border-color .18s ease, color .18s ease;
}
.opt-t{ flex:1 1 auto; min-width:0; }

.opt.is-picked{ border-color:var(--stage); background:color-mix(in srgb, var(--stage) 7%, #fff); }
.opt.is-picked .opt-mark{ border-color:var(--stage); background:var(--stage); color:#fff; }

.opt.is-right{
  border-color:var(--stage); background:color-mix(in srgb, var(--stage) 14%, #fff);
  animation:quiz-spring .5s cubic-bezier(.2,1.5,.4,1) both;
}
.opt.is-right .opt-mark{ border-color:var(--stage); background:var(--stage); color:#fff; }
@keyframes quiz-spring{ 0%{ transform:scale(1); } 34%{ transform:scale(1.035); } 70%{ transform:scale(.996); } 100%{ transform:scale(1); } }

.opt.is-wrong{ border-color:var(--danger); background:color-mix(in srgb, var(--danger) 7%, #fff); }
.opt.is-wrong .opt-mark{ border-color:var(--danger); background:var(--danger); color:#fff; }
.opt.is-dim{ opacity:.5; }

/* ---- feedback ---- */

.quiz-fb{
  min-height:56px;
  border-radius:var(--radius); padding:12px 16px;
  border:1px solid transparent; background:transparent;
  font-size:14.5px; color:var(--muted);
  display:flex; align-items:center; gap:12px;
}
.quiz-fb.is-ok{
  background:color-mix(in srgb, var(--stage) 11%, #fff);
  border-color:color-mix(in srgb, var(--stage) 35%, transparent);
  color:var(--ink);
  animation:lab-enter .3s ease both;
}
.quiz-fb.is-no{
  background:color-mix(in srgb, var(--danger) 8%, #fff);
  border-color:color-mix(in srgb, var(--danger) 32%, transparent);
  color:var(--ink);
  animation:lab-enter .3s ease both;
}
.quiz-fb b{ font-weight:600; }
.quiz-fb-k{
  flex:0 0 auto; font-family:var(--font-mono); font-size:9.5px;
  letter-spacing:.12em; text-transform:uppercase;
}
.quiz-fb.is-ok .quiz-fb-k{ color:var(--stage-ink); }
.quiz-fb.is-no .quiz-fb-k{ color:var(--danger); }

.quiz-actions{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.quiz-actions .lw-label{ margin-left:auto; }

/* ---- results ---- */

.quiz-result{
  grid-row:2 / span 3;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:14px; text-align:center; min-height:0;
}
.quiz-score{
  font-family:var(--font-display); font-weight:700;
  font-size:clamp(44px, 8vw, 84px); line-height:1; letter-spacing:-.03em;
  color:var(--stage-ink);
}
.quiz-score span{ color:var(--muted); font-size:.42em; }
.quiz-verdict{ font-family:var(--font-display); font-weight:600; font-size:clamp(17px,2.2vw,24px); max-width:28ch; }
.quiz-review{ display:flex; gap:7px; flex-wrap:wrap; justify-content:center; margin-top:4px; }
.quiz-chip{
  display:inline-flex; align-items:center; gap:7px;
  font-family:var(--font-mono); font-size:10.5px; letter-spacing:.08em;
  padding:6px 11px; border-radius:var(--radius-pill);
  border:1px solid var(--line); background:#fff; color:var(--muted);
}
.quiz-chip.is-ok{ border-color:color-mix(in srgb, var(--stage) 45%, transparent); color:var(--stage-ink); }
.quiz-chip.is-no{ border-color:color-mix(in srgb, var(--danger) 45%, transparent); color:var(--danger); }

/* ---- celebration ---- */

#confetti{
  position:fixed; inset:0; width:100%; height:100%;
  pointer-events:none; z-index:60;
}

@media (max-width:860px){
  .quiz-dot{ width:20px; }
  .quiz-q h2{ font-size:18px; max-width:none; }
  .opt{ padding:11px 13px; font-size:15px; gap:10px; }
  .opt-mark{ width:23px; height:23px; font-size:10.5px; }
  .quiz-fb{ min-height:auto; font-size:14.5px; padding:10px 13px; }
  .quiz-streak b{ font-size:16px; }
}

@media (prefers-reduced-motion:reduce){
  #confetti{ display:none; }
}

/* ============================================================
   TOKENIZER — the apparatus for AI Core 03.

   Planned into three lectures before being built bespoke, per the
   >=2-lectures rule: 03 Tokens (here), 04 The context window (real
   chunks fill the box instead of abstract cells), 30 Token economics
   (the same chunks, priced).
   ============================================================ */

/* Rows hug rather than stretch. A dark panel stretched to fill a tall
   viewport reads as a broken screen; the same slack left as light paper
   reads as breathing room. So the ink sizes to its content and the
   leftover falls to the page. */
.tokenlab{
  display:grid;
  /* Three rows, three jobs: the head, the bench, the finding. Every row
     hugs and the slack falls to PAPER at the bottom. Giving the readout
     the slack instead re-creates the wall of empty ink that round 1
     removed — a stretched dark panel reads as a broken screen. */
  grid-template-rows:auto auto auto;
  align-content:start;
  gap:clamp(10px, 1.6vh, 18px);
  height:100%; min-height:0;
}

/* the workbench: what the student does on paper at the left, what the
   machine measured in ink at the right */
.tok-bench{
  display:grid;
  grid-template-columns:minmax(220px, 2fr) minmax(0, 3fr);
  gap:clamp(12px, 1.8vw, 22px);
  align-items:start; min-width:0;
}
.tok-controls{ display:flex; flex-direction:column; gap:10px; min-width:0; }

.tok-head{ display:flex; align-items:baseline; gap:12px; flex-wrap:wrap; }
.tok-head h2{ font-size:clamp(20px, 2.2vw, 29px); margin:0; }
.tok-hint{ color:var(--muted); font-size:15.5px; flex:1 1 240px; min-width:0; }

/* ---- the controls: paper, because they are what the student does ---- */

.tok-in{
  width:100%; min-width:0;
  font-family:var(--font-mono); font-size:14px; color:var(--ink);
  padding:10px 13px;
  border:1px solid var(--line); border-radius:var(--radius-sm);
  background:#fff; outline:0; box-shadow:var(--shadow-sm);
}
.tok-in:focus{ border-color:var(--stage); box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 20%, transparent); }

/* The picker and the comparison are ONE control: each row is a button
   AND a bar. A row's bar and number fill in only once the row has been
   measured before your eyes, so the chart assembles itself from the
   student's own exploration — staging without gating. */
.tok-list{
  display:flex; flex-direction:column; gap:4px;
  border:1px solid var(--line); border-radius:var(--radius-sm);
  background:#fff; box-shadow:var(--shadow-sm); padding:6px;
}
.spec{
  display:grid; grid-template-columns:minmax(72px, auto) minmax(0,1fr) 26px;
  align-items:center; gap:9px;
  padding:5px 8px; border:0; border-radius:6px;
  background:transparent; cursor:pointer; text-align:left;
  font:inherit; color:var(--ink);
}
.spec:hover{ background:var(--surface-2); }
.spec:focus-visible{ outline:2px solid var(--stage); outline-offset:-2px; }
.spec.is-on{ background:color-mix(in srgb, var(--stage) 10%, transparent); }
.spec-k{ font-size:14px; font-weight:500; white-space:nowrap; }
.spec.is-on .spec-k{ color:var(--stage-ink); font-weight:600; }
.spec-bar{
  display:block; height:8px; border-radius:4px;
  background:var(--surface-2); overflow:hidden;
}
.spec-bar i{
  display:block; height:100%; border-radius:4px;
  background:color-mix(in srgb, var(--stage) 45%, #fff);
  transition:width .5s cubic-bezier(.16,.9,.3,1);
}
.spec.is-on .spec-bar i{ background:var(--stage); }
.spec-v{
  font-family:var(--font-mono); font-variant-numeric:tabular-nums;
  font-size:11px; color:var(--muted); text-align:right;
}
.spec.is-on .spec-v{ color:var(--stage-ink); font-weight:600; }
.spec-cap{
  font-family:var(--font-mono); font-size:9.5px; letter-spacing:.06em;
  color:var(--muted); margin:0; padding:0 2px;
  animation:lab-enter .4s ease both;
}

/* ---- the readout: the machine speaking ---- */

.tok-readout{
  min-height:0; overflow:hidden;
  display:flex; flex-direction:column; gap:12px;
  border-radius:var(--radius); background:var(--c-ink-900);
  padding:clamp(13px, 1.7vw, 20px); box-shadow:var(--shadow);
}
.tok-readout-head{ display:flex; align-items:center; justify-content:space-between; gap:12px; }
.tok-readout-head .lw-label{ color:var(--c-ink-400); }

/* the chunks. Alternating tints are the only thing that makes a
   boundary visible when two neighbours are both plain words. */
/* Bounded, not stretched: the widest specimen is 29 chunks, which wraps
   to three rows. Anything taller is clipped rather than allowed to
   scroll, because rule 1 outranks seeing every chunk. */
/* min-height is two rows of chunks: the strip may absorb slack, but it
   may never shrink to the point of clipping the thing being taught.
   If it wants to go below this, something ELSE on the beat has to go. */
/* Hug the chunks, never shrink below them. If the beat cannot afford the
   room, something ELSE goes — the chunks are the lecture. */
.tok-strip{
  flex:0 0 auto; min-height:58px; max-height:34vh; overflow:hidden;
  display:flex; flex-wrap:wrap; align-content:flex-start; gap:3px;
  padding:10px; border-radius:var(--radius-sm);
  background:rgba(201,209,217,.05);
  box-shadow:inset 0 0 0 1px rgba(201,209,217,.09);
}
.tok-chip{
  font-family:var(--font-mono); font-size:13px; line-height:1.5;
  padding:3px 5px; border-radius:4px; white-space:pre;
  background:color-mix(in srgb, var(--stage) 30%, transparent);
  color:var(--c-paper);
  /* the delay is set per chip so the text visibly gets CHOPPED left to
     right, rather than appearing already chopped */
  animation:tok-chop .22s cubic-bezier(.16,.9,.3,1) both;
}
@keyframes tok-chop{
  from{ opacity:0; transform:translateY(-5px) scaleX(.7); }
  to{ opacity:1; transform:none; }
}
.tok-chip:nth-child(even){ background:color-mix(in srgb, var(--stage) 55%, transparent); }

/* a leading space belongs to the token after it, which is invisible
   and therefore the single most confusing thing on this screen */
.tok-chip .sp{ opacity:.4; }

/* the BEFORE state of a chop: the text sits whole for a beat, so the
   splitting reads as something that HAPPENED to it */
.tok-whole{
  font-family:var(--font-mono); font-size:13px; line-height:1.5;
  padding:3px 5px; white-space:pre-wrap; word-break:break-all;
  color:var(--c-ink-300);
}
/* while chopping, each chip lands with a brief flash on its left edge —
   the cut itself, not just the piece */
.tok-strip.is-chop .tok-chip{
  animation:tok-chop .22s cubic-bezier(.16,.9,.3,1) both,
            tok-cut .34s ease-out both;
}
@keyframes tok-cut{
  0%{ box-shadow:inset 2px 0 0 var(--c-paper); }
  100%{ box-shadow:inset 0 0 0 transparent; }
}

/* emoji and non-Latin text can split ACROSS a character, so a token is
   sometimes a fragment of a character rather than a character. That is
   the point, so it is marked rather than hidden. */
.tok-chip.is-partial{
  background:rgba(245,215,110,.16); color:var(--warn);
  font-size:11px; letter-spacing:.04em;
}

.tok-readouts{ display:flex; gap:clamp(14px, 2.4vw, 30px); flex-wrap:wrap; }
.tok-k{ font-family:var(--font-mono); font-size:9px; letter-spacing:.12em; text-transform:uppercase; color:var(--c-ink-400); display:block; }
.tok-v{ font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:19px; font-weight:600; color:var(--c-ink-300); line-height:1.2; }
.tok-metric.is-key .tok-v{ color:var(--stage); }
.tok-metric.is-key .tok-k{ color:var(--stage); }


/* ---- the tokenizer switch ---- */

.tok-foot{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.tok-enc{ display:flex; gap:0; border:1px solid var(--line); border-radius:var(--radius-pill); overflow:hidden; background:#fff; }
.tok-enc button{
  font-family:var(--font-mono); font-size:11px; letter-spacing:.04em;
  padding:7px 13px; border:0; background:transparent; color:var(--muted); cursor:pointer;
}
.tok-enc button.is-on{ background:var(--stage); color:#fff; }
.tok-enc button:focus-visible{ outline:2px solid var(--stage); outline-offset:-2px; }
/* the machine's note lives inside the readout, so it speaks in ink */
.tok-note{ font-size:14px; color:var(--c-ink-300); margin:0; min-width:0; animation:lab-enter .3s ease both; }
.tok-note b{ color:var(--c-paper); font-weight:600; }

/* the ending: the finding may stretch to the bench, not to a caption
   column. It carries its own Continue so the student moves on from
   where their eyes already are, not from the footbar. */
.tok-finding{ max-width:none; padding:12px 16px; }
.tok-finding.is-shown{ display:flex; align-items:center; gap:18px; flex-wrap:wrap; }
.tok-finding-t{ flex:1 1 320px; min-width:0; }
.tok-finding #tok-go{ flex:0 0 auto; }
.tok-finding p{ font-size:clamp(15px, 2.2cqi, 17.5px); margin-top:5px; }
.finding-go{ margin-top:11px; }
/* answered, the sub-line is redundant: the finding restates the 44
   characters. One response per interaction (rule 9), and the height
   pays for the Continue that took its place. */
.open.is-answered .open-sub{ display:none; }

/* ---- the evidence, on PAPER ----
   A specimen the student is asked to look at never goes into the dark
   panel, wherever it appears (rules 2 + 27) — so check evidence is a
   paper card presented exactly the way beat 1 presented its lines: the
   same recurring visual character across the whole lecture. */

.check-ev{ display:flex; flex-direction:column; gap:9px; min-width:0; }
/* Dropped only when a pane squeezes a DESKTOP stage — never on a phone,
   where the result sub-beat IS the evidence screen. [data-narrow-drop]
   cannot make that distinction: a phone stage is also narrow. */
@media (min-width:861px){
  .lab-stage[data-narrow="1"] .check-ev{ display:none; }
}
.check-ev-lead{ margin:0; font-size:15px; color:var(--muted); }
.check-ev-cards{ display:flex; flex-direction:column; gap:9px; min-width:0; }
.ev-card{
  padding:11px 14px;
  border:1px solid var(--line); border-radius:var(--radius-sm);
  background:#fff; box-shadow:var(--shadow-sm);
  display:flex; flex-direction:column; gap:8px; min-width:0;
}
.ev-card-t{
  display:flex; align-items:baseline; gap:10px; min-width:0;
  font-family:var(--font-mono); font-size:12.5px; color:var(--ink);
}
.ev-card-t .k{ color:var(--muted); font-size:11px; }
.ev-card-t .txt{ flex:1; min-width:0; overflow-wrap:anywhere; }
.ev-count{
  font-family:var(--font-mono); font-variant-numeric:tabular-nums;
  font-size:12.5px; font-weight:600; color:var(--stage-ink);
  white-space:nowrap;
  border-radius:4px; padding:1px 5px;
}
.ev-strip{ display:flex; flex-wrap:wrap; gap:3px; }
.ev-meta{
  font-family:var(--font-mono); font-size:10px; letter-spacing:.05em;
  color:var(--muted);
}

/* the demonstration: grading lights up the part of the evidence that
   settles the question. The state survives reduced motion; only the
   pulse dies. */
/* one class deeper than the nth-child tint rules, which sit LATER in
   the file and would win a specificity tie (rule 10) */
.check-ev .ev-strip .tok-chip.is-mark{
  background:var(--stage); color:#fff;
  animation:ev-mark .55s ease 2;
}
.ev-count.is-mark{
  background:color-mix(in srgb, var(--stage) 14%, #fff);
  animation:ev-mark .55s ease 2;
}
@keyframes ev-mark{ 50%{ transform:scale(1.14); } }

/* ---- inline check ----
   A check question is not a lecture title: it sizes off the column
   (cqi, never vw — opening the pane narrows this column) and stays
   small enough that four options and a verdict fit an 800px screen. */

.check-q{
  font-size:clamp(18px, 5.6cqi, 24px);
  max-width:30ch;
  margin:0 0 13px;
}
.quiz-opts--check .opt{ padding:12px 15px; font-size:15.5px; gap:12px; }
.quiz-opts--check .opt-mark{ width:25px; height:25px; font-size:11px; }
.lab-finding-slot .quiz-fb{ margin-top:0; }
.lab-instr .quiz-fb{ flex:0 0 auto; margin-top:14px; }
/* the result sub-beat's own way forward: visible only on a phone,
   where the question side (and its Next button) is off screen */
.quiz-fb .fb-next{ display:none; margin-top:11px; align-self:flex-start; }
.lab-stage[data-sub="1"] .quiz-fb{ flex-wrap:wrap; }
.lab-stage[data-sub="1"] .quiz-fb .fb-next{ display:flex; flex-basis:100%; justify-content:center; }

/* ---- the closing card ---- */

.close-card{
  height:100%; min-height:0; overflow:hidden;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:16px; text-align:center;
}
.close-card h2{ font-size:clamp(21px, 2.6vw, 33px); max-width:22ch; margin:0; }
/* the replay: the student's own two lines, re-chopped. Left-aligned
   inside the centred card — the cards are specimens, not headings. */
.close-replay{
  width:100%; max-width:560px;
  display:flex; flex-direction:column; gap:9px; text-align:left;
}
/* the landing arrives only after the replay has played */
.close-land{ display:none; flex-direction:column; align-items:center; gap:13px; }
.close-land.is-shown{ display:flex; animation:lab-enter .5s ease both; }
.close-sub{ margin:0; font-size:16px; color:var(--muted); max-width:54ch; }
/* the punchline never wraps: it is one breath, said once */
.close-card .close-land h2{ max-width:none; white-space:nowrap; font-size:clamp(19px, 3vw, 33px); }
.close-state.is-mastered{ gap:0; }
.close-check{ width:54px; height:54px; }
.close-check circle{ fill:color-mix(in srgb, var(--stage) 10%, transparent); stroke:var(--stage); stroke-width:2.5; }
.close-check path{
  fill:none; stroke:var(--stage); stroke-width:4;
  stroke-linecap:round; stroke-linejoin:round;
  stroke-dasharray:34; stroke-dashoffset:34;
  animation:check-draw .5s ease .3s forwards;
}
@keyframes check-draw{ to{ stroke-dashoffset:0; } }
.lab-anchor-list{
  margin:0; padding:0; list-style:none;
  display:grid; gap:9px; text-align:left; max-width:52ch;
}
.lab-anchor-list li{
  position:relative; padding-left:19px;
  font-size:15.5px; line-height:1.55; color:var(--muted);
}
.lab-anchor-list li::before{
  content:''; position:absolute; left:0; top:.62em;
  width:7px; height:7px; border-radius:2px; background:var(--stage);
}
.lab-anchor-list b{ color:var(--ink); font-weight:600; }
.close-next{ display:flex; gap:9px; align-items:center; flex-wrap:wrap; justify-content:center; }

@media (max-width:860px){
  .tok-head h2{ font-size:19px; }
  .tok-hint{ font-size:14px; }
  .tok-chip{ font-size:11.5px; padding:2px 4px; }
  .tok-v{ font-size:16px; }
  .tok-readouts{ gap:14px; }
  .tok-bench{ grid-template-columns:minmax(0,1fr); gap:10px; }
  .tok-list{ display:grid; grid-template-columns:1fr 1fr; gap:2px 8px; }
  .spec{ padding:4px 7px; grid-template-columns:minmax(58px,auto) minmax(0,1fr) 22px; gap:7px; }
  .spec-k{ font-size:12px; }
  .tok-note{ font-size:12px; }
  .pred-row .v{ font-size:11px; }
  .close-card h2{ font-size:19px; }
  .lab-anchor-list li{ font-size:14.5px; }
}

/* ============================================================
   THE OPENING BEAT — look, then predict.

   The thing you are told to look at sits directly under the
   sentence that told you to look at it, ON PAPER. It has not been
   measured yet, so it is teaching, not machine output — sending it
   into the dark instrument panel was the wrong call.

   Staged: lines type themselves in and shimmer while they wait,
   then a button brings the question up. One idea at a time.
   ============================================================ */

/* `safe center` is load-bearing, not a nicety. Plain `center` on a flex
   item taller than its container spills it equally off BOTH ends, so the
   headline gets clipped and there is no way to reach it. `safe` falls
   back to start-alignment the moment it would overflow. */
.open{
  height:100%; min-height:0; overflow:hidden;
  display:flex; align-items:safe center; justify-content:center;
  container-type:inline-size;
}
.open-wrap{ width:min(680px, 100%); }

.open-h{
  font-size:clamp(21px, 4.2cqi, 34px);
  margin:0 0 15px;
}
/* once the answer is in, the headline has done its job and the room is
   needed by the result */
.open.is-answered .open-h{ font-size:clamp(19px, 3.2cqi, 25px); margin-bottom:13px; }
.open.is-answered .open-sub{ display:none; }
/* Once the question is up the sub-line has done its job too: the ask
   heading restates the point and the room is needed by the options —
   the same rule-9 cut the answered state already makes. The inner-clip
   probe caught "Lock it in" cut at 1366x768 (AA 01 round 1). */
.open.is-asking .open-sub{ display:none; }

.open-lines{ display:grid; gap:9px; }

.open-line{
  padding:13px 15px;
  border:1px solid var(--line); border-radius:var(--radius-sm);
  background:#fff; box-shadow:var(--shadow-sm);
}
.open-line-t{
  font-family:var(--font-mono); font-size:clamp(11.5px, 2cqi, 14px);
  color:var(--ink); white-space:nowrap; overflow:hidden;
  display:flex; align-items:center;
}
.open-line-t .k{ color:var(--muted); margin-right:11px; }

/* the caret only exists while that line is being written */
.open-line-t .cursor{
  display:inline-block; width:.55ch; height:1.05em; margin-left:1px;
  background:var(--stage); vertical-align:-.15em;
  animation:lab-blink 1.05s steps(2,start) infinite;
}

/* a line that is waiting to be acted on keeps breathing, so the
   screen never reads as a screenshot */
.open-line.is-live{ animation:open-shimmer 2.6s ease-in-out infinite; }
@keyframes open-shimmer{
  0%,100%{ border-color:var(--line); box-shadow:var(--shadow-sm); }
  50%{ border-color:color-mix(in srgb, var(--stage) 55%, transparent);
       box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 13%, transparent); }
}

.open-sub{
  color:var(--muted); font-size:clamp(14.5px, 2.3cqi, 17px);
  margin:14px 0 16px;
}

.open-strip{
  display:none; flex-wrap:wrap; gap:3px; margin-top:9px;
  padding-top:9px; border-top:1px solid var(--line);
}
.open-line.is-shown .open-strip{ display:flex; }

/* chunks on paper, not on ink — same widget, opposite ground.
   Serves beat 1's specimen lines AND beat 3's evidence cards: the chip
   has exactly two skins, decided by the surface it sits on. */
.open-strip .tok-chip, .ev-strip .tok-chip{
  font-size:11px; padding:2px 4px; animation:none;
  background:color-mix(in srgb, var(--stage) 16%, #fff);
  color:var(--stage-ink);
}
.open-strip .tok-chip:nth-child(even), .ev-strip .tok-chip:nth-child(even){
  background:color-mix(in srgb, var(--stage) 32%, #fff);
}
.open-strip .tok-chip.is-partial, .ev-strip .tok-chip.is-partial{
  background:color-mix(in srgb, var(--warn) 34%, #fff); color:#7a5c00;
}

/* The paper variant sets animation:none, which also silences a CHOP —
   and the closing replay is nothing but one. Re-arm it, with a stage
   cut-flash: the ink version's paper-white flash is invisible here. */
.ev-strip.is-chop .tok-chip{
  animation:tok-chop .22s cubic-bezier(.16,.9,.3,1) both,
            ev-cut .34s ease-out both;
}
@keyframes ev-cut{
  0%{ box-shadow:inset 2px 0 0 var(--stage); }
  100%{ box-shadow:inset 0 0 0 transparent; }
}
.ev-strip .tok-whole{ color:var(--muted); font-size:11px; padding:2px 4px; }

.open-count{
  margin-left:auto; flex:0 0 auto;
  font-family:var(--font-mono); font-variant-numeric:tabular-nums;
  font-size:13px; font-weight:600; color:var(--muted);
  transition:color .3s ease;
}
.open-line.is-shown .open-count{ color:var(--stage-ink); }
/* heavy = the stage accent at full weight. Danger-red would collide with
   the checks, where red means WRONG — and being expensive is not wrong. */
.open-line.is-heavy.is-shown .open-count{ color:var(--stage); font-weight:700; }

.open-q{ margin-top:4px; }
.open-ask{
  font-family:var(--font-display); font-weight:600;
  font-size:clamp(16.5px, 2.6cqi, 20px); margin:0 0 12px;
}
.open-out .lab-finding{ margin-top:16px; max-width:none; }
.open-out .lab-finding p{ font-size:clamp(15.5px, 2.5cqi, 18px); }
.open-out .lab-finding .said{ font-weight:700; color:var(--stage-ink); }
.open-out .lab-finding.is-miss .said{ color:var(--danger); }

@media (max-width:860px){
  .open-h{ font-size:20px; margin-bottom:14px; }
  .open-line{ padding:10px 12px; }
  .open-sub{ font-size:13px; margin:11px 0 13px; }
}


/* ============================================================
   AI CORE 01 — the clip beat, the pair on paper, the chat
   apparatus, scenario cards, the written/grown replay.
   Paper = what the student did; ink = what the machine said.
   ============================================================ */

/* Entering content inside a measured box fades and SCALES, never
   translates (rule 34): a translated child extends the scroll region in
   flight, and a display toggle on beat re-entry replays the animation. */
@keyframes lab-enter-scale{ from{ opacity:0; transform:scale(.985); } to{ opacity:1; transform:none; } }
.clip-finding.is-shown, .twinlab .tok-finding.is-shown, .sortlab .tok-finding.is-shown,
.open-out .lab-finding.is-shown,
.chat-switch.lab-swap, .chat-b--q, .chat-b--a, .scn-card.is-flipped .scn-flip,
.close-replay--twin ~ .close-land.is-shown{ animation-name:lab-enter-scale; }

/* ---- clip beat ---- */
.clip-beat{ height:100%; min-height:0; display:flex; flex-direction:column; gap:10px; position:relative; }
.clip-host{ flex:1 1 auto; min-height:0; display:flex; flex-direction:column; }
.clip-host .vid-stack{ flex:1 1 auto; min-height:0; height:auto; }
/* 2px of slack: a 16:9 frame solved from cqh rounds up and spills the beat */
.clip-host .vid-frame{ width:min(100cqw, calc(177.78cqh - 4px)); }
.vid-video{ position:absolute; inset:0; width:100%; height:100%; object-fit:contain; background:var(--c-ink-900); }
/* the ending lands ON the held last picture, bottom third, paper card.
   No translate (rule 34 and the enter animation own transform): it is
   centred by auto margins inside left/right insets. */
.clip-finding.is-shown{
  position:absolute; left:4%; right:4%; bottom:clamp(12px, 4cqh, 30px); z-index:2;
  margin:0 auto; width:auto; max-width:760px;
  background:rgba(255,255,255,.94); backdrop-filter:blur(6px);
  box-shadow:var(--shadow);
}
/* the caption rides the bottom strip of the frame; the TSX keeps that
   strip empty, so it never lands on the thing being taught */
.vid-frame > .vid-cc{
  position:absolute; left:0; right:0; bottom:0; margin:0; min-height:0;
  padding:3cqi 5cqi 2.2cqi;
  background:linear-gradient(180deg, transparent, rgba(13,17,23,.62));
}
.vid-frame > .vid-cc:empty{ display:none; }
/* the placeholder is teaching, not machine output: it sits on paper */
.clip-ph{ position:absolute; inset:0; display:grid; place-items:center; background:var(--surface-2); }
.clip-ph-card{ display:flex; flex-direction:column; align-items:center; gap:10px; text-align:center; padding:5cqi; max-width:46ch; }
.clip-ph-glyph{ width:44px; height:44px; border-radius:50%; display:grid; place-items:center; background:#fff; border:1px solid var(--line); color:var(--stage-ink); }
.clip-ph-t{ margin:0; font-family:var(--font-display); font-weight:600; font-size:clamp(15px, 2.6cqi, 22px); line-height:1.3; }
.vid-frame.is-placeholder{ background:var(--surface-2); box-shadow:var(--shadow-sm); border:1px solid var(--line); }
.vid-chapter-tag{ font-family:var(--font-mono); font-size:9.5px; letter-spacing:.08em; text-transform:uppercase; opacity:.7; margin-left:4px; }
.clip-finding{ flex:0 0 auto; max-width:none; align-items:center; gap:14px; justify-content:space-between; }
.clip-finding.is-shown{ display:flex; }
.clip-finding-t{ flex:1; min-width:0; }
.clip-finding p{ margin-top:3px; font-size:clamp(15.5px, 1.3vw, 18px); }
.lab-transcript{ display:grid; gap:2px; }

/* ---- the pair on paper (beat 2, and check 1's evidence) ---- */
.open-wrap--wide{ width:min(820px, 100%); }
.twice{ display:grid; gap:9px; }
.ans-q{
  display:flex; gap:11px; align-items:baseline; padding:10px 14px; overflow:hidden;
  border-radius:var(--radius-sm); background:var(--surface-2); border:1px dashed var(--line);
  font-size:15.5px; color:var(--ink); line-height:1.45;
}
.ans-k{ flex:0 0 auto; font-family:var(--font-mono); font-size:12px; color:var(--muted); }
.ans-card{
  display:flex; gap:11px; align-items:baseline; padding:12px 16px; overflow:hidden;
  border:1px solid var(--line); border-radius:var(--radius-sm);
  background:#fff; box-shadow:var(--shadow-sm);
  font-size:16px; line-height:1.5; color:var(--ink);
  transition:border-color .3s ease, box-shadow .3s ease;
}
.ans-card .ans-t{ flex:1; min-width:0; }
.ans-card .cursor, .ans-q .cursor{
  display:inline-block; width:.55ch; height:1.05em; margin-left:1px;
  background:var(--stage); vertical-align:-.15em;
  animation:lab-blink 1.05s steps(2,start) infinite;
}
.ans-card.is-live{ animation:open-shimmer 2.6s ease-in-out infinite; }
.ans-card.is-mark{
  border-color:var(--stage);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 18%, transparent);
  animation:ev-mark .55s ease 2;
}
.ans-third .ans-card{ border-style:dashed; }
.ans-third .ans-card.is-shown{ border-style:solid; border-color:color-mix(in srgb, var(--stage) 55%, transparent); }
.open.is-answered .twice{ gap:6px; }
.open.is-answered .ans-card{ padding:9px 13px; font-size:14.5px; }
.open.is-answered .ans-q{ padding:8px 13px; font-size:14px; }
.stamp-row{ display:flex; gap:6px; flex-wrap:wrap; }
.stamp-chip{
  font-family:var(--font-mono); font-size:11.5px; letter-spacing:.04em;
  padding:4px 9px; border-radius:var(--radius-pill);
  border:1px solid var(--line); background:#fff; color:var(--muted);
  transition:background .3s ease, color .3s ease, border-color .3s ease;
}
.stamp-chip.is-mark{ background:var(--stage); color:#fff; border-color:var(--stage); animation:ev-mark .55s ease 2; }

/* ---- the chat apparatus (lab-chat.js) ---- */
.twinlab{ height:100%; min-height:0; display:flex; flex-direction:column; gap:12px; }
.chat-host{ flex:1 1 auto; min-height:0; display:flex; }
.chat{ flex:1; min-height:0; min-width:0; display:grid; grid-template-columns:minmax(220px, 290px) minmax(0,1fr); gap:16px; align-items:start; align-content:start; }
.chat-side{ display:flex; flex-direction:column; gap:10px; min-height:0; min-width:0; }
.chat-main{ display:flex; flex-direction:column; gap:10px; min-height:0; min-width:0; }
.chat-composer{ display:flex; flex-direction:column; gap:7px; }
.chat-chips{ display:flex; flex-wrap:wrap; gap:6px; }
.chat-chip{
  font:inherit; font-size:13.5px; padding:5px 11px; border-radius:var(--radius-pill);
  border:1px solid var(--line); background:#fff; color:var(--muted); cursor:pointer;
  transition:border-color .16s ease, color .16s ease, background .16s ease;
}
.chat-chip:hover{ color:var(--ink); border-color:var(--ink); }
.chat-chip.is-on{ background:color-mix(in srgb, var(--stage) 12%, #fff); border-color:color-mix(in srgb, var(--stage) 45%, transparent); color:var(--stage-ink); font-weight:500; }
.chat-msg{
  font-size:15px; line-height:1.5; padding:10px 13px;
  border:1px solid var(--line); border-radius:var(--radius-sm); background:#fff; box-shadow:var(--shadow-sm);
}
.chat-composer .lw-btn{ align-self:flex-start; }
.chat-switch{ display:flex; flex-direction:column; gap:7px; }
.chat-src{ display:flex; border:1px solid var(--line); border-radius:var(--radius-sm); overflow:hidden; background:#fff; }
.chat-src button{ flex:1; font:inherit; font-size:14px; padding:8px 9px; border:0; background:transparent; color:var(--muted); cursor:pointer; }
.chat-src button.is-on{ background:var(--ink); color:#fff; }
.chat-panel{
  padding:9px 12px; border-radius:var(--radius-sm);
  background:var(--surface-2); border:1px dashed var(--line);
  font-size:14px; color:var(--muted); display:flex; flex-direction:column; gap:6px; min-height:0;
}
.chat-panel-big{ margin:0; font-family:var(--font-display); font-weight:600; font-size:20px; color:var(--ink); }
.chat-panel-note{ margin:0; font-size:14px; line-height:1.5; }
.chat-rules{ margin:0; padding:0 0 0 18px; display:grid; gap:3px; font-size:14px; line-height:1.4; }
.chat-rules li{ display:flex; gap:6px; flex-wrap:wrap; }
.chat-rules li span{ color:var(--muted); }
.chat-rules li b{ color:var(--ink); font-weight:600; }
/* two ink lanes that HUG their content; leftover space falls to paper */
.chat-lanes{ display:grid; grid-template-columns:1fr 1fr; gap:12px; min-height:0; min-width:0; align-content:start; align-items:start; }
.chat-lane{
  background:var(--c-ink-900); border-radius:var(--radius); padding:14px 16px;
  display:flex; flex-direction:column; gap:11px; min-width:0; color:var(--c-ink-300);
}
.chat-lane-head{ display:flex; justify-content:space-between; gap:8px; }
.chat-lane-head .lw-label{ color:var(--c-ink-400); }
.chat-lane-src{ text-align:right; }
.chat-thread{ display:flex; flex-direction:column; gap:8px; min-height:2.4em; }
.chat-b{ max-width:94%; padding:10px 13px; border-radius:12px; font-size:15px; line-height:1.5; overflow-wrap:anywhere; }
.chat-b--q{ align-self:flex-end; background:#fff; color:var(--ink); border-bottom-right-radius:4px; animation:lab-enter .3s ease both; }
.chat-b--a{ align-self:flex-start; background:var(--c-ink-700); color:var(--c-ink-300); border-bottom-left-radius:4px; animation:lab-enter .3s ease both; }
.chat-b--a[data-src="rules"]{ border-left:2px solid var(--c-ink-400); }
.chat-b-t:not(.is-done)::after{
  content:''; display:inline-block; width:.5ch; height:1em; margin-left:2px;
  background:var(--stage); vertical-align:-.15em;
  animation:lab-blink 1.05s steps(2,start) infinite;
}

/* ---- scenario cards (check 2): grading FLIPS them ---- */
.scn-card{
  display:flex; gap:11px; align-items:baseline; padding:11px 14px;
  border:1px solid var(--line); border-radius:var(--radius-sm);
  background:#fff; box-shadow:var(--shadow-sm);
  font-size:15px; line-height:1.45; color:var(--ink);
  transition:border-color .3s ease, box-shadow .3s ease;
}
.scn-t{ flex:1; min-width:0; }
.scn-flip{ display:none; flex-direction:column; align-items:flex-end; gap:3px; flex:0 0 auto; text-align:right; font-size:12.5px; color:var(--muted); max-width:40%; line-height:1.3; }
.scn-card.is-flipped .scn-flip{ display:flex; animation:lab-enter .35s ease both; }
.scn-tag{ font-family:var(--font-mono); font-size:11px; letter-spacing:.1em; text-transform:uppercase; padding:2px 7px; border-radius:var(--radius-pill); }
.scn-tag[data-tag="written"]{ background:var(--surface-2); color:var(--muted); border:1px solid var(--line); }
.scn-tag[data-tag="grown"]{ background:var(--stage); color:#fff; }
.scn-card.is-mark{ border-color:var(--stage); box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 18%, transparent); }
.opt-card{ display:none; font-size:13.5px; line-height:1.4; color:var(--muted); font-weight:400; margin-top:3px; }
.lab-stage[data-narrow="1"] .opt-card{ display:block; }
.lab-stage[data-narrow="1"] .opt.is-dim .opt-card{ display:none; }
.lab-stage[data-narrow="1"] .lab-instr .quiz-fb{ margin-top:8px; padding:10px 14px; }
.lab-stage[data-narrow="1"] .quiz-fb:empty{ display:none; }
.lab-stage[data-narrow="1"] .quiz-opts--check .opt{ padding:9px 13px; }
.lab-stage[data-narrow="1"] .quiz-opts--check{ gap:7px; }

/* ---- the written / grown replay (recap) ---- */
.close-replay--twin{ max-width:680px; }
.close-next a.lw-btn{ text-decoration:none; }
.replay-lanes{ display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-top:8px; }
.replay-lane{ display:flex; flex-direction:column; gap:6px; min-width:0; }
.replay-list{ display:flex; flex-direction:column; gap:5px; }
.replay-b{
  font-size:14px; line-height:1.45; padding:7px 10px; border-radius:8px;
  background:var(--surface-2); border:1px solid var(--line); color:var(--muted); min-height:1.4em;
}
.replay-b.is-stamp{ animation:stamp-in .22s ease both; }
.replay-b--g{ background:color-mix(in srgb, var(--stage) 6%, #fff); border-color:color-mix(in srgb, var(--stage) 40%, transparent); color:var(--ink); }
@keyframes stamp-in{ 0%{ transform:scale(.96); opacity:0; } 100%{ transform:none; opacity:1; } }

/* a pane-squeezed desktop stage: one column, the message preview and
   the source panel go (the lanes show the message itself once sent) */
.lab-stage[data-narrow="1"] .chat{ grid-template-columns:1fr; gap:10px; }
.lab-stage[data-narrow="1"] .chat-msg{ display:none; }
.lab-stage[data-narrow="1"] .chat-panel{ display:none; }
.lab-stage[data-narrow="1"] .chat-composer > .lw-label{ display:none; }

@media (max-width:860px){
  .opt-card{ display:block; }
  /* the phone's lanes show the reply only: the student's message is the
     highlighted chip they just pressed, and two copies of it cost 120px */
  .chat-b--q{ display:none; }
  /* the flip lands UNDER the scenario text on a phone, not beside it:
     a 44% side column turns every card into four lines */
  .scn-card{ flex-wrap:wrap; }
  .close-card > .lw-label{ display:none; }
  .replay-lanes{ margin-top:4px; }
  .close-card{ gap:10px; }
  .scn-card.is-flipped .scn-flip{ flex:1 1 100%; flex-direction:row; align-items:center; gap:8px; max-width:none; text-align:left; }
  .check-ev-lead{ display:none; }
  .chat{ grid-template-columns:1fr; gap:8px; }
  .chat-lanes{ grid-template-columns:1fr; gap:8px; }
  .chat-panel{ display:none; }
  .chat-msg{ display:none; }
  .chat-composer > .lw-label{ display:none; }
  .chat-chip{ font-size:13px; padding:4px 9px; }
  .chat-lane{ padding:10px 12px; gap:7px; }
  .chat-b{ font-size:14.5px; padding:8px 11px; }
  .scn-card{ font-size:14px; padding:9px 11px; }
  .scn-flip{ max-width:44%; font-size:12px; }
  .check-ev-cards{ gap:7px; }
  .replay-lanes{ grid-template-columns:1fr; }
  .open-wrap--wide .open-h{ font-size:22px; }
  .ans-card{ padding:10px 12px; font-size:14.5px; }
  .clip-finding{ flex-direction:column; align-items:flex-start; gap:8px; }
}

/* ============================================================
   LAB LEVELS — the sorting apparatus (lab-levels.js).
   Sort mode only; the ladder is AA 04's job.

   The zone strip is the machine's surface (ink). The deck and
   every placed card are paper: the student's decisions. Machine
   marks — pins, the Moved tag, the settle pulse — take the stage
   accent. Rows hug their content; leftover space falls to paper
   (rule 14). Entering cards scale, never translate (rule 34).
   ============================================================ */

.levels{ display:flex; flex-direction:column; gap:10px; min-height:0; }

.levels-zones{
  display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:8px;
  background:var(--c-ink-900); border-radius:var(--radius); padding:10px;
}
.lv-zone{ display:flex; flex-direction:column; gap:8px; min-width:0; border-radius:var(--radius-sm); }
.lv-zone-head{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  font-family:var(--font-mono); font-size:11.5px; font-weight:500;
  text-transform:uppercase; letter-spacing:.12em; color:var(--c-ink-300);
  background:var(--c-ink-800); border:1px dashed var(--c-ink-600);
  border-radius:var(--radius-sm); padding:6px 12px; cursor:pointer; text-align:left;
}
.lv-zone-hint{ color:var(--stage); opacity:0; transition:opacity .16s ease; }
.is-arming .lv-zone-hint{ opacity:1; }
.is-arming .lv-zone-head,
.lv-zone.is-over .lv-zone-head{ border-color:var(--stage); color:#fff; }
.lv-zone-cards{ display:flex; flex-direction:column; gap:5px; min-height:0; }

/* the deck: paper cards, each stating its mechanism */
.levels-deck{ display:flex; flex-direction:column; gap:8px; min-height:0; }
.lv-deck{ display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:8px; }
.lv-card{
  font-family:var(--font-body); font-size:14.5px; line-height:1.45; text-align:left;
  background:#fff; color:var(--ink); border:1px solid var(--line);
  border-radius:var(--radius-sm); padding:10px 13px; cursor:grab;
  box-shadow:var(--shadow-sm);
  transition:border-color .16s ease, box-shadow .16s ease, transform .07s ease;
}
.lv-card:hover{ border-color:var(--stage); }
.lv-card.is-armed{
  border-color:var(--stage);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 28%, transparent);
}
.lv-card:active{ cursor:grabbing; }

/* a placed card: flipped to label + pin diagram + one line why */
.lv-placed{
  display:flex; flex-direction:column; gap:4px;
  background:#fff; border-radius:var(--radius-sm); padding:7px 10px;
  border:1px solid var(--line);
  transition:transform .28s ease, opacity .28s ease;
}
.lv-placed.is-arriving{ transform:scale(.94); opacity:0; }
.lv-placed-head{ display:flex; align-items:center; gap:8px; min-width:0; }
.lv-placed-k{ font-family:var(--font-display); font-size:14px; font-weight:600; letter-spacing:-.01em; }
.lv-tag{
  font-family:var(--font-mono); font-size:10.5px; font-weight:500;
  text-transform:uppercase; letter-spacing:.1em;
  color:var(--stage-ink); background:color-mix(in srgb, var(--stage) 16%, #fff);
  border-radius:var(--radius-pill); padding:2px 8px; white-space:nowrap;
}
.lv-placed-note{ font-size:14px; line-height:1.35; color:var(--muted); }
.lv-placed--mini{ padding:6px 9px; flex-direction:row; align-items:center; gap:8px; }

/* the pin diagram: trigger chip aside, the lane, the output, the tray.
   Solid = pinned (with pin dots in the stage accent), dashed = open. */
.lvp{ display:inline-flex; align-items:center; gap:5px; height:20px; }
.lvp i, .lvp b{ display:inline-block; }
.lvp-trig{
  width:14px; height:14px; border-radius:50%;
  border:1.5px dashed var(--muted); position:relative; flex:none;
}
.lvp-trig::after{
  content:''; position:absolute; left:5.5px; top:2.5px; width:1.5px; height:5px;
  background:var(--muted); transform-origin:bottom;
}
.lvp-lane{
  display:inline-flex; align-items:center; gap:3px; padding:2.5px 5px;
  border:1.5px solid var(--ink); border-radius:5px; position:relative; flex:none;
}
.lvp-lane--open{ border-style:dashed; border-color:var(--muted); }
.lvp-step{ width:8px; height:8px; border-radius:2px; background:var(--c-ink-600); }
.lvp-lane--open .lvp-step{ background:transparent; border:1px dashed var(--muted); }
.lvp-step.is-glow{
  background:var(--stage);
  box-shadow:0 0 6px 1px color-mix(in srgb, var(--stage) 65%, transparent);
}
.lvp-out{
  width:12px; height:12px; border-radius:3px;
  border:1.5px solid var(--ink); position:relative; flex:none;
}
.lvp-out--open{ border-style:dashed; border-color:var(--muted); }
.lvp-tray{
  width:14px; height:9px; border-radius:0 0 4px 4px;
  border:1.5px solid var(--muted); border-top:none; position:relative; flex:none;
}
/* the pins themselves: dots in the stage accent on whatever is pinned */
.lvp-lane:not(.lvp-lane--open)::after,
.lvp-out:not(.lvp-out--open)::after{
  content:''; position:absolute; top:-4px; right:-3px; width:7px; height:7px;
  border-radius:50%; background:var(--stage-ink); border:1.5px solid #fff;
}
/* the pins DRAW on placement rather than appear */
.lv-placed.is-drawing .lvp-lane::after,
.lv-placed.is-drawing .lvp-out::after{ animation:lvp-pin .4s ease .2s backwards; }
@keyframes lvp-pin{ from{ transform:scale(0); } to{ transform:scale(1); } }
/* on a miss, the ONE pin that settles it pulses */
.lvp .is-settle, .lvp-lane.is-settle, .lvp-out.is-settle, .lvp-trig.is-settle, .lvp-tray.is-settle{
  animation:lvp-settle 1.1s ease .45s 3;
}
@keyframes lvp-settle{
  0%, 100%{ box-shadow:0 0 0 0 transparent; }
  35%{ box-shadow:0 0 0 4px color-mix(in srgb, var(--stage) 38%, transparent); }
}

/* the replay at recap scale: mini cards fly in, then every pin at once */
.levels--replay .levels-zones{ padding:10px; gap:8px; }
.levels--replay .lv-zone-name{
  font-family:var(--font-mono); font-size:11.5px; font-weight:500;
  text-transform:uppercase; letter-spacing:.12em; color:var(--c-ink-300);
}
.levels--replay .lv-placed--mini.is-flying{ opacity:0; transform:scale(.9); }
.levels--replay .lvp-lane::after,
.levels--replay .lvp-out::after{ transform:scale(0); }
.levels--replay.is-pins-drawn .lvp-lane::after,
.levels--replay.is-pins-drawn .lvp-out::after{ transform:scale(1); transition:transform .3s ease; }

@media (prefers-reduced-motion: reduce){
  .lv-placed, .lv-placed.is-arriving{ transform:none; opacity:1; transition:none; }
  .lv-placed.is-drawing .lvp-lane::after,
  .lv-placed.is-drawing .lvp-out::after,
  .lvp .is-settle, .lvp-lane.is-settle, .lvp-out.is-settle,
  .lvp-trig.is-settle, .lvp-tray.is-settle{ animation:none; }
  .levels--replay .lvp-lane::after, .levels--replay .lvp-out::after{ transform:scale(1); }
}

/* a narrow stage keeps the three zones side by side (stacking them is
   taller than the no-scroll budget); the labels are short on purpose.
   Placed cards drop their note; the pins still say why. */
.lab-stage[data-narrow="1"] .levels-zones{ gap:6px; padding:8px; }
.lab-stage[data-narrow="1"] .lv-placed-note{ display:none; }
.lab-stage[data-narrow="1"] .lv-zone-hint{ display:none; }
.lab-stage[data-narrow="1"] .lv-card{ font-size:14px; padding:8px 10px; }

/* ============================================================
   AA 01 — the pin-diagram beats: the prediction card that grows
   its pins, the check evidence that GRADES with them, the sort
   lab shell, the closing machines.
   Coral (the stage accent) = what the machine did; paper = what
   the student decided.
   ============================================================ */

.pin-card{
  position:relative; text-align:left;
  background:#fff; border:1px solid var(--line); border-radius:var(--radius);
  box-shadow:var(--shadow-sm); padding:16px 20px; margin:14px 0 4px;
  display:flex; flex-direction:column; gap:10px;
}
.pin-card.is-live{ animation:open-shimmer 2.4s ease-in-out infinite; }
.pin-card-t{ margin:0; font-size:16px; line-height:1.55; }
.pin-card .cursor{ display:inline-block; width:8px; height:1em; background:var(--stage); vertical-align:-2px; margin-left:2px; animation:lab-blink 1.05s steps(2,start) infinite; }

/* the big diagram: same DOM as the widget's, at stage scale */
.lvp--lg{ height:56px; gap:14px; }
.lvp--lg .lvp-trig{ width:40px; height:40px; border-width:2px; }
.lvp--lg .lvp-trig::after{ left:17px; top:8px; width:2.5px; height:13px; }
.lvp--lg .lvp-lane{ gap:9px; padding:8px 14px; border-width:2.5px; border-radius:12px; }
.lvp--lg .lvp-step{ width:24px; height:24px; border-radius:6px; }
.lvp--lg .lvp-out{ width:34px; height:34px; border-width:2.5px; border-radius:8px; }
.lvp--lg .lvp-tray{ width:38px; height:22px; border-width:2.5px; }
.lvp--lg .lvp-lane:not(.lvp-lane--open)::after,
.lvp--lg .lvp-out:not(.lvp-out--open)::after{ width:13px; height:13px; top:-7px; right:-6px; border-width:2px; }

/* the prediction's reveal: the diagram grows piece by piece */
.pin-diagram{ padding-top:4px; }
.pin-diagram .lvp-trig, .pin-diagram .lvp-lane, .pin-diagram .lvp-out, .pin-diagram .lvp-tray{
  opacity:0; transform:scale(.85); transition:opacity .3s ease, transform .3s ease;
}
.pin-diagram .lvp-lane::after, .pin-diagram .lvp-out::after{ transform:scale(0); transition:transform .3s ease .1s; }
.pin-diagram .lvp-step.is-glow{ box-shadow:none; background:transparent; transition:background .3s ease, box-shadow .3s ease; }
.pin-diagram.show-trig .lvp-trig{ opacity:.75; transform:scale(1) translateX(-6px); }
.pin-diagram.show-lane .lvp-lane{ opacity:1; transform:scale(1); }
.pin-diagram.show-lane .lvp-lane::after{ transform:scale(1); }
.pin-diagram.show-glow .lvp-step.is-glow{
  background:var(--stage);
  box-shadow:0 0 10px 2px color-mix(in srgb, var(--stage) 65%, transparent);
}
.pin-diagram.show-out .lvp-out{ opacity:1; transform:scale(1); }
.pin-diagram.show-out .lvp-out::after{ transform:scale(1); }
.pin-diagram.show-tray .lvp-tray{ opacity:1; transform:scale(1); }

/* the check evidence: the flow as pins, on paper, that GRADES */
.ev-flow{
  background:#fff; border:1px solid var(--line); border-radius:var(--radius);
  box-shadow:var(--shadow-sm); padding:18px 20px;
  display:flex; flex-direction:column; gap:14px; align-items:flex-start;
}
.ev-list{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.ev-list .lw-label{ margin-right:2px; }
.ev-list-chip{
  font-family:var(--font-mono); font-size:14px; font-weight:600;
  padding:4px 12px; border-radius:var(--radius-pill);
  border:1.5px solid var(--ink); background:#fff;
}
/* each option lights the piece that settles it (rule 27) */
.ev-flow[data-mark="trig-aside"] .lvp-trig{ animation:lvp-aside 1.2s ease both; }
@keyframes lvp-aside{ 40%{ transform:translateX(-16px); opacity:.4; } 100%{ transform:translateX(-10px); opacity:.55; } }
.ev-flow[data-mark="pins-draw"] .lvp-lane::after,
.ev-flow[data-mark="pins-draw"] .lvp-out::after{ animation:lvp-pin .5s ease both; }
.ev-flow[data-mark="list-pulse"] .ev-list-chip{ animation:lvp-settle 1.1s ease 2; }
.ev-flow[data-mark="lane-pulse"] .lvp-lane{ animation:lvp-settle 1.1s ease 2; }
.ev-flow[data-mark="lane-pulse"] .lvp-step.is-glow{ animation:lvp-settle 1.1s ease .2s 2; }
.ev-flow[data-mark="glow-bright"] .lvp-step.is-glow{
  animation:none;
  box-shadow:0 0 18px 5px color-mix(in srgb, var(--stage) 80%, transparent);
}
.ev-flow[data-mark="longer"] .lvp-lane::after,
.ev-flow[data-mark="longer"] .lvp-out::after{ animation:lvp-pin .5s ease both; }
.ev-flow[data-mark="trig-lift"] .lvp-trig{ animation:lvp-lift .9s ease both; }
@keyframes lvp-lift{ to{ transform:translateY(-14px); opacity:.25; } }
/* the correct answer to check 2: the pins POP and the card opens */
.ev-flow[data-mark="unpin"] .lvp-lane::after,
.ev-flow[data-mark="unpin"] .lvp-out::after{ transform:scale(0); transition:transform .4s ease .2s; }
.ev-flow[data-mark="unpin"] .lvp-lane{ border-style:dashed; border-color:var(--muted); transition:border-color .3s ease .5s; }
.ev-flow[data-mark="unpin"] .lvp-out{ border-style:dashed; border-color:var(--muted); transition:border-color .3s ease .5s; }
.ev-flow[data-mark="unpin"] .ev-list-chip{ border-style:dashed; border-color:var(--muted); color:var(--muted); transition:all .3s ease .5s; }

/* the sort lab shell. It HUGS its content (rule 14): leftover space
   falls to paper below, and the beat-entry animation has room to land. */
.sortlab{ min-height:0; display:flex; flex-direction:column; gap:10px; }
.levels-host{ flex:0 1 auto; min-height:0; display:flex; flex-direction:column; justify-content:flex-start; }
.sortlab .tok-finding{ flex:0 0 auto; }

/* the recap fallback: the clip's three machines */
.close-machines{ display:flex; gap:26px; justify-content:center; flex-wrap:wrap; }
.close-machine{
  display:flex; flex-direction:column; align-items:center; gap:10px;
  padding:16px 20px; background:#fff; border:1px solid var(--line);
  border-radius:var(--radius); box-shadow:var(--shadow-sm);
  opacity:0; transform:scale(.94); transition:opacity .4s ease, transform .4s ease;
}
.close-machine.is-in{ opacity:1; transform:scale(1); }
.close-replay--sort{ max-width:760px; }
.close-soon{ font-size:15px; color:var(--muted); }
.close-soon b{ font-family:var(--font-mono); font-size:10.5px; font-weight:500; text-transform:uppercase; letter-spacing:.1em; color:var(--stage-ink); background:color-mix(in srgb, var(--stage) 16%, #fff); border-radius:var(--radius-pill); padding:3px 9px; margin-left:8px; }

@media (prefers-reduced-motion: reduce){
  .pin-card.is-live{ animation:none; }
  .pin-diagram .lvp-trig, .pin-diagram .lvp-lane, .pin-diagram .lvp-out, .pin-diagram .lvp-tray,
  .pin-diagram .lvp-lane::after, .pin-diagram .lvp-out::after{ transition:none; }
  .close-machine{ transition:none; opacity:1; transform:none; }
  .ev-flow [class*="lvp-"]{ animation:none !important; }
}

/* ============================================================
   LAB FLOW — the decision-rail apparatus (lab-flow.js).
   Doors mode only; sieve / trigger / fan-out / scoping / gallery
   are their lectures' jobs (AA 17, 18, 21, 29, 40).

   The corridor is the machine's surface (ink): three doors in a
   fixed order. The rooms and the deck are paper: the student's
   decisions land there. Machine marks — a door opening, the timer
   chip, the Moved tag, the meter — take the stage accent. Rows hug
   their content (rule 14); entering cards scale, never translate
   (rule 34); nothing here carries overflow:hidden it does not
   need (rule 48).
   ============================================================ */

.flow{ display:flex; flex-direction:column; gap:8px; min-height:0; }

/* the corridor */
.flow-corridor{
  background:var(--c-ink-900); border-radius:var(--radius); padding:8px;
  display:flex; flex-direction:column; gap:6px;
}
.fl-walker{
  display:flex; align-items:center; gap:10px; min-width:0;
  color:var(--c-ink-300); font-size:14px; line-height:1.35;
  padding:2px 4px 4px;
}
.fl-walker .lw-label{ color:var(--stage); flex:0 0 auto; }
.fl-walker-t{ color:#fff; min-width:0; }
.fl-doors{ display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:8px; }
.fd{
  position:relative; display:flex; flex-direction:column; gap:4px; min-width:0;
  background:var(--c-ink-800); border:1px dashed var(--c-ink-600);
  border-radius:var(--radius-sm); padding:8px 10px 8px;
  transition:border-color .18s ease, background .18s ease, box-shadow .18s ease;
}
.fd.is-live{ border-style:solid; border-color:var(--stage); background:var(--c-ink-700); box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 22%, transparent); }
.fd.is-open{ border-style:solid; border-color:var(--stage); }
.fd.is-shut{ border-style:solid; border-color:var(--c-ink-600); opacity:.78; }
.fd.is-wrong{ animation:fd-pushback .5s ease; }
@keyframes fd-pushback{ 25%{ transform:translateX(-5px); } 60%{ transform:translateX(4px); } 100%{ transform:none; } }
.fd-label{
  font-family:var(--font-mono); font-size:12px; font-weight:600;
  text-transform:uppercase; letter-spacing:.12em; color:#fff;
  display:flex; align-items:center; gap:8px;
}
/* the door itself: a rounded-top frame; the leaf opens (skews away) when the answer is yes */
.fd-glyph{ position:absolute; right:10px; top:9px; width:16px; height:22px; border:2px solid var(--c-ink-400); border-bottom:0; border-radius:8px 8px 0 0; display:block; }
.fd-glyph i{ position:absolute; inset:2px 2px 0 2px; background:var(--c-ink-400); border-radius:6px 6px 0 0; transform-origin:left center; transition:transform .4s ease, background .3s ease; }
.fd.is-live .fd-glyph{ border-color:var(--stage); }
.fd.is-live .fd-glyph i{ background:var(--stage); }
.fd.is-open .fd-glyph{ border-color:var(--stage); }
.fd.is-open .fd-glyph i{ background:var(--stage); transform:perspective(60px) rotateY(-62deg); }
.fd.is-shut .fd-glyph i{ background:var(--c-ink-600); }
.fd-q{ font-size:12.5px; line-height:1.35; color:var(--c-ink-300); padding-right:22px; }
.fd-ans{ display:flex; gap:6px; margin-top:2px; }
.fd-a{
  font-family:var(--font-mono); font-size:12.5px; font-weight:600; letter-spacing:.04em;
  background:#fff; color:var(--ink); border:1px solid var(--line); border-radius:var(--radius-pill);
  padding:4px 12px; cursor:pointer; transition:border-color .15s ease, background .15s ease, opacity .15s ease;
}
.fd-a:hover{ border-color:var(--stage); }
.fd-a.is-picked{ background:var(--stage); border-color:var(--stage); color:#fff; }
.fd-a:disabled{ cursor:default; opacity:.55; }
.fd-a.is-picked:disabled{ opacity:1; }
.fd:not(.is-live):not(.is-open):not(.is-shut) .fd-a{ opacity:.35; pointer-events:none; }
.fd-line{ font-size:13px; line-height:1.4; color:#fff; padding-top:2px; }
.fd.is-wrong .fd-line{ color:var(--stage); }
.fd.is-wrong .fd-line::before{ content:'↳ '; }

/* the rooms: paper, the script room cheap and small, the agent room loud */
.fl-rooms{ display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:8px; }
.fl-room{
  background:#fff; border:1px solid var(--line); border-radius:var(--radius-sm);
  padding:6px 9px; display:flex; flex-direction:column; gap:5px; min-width:0;
  box-shadow:var(--shadow-sm);
}
.fl-room--agent{ border-color:color-mix(in srgb, var(--stage) 40%, var(--line)); }
.fl-room.is-hot{ box-shadow:0 0 0 2px color-mix(in srgb, var(--stage) 22%, transparent), var(--shadow-sm); }
.fl-room-head{ display:flex; align-items:center; justify-content:space-between; gap:8px; min-width:0; }
.fl-room-sign{
  font-family:var(--font-mono); font-size:11.5px; font-weight:600;
  text-transform:uppercase; letter-spacing:.12em; color:var(--ink);
}
.fl-meter{ display:flex; align-items:center; gap:6px; min-width:0; }
.fl-meter-k{ font-family:var(--font-mono); font-size:10.5px; color:var(--muted); white-space:nowrap; }
.fl-meter-bar{ width:46px; height:6px; border-radius:3px; background:var(--line); display:block; position:relative; }
.fl-meter-bar b{ position:absolute; left:0; top:0; bottom:0; border-radius:3px; background:var(--stage); transition:width .45s ease; }
.fl-meter-n{ font-family:var(--font-mono); font-size:11px; color:var(--muted); min-width:1ch; text-align:right; }
.fl-landed{ display:flex; flex-direction:column; gap:3px; min-height:0; }
.fl-placed{
  display:flex; align-items:center; gap:6px; width:100%; min-width:0;
  background:var(--c-cream); border:1px solid var(--line); border-radius:8px; padding:2px 8px;
  transform-origin:center; transition:transform .22s ease, opacity .22s ease;
}
.fl-placed .fl-chip{ margin-left:auto; }
.fl-tag--pre{ background:transparent; color:var(--muted); padding:0 2px; font-size:12px; }
.fl-last{ font-size:13.5px; line-height:1.4; color:var(--muted); padding:6px 10px; background:var(--c-cream); border:1px solid var(--line); border-radius:8px; }
.fl-last b{ color:var(--ink); }
.fl-last i{ color:var(--stage-ink); }
.fl-placed.is-arriving{ transform:scale(.92); opacity:0; }
.fl-placed.is-moved{ border-color:color-mix(in srgb, var(--stage) 45%, var(--line)); }
.fl-placed-k{ font-size:12.5px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; flex:1 1 auto; }
.fl-chip{
  font-family:var(--font-mono); font-size:10px; font-weight:600; letter-spacing:.06em;
  color:var(--stage-ink); border:1px solid var(--stage); border-radius:var(--radius-pill);
  padding:1px 7px; white-space:nowrap; background:color-mix(in srgb, var(--stage) 10%, #fff);
}
.fl-chip--ask{ color:var(--muted); border-color:var(--line); background:transparent; }
.fl-tag{
  font-family:var(--font-mono); font-size:10px; font-weight:600; letter-spacing:.08em; text-transform:uppercase;
  color:#fff; background:var(--stage); border-radius:var(--radius-pill); padding:1px 7px;
}
.fl-placed.is-pre .fl-tag{ background:var(--muted); }

/* the deck: paper cards, each a job stated by what it should produce */
.flow-deck{ display:flex; flex-direction:column; gap:6px; min-height:0; }
.fl-deck{ display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:7px; }
.fl-card{
  font-family:var(--font-body); font-size:14px; line-height:1.4; text-align:left;
  background:#fff; color:var(--ink); border:1px solid var(--line);
  border-radius:var(--radius-sm); padding:8px 11px; cursor:pointer; box-shadow:var(--shadow-sm);
  transition:border-color .16s ease, box-shadow .16s ease;
}
.fl-card:hover{ border-color:var(--stage); }
.fl-card.is-walking{ border-color:var(--stage); box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 28%, transparent); }
.is-walking .fl-card:not(.is-walking){ opacity:.55; }

/* mini corridors: the prediction's reveal, the check's walk, the replay */
.flow--mini, .flow--ask{ gap:8px; }
.flow-corridor--mini{ padding:7px; }
.flow-corridor--mini .fl-doors{ gap:6px; }
.flow-corridor--mini .fd{ padding:6px 8px 7px; gap:2px; }
.flow-corridor--mini .fd-label{ font-size:11px; }
.flow-corridor--mini .fd-glyph{ width:13px; height:18px; right:8px; top:7px; }
.flow-corridor--mini .fd-line{ font-size:12px; }
.fl-mini-card{
  background:#fff; border:1px solid var(--line); border-radius:var(--radius-sm);
  padding:8px 11px; font-size:14px; line-height:1.4; box-shadow:var(--shadow-sm);
}
.fl-mini-card--job{ font-size:15px; font-weight:500; }
.fl-mini-land{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; font-size:13.5px; min-width:0; }
.fl-mini-land .fl-room-sign{ padding:3px 9px; border:1.5px solid var(--ink); border-radius:var(--radius-pill); }
.fl-room-sign--agent{ border-color:var(--stage) !important; color:var(--stage-ink); }
.fl-mini-landt{ color:var(--muted); }
.flow--mini.is-landed .fl-mini-land, .flow--ask.is-landed .fl-mini-land{ animation:lab-enter-scale .3s ease both; }
.flow--replay .fl-rooms{ gap:6px; }
.flow--replay .fl-room{ padding:6px 8px; }
.fl-placed--mini{ padding:1px 7px; }
.fl-placed--mini .fl-placed-k{ font-size:12px; }
.fl-placed--mini .fl-chip{ font-size:9px; }
.fl-placed.is-flying{ opacity:0; transform:scale(.9); }

@media (prefers-reduced-motion: reduce){
  .fd, .fd-glyph i, .fl-placed, .fl-meter-bar b{ transition:none; }
  .fd.is-wrong{ animation:none; }
  .flow--mini.is-landed .fl-mini-land, .flow--ask.is-landed .fl-mini-land{ animation:none; }
}

/* ============================================================
   AA 02 — the cheapest flow: the four wish cards that ARE the
   prediction's options, the reveal that walks each one, the doors
   lab shell, the check that is a walk and the check that is three
   drawn builds, the closing rooms.
   Dark green (the stage accent) = what the machine did; paper =
   what the student decided.
   ============================================================ */

/* beat 1: four wishes on paper, tap one */
.wish-grid{ display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:8px; margin:10px 0 4px; text-align:left; }
.wish{
  position:relative; display:flex; flex-direction:column; gap:6px; min-width:0;
  background:#fff; border:1px solid var(--line); border-radius:var(--radius);
  padding:9px 12px; cursor:pointer; box-shadow:var(--shadow-sm); text-align:left;
  font-family:var(--font-body); color:var(--ink);
  opacity:0; transform:scale(.96); transition:opacity .35s ease, transform .35s ease, border-color .16s ease, box-shadow .16s ease;
}
.wish.is-in{ opacity:1; transform:scale(1); }
.wish:hover{ border-color:var(--stage); }
.wish.is-picked{ border-color:var(--stage); box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 26%, transparent); }
.wish.is-dim{ opacity:.5; }
.wish:disabled{ cursor:default; }
.wish-k{ font-family:var(--font-mono); font-size:10.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }
.wish-t{ font-size:14px; line-height:1.4; }
.open-wrap--wish{ width:min(860px, 100%); }
.open.open--top{ align-items:flex-start; }   /* rule 7: this beat GROWS (the reveal), so it never centres */
.pr-walk{ margin:6px 0 0; }
.pr-walk .flow-corridor--mini{ padding:6px; }
.open--top.is-answered .open-h{ margin-bottom:8px; }
.open--top .open-out .lab-finding{ margin-top:8px; }
.open--top .open-out .lab-finding.is-shown{ animation-name:lab-enter-scale; }   /* rule 34 */
.open--top .open-out .lab-finding p{ font-size:clamp(14.5px, 2.2cqi, 16.5px); }
.pr-walk .fl-mini-card{ display:none; }      /* the card text sits on the wish itself */
.pr-walk .flow--mini{ gap:6px; }
.wish-res{ display:flex; align-items:center; gap:6px; font-size:12.5px; }
.wish-res .fl-room-sign{ font-size:10.5px; padding:2px 8px; border:1.5px solid var(--ink); border-radius:var(--radius-pill); }
.wish.is-walking{ border-color:var(--stage); box-shadow:0 0 0 3px color-mix(in srgb, var(--stage) 22%, transparent); }
/* once the answer is in, the cards give the room to the reveal (rule 9: the
   wish text has done its job; the room sign and chip say what it became) */
.open.is-answered .wish-t{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; font-size:13px; line-height:1.3; }
.open.is-answered .wish{ padding:6px 10px; gap:2px; }
.open.is-answered #pr-label{ display:none; }
.open.is-answered .wish-grid{ gap:6px; margin:6px 0 2px; }
#pr-out.is-shown{ margin-top:6px; }

/* beat 2: the doors lab shell hugs its content (rule 14) */
.doorslab{ min-height:0; display:flex; flex-direction:column; gap:6px; }
.doorslab .tok-finding{ padding:10px 14px; }
.doorslab .tok-finding.is-shown{ animation-name:lab-enter-scale; }   /* rule 34 */
.doorslab .tok-head h2{ font-size:clamp(19px, 2vw, 26px); }
.flow-host{ flex:0 1 auto; min-height:0; }
.doorslab .tok-finding{ flex:0 0 auto; }

/* beat 4: check 1 walks; the evidence column shows the three rooms, empty */
.ev-rooms{ display:flex; flex-direction:column; gap:8px; }
.ev-rooms .fl-rooms{ grid-template-columns:repeat(3, minmax(0,1fr)); gap:6px; }
.ev-rooms .fl-room{ padding:6px 8px; gap:4px; }
.ev-rooms .fl-meter-k{ display:none; }
.ev-rooms .fl-room-sign{ font-size:10.5px; }
.check-ev .flow--ask{ margin-top:4px; }
#c-opts .flow--ask .fl-mini-card{ display:none; }          /* the question already states the job */
#c-opts .flow--ask .fl-doors{ grid-template-columns:1fr; gap:5px; }
#c-opts .flow--ask .fd{ display:grid; grid-template-columns:minmax(0,1fr) auto; align-items:center; column-gap:10px; row-gap:3px; padding:6px 10px 7px; }
#c-opts .flow--ask .fd-label{ font-size:11px; grid-column:1; grid-row:1; }
#c-opts .flow--ask .fd-ans{ margin-top:0; grid-column:2; grid-row:1; }
#c-opts .flow--ask .fd-q{ font-size:12.5px; padding-right:0; grid-column:1 / -1; grid-row:2; }
#c-opts .flow--ask .fd-glyph{ display:none; }
#c-opts .flow--ask .fd-line{ grid-column:1 / -1; grid-row:3; font-size:12.5px; }
#c-opts .flow--ask .fl-mini-land{ margin-top:6px; }
#c-opts .flow--ask.is-landed .fd-q{ display:none; }   /* graded: the label and the true line carry it (rule 15) */
.ev-rooms .fl-placed .fl-chip{ display:none; }         /* the echo in the room is the label; the chip is beside the doors */
/* check 2: three drawn builds inside the options */
.build{ display:flex; flex-wrap:wrap; align-items:center; gap:6px 10px; min-width:0; }
.build-d{ display:flex; gap:4px; align-items:flex-end; }
.build-d i{ width:10px; height:15px; border:1.5px solid var(--muted); border-bottom:0; border-radius:5px 5px 0 0; display:inline-block; position:relative; }
.build-d i.o{ border-color:var(--stage); }
.build-d i.o::after{ content:''; position:absolute; inset:2px 2px 0 2px; background:var(--stage); border-radius:3px 3px 0 0; transform:perspective(40px) rotateY(-60deg); transform-origin:left center; }
.build-room{ font-family:var(--font-mono); font-size:10.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); display:flex; align-items:center; gap:8px; }
.build-meter{ display:flex; gap:2px; width:56px; }
.build-meter i{ flex:1; height:5px; border-radius:2px; background:var(--line); }
.build-meter i.on{ background:var(--stage); }
.build-cap{ flex:1 1 100%; font-size:14px; line-height:1.35; }
.opt.is-right .build-meter i.on, .opt.is-wrong .build-meter i.on{ animation:lvp-settle 1.1s ease 2; }
.ev-job{
  background:#fff; border:1px solid var(--line); border-radius:var(--radius);
  box-shadow:var(--shadow-sm); padding:14px 16px; font-size:15.5px; line-height:1.5;
}
.ev-job .lw-label{ display:block; margin-bottom:6px; }

/* beat 5: the closing rooms (the replay, or the clip's whole-desk picture) */
.close-replay--flow{ max-width:760px; }
.close-rooms{ display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:10px; }
.close-room{
  display:flex; flex-direction:column; align-items:center; gap:6px;
  padding:14px 12px; background:#fff; border:1px solid var(--line);
  border-radius:var(--radius); box-shadow:var(--shadow-sm);
  opacity:0; transform:scale(.94); transition:opacity .4s ease, transform .4s ease;
}
.close-room.is-in{ opacity:1; transform:scale(1); }
.close-room b{ font-family:var(--font-display); font-size:28px; line-height:1; }
.close-room .fl-room-sign{ color:var(--muted); }
.close-room--agent b{ color:var(--stage-ink); }

@media (prefers-reduced-motion: reduce){
  .wish{ transition:none; opacity:1; transform:none; }
  .close-room{ transition:none; opacity:1; transform:none; }
}

/* ---- lab-flow + AA 02 on a phone (the shell's 860px line) ----
   Doors become ROWS (label · question · Yes/No), the rooms keep their
   sign, count and meter but drop the pills (the strip under them says
   where the last card went), the deck goes to two columns. The same
   row shape serves the prediction's reveal corridor and check 1. */
@media (max-width:860px){
  .fl-doors{ grid-template-columns:1fr; gap:6px; }
  .fd{ display:grid; grid-template-columns:84px minmax(0,1fr) auto; align-items:center; column-gap:8px; row-gap:3px; padding:6px 9px; }
  .fd-glyph{ display:none; }
  .fd-label{ font-size:11px; }
  .fd-q{ font-size:12px; padding-right:0; }
  .fd-ans{ margin-top:0; }
  .fd-line{ grid-column:1 / -1; font-size:12px; }
  .flow-corridor{ padding:8px; gap:6px; }
  .fl-walker{ display:none; }
  .fl-rooms{ gap:5px; }
  .fl-room{ padding:5px 7px; gap:3px; }
  .fl-room-head{ flex-wrap:wrap; row-gap:2px; }
  .fl-room-sign{ font-size:10.5px; }
  .fl-meter-k{ display:none; }
  .fl-meter-bar{ width:28px; }
  .fl-landed{ display:none; }
  .fl-deck{ grid-template-columns:repeat(2, minmax(0,1fr)); gap:6px; }
  .fl-card{ font-size:13px; padding:6px 8px; line-height:1.35; }
  .fl-last{ font-size:12.5px; padding:5px 8px; }
  .wish-grid{ gap:6px; margin:8px 0 2px; }
  .wish{ padding:7px 9px; gap:3px; }
  .wish-t{ font-size:13px; line-height:1.35; }
  .pr-walk .fl-mini-land{ font-size:12px; }
  .ev-rooms .fl-rooms{ grid-template-columns:repeat(3, minmax(0,1fr)); }
  .open.is-answered .wish-t{ display:none; }
}

/* a narrow stage (the pane open on a small laptop) is the phone's problem
   with a mouse (rule 35): the doors take the row shape, the pills go */
.lab-stage[data-narrow="1"] .fl-doors{ grid-template-columns:1fr; gap:6px; }
.lab-stage[data-narrow="1"] .fd{ display:grid; grid-template-columns:84px minmax(0,1fr) auto; align-items:center; column-gap:8px; row-gap:3px; padding:6px 9px; }
.lab-stage[data-narrow="1"] .fd-glyph{ display:none; }
.lab-stage[data-narrow="1"] .fd-q{ font-size:12px; padding-right:0; }
.lab-stage[data-narrow="1"] .fd-ans{ margin-top:0; }
.lab-stage[data-narrow="1"] .fd-line{ grid-column:1 / -1; font-size:12px; }
.lab-stage[data-narrow="1"] .fl-landed{ display:none; }
.lab-stage[data-narrow="1"] .fl-meter-k{ display:none; }
.lab-stage[data-narrow="1"] .open.is-answered .wish-t{ display:none; }

/* ============================================================
   PATH PAGE — this one may scroll. It is not an interactive.
   ============================================================ */

/* Rendered inside the SITE chrome (base.html: navbar + footer), so the page
   claims its own type — base.html's body carries .font-poppins, and the path
   was designed in the lab's Inter/Space Grotesk. */
.path-wrap{
  max-width:1060px; margin:0 auto;
  padding:clamp(28px,5vw,64px) clamp(16px,4vw,28px) 80px;
  font-family:var(--font-body);
}

.path-hero{ margin-bottom:clamp(30px,4vw,52px); }
.path-hero h1{ font-size:clamp(32px,5vw,54px); margin:12px 0 14px; max-width:16ch; }
.path-hero p{ color:var(--muted); font-size:clamp(15px,1.5vw,18px); max-width:56ch; margin:0; }

.path-meter{ display:flex; gap:28px; margin-top:26px; flex-wrap:wrap; }
.path-meter-v{ font-family:var(--font-display); font-weight:700; font-size:26px; line-height:1.1; }
.path-meter-k{ display:block; margin-top:2px; }

.path-rail{ position:relative; }
.path-rail::before{
  content:''; position:absolute; left:19px; top:14px; bottom:14px; width:2px;
  background:linear-gradient(180deg, var(--c-indigo), var(--c-violet), var(--c-teal), var(--c-coral), var(--c-yellow));
  opacity:.3;
}

.path-stage{ position:relative; padding-left:60px; margin-bottom:14px; }

.path-node{
  position:absolute; left:0; top:22px;
  width:40px; height:40px; border-radius:50%;
  display:grid; place-items:center;
  font-family:var(--font-mono); font-size:13px; font-weight:600;
  background:#fff; color:var(--stage-ink);
  border:2px solid var(--stage);
  box-shadow:var(--shadow-sm);
}
.path-stage.is-locked .path-node{ border-color:var(--line); color:var(--muted); background:var(--surface-2); }

.path-card{
  border:1px solid var(--line);
  border-radius:var(--radius);
  background:#fff;
  box-shadow:var(--shadow-sm);
  padding:clamp(18px,2.2vw,26px);
  border-left:4px solid var(--stage);
  transition:box-shadow .2s ease, transform .2s ease;
}
.path-stage.is-locked .path-card{ background:var(--surface-2); border-left-color:color-mix(in srgb, var(--stage) 35%, var(--line)); }
.path-card:hover{ box-shadow:var(--shadow); }

.path-card-head{ display:flex; align-items:flex-start; gap:14px; flex-wrap:wrap; margin-bottom:8px; }
.path-card h2{ font-size:clamp(20px,2.2vw,27px); margin:0; }
.path-card-meta{ margin-left:auto; display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
.path-promise{ color:var(--muted); margin:0 0 16px; max-width:60ch; font-size:15px; }

.path-lessons{ display:flex; gap:7px; flex-wrap:wrap; }

.lesson-chip{
  display:inline-flex; align-items:center; gap:8px;
  font-size:13px; text-decoration:none; color:var(--ink);
  border:1px solid var(--line); border-radius:var(--radius-pill);
  padding:7px 14px 7px 10px; background:#fff;
  transition:border-color .16s ease, background .16s ease, transform .07s ease;
  cursor:pointer;
}
.lesson-chip:hover{ border-color:var(--stage); background:color-mix(in srgb, var(--stage) 7%, #fff); }
.lesson-chip:active{ transform:translateY(1px); }
.lesson-chip .n{ font-family:var(--font-mono); font-size:10.5px; color:var(--muted); }
.lesson-chip.is-done{ border-color:color-mix(in srgb, var(--stage) 45%, var(--line)); }
.lesson-chip.is-done .n{ color:var(--stage-ink); }
.lesson-chip.is-locked{ color:var(--muted); background:transparent; cursor:default; }
.lesson-chip.is-locked:hover{ border-color:var(--line); background:transparent; }
.lesson-chip.is-free{ border-color:var(--stage); background:color-mix(in srgb, var(--stage) 10%, #fff); font-weight:500; }
.lesson-chip.is-more{ border-style:dashed; color:var(--muted); }

.path-cta{
  display:none; align-items:center; gap:14px; flex-wrap:wrap;
  margin-top:16px; padding:14px 16px;
  border-radius:var(--radius-sm);
  background:color-mix(in srgb, var(--stage) 10%, #fff);
  border:1px solid color-mix(in srgb, var(--stage) 30%, transparent);
  font-size:14px;
}
.path-cta.is-shown{ display:flex; animation:lab-enter .3s ease both; }
.path-cta .lw-btn{ margin-left:auto; }

.path-note{ margin-top:44px; font-family:var(--font-mono); font-size:10.5px; line-height:1.8; color:var(--muted); opacity:.8; }

/* ============================================================
   RESPONSIVE — mobile keeps the no-scroll promise by splitting
   each step into smaller beats instead of shrinking the type.
   ============================================================ */

@media (max-width:860px){
  .lab-stage{
    grid-template-columns:1fr;
    grid-template-rows:auto auto auto;
    grid-template-areas:"teach" "instr" "finding";
    align-content:start;
    gap:16px;
  }
  .lab-stage[data-sub="0"] .lab-instr,
  .lab-stage[data-sub="0"] .lab-finding-slot{ display:none; }
  .lab-stage[data-sub="1"] .lab-teach{ display:none; }
  /* on the instrument beat the panel hugs its content rather than
     stretching, so a short readout is not a wall of empty dark */
  .lab-stage[data-sub="1"]{ grid-template-rows:minmax(0,auto) auto; grid-template-areas:"instr" "finding"; }
  .lab-readout{ flex:0 1 auto; }

  /* the topbar keeps only what a phone needs: get out, where am I on the
     path, which step, and the two drawers. The lamps duplicate the count.
     The wordmark goes too: at 390px it would crowd the pips off the bar. */
  .lab-logo{ display:none; }
  .lab-crumb{ display:none; }
  .lab-back-t{ display:none; }
  .lab-lamps{ display:none; }
  .lab-topbar{ gap:12px; }
  .lab-topright{ gap:8px; }
  #step-count{ white-space:nowrap; }
  .lab-pip{ width:16px; }

  /* no room for a persistent rail or pane on a phone: both become
     overlay drawers opened from the topbar, so the stage keeps its height */
  .lab-rail{ display:none; }
  .lab-tools{ left:0; width:100%; }
  .lab-tools-tabs{ display:flex; }
  .lab-tools-head #tools-title{ flex:0 0 auto; }
  .lab-topbtn--tools{ display:grid; }
  .lab-pane{
    position:absolute; right:0; top:0; bottom:0; z-index:6;
    width:min(328px, 86vw);
    box-shadow:var(--shadow);
    transition:none;
  }
  .lab-shell.pane-closed .lab-pane{ display:none; width:min(328px, 86vw); border-left-width:1px; }

  /* a full-bleed beat keeps a definite row height. The video frame solves
     itself with container-type:size, which measures zero inside an auto row. */
  .lab-stage[data-layout="full"], .lab-stage[data-layout="bleed"]{
    grid-template-rows:minmax(0,1fr);
    grid-template-areas:"instr";
  }
  .lab-stage[data-layout="full"] .lab-readout{ flex:1 1 auto; }
  .lab-footnote{ display:none; }
  .lab-est{ display:none; }
  .lab-title{ max-width:none; }
  .lab-prose{ max-width:none; }
  .lab-row{ grid-template-columns:7ch minmax(0,1fr) 5.5ch; gap:8px; }
  .lab-scale{ padding-left:calc(7ch + 8px); padding-right:calc(5.5ch + 8px); }
  .path-stage{ padding-left:0; }
  .path-node{ position:static; margin-bottom:12px; }
  .path-rail::before{ display:none; }
}

@media (prefers-reduced-motion:reduce){
  *, *::before, *::after{
    animation-duration:.001ms !important; animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
}

/* ============================================================
   SHORT VIEWPORTS — must stay LAST in this file.

   These override base rules at equal specificity, so source order
   is what makes them win. Moved here after they silently lost to
   `.close-card` and cost a debug cycle.
   ============================================================ */

/* Short viewports are the common case, not the edge case: a 1366x768
   laptop is ~640px of viewport once browser chrome is gone. Tighten
   rather than overflow. */
@media (max-height: 730px){
  /* the hint beside the heading is commentary: it goes before the
     instrument does (rule 15), and a wrapped hint costs a whole row */
  .tok-hint{ display:none; }
  .quiz-opts--check .opt{ padding:9px 13px; font-size:14.5px; }
  .quiz-opts--check{ gap:7px; }
  .check-q{ font-size:clamp(15.5px, 4.6cqi, 19px); margin-bottom:10px; }
  .quiz-fb{ font-size:14.5px; padding:10px 13px; min-height:auto; }
  .close-card{ gap:11px; }
  .close-card h2{ font-size:clamp(19px, 2.2vw, 26px); }
  .lab-anchor-list{ gap:6px; }
  .lab-anchor-list li{ font-size:14.5px; }
  .close-sub{ font-size:14.5px; }
  .spec{ padding:3px 8px; }
  .tok-list{ padding:4px; gap:2px; }
  .tokenlab{ gap:9px; }
  .tok-bench{ gap:10px; }
  .tok-controls{ gap:8px; }
  .tok-in{ padding:7px 11px; font-size:13px; }
  .tok-readout{ padding:11px 13px; gap:9px; }
  .tok-strip{ min-height:46px; }
  .tok-note{ font-size:13px; }
  .tok-finding{ padding:9px 13px; }
  .open-out .lab-finding{ padding:11px 14px; }
  .finding-go{ margin-top:8px; }
  .ev-card{ padding:8px 11px; gap:6px; }
  .check-ev-lead{ font-size:14px; }
  .ev-strip .tok-chip{ font-size:10px; padding:1px 3px; }
  .tok-finding p{ font-size:14.5px; margin-top:4px; }
  .open-h{ font-size:clamp(19px, 3.6cqi, 28px); margin-bottom:8px; }
  .open-line{ padding:9px 13px; }
  .open-lines{ gap:7px; }
  .open-strip{ margin-top:6px; padding-top:6px; }
  .open-out .lab-finding{ margin-top:11px; }
  .open-out .lab-finding p{ font-size:15px; }
}

/* Below this the machine's note is what goes — the chunks and the bars
   both outrank commentary about them (rule 15: cut in a stated order). */
@media (max-height: 660px){
  .tok-note{ display:none; }
  .spec-cap{ display:none; }
}

/* AI Core 01: the pair, the lanes and the cards tighten before anything
   is lost; the rules panel note is what goes first (rule 15: cut in a
   stated order, the lanes outrank the commentary beside them). */
@media (max-height: 730px){
  .ans-card{ padding:9px 13px; font-size:14.5px; }
  .ans-q{ padding:8px 12px; font-size:14px; }
  .twice{ gap:6px; }
  .chat-lane{ padding:10px 12px; gap:8px; }
  .chat-b{ font-size:14px; padding:8px 11px; }
  /* short: the message preview goes (the pressed chip IS the message) */
  .chat-msg{ display:none; }
  .chat-composer > .lw-label{ display:none; }
  .chat-panel{ padding:8px 10px; }
  .chat-rules{ gap:2px; }
  .scn-card{ padding:7px 11px; font-size:14px; }
  .scn-flip{ font-size:12px; }
  .check-ev-cards{ gap:6px; }
  .replay-b{ font-size:14px; padding:5px 9px; }
  .replay-lanes{ margin-top:4px; gap:8px; }
  .replay-list{ gap:4px; }
  .close-replay--twin + .close-land{ gap:8px; }
  .close-card > .lw-label{ display:none; }
  .chat-panel-note{ display:none; }
  .clip-finding p{ font-size:15px; }
  .twinlab{ gap:9px; }
}
@media (max-height: 660px){
  .clip-finding .lw-label{ display:none; }
  .check-ev-lead{ display:none; }
  .tok-hint{ display:none; }
}

/* The OPEN beats in their fullest states at the shortest heights:
   spacing goes before type (rule 43), and every cut here was measured
   against the inner-clip probe at 1366x640, where the tokens predict
   finding sat 29px below its box and the pair beat 32px (AA 01 round 1). */
@media (max-height: 660px){
  .open-h{ font-size:clamp(17px, 3cqi, 22px); margin-bottom:6px; }
  .open.is-answered .open-h{ font-size:clamp(16px, 2.6cqi, 20px); margin-bottom:6px; }
  .open-line{ padding:7px 11px; }
  .open-lines{ gap:6px; }
  .open-strip{ margin-top:4px; padding-top:4px; }
  .open-q{ margin-top:2px; }
  .open-ask{ font-size:16px; margin-bottom:8px; }
  .quiz-opts--check{ gap:6px; }
  .quiz-opts--check .opt{ padding:8px 12px; }
  /* the base .open.is-answered shrinkers are (0,3,0): match them or lose */
  .twice, .open.is-answered .twice{ gap:4px; }
  .ans-card, .open.is-answered .ans-card{ padding:8px 11px; }
  .ans-q, .open.is-answered .ans-q{ padding:6px 10px; }
  .open-out .lab-finding{ margin-top:8px; padding:9px 12px; }
  .open-out .lab-finding p{ font-size:14.5px; }
  .finding-go{ margin-top:6px; }
}
/* on a short screen the source panel yields to the finding once it has
   landed (the finding restates what the panel showed); below 600px it goes
   entirely: the lanes outrank the note beside them */
@media (max-height: 730px){
  .twinlab.is-found .chat-panel{ display:none; }
}
@media (max-height: 600px){
  .chat-panel{ display:none; }
}
/* lab-levels on a short viewport: spacing goes before type (rule 43).
   The cards outrank everything; the deck label, the note beside the pins
   and a deck row are what go. Nothing student-facing drops under 14px. */
@media (max-height: 730px){
  .levels{ gap:8px; }
  .levels-zones{ padding:7px; gap:6px; }
  .lv-zone-head{ padding:4px 9px; }
  .lv-deck{ gap:5px; grid-template-columns:repeat(3, minmax(0,1fr)); }
  .lv-card{ padding:7px 10px; font-size:14px; }
  .lv-placed{ padding:6px 9px; gap:3px; }
  .lv-placed-note{ display:none; }   /* the pins still say why; the note is the supplement */
  .lv-deck-label{ display:none; }
  .sortlab{ gap:8px; }
}
@media (max-height: 660px){
  .sortlab .tok-hint{ display:none; }
}
/* AA 01 beats on a short viewport: spacing before type (rule 43) */
@media (max-height: 730px){
  .pin-card{ padding:12px 16px; margin:10px 0 2px; }
  .pin-card-t{ font-size:15px; line-height:1.45; }
  .pin-card > .lw-label{ display:none; }
  .ev-flow{ padding:12px 14px; gap:10px; }
  .lvp--lg{ height:46px; gap:10px; }
  .lvp--lg .lvp-trig{ width:32px; height:32px; }
  .lvp--lg .lvp-trig::after{ left:13px; top:6px; width:2px; height:11px; }
  .lvp--lg .lvp-step{ width:18px; height:18px; }
  .lvp--lg .lvp-out{ width:28px; height:28px; }
  .lvp--lg .lvp-tray{ width:32px; height:18px; }
  .sortlab{ gap:9px; }
  .sortlab .tok-hint{ display:block; }   /* the instruction outranks the generic hint cut */
  .close-machines{ gap:14px; }
  .close-machine{ padding:10px 14px; }
}
@media (max-height: 640px){
  #pin-sub{ display:none; }
  .close-machines{ display:none; }   /* the landing outranks the fallback picture */
}

/* lab-flow + AA 02 beats on a short viewport: spacing before type (rule 43).
   Base rules above are single-class; these match that specificity and win by
   source order (rule 10). */
@media (max-height: 730px){
  .flow{ gap:8px; }
  .flow-corridor{ padding:8px; gap:6px; }
  .fd{ padding:7px 9px 8px; gap:3px; }
  .fd-q{ font-size:12.5px; }
  .fd-a{ padding:3px 10px; font-size:12px; }
  .fd-line{ font-size:12.5px; }
  .fl-room{ padding:6px 8px; gap:4px; }
  .fl-placed{ padding:2px 7px; }
  .fl-last{ font-size:12.5px; padding:4px 8px; }
  .fl-card{ padding:6px 9px; font-size:13.5px; }
  .fl-deck-label{ display:none; }
  .doorslab{ gap:8px; }
  .doorslab .tok-hint{ display:block; } /* the instruction outranks the generic hint cut */
  .wish-grid{ gap:6px; margin:8px 0 2px; }
  .wish{ padding:7px 10px; gap:3px; }
  .wish-t{ font-size:13.5px; line-height:1.35; }
  .pr-walk .flow-corridor--mini{ padding:5px; }
  .pr-walk .fd{ padding:4px 7px 5px; }
  .pr-walk .fd-line{ font-size:11.5px; }
  .fl-mini-land{ font-size:12.5px; }
  .close-rooms{ gap:8px; }
  .close-room{ padding:10px; }
  .close-room b{ font-size:24px; }
}
@media (max-height: 660px){
  .doorslab .tok-hint{ display:none; }
  #pr-sub, #pr-label{ display:none; }
  .fd-q{ display:none; }               /* the label and the four walked wishes already taught the door */
  .fl-walker{ display:none; }
  .fl-last{ display:none; }
  .pr-walk .fl-mini-landt{ display:none; }
  .wish-k{ display:none; }
  .open--top.is-answered .wish{ padding:5px 9px; }
  .open--top.is-answered .wish-grid{ gap:5px; }
  .close-rooms{ display:none; }        /* the landing outranks the fallback picture */
}
