/* ==========================================================================
   site_toybox.css — teloriva marketing site (landing + blog), toy-box system
   Light lifted cards, full-palette accents, scroll-scene landing.
   Fonts loaded in templates: Bricolage Grotesque (display) + Karla (body).
   ========================================================================== */
:root{
  /* ============================================================
     LAYER 1 — DESIGN TOKENS (single source of truth), two tiers:
       • theme-agnostic primitives + accent palette   → this :root
       • per-theme surfaces / text / elevation         → light + dark blocks below
     Switch theme with  data-tb-theme="light|dark"  on any element (put it on
     <html> for the whole page). Default is LIGHT, so the marketing brand stays
     light and no-JS pages are unaffected. To follow the OS with no styling of
     your own, one line at boot is enough, e.g.:
       document.documentElement.dataset.tbTheme =
         matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
     Each theme's values appear exactly once — no duplicated dark block to drift.
     ============================================================ */

  /* --- Brand hue, one knob ------------------------------------------------
     The wordmark's ink is #101080 / #200080 — sRGB hue 240–255°. The accent
     family used to sit at 300°, i.e. 45° magenta-ward of the logo, which is
     the generic indigo-violet register. Rotating this one number moves the
     accent, the tinted ground, the rings and every color-mix that derives
     from them back onto the logo, and moves them back again if it's wrong.
     Lightness and chroma are unchanged on purpose: this corrects a drift, it
     does not repaint the page. --- */
  --brand-h: 268;    /* accent / chrome. was 300. */
  --ground-h: 255;   /* page ground + ink: near-neutral, cooler than the accent */

  /* --- Accent palette: self-contained fills (each pairs with its own -ink),
         so it is identical in light and dark. --- */
  --violet: oklch(58% 0.19 var(--brand-h));
  --lime:   oklch(80% 0.19 130);  --lime-ink: oklch(32% 0.1 130);
  --tang:   oklch(72% 0.17 55);   --tang-deep: oklch(52% 0.15 50);
  --cyan:   oklch(78% 0.11 210);  --cyan-ink: oklch(30% 0.08 220);
  --rose:   oklch(70% 0.16 10);

  /* --- Aliases that resolve per-theme (lazy var lookup) --- */
  --surface:      var(--card);   /* raised card / panel face */
  --surface-sunk: var(--bg);     /* inset field (inputs sit on this) */

  /* --- Focus-ring geometry (the color comes from the active theme) --- */
  --ring:        0 0 0 4px var(--ring-color);
  --ring-strong: 0 0 0 3px var(--ring-color-strong);

  /* --- Radius --- */
  --r-lg: 28px; --r-md: 18px; --r-sm: 12px; --r-pill: 999px;

  /* --- Spacing scale (4px base). Prefer these over ad-hoc rem values. --- */
  --space-1:.25rem; --space-2:.5rem;  --space-3:.75rem; --space-4:1rem;
  --space-5:1.5rem; --space-6:2rem;   --space-8:3rem;   --space-10:5rem; --space-12:8rem;

  /* --- Type --- */
  --display:"Bricolage Grotesque", "Arial Black", sans-serif;
  --body:"Karla", system-ui, sans-serif;

  /* --- Type scale: six steps, and only these. Sizes used to be ad-hoc
         clamp()s scattered through the file, which is how a page ends up with
         four different "section heading" sizes that mean the same thing. --- */
  --t-display: clamp(2.6rem, 7vw, 5.6rem);    /* h1 only */
  --t-chapter: clamp(2.2rem, 5.2vw, 3.6rem);  /* chapter h2 */
  --t-panel:   clamp(1.5rem, 2.6vw, 2.1rem);  /* panel h3 */
  --t-lead:    clamp(1.05rem, 1.3vw, 1.2rem); /* .line */
  --t-body:    1rem;
  --t-meta:    .82rem;                        /* eyebrow, caption, UI texture */

  /* --- Motion --- */
  --ease: cubic-bezier(.22,1,.36,1);
  --dur-fast:.15s; --dur:.25s;

  /* --- Z-scale --- */
  --z-nav: 50; --z-bar: 45; --z-toast: 70;

  color-scheme: light;   /* the dark block below opts back out */
}

/* ==== LIGHT THEME (default) ================================================ */
:root, [data-tb-theme="light"]{
  /* the ground is deliberately near-neutral: at 0.008 chroma on the accent hue
     the whole page read lilac, which is the look this brand is not */
  --bg:     oklch(97.8% 0.005 var(--ground-h));
  --card:   oklch(99.5% 0.002 var(--ground-h));
  --ink:    oklch(22% 0.02 var(--ground-h));
  --soft:   oklch(45% 0.02 var(--ground-h));
  --violet-deep: oklch(46% 0.17 var(--brand-h));   /* text-safe accent on light */

  --fill-soft:   oklch(94.5% 0.012 var(--ground-h)); /* segmented controls, day chips */
  --hover:       oklch(93% 0.02 var(--ground-h));    /* subtle hover wash */
  --border:      oklch(88% 0.02 var(--ground-h));    /* input + hairline borders */
  --border-dash: oklch(85% 0.02 var(--ground-h));    /* dashed dividers */

  --ring-color:        oklch(58% 0.19 var(--brand-h) / .15);
  --ring-color-strong: oklch(58% 0.19 var(--brand-h) / .30);
  --scrim: oklch(22% 0.02 var(--ground-h) / .38);    /* modal backdrop veil */
  --lift: 0 2px 4px rgb(24 22 70 / .06), 0 12px 28px -8px rgb(24 22 70 / .16), 0 32px 64px -24px rgb(24 22 70 / .22);
}

/* ==== DARK THEME =========================================================== */
[data-tb-theme="dark"]{
  color-scheme: dark;
  --bg:     oklch(21% 0.018 var(--ground-h));
  --card:   oklch(25.5% 0.022 var(--ground-h));
  --ink:    oklch(95% 0.008 var(--ground-h));
  --soft:   oklch(72% 0.018 var(--ground-h));
  --violet-deep: oklch(80% 0.13 var(--brand-h));   /* text-safe accent on dark */

  --fill-soft:   oklch(31% 0.018 var(--ground-h));
  --hover:       oklch(33% 0.024 var(--ground-h));
  --border:      oklch(40% 0.018 var(--ground-h));
  --border-dash: oklch(37% 0.018 var(--ground-h));

  --ring-color:        oklch(72% 0.19 var(--brand-h) / .32);
  --ring-color-strong: oklch(72% 0.19 var(--brand-h) / .50);
  --scrim: oklch(8% 0.02 var(--ground-h) / .60);
  --lift: 0 2px 4px rgb(0 0 0 / .35), 0 12px 28px -8px rgb(0 0 0 / .55), 0 32px 64px -24px rgb(0 0 0 / .65);
}
*{box-sizing:border-box;margin:0}
/* overflow-x:clip on the root, not hidden: `hidden` on body only reaches the
   viewport by propagation, and once it has propagated body itself computes
   back to visible — so a child wide enough still drags the document sideways.
   `clip` does the clipping without making the root a scroll container, which
   is what would break position:sticky and every pinned ScrollTrigger scene on
   this page. Nothing here is allowed to scroll the page horizontally; a block
   that genuinely needs to scroll sideways does it inside itself (see
   .fitstage). */
html{scroll-behavior:smooth;overflow-x:clip;
  -webkit-tap-highlight-color:color-mix(in oklch, var(--violet) 22%, transparent)}
/* two declarations, not one: a browser without `clip` keeps the old `hidden`
   and the old propagation behaviour rather than losing the clip entirely */
body{font-family:var(--body);background:var(--bg);color:var(--ink);
  overflow-x:hidden;overflow-x:clip}
img,svg{max-width:100%}
h1,h2,h3,h4{font-family:var(--display);line-height:1.02;text-wrap:balance;letter-spacing:-.015em}
p{text-wrap:pretty}
a{color:inherit}
/* no 300ms tap delay on anything a finger is meant to hit */
a,button,summary,[role="tab"],[role="button"]{touch-action:manipulation}
.wrap{width:min(1140px, 92vw);margin-inline:auto}

.card{background:var(--card);border-radius:var(--r-lg);box-shadow:var(--lift)}
/* 44ch under a 4rem display face is what produced the ragged three-line
   blocks: the measure has to grow with the head it sits under */
.line{font-size:var(--t-lead);color:var(--soft);font-weight:600;max-width:58ch;line-height:1.55}

.ph{
  display:grid;place-items:center;text-align:center;gap:.3rem;
  border:2px dashed oklch(75% 0.05 var(--ground-h));border-radius:var(--r-md);
  background:repeating-linear-gradient(45deg, oklch(96% 0.01 var(--ground-h)) 0 14px, oklch(93.5% 0.015 var(--ground-h)) 14px 28px);
  color:var(--soft);font-weight:700;font-size:.85rem;padding:1rem;min-height:120px;
}
.ph::before{content:"🖼";font-size:1.6rem}

/* keyboard escape hatch past the fixed nav, on every page that includes it */
.skip-link{position:fixed;top:1rem;left:50%;translate:-50% -200%;z-index:var(--z-toast);
  background:var(--violet);color:white;font-family:var(--display);font-weight:800;font-size:.9rem;
  padding:.7em 1.4em;border-radius:var(--r-pill);box-shadow:var(--lift);text-decoration:none;
  transition:translate var(--dur) var(--ease)}
.skip-link:focus{translate:-50% 0}

/* pill nav.
   It floats over full-bleed display type, so it tucks away while you read
   downward and comes back the moment you scroll up, reach the top, or tab
   into it. `.is-tucked` is added by toybox-entry.js; with no JS the bar simply
   stays put, which is the old behaviour and still usable. */
.tb-nav{position:fixed;top:1rem;left:50%;translate:-50% 0;z-index:var(--z-nav);display:flex;gap:.4rem;align-items:center;
  background:color-mix(in oklch, var(--card) 85%, transparent);backdrop-filter:blur(12px);border-radius:999px;
  box-shadow:var(--lift);padding:.45rem .6rem;max-width:96vw;flex-wrap:wrap;justify-content:center;
  transition:translate .28s var(--ease)}
.tb-nav.is-tucked{translate:-50% calc(-100% - 1.5rem)}
.tb-nav.is-tucked:focus-within,.tb-nav.is-tucked:hover{translate:-50% 0}
/* On the landing page the stage bar owns the top 44px and never tucks, so the
   pill floats just under it. `.has-stagebar` is set on <body> rather than
   sniffed with :has() so the two files stay independently readable. */
.has-stagebar .tb-nav{top:3.5rem}
.has-stagebar .tb-nav.is-tucked{translate:-50% calc(-100% - 4rem)}
.has-stagebar .tb-nav.is-tucked:focus-within,.has-stagebar .tb-nav.is-tucked:hover{translate:-50% 0}
.tb-nav a, .tb-nav button{font-weight:700;font-size:.88rem;text-decoration:none;padding:.45em 1em;border-radius:999px;font-family:var(--body);border:0;background:none;cursor:pointer;color:inherit}
.tb-nav a:hover, .tb-nav button:hover{background:var(--hover)}
.tb-nav a:focus-visible,.tb-nav button:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.tb-nav .logo{font-family:var(--display);font-weight:800;background:var(--ink);color:var(--card)}
.tb-nav .logo-img{display:flex;align-items:center;padding:.3em .6em}
.tb-nav .logo-img img{height:22px;width:auto;display:block}
.tb-nav .logo-img:hover{background:none}
.tb-nav .go{background:var(--violet);color:white}
.tb-nav .go:hover{background:var(--violet-deep)}
/* the signed-in slot (Dashboard), where "Log in" sits for everyone else. A soft
   fill marks it as "you are already in" without competing with the violet CTA;
   hover still steps up to --hover, so the link keeps its feedback. */
.tb-nav .tb-nav__me{background:var(--fill-soft);color:var(--violet-deep)}

/* the EN/DE switcher. A real <form> posting to set_language, so it works with
   no JS and sets the cookie the rest of the site already reads. */
.langpick{display:inline-flex;gap:.1rem;background:var(--fill-soft);border-radius:999px;padding:.15rem;margin-inline:.2rem}
.langpick button{font-family:var(--display);font-weight:800;font-size:.72rem;letter-spacing:.04em;
  padding:.35em .7em;color:var(--soft);border:0;background:none;cursor:pointer;border-radius:999px;
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease)}
.langpick button:hover{background:var(--hover);color:var(--ink)}
.langpick button[aria-current="true"]{background:var(--card);color:var(--violet-deep);box-shadow:0 1px 2px rgb(24 22 70 / .1)}
.langpick button:focus-visible{outline:none;box-shadow:var(--ring-strong)}

/* progress worm. The landing page replaced it with the stage bar below —
   a 5px rainbow gradient reports progress but names nothing — but the blog
   has no chapters to name and still uses it. */
.worm{position:fixed;left:0;top:0;height:5px;width:100%;transform-origin:left;
  background:linear-gradient(90deg,var(--violet),var(--tang),var(--lime),var(--cyan));
  scale:0 1;z-index:var(--z-nav)}
.no-js .worm{display:none}

/* ==========================================================================
   THE STAGE BAR — the page's spine, and its only in-page navigation.
   A lesson genuinely is an ordered stage sequence, so the product's own
   transport is promoted into page chrome: outside the flagship it names the
   chapter you are in, inside it, it is the real transport and scroll is what
   scrubs it. It replaces the rainbow progress worm, which reported progress
   but never said where you were.
   With no JS it is five working anchors and the first chapter's name — which
   is still more navigation than the page had before.
   ========================================================================== */
.stagebar{position:sticky;top:0;z-index:var(--z-bar);
  background:color-mix(in oklch, var(--bg) 88%, transparent);backdrop-filter:blur(10px);
  border-bottom:1px solid var(--border)}
.stagebar__in{display:flex;align-items:center;gap:.6rem 1rem;min-height:44px;padding-block:.3rem}
.stagebar__dots{list-style:none;padding:0;margin:0;display:flex;align-items:center;gap:.15rem;
  min-width:0;overflow-x:auto;scrollbar-width:none;scroll-snap-type:x proximity}
.stagebar__dots::-webkit-scrollbar{display:none}
.stagebar__dots a{display:flex;align-items:center;gap:.45rem;text-decoration:none;white-space:nowrap;
  scroll-snap-align:start;border-radius:var(--r-pill);padding:.3em .7em;
  font-family:var(--display);font-weight:800;font-size:.74rem;letter-spacing:.02em;color:var(--soft);
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease)}
.stagebar__dots a::before{content:"";flex:none;width:.5rem;height:.5rem;border-radius:50%;
  background:var(--border);transition:background var(--dur) var(--ease),scale var(--dur) var(--ease)}
.stagebar__dots a:hover{background:var(--hover);color:var(--ink)}
.stagebar__dots a:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.stagebar__dots a[aria-current="true"]{color:var(--ink);background:var(--card);box-shadow:0 1px 2px rgb(24 22 70 / .1)}
.stagebar__dots a[aria-current="true"]::before{background:var(--violet);scale:1.2}
/* the chapter counter: the orientation half of the bar, always present */
.stagebar__label{margin-inline-start:auto;flex:none;font-family:var(--display);font-weight:800;
  font-size:var(--t-meta);color:var(--soft);white-space:nowrap;font-variant-numeric:tabular-nums}
.stagebar__label b{color:var(--ink)}

/* the transport half: only shown while the flagship is the chapter on screen */
.stagebar__transport{display:flex;align-items:center;gap:.25rem;flex:none}
.stagebar__transport[hidden]{display:none}
.sb-cmd{width:1.75rem;height:1.75rem;border:0;border-radius:50%;background:var(--card);
  box-shadow:0 1px 2px rgb(24 22 70 / .12);color:var(--ink);display:grid;place-items:center;
  cursor:pointer;font-size:.8rem;padding:0;
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease),translate var(--dur) var(--ease)}
.sb-cmd svg{width:1em;height:1em;display:block}
.sb-cmd:hover{background:var(--violet);color:#fff}
.sb-cmd:active{translate:0 1px}
.sb-cmd:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.sb-stage{font-family:var(--display);font-weight:800;font-size:.72rem;color:var(--soft);
  white-space:nowrap;margin-inline-start:.35rem;font-variant-numeric:tabular-nums}
.sb-stage b{color:var(--violet-deep)}

@media (max-width:880px){
  /* the label is the thing that must survive: a dot rail with no name is the
     rainbow worm again. The transport stays; the chapter counter goes. */
  .stagebar__in{gap:.5rem}
  .stagebar__label{display:none}
  .stagebar__dots a span{display:none}
  .stagebar__dots a{padding:.45em}
  .stagebar__dots a[aria-current="true"] span{display:inline}
  .sb-stage{font-size:.66rem}
}

.scene{position:relative}
/* Two heading tiers carry the page hierarchy:
   tier 1 = a chapter scene, h2 alone at full size, no eyebrow;
   tier 2 = a panel inside a chapter, role eyebrow + smaller h3.
   Never put an eyebrow on a tier-1 head: the size is the signal. */
.scene-head{padding:var(--space-8) 0 var(--space-5);text-align:center}
.scene-head h2{font-size:var(--t-chapter)}
.scene-head .line{margin:1rem auto 0}

/* full-viewport pinned stop: title + depiction stay together on screen */
/* top padding clears the fixed pill nav so pinned titles never sit under it */
.scene--stop{min-height:100vh;min-height:100dvh;display:grid;align-content:center;padding:6rem 0 2rem}
.scene--stop .scene-head{padding:0 0 1.8rem}
.scene--stop .scene-head h2{font-size:clamp(1.8rem, 4.2vw, 3rem)}

/* hero */
.tb-hero{min-height:100vh;min-height:100dvh;display:grid;place-items:center;position:relative;overflow:hidden;
  padding-block:max(6rem, env(safe-area-inset-top) + 5rem) max(4rem, env(safe-area-inset-bottom) + 3rem)}
.tb-hero h1{font-size:var(--t-display);text-align:center;position:relative;z-index:2}
.tb-hero h1 .w{display:inline-block;white-space:pre}
.tb-hero h1 .run{color:var(--violet)}
.tb-hero h1 .room{color:var(--tang)}
.tb-hero .line{text-align:center;margin:1.4rem auto 0;position:relative;z-index:2}
/* the one line on the page that names who it is for */
.hero-who{position:relative;z-index:2;text-align:center;margin:1.3rem auto 0;max-width:46ch;
  color:var(--soft);font-weight:700;font-size:.92rem;line-height:1.5}
.hero-cta{position:relative;z-index:2;display:flex;gap:.8rem;justify-content:center;margin-top:2rem;flex-wrap:wrap}
.chip-btn{font-family:var(--display);font-weight:700;font-size:1rem;text-decoration:none;padding:.7em 1.7em;
  border-radius:999px;box-shadow:var(--lift);border:0;cursor:pointer;display:inline-block;
  transition:box-shadow var(--dur) var(--ease), translate var(--dur) var(--ease),
             background-color var(--dur) var(--ease)}
.chip-btn:hover{translate:0 -2px;box-shadow:var(--lift), 0 0 0 3px var(--ring-color)}
.chip-btn:active{translate:0 0}
.chip-btn:focus-visible{outline:none;box-shadow:var(--lift), var(--ring-strong)}
.chip-btn--violet{background:var(--violet);color:white}
.chip-btn--violet:hover{background:var(--violet-deep)}
.chip-btn--card{background:var(--card);color:var(--ink)}
/* orange marks a moment where a human acts — and only that (see :root note) */
.chip-btn--act{background:var(--tang);color:#fff}
.chip-btn--act:hover{background:var(--tang-deep)}
.chip-btn--sm{padding:.5em 1.1em;font-size:.85rem}
.toy{position:absolute;border-radius:var(--r-md);box-shadow:var(--lift);display:grid;place-items:center;font-size:1.6rem;background:var(--card);width:74px;height:74px;overflow:hidden}
.toy img{width:100%;height:100%;object-fit:cover;border-radius:var(--r-md);display:block}
.toy--a{top:16%;left:10%;background:var(--lime)}
.toy--b{top:22%;right:12%;background:var(--cyan)}
.toy--c{bottom:24%;left:16%;background:var(--tang)}
.toy--d{bottom:18%;right:16%;background:var(--rose)}
.toy--e{top:52%;left:4%}
.toy--f{top:58%;right:5%}
.hero-hint{position:absolute;bottom:2rem;left:50%;translate:-50% 0;color:var(--soft);font-weight:700;font-size:.85rem;z-index:2}
.scroll-arrow{
  display:grid;place-items:center;width:52px;height:52px;border-radius:50%;
  background:var(--card);color:var(--violet);box-shadow:var(--lift);
  animation:arrow-bob 1.6s cubic-bezier(.45,0,.55,1) infinite;
}
.scroll-arrow:hover{color:var(--violet-deep)}
@keyframes arrow-bob{
  0%,100%{transform:translateY(0)}
  50%{transform:translateY(9px)}
}
@media (prefers-reduced-motion: reduce){ .scroll-arrow{animation:none} }

/* Narrow hero. The six toy positions are percentages authored against a 1440
   stage, so on a phone the projector lands on the eyebrow, the trophy and the
   flashcard land on the proof chips, and the star lands on the second button.
   Below 880px they stop being scenery scattered behind the type and become a
   single row underneath it — same six toys, no collisions. */
@media (max-width:880px){
  .tb-hero{grid-template-columns:repeat(6,minmax(0,auto));justify-content:center;align-content:center;
    row-gap:1.8rem;column-gap:.5rem;padding-inline:1rem}
  .tb-hero > div{grid-column:1/-1;grid-row:1}
  .toy{position:static;grid-row:2;width:min(48px,12.5vw);height:min(48px,12.5vw)}
  .hero-hint{position:static;grid-column:1/-1;grid-row:3;translate:none;justify-self:center}
}

/* ==========================================================================
   LANDING KIT — shared pieces every scene composes from.
   Rule of the page: one role + one job + one visible product surface per
   section. Decorative art only ever supports a mock of the real UI.
   ========================================================================== */
.eyebrow{display:block;font-family:var(--display);font-weight:800;font-size:var(--t-meta);
  letter-spacing:.1em;text-transform:uppercase;color:var(--violet-deep);margin-bottom:.7rem}
.eyebrow--center{text-align:center}
.anchor-alias{display:block;height:0;overflow:hidden}
/* every in-page anchor target, not just the ones that happen to be .scene.
   The offset clears the sticky stage bar, which is what the chapter links
   land under. */
.scene,.moment,.proof,.audience,.finale,.cs-act{scroll-margin-top:6.5rem}

/* short factual clauses — never slogans */
.proof-chips{list-style:none;padding:0;display:flex;flex-wrap:wrap;gap:.5rem;margin-top:1.4rem}
.proof-chips--center{justify-content:center}
.proof-chips li{background:var(--fill-soft);color:var(--soft);font-weight:700;font-size:.84rem;
  padding:.42em 1em;border-radius:var(--r-pill)}
.proof-chips a{color:var(--violet-deep);text-decoration:none}
.proof-chips a:hover{text-decoration:underline}
.scene-head .proof-chips{justify-content:center}

/* "what you're looking at" line under a product surface */
.product-caption{color:var(--soft);font-weight:600;font-size:.98rem;line-height:1.5;max-width:62ch}
.product-caption--center{max-width:62ch}
.product-caption b{color:var(--ink);font-family:var(--display);font-weight:800}
.product-caption--center{margin:1rem auto 0;text-align:center}
.footnote{color:var(--soft);font-weight:600;font-size:.86rem;text-align:center;margin-top:2.4rem;
  max-width:80ch;margin-inline:auto}

/* human-approved / logged stamp */
.stamp-ok{justify-self:start;font-weight:700;color:var(--lime-ink);background:var(--lime);
  border-radius:var(--r-pill);padding:.3em 1em;font-size:.82rem;white-space:nowrap}

/* device frames — the only container a product mock is allowed to live in */
.tb-device{background:var(--card);border-radius:var(--r-lg);box-shadow:var(--lift);padding:1rem;position:relative}
.tb-device__screen{position:relative;background:var(--bg);border-radius:var(--r-md);overflow:hidden}
.tb-device--tv{padding:1.1rem 1.1rem .9rem}
.tb-device--laptop::after{content:"";display:block;height:8px;width:34%;margin:.7rem auto 0;
  border-radius:0 0 10px 10px;background:var(--border)}
.tb-device--phone{width:min(330px,86vw);padding:.7rem;border-radius:34px}
.tb-device--phone .tb-device__screen{border-radius:26px}
.tb-device--board{padding:.8rem}

/* --------------------------------------------------------------------------
   FIT STAGE — how a desktop-shaped product surface reaches a phone.

   Four blocks on this page *are* their arrangement: the Auto-Teach frame is a
   projector, the Canvas board is an infinite canvas, the trip strip is three
   stations on one rail, the Studio run is a TV. Collapsing them to one column
   below 900px does not make them small, it makes them a different object — the
   reader gets a list of parts and never sees the thing. So on a narrow
   viewport those blocks keep the laptop arrangement, laid out at a fixed
   *design width* of their own, and the whole frame is scaled down to the
   viewport instead. Same object, much smaller, the way a phone shows a
   document rather than reflowing it.

   Two elements, always: .fitstage (holds the block's place in normal flow at
   the scaled size) wrapping exactly one .fitstage__in (laid out at the design
   width, then transformed). The wrapper is also the grid/flex item wherever
   the block used to be one — see .csr-fit{grid-area:device}.

     --fit-w : the design width, authored per block below. A constant.
     --fit-h : the block's height at that width. Set by JS, because transform
               does not affect layout and the flow still has to reserve room.
     --fit-k : the scale. Set by JS from the measured available width.

   `.is-fit` is added by toybox-entry.js only once it has measured the block,
   so with no JS every rule here is inert and the stacked storyboard renders —
   the page's fallback-first rule. That is also why the collapse rules further
   down are written `.fitstage:not(.is-fit) …`: they are the no-JS path now.
   -------------------------------------------------------------------------- */
/* min-width:0 is load-bearing, not tidiness. A fit stage that is a grid or
   flex item (.csr-fit is one — grid-area:device) otherwise takes its automatic
   minimum size from its content, and its content is deliberately 760px wide.
   The track grew to 760px, the measured width came back as 760px, the scale
   came out 1, and the un-shrunk frame pushed the whole page sideways. */
.fitstage{display:block;min-width:0}
.fitstage__in{min-width:0}
@media (max-width:899px){
  /* The stage keeps its container's width rather than bleeding to the
     viewport: .wrap is already 92vw, so a breakout would buy about 3% more
     scale and cost the frame its alignment with the head and caption that
     explain it. Height is the part CSS cannot do on its own — a transformed
     box still occupies its untransformed size in flow.

     The stage is also a scroll container, so nothing inside one of these
     frames can ever reach the page: if a measurement is off, or an act is
     wider than its design width, it scrolls *here* and the document stays
     put. With the scale right this never appears.

     overflow-y has to be hidden for overflow-x to scroll at all, and that
     clip lands on the padding box — which would shave the device's drop
     shadow and the trip cards' lift. Hence the block padding, cancelled by
     an equal negative margin so the block's footprint in the page is
     unchanged. It is block padding only: side padding would land inside
     clientWidth and throw off the measured scale. */
  .fitstage.is-fit{--fit-pad:12px;
    max-width:100%;
    height:calc(var(--fit-h,0px) * var(--fit-k,1) + 2 * var(--fit-pad));
    padding-block:var(--fit-pad);margin-block:calc(-1 * var(--fit-pad));
    overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;
    scrollbar-width:none}
  .fitstage.is-fit::-webkit-scrollbar{display:none}
  .fitstage.is-fit > .fitstage__in{width:var(--fit-w);
    transform:scale(var(--fit-k,1));transform-origin:top left;
    /* the scaled subtree is one picture — mobile text inflation would resize
       individual runs of type inside it and break the arrangement */
    -webkit-text-size-adjust:100%;text-size-adjust:100%}
}

/* mock chrome shared by studio / projector / report surfaces */
.mock{padding:clamp(.9rem,2vw,1.3rem);display:flex;flex-direction:column;gap:.8rem;height:100%}
.mock-bar{display:flex;align-items:center;gap:.6rem;font-weight:700;font-size:.82rem;color:var(--soft)}
.mock-dot{width:10px;height:10px;border-radius:50%;background:var(--lime);flex:none;
  box-shadow:0 0 0 4px color-mix(in oklch, var(--lime) 35%, transparent)}
.mock-lbl{font-family:var(--display);font-weight:800;font-size:.8rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--soft)}
.mock-note{color:var(--soft);font-weight:600;font-size:.84rem;line-height:1.45;margin-top:auto}

/* the Auto-Teach chapter's frame is full width inside its wrap */
.classroom .tb-device--tv{width:100%}

/* studio mock — Content Studio's drafting seat */
.mock--studio .mock-body{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);gap:1.2rem;flex:1}
.st-tree{list-style:none;padding:0;display:grid;gap:.4rem;align-content:start}
.st-row{background:var(--fill-soft);border-radius:10px;padding:.5em .8em;font-weight:600;font-size:.86rem;
  color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
@media (max-width:880px){ .st-row{white-space:normal;overflow:visible} }
.st-row b{font-family:var(--display);font-weight:800;color:var(--violet-deep);margin-right:.4em}
.st-row--l1{margin-left:.8rem}
.st-row--l2{margin-left:1.6rem}
.st-row--l3{margin-left:2.4rem;background:transparent;border:2px solid var(--border);color:var(--soft)}
.st-row.is-on{background:var(--violet);color:#fff}
.st-row.is-on b{color:#fff}
.st-pane{display:grid;grid-template-rows:auto minmax(96px,1fr) auto;gap:.7rem;justify-items:start}
/* the selected stage, previewed as the slide it will actually put on the wall */
.st-thumb{width:100%;height:100%;border-radius:var(--r-sm);background:var(--card);
  border:2px solid var(--border);padding:1rem;display:flex;flex-direction:column;gap:.6rem;
  justify-content:space-between;overflow:hidden}
.st-thumb__k{font-family:var(--display);font-weight:800;font-size:.68rem;letter-spacing:.09em;
  text-transform:uppercase;color:var(--soft);opacity:.75}
.st-thumb__q{font-family:var(--display);font-weight:800;font-size:1rem;line-height:1.15;color:var(--ink)}
.st-thumb__steps{list-style:none;padding:0;display:grid;gap:.4rem;font-size:.78rem;
  font-weight:600;color:var(--soft)}
.st-thumb__steps li{display:flex;align-items:center;gap:.45rem}
.st-thumb__steps i{flex:none;display:grid;place-items:center;width:1.2rem;height:1.2rem;
  border-radius:50%;background:var(--fill-soft);color:var(--violet-deep);
  font-family:var(--display);font-style:normal;font-weight:800;font-size:.65rem}

/* ==========================================================================
   AUTO-TEACH STUDIO — one frame, two acts
   The Studio composer becomes an outline, the outline publishes, and the same
   screen becomes the projector. Two temperatures inside one chassis: the
   authoring act keeps the site's cool violet-on-paper, the room act switches
   to the classroom product's warm cream, so "we left the tool and entered the
   lesson" is felt before it is read.

   Fallback-first, like every scene here: with no JS both acts render stacked
   and complete. Everything below that is scoped to .at.is-live, which the
   entry script adds only once it can drive the frame.
   ========================================================================== */
.at{--at-room:oklch(97.5% 0.024 85);--at-night:oklch(27% 0.062 265);
  width:min(1300px,94vw);margin-top:clamp(2.4rem,5vw,4rem)}
.at-sprite{position:absolute;width:0;height:0;overflow:hidden}
.at svg:not(.at-face):not(.at-sprite){width:1em;height:1em;display:block;flex:none}
/* the script drives this scene almost entirely with [hidden], and half the
   elements it hides carry a display of their own — so hidden wins outright */
.at [hidden]{display:none !important}

.at-head__say .line{margin-top:.5rem}
.at-h{font-size:var(--t-chapter);margin-top:.3rem;max-width:20ch}
.at-head__say .line{max-width:56ch}

/* the four moves, as a strip of real controls: pressing one jumps the frame */
.at-steps{list-style:none;padding:0;margin:1.5rem 0 1rem;display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));gap:.55rem}
.at-step{width:100%;height:100%;text-align:start;font:inherit;border:0;cursor:pointer;
  background:var(--fill-soft);border-radius:var(--r-md);padding:.7rem .85rem;
  display:flex;gap:.65rem;align-items:flex-start;
  transition:background var(--dur) var(--ease),box-shadow var(--dur) var(--ease),color var(--dur) var(--ease)}
.at-step:hover{background:var(--hover)}
.at-step:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.at-step i{font-style:normal;font-family:var(--display);font-weight:800;font-size:.78rem;
  width:1.55rem;height:1.55rem;flex:none;display:grid;place-items:center;border-radius:50%;
  background:var(--card);color:var(--soft)}
.at-step b{font-family:var(--display);font-weight:800;font-size:.98rem;display:block}
.at-step em{font-style:normal;display:block;color:var(--soft);font-weight:600;font-size:.78rem;line-height:1.35}
.at-step.is-done i{background:var(--lime);color:var(--lime-ink)}
.at-step.is-on{background:var(--card);box-shadow:var(--lift)}
.at-step.is-on i{background:var(--violet);color:#fff}

.at-device{padding:1rem}
.at-screen{background:var(--card)}
.at-act{display:block}
.at-act + .at-act{border-top:2px dashed var(--border-dash)}

/* ---- act one · the Studio ------------------------------------------------ */
.at-bar{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;
  border-bottom:1px solid var(--border);background:var(--card);font-size:.78rem}
.at-bar__back{color:var(--soft);font-size:1rem}
.at-brand{display:inline-flex;align-items:center;gap:.35rem;font-family:var(--display);font-weight:800}
.at-brand i{display:grid;place-items:center;width:1.35rem;height:1.35rem;border-radius:7px;
  background:var(--violet);color:#fff;font-size:.8rem}
.at-bar__sep{width:1px;height:1.1rem;background:var(--border)}
.at-bar__title{font-weight:700;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  border-bottom:1px dashed var(--border);padding-bottom:1px}
.at-bar__right{margin-left:auto;display:flex;align-items:center;gap:.45rem;flex:none}
.at-kbd{display:inline-flex;gap:.2rem}
.at-kbd b{font-family:var(--display);font-size:.6rem;font-weight:800;color:var(--soft);
  background:var(--fill-soft);border-radius:5px;padding:.15em .4em}
.at-save{font-size:.68rem;font-weight:700;color:var(--soft);display:inline-flex;align-items:center;gap:.3rem}
.at-save::before{content:"";width:.42rem;height:.42rem;border-radius:50%;background:var(--lime)}
.at-pub-pill{display:inline-flex;align-items:center;gap:.28rem;font-family:var(--display);font-weight:800;
  font-size:.66rem;letter-spacing:.04em;background:var(--lime);color:var(--lime-ink);
  border-radius:var(--r-pill);padding:.25em .7em}
.at-pub-btn{display:inline-flex;align-items:center;gap:.3rem;font-family:var(--display);font-weight:800;
  font-size:.7rem;background:var(--violet);color:#fff;border-radius:var(--r-pill);padding:.34em .85em;
  transition:filter var(--dur) var(--ease)}
.at-pub-btn.is-hit{filter:brightness(1.25)}

.at-work{display:grid;grid-template-columns:14rem minmax(0,1fr);min-height:0}
.at-outline{border-right:1px solid var(--border);background:var(--bg);padding:.6rem .55rem;min-height:0;overflow:hidden}
.at-pane-h{font-family:var(--display);font-weight:800;font-size:.64rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--soft);margin-bottom:.45rem}
.at-outline__empty{font-size:.72rem;font-weight:600;color:var(--soft);line-height:1.45;
  border:2px dashed var(--border-dash);border-radius:var(--r-sm);padding:.7rem}
.at-tree{list-style:none;padding:0;display:grid;gap:.18rem}
.at-tree li{display:flex;align-items:center;gap:.35rem;font-size:.7rem;font-weight:700;
  border-radius:7px;padding:.24em .4em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.at-tree__u{background:var(--fill-soft);color:var(--violet-deep)}
.at-tree__s{background:var(--fill-soft);margin-left:.5rem}
.at-tree li.at-tree__t{display:block;margin-left:1.1rem;color:var(--soft);font-weight:600;font-size:.67rem;
  border-left:2px solid var(--border);border-radius:0;padding-left:.5rem}
/* ghost rows while the AI is still writing that part of the tree */
.at-tree li.is-ghost{color:transparent;background:var(--fill-soft);border-left-color:transparent;
  animation:at-ghost 1.1s var(--ease) infinite}
.at-tree li.is-ghost svg{visibility:hidden}

.at-main{padding:1rem 1.15rem;min-height:0;display:grid;gap:.55rem}
.at-view[hidden]{display:none}
.at-view{min-height:0;display:grid;align-content:start;gap:.55rem}

/* the composer */
/* Chrome inside a picture of a product, not document structure — these were
   <h4>s, which made a mock's caption a heading in the page's outline. They are
   <p> now and carry the display face explicitly. */
.at-comp-h{font-family:var(--display);font-weight:800;letter-spacing:-.015em;
  line-height:1.05;font-size:clamp(1.1rem,1.9vw,1.5rem)}
.at-comp-sub{font-size:.79rem;font-weight:600;color:var(--soft)}
.at-comp-sub b{color:var(--ink);font-family:var(--display);font-weight:800}
.at-prompt{position:relative;background:var(--surface-sunk);border:2px solid var(--border);
  border-radius:var(--r-sm);padding:.65rem .75rem;min-height:4.6rem}
.at.is-live .at-prompt{border-color:var(--violet);box-shadow:var(--ring)}
.at-prompt__txt{font-size:.86rem;font-weight:600;line-height:1.5}
.at-caret{display:none;width:2px;height:1.05em;background:var(--violet);vertical-align:-3px;margin-left:1px}
.at.is-typing .at-caret{display:inline-block;animation:at-blink 1s steps(2,end) infinite}
.at-prompt__ph{position:absolute;inset:.65rem .75rem auto;font-size:.86rem;font-weight:600;color:var(--soft);opacity:.7}
.at-prompt__ph[hidden]{display:none}
.at-attach{display:flex;align-items:center;gap:.4rem;font-size:.72rem;font-weight:700;color:var(--soft);
  border:2px dashed var(--border-dash);border-radius:var(--r-sm);padding:.4rem .6rem}
.at-attach span{font-family:var(--display);font-weight:800;color:var(--violet-deep)}

.at-coach{border:2px dashed var(--tang);border-radius:var(--r-sm);padding:.5rem .65rem;display:grid;gap:.35rem}
.at-coach[hidden]{display:none}
.at-coach__meter{display:block;height:5px;border-radius:3px;background:var(--fill-soft);overflow:hidden}
.at-coach__meter i{display:block;height:100%;width:var(--w);background:var(--tang);transition:width .6s var(--ease)}
.at-coach__lead{font-size:.7rem;font-weight:800;color:var(--soft);font-family:var(--display);letter-spacing:.02em}
.at-coach__tips{list-style:none;padding:0;display:grid;gap:.18rem}
.at-coach__tips li{font-size:.72rem;font-weight:600;color:var(--soft)}
.at-coach__tips li::before{content:"+";color:var(--tang);font-weight:800;margin-right:.35em}
.at-coach__tips li[hidden]{display:none}

.at-fields{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:.4rem}
.at-field{display:grid;gap:.1rem;background:var(--fill-soft);border-radius:9px;padding:.35rem .55rem;min-width:0}
.at-field > span{font-family:var(--display);font-weight:800;font-size:.58rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--soft)}
.at-field > b{font-size:.78rem;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.at-field--wide{grid-column:1/-1}
.at-field--wide > b{white-space:normal;font-weight:600;font-size:.74rem;line-height:1.4}

.at-more__t{display:flex;align-items:baseline;gap:.35rem;font-size:.74rem;font-weight:800;
  color:var(--soft);font-family:var(--display);background:none;border:0;padding:.2rem 0;cursor:pointer;
  text-align:start;width:100%}
.at-more__t:hover{color:var(--ink)}
.at-more__t:focus-visible{outline:none;box-shadow:var(--ring-strong);border-radius:6px}
.at-more__t em{font-style:normal;font-family:var(--body);font-weight:600;font-size:.7rem;opacity:.8}
.at-more__chev{display:inline-block;transition:rotate var(--dur) var(--ease)}
.at-more.is-open .at-more__chev{rotate:90deg}
.at-more__body{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.4rem;margin-top:.45rem}
.at-more__body[hidden]{display:none}

.at-go{position:relative;justify-self:start;margin-top:.2rem;display:inline-flex;align-items:center;gap:.45rem;
  font-family:var(--display);font-weight:800;font-size:.92rem;color:#fff;background:var(--violet);
  border:0;border-radius:var(--r-pill);padding:.6em 1.5em;cursor:pointer;box-shadow:var(--lift);
  transition:transform var(--dur) var(--ease),filter var(--dur) var(--ease)}
.at-go:hover{filter:brightness(1.1)}
.at-go:active{transform:translateY(1px)}
.at-go:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.at-go[disabled]{opacity:.55;cursor:default}
/* one ring, once the frame is on screen — an invitation, not a firework */
.at.is-live .at-go:not([disabled])::after{content:"";position:absolute;inset:-4px;border-radius:inherit;
  border:2px solid var(--violet);animation:at-ring 2.6s var(--ease) infinite}
.at-go__note{font-size:.68rem;font-weight:600;color:var(--soft)}

/* generating */
.at-view--gen{align-content:center;justify-items:center;min-height:14rem}
.at-gen{width:min(34rem,100%);background:var(--card);border-radius:var(--r-md);box-shadow:var(--lift);
  padding:1.1rem 1.3rem;display:grid;gap:.8rem}
.at-gen__h{display:flex;align-items:center;gap:.6rem}
.at-gen__h b{font-family:var(--display);font-weight:800;font-size:1rem}
.at-gen__h i{margin-left:auto;font-style:normal;font-weight:700;font-size:.76rem;color:var(--soft);
  font-variant-numeric:tabular-nums}
.at-gen__spin{width:1.9rem;height:1.9rem;flex:none;border-radius:50%;background:var(--violet);color:#fff;
  display:grid;place-items:center;font-size:.95rem;animation:at-spin 3s linear infinite}
.at-gen__phases{list-style:none;padding:0;display:grid;gap:.4rem}
.at-gen__phases li{display:flex;align-items:center;gap:.55rem;font-size:.83rem;font-weight:700;
  color:var(--soft);opacity:.5;transition:opacity var(--dur) var(--ease),color var(--dur) var(--ease)}
.at-gen__phases li::before{content:"";width:.8rem;height:.8rem;flex:none;border-radius:50%;
  box-shadow:inset 0 0 0 2px var(--border)}
.at-gen__phases li.is-doing{opacity:1;color:var(--ink)}
.at-gen__phases li.is-doing::before{box-shadow:inset 0 0 0 2px var(--violet);animation:at-pulse 1.1s ease-in-out infinite}
.at-gen__phases li.is-done{opacity:1}
.at-gen__phases li.is-done::before{background:var(--lime);box-shadow:none}
.at-gen__status{font-size:.72rem;font-weight:600;color:var(--soft)}

/* the built session */
.at-hub__h{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;flex-wrap:wrap}
.at-hub__t{font-family:var(--display);font-weight:800;font-size:1.05rem}
.at-hub__m{font-size:.72rem;font-weight:700;color:var(--soft)}
.at-stages{list-style:none;padding:0;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:.3rem .5rem;align-content:start}
/* one row per stage now that the component-key column is gone: the stage
   titles beside it already said the same thing in the visitor's language */
.at-stages li{display:grid;grid-template-columns:auto minmax(0,1fr);gap:0 .5rem;align-items:center;
  background:var(--fill-soft);border-radius:9px;padding:.36rem .55rem}
.at-stages i{font-style:normal;font-family:var(--display);font-weight:800;font-size:.68rem;
  color:var(--violet-deep)}
.at-stages b{font-size:.75rem;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.at.is-live .at-stages li{opacity:0;transform:translateY(6px);
  transition:opacity .3s var(--ease),transform .3s var(--ease)}
.at.is-live .at-stages li.is-in{opacity:1;transform:none}

/* the receipt: what one sentence bought, and the stub that starts the lesson.
   It used to total our output — stages, components, narrated lines, images.
   It now totals the only figures that belong to the visitor's day. */
.at-receipt{display:grid;grid-template-columns:minmax(0,1fr) auto;border-top:2px dashed var(--border-dash);
  background:var(--card);border-radius:0 0 var(--r-md) var(--r-md);overflow:hidden}
.at-receipt[hidden]{display:none}
.at-receipt__body{padding:.7rem 1.15rem}
.at-receipt__lbl{font-family:var(--display);font-weight:800;font-size:.62rem;letter-spacing:.11em;
  text-transform:uppercase;color:var(--soft)}
.at-receipt__total{font-family:var(--display);font-weight:800;font-size:clamp(.95rem,1.7vw,1.25rem);
  line-height:1.2;margin:.25rem 0 .3rem;max-width:32ch}
.at-receipt__total b{color:var(--violet)}
.at-receipt__fine{font-size:.67rem;font-weight:600;color:var(--soft)}
.at-receipt__stub{border:0;border-left:3px dashed var(--card);cursor:pointer;background:var(--violet);color:#fff;
  padding:.7rem 1.5rem;display:grid;justify-items:center;align-content:center;gap:.1rem;font:inherit;
  transition:filter var(--dur) var(--ease)}
.at-receipt__stub:hover{filter:brightness(1.12)}
.at-receipt__stub:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.at-receipt__stub svg{font-size:1.15rem}
.at-receipt__stub b{font-family:var(--display);font-weight:800;font-size:1rem}
.at-receipt__stub span{font-size:.64rem;font-weight:700;opacity:.85}

/* ---- act two · the room -------------------------------------------------- */
.at-act--player{background:var(--at-room)}
.at-ptop{display:flex;align-items:center;gap:1rem;padding:.45rem .7rem;background:var(--card);
  border-bottom:1px solid var(--border)}
.at-ptop__titles{min-width:0;flex:1 1 auto}
.at-ptop__titles b{display:block;font-family:var(--display);font-weight:800;font-size:.86rem;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.at-ptop__titles span{display:block;font-size:.7rem;font-weight:700;color:var(--soft);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.at-prog{flex:0 1 15rem;display:grid;gap:.22rem}
.at-prog__track{display:block;height:5px;border-radius:3px;background:var(--fill-soft);overflow:hidden}
.at-prog__track i{display:block;height:100%;width:var(--p);background:var(--violet);transition:width .5s var(--ease)}
.at-prog__txt{font-family:var(--display);font-weight:800;font-size:.6rem;letter-spacing:.05em;
  color:var(--soft);text-align:center}
.at-ptop__tools{display:flex;align-items:center;gap:.25rem;flex:none}
.at-live{display:inline-flex;align-items:center;gap:.32rem;font-family:var(--display);font-weight:800;
  font-size:.62rem;letter-spacing:.06em;text-transform:uppercase;background:var(--lime);color:var(--lime-ink);
  border-radius:var(--r-pill);padding:.25em .7em;margin-right:.2rem}
.at-live i{width:.4rem;height:.4rem;border-radius:50%;background:currentColor;animation:at-pulse 1.7s ease-in-out infinite}
.at-live.is-held{background:var(--tang);color:#fff}
.at-live.is-held i{animation:none}
.at-ico{width:1.6rem;height:1.6rem;flex:none;border-radius:8px;display:grid;place-items:center;
  background:var(--fill-soft);color:var(--soft);font-size:.86rem}
.at-ico--exit{background:var(--rose);color:#fff}

.at-pmain{display:grid;grid-template-columns:minmax(0,1fr) 12.5rem;gap:.55rem;padding:.55rem;min-height:0}
.at-pstage{position:relative;background:var(--card);border-radius:var(--r-md);box-shadow:var(--lift);
  min-height:0;overflow:hidden}
.at-board{padding:clamp(.85rem,1.6vw,1.4rem);height:100%;min-height:0}
.at-board[hidden]{display:none}
.at-kind{display:inline-flex;align-items:center;gap:.35rem;font-family:var(--display);font-weight:800;
  font-size:.66rem;letter-spacing:.1em;text-transform:uppercase;color:var(--violet-deep)}
.at-kind--sm{font-size:.6rem;color:var(--soft)}
.at-kind--dark{color:oklch(85% 0.1 90)}
.at-board__h{font-family:var(--display);font-weight:800;font-size:clamp(1.15rem,2.4vw,1.9rem);
  line-height:1.08;letter-spacing:-.015em;text-wrap:balance;margin-top:.35rem}

/* 1 · opening */
.at-board--intro{background:var(--at-night);color:#fff;display:grid;
  grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:clamp(1rem,3vw,2.4rem)}
.at-board--intro .at-board__h{color:#fff}
.at-intro__b{margin-top:.5rem;font-weight:600;color:oklch(88% 0.03 265);font-size:.92rem}
.at-intro__img{width:clamp(7rem,15vw,12rem);height:auto;border-radius:50%;
  box-shadow:0 0 0 1px rgb(255 255 255 / .08),0 18px 46px -18px rgb(255 200 80 / .6)}

/* 2 · objectives */
.at-goals{list-style:none;padding:0;display:grid;gap:.6rem;margin-top:.8rem}
.at-goals li{display:grid;grid-template-columns:auto minmax(0,1fr);gap:.6rem;align-items:start;
  font-weight:700;font-size:clamp(.92rem,1.55vw,1.25rem);line-height:1.25}
.at-goals svg{font-size:1.1em;color:var(--violet);margin-top:.1em}
.at-crit{margin-top:.9rem;background:var(--fill-soft);border-radius:var(--r-sm);padding:.6rem .8rem}
.at-crit ul{list-style:none;padding:0;display:grid;gap:.25rem;margin-top:.3rem}
.at-crit li{font-size:.82rem;font-weight:600;color:var(--soft);padding-left:1.1rem;position:relative}
.at-crit li::before{content:"✓";position:absolute;left:0;color:var(--lime-ink);font-weight:800}

/* 3 · image explainer */
.at-board--expl{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);
  gap:clamp(.8rem,2vw,1.8rem);align-items:center}
.at-expl__secs{list-style:none;padding:0;display:grid;gap:.5rem;margin-top:.7rem}
.at-expl__secs li{background:var(--fill-soft);border-radius:var(--r-sm);padding:.5rem .7rem;
  border-left:3px solid transparent;transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease)}
.at-expl__secs li.is-reading{background:var(--card);border-left-color:var(--violet);box-shadow:var(--lift)}
.at-expl__secs b{display:block;font-family:var(--display);font-weight:800;font-size:.92rem}
.at-expl__secs span{display:block;font-size:.78rem;font-weight:600;color:var(--soft);line-height:1.4}
.at-expl__fig{position:relative;margin:0;border-radius:var(--r-md);overflow:hidden;background:var(--at-night)}
.at-expl__fig img{display:block;width:100%;height:auto}
.at-spot{position:absolute;left:var(--x,50%);top:var(--y,50%);width:var(--r,34%);aspect-ratio:1;
  translate:-50% -50%;border-radius:50%;opacity:0;
  box-shadow:0 0 0 2px oklch(96% 0.02 210 / .55),0 0 0 9999px oklch(18% 0.05 265 / .74);
  transition:left .7s var(--ease),top .7s var(--ease),width .7s var(--ease),opacity .7s var(--ease)}
.at.is-live .at-board--expl.is-lit .at-spot{opacity:1}

/* 4 · class poll */
.at-board--poll{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);
  gap:clamp(.8rem,2vw,1.8rem);align-items:center}
.at-poll__free{margin-top:.5rem;font-size:.76rem;font-weight:700;color:var(--soft)}
.at-cam{margin-top:.7rem;display:inline-flex;align-items:center;gap:.4rem;font-size:.72rem;font-weight:800;
  font-family:var(--display);letter-spacing:.03em;color:var(--cyan-ink);background:var(--cyan);
  border-radius:var(--r-pill);padding:.3em .8em}
.at-cam b{font-variant-numeric:tabular-nums;font-size:.86rem}
.at-poll__opts{list-style:none;padding:0;display:grid;gap:.4rem}
.at-poll__opts li{position:relative;isolation:isolate;display:flex;align-items:center;gap:.55rem;
  background:var(--fill-soft);border-radius:11px;padding:.5em .75em;font-weight:700;
  font-size:clamp(.82rem,1.25vw,1rem)}
.at-poll__opts li > span{font-family:var(--display);font-weight:800;color:var(--violet-deep);flex:none}
.at-poll__opts em{font-style:normal;min-width:0;flex:1 1 auto}
.at-poll__opts b{font-variant-numeric:tabular-nums;font-family:var(--display);font-weight:800;flex:none;
  color:var(--soft);font-size:.9em}
.at-poll__opts i{position:absolute;z-index:-1;inset:0 auto 0 0;width:var(--w,0%);border-radius:11px;
  background:color-mix(in oklch,var(--cyan) 62%,transparent);transition:width .8s var(--ease)}
.at-poll__opts li.is-top{box-shadow:inset 0 0 0 2px var(--cyan)}

/* 5 · sequence, at the board */
.at-board--seq{display:grid;align-content:center;gap:.7rem}
.at-seq__hint{margin-top:.4rem;font-size:.78rem;font-weight:600;color:var(--soft)}

/* the tray: five scrambled planets, each carried off into its slot below */
.at-seq__tray{list-style:none;display:flex;flex-wrap:wrap;gap:.4rem;padding:0;margin:0}
.at-seq__tray li{display:flex;align-items:center;gap:.35rem;background:var(--fill-soft);
  border-radius:var(--r-pill);padding:.3rem .8rem .3rem .3rem;font-family:var(--display);
  font-weight:800;font-size:.72rem;color:var(--soft);
  transition:opacity var(--dur) var(--ease),transform var(--dur) var(--ease)}
.at-seq__tray li.is-taken{opacity:0;transform:translateY(10px) scale(.65);pointer-events:none}

/* small CSS-drawn planet spheres, shared by the tray and the slots */
.at-planet{display:inline-block;width:1.35em;height:1.35em;border-radius:50%;flex:none;
  box-shadow:inset -.14em -.14em .22em oklch(0% 0 0 / .28),inset .1em .1em .18em oklch(100% 0 0 / .35)}
.at-planet--mercury{background:oklch(66% 0.015 70)}
.at-planet--venus{background:oklch(81% 0.08 85)}
.at-planet--earth{background:radial-gradient(circle at 35% 30%,oklch(70% 0.13 230),oklch(55% 0.12 150) 70%)}
.at-planet--mars{background:oklch(60% 0.15 35)}
.at-planet--jupiter{background:repeating-linear-gradient(0deg,oklch(80% 0.07 75) 0 15%,oklch(71% 0.08 68) 15% 30%)}

.at-seq__slots{list-style:none;padding:0;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:.5rem}
.at-seq__slots li{border:2px dashed var(--border-dash);border-radius:var(--r-sm);padding:.6rem .4rem;
  display:grid;justify-items:center;gap:.3rem;
  transition:border-color var(--dur) var(--ease),border-style var(--dur) var(--ease),background-color var(--dur) var(--ease)}
.at-seq__slots i{font-style:normal;font-family:var(--display);font-weight:800;font-size:.66rem;color:var(--soft)}
.at-seq__slots .at-planet{opacity:0;transform:scale(.4) translateY(-10px);
  transition:opacity var(--dur) var(--ease),transform var(--dur) var(--ease)}
.at-seq__slots b{font-family:var(--display);font-weight:800;font-size:clamp(.82rem,1.3vw,1.05rem);opacity:0;
  transition:opacity var(--dur) var(--ease)}
.at-seq__slots li.is-placed{border-style:solid;border-color:var(--lime);background:color-mix(in oklch,var(--lime) 22%,transparent)}
.at-seq__slots li.is-placed .at-planet{opacity:1;transform:none}
.at-seq__slots li.is-placed b{opacity:1}
.at-seq__note{font-size:.8rem;font-weight:700;color:var(--lime-ink);background:var(--lime);
  border-radius:var(--r-sm);padding:.45rem .7rem;justify-self:start}
.at-seq__note.is-waiting{background:var(--fill-soft);color:var(--soft)}

/* 6 · exit check */
.at-exit{list-style:none;padding:0;display:grid;gap:.4rem;margin-top:.8rem}
.at-exit li{display:flex;align-items:center;gap:.7rem;background:var(--fill-soft);border-radius:var(--r-sm);
  padding:.5rem .75rem;font-weight:700;font-size:clamp(.82rem,1.3vw,1.02rem)}
.at-exit span{min-width:0;flex:1 1 auto}
.at-tally{font-style:normal;flex:none;font-family:var(--display);font-weight:800;font-size:.66rem;
  letter-spacing:.03em;text-transform:uppercase;border-radius:var(--r-pill);padding:.28em .8em}
.at-tally--got{background:var(--lime);color:var(--lime-ink)}
.at-tally--part{background:var(--tang);color:#fff}
.at-exit__note{margin-top:.8rem;font-size:.74rem;font-weight:600;color:var(--soft)}

/* the reveal used by the objectives, the explainer and the exit check */
.at.is-live [data-at-reveal]{opacity:0;transform:translateY(9px);
  transition:opacity .38s var(--ease),transform .38s var(--ease)}
.at.is-live [data-at-reveal].is-shown{opacity:1;transform:none}

/* Pixie — one head, and its screen holds the cue, the line, the controls */
.at-pixie{position:relative;background:var(--card);border-radius:var(--r-md);box-shadow:var(--lift);
  padding:.55rem;align-self:start}
.at-pixie__ant{position:absolute;top:-.6rem;left:50%;translate:-50% 0;width:2px;height:.6rem;background:var(--border)}
.at-pixie__ant::after{content:"";position:absolute;top:-.32rem;left:50%;translate:-50% 0;width:.42rem;height:.42rem;
  border-radius:50%;background:var(--violet)}
.at-pixie__screen{background:var(--at-night);border-radius:14px;padding:.6rem;display:grid;gap:.45rem}
.at-face{width:100%;max-width:5.6rem;margin-inline:auto;display:block}
.at-eye{fill:oklch(86% 0.11 210);transition:none}
.at-mouth{stroke:oklch(86% 0.11 210);transform-origin:36px 48px}
.at-pixie[data-state="talking"] .at-mouth{animation:at-talk .5s ease-in-out infinite}
.at-pixie[data-state="thinking"] .at-eye{opacity:.55}
.at-face .at-eye{animation:at-blinkeye 5.5s infinite}
.at-cue{display:flex;align-items:center;justify-content:center;gap:.3rem;font-family:var(--display);
  font-weight:800;font-size:.6rem;letter-spacing:.14em;color:oklch(84% 0.09 215)}
.at-say{background:rgb(255 255 255 / .09);border-radius:10px;padding:.45rem .55rem}
.at-say__who{font-family:var(--display);font-weight:800;font-size:.56rem;letter-spacing:.1em;
  text-transform:uppercase;color:oklch(84% 0.09 215)}
.at-say__txt{margin-top:.18rem;font-size:.73rem;font-weight:600;line-height:1.45;color:oklch(96% 0.01 265)}
.at-pixie__acts{display:flex;justify-content:center;gap:.3rem}
.at-pixie__acts .at-ico{background:rgb(255 255 255 / .12);color:oklch(92% 0.02 265);
  width:1.5rem;height:1.5rem;font-size:.8rem}

/* the classroom camera — a .tb-device mock (the standard frame for any
   product/screen mock, per DESIGN.md), only ever on screen for the
   volunteer-picking board; toybox-entry.js paintBoard hides/shows it and
   toggles is-scanning / is-picked, the one place `s.seq` is set */
.at-webcam{margin-top:.6rem}
.at-webcam__frame{aspect-ratio:1;background:var(--at-night)}
.at-webcam__head{position:absolute;left:var(--x);top:var(--y);translate:-50% -50%;
  width:15%;aspect-ratio:1;pointer-events:none}
.at-webcam__head::before{content:"";position:absolute;inset:0;border-radius:50%;background:var(--soft)}
.at-webcam__head::after{content:"";position:absolute;left:50%;bottom:-60%;translate:-50% 0;
  width:175%;height:85%;border-radius:50% 50% 0 0;background:var(--soft)}
.at-webcam__box{position:absolute;left:18%;top:26%;translate:-50% -50%;
  width:22%;height:26%;border:2px solid var(--cyan);border-radius:var(--r-sm);opacity:0;
  transition:opacity .25s var(--ease),border-color .25s var(--ease)}
.at-webcam.is-scanning .at-webcam__box{opacity:1;animation:at-webcam-scan 3.2s step-end infinite}
.at-webcam.is-picked .at-webcam__box{opacity:1;left:30%;top:66%;border-color:var(--lime)}
@keyframes at-webcam-scan{
  0%    {left:18%;top:26%}
  16.66%{left:50%;top:18%}
  33.33%{left:82%;top:28%}
  50%   {left:30%;top:66%}
  66.66%{left:64%;top:70%}
  83.33%{left:86%;top:64%}
  100%  {left:18%;top:26%}
}
.at-webcam__tag{position:absolute;left:30%;top:66%;translate:-50% calc(50% + 14px);
  opacity:0;transform:scale(.6);white-space:nowrap;pointer-events:none;
  transition:opacity .2s var(--ease) .1s,transform .2s var(--ease) .1s}
.at-webcam.is-picked .at-webcam__tag{opacity:1;transform:scale(1)}
.at-webcam__note{display:flex;justify-content:center;width:100%;margin-top:.5rem;box-sizing:border-box}

/* the command bar */
.at-pdock{position:relative;display:flex;align-items:center;justify-content:center;gap:.35rem;
  padding:.35rem .8rem .6rem}
.at-cmd{width:2.05rem;height:2.05rem;border:0;border-radius:50%;background:var(--card);box-shadow:var(--lift);
  color:var(--ink);display:grid;place-items:center;cursor:pointer;font-size:.95rem;
  transition:transform var(--dur) var(--ease),background var(--dur) var(--ease),color var(--dur) var(--ease)}
.at-cmd:hover{background:var(--violet);color:#fff}
.at-cmd:active{transform:translateY(1px)}
.at-cmd:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.at-cmd--go{width:2.45rem;height:2.45rem;background:var(--violet);color:#fff;font-size:1.1rem}
.at-cmd--go:hover{filter:brightness(1.12);background:var(--violet)}
.at-cmd--txt{width:auto;border-radius:var(--r-pill);padding:0 .95rem;height:2.05rem;gap:.4rem;
  display:inline-flex;font-family:var(--body);font-weight:700;font-size:.76rem}
.at-pdock__sep{width:1px;height:1.3rem;background:var(--border);margin-inline:.3rem}
.at-pdock__note{position:absolute;right:1rem;font-size:.66rem;font-weight:700;color:var(--soft)}

/* ---- the frame's own caption + transport --------------------------------- */
.at-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.8rem;margin-top:1.1rem}
.at-foot__say{font-weight:700;font-size:.92rem;color:var(--soft);max-width:62ch}
.at-foot__acts{display:flex;gap:.5rem;flex-wrap:wrap}
.at-foot__acts [hidden]{display:none}

/* ---- the override beat: the teacher takes the wheel ----------------------
   The headline promises "you still run the room" and the run used to end
   without ever showing it. This is that beat, and it is the last thing on
   screen before the CTA band. It is also the only place in the flagship where
   orange appears, because orange means a human just acted. */
.at-held{position:absolute;inset:0;z-index:3;display:grid;align-content:center;justify-items:center;
  gap:.6rem;text-align:center;padding:clamp(1rem,4vw,2.4rem);
  background:color-mix(in oklch, oklch(96% 0.05 60) 93%, transparent);backdrop-filter:blur(3px)}
.at-held[hidden]{display:none}
.at-held__tag{font-family:var(--display);font-weight:800;font-size:.72rem;letter-spacing:.08em;
  text-transform:uppercase;color:#fff;background:var(--tang);border-radius:var(--r-pill);padding:.3em 1em}
.at-held b{font-family:var(--display);font-weight:800;font-size:clamp(1.2rem,2.6vw,2rem);line-height:1.1}
.at-held p{color:oklch(38% .05 60);font-weight:600;max-width:38ch;font-size:.92rem;line-height:1.5}
/* the dock goes warm the moment it is holding the wheel */
.at-pdock.is-held{background:color-mix(in oklch, var(--tang) 14%, transparent);border-radius:var(--r-pill)}
.at-pdock.is-held .at-cmd--go{background:var(--tang)}
.at-pdock.is-held .at-cmd--go:hover{background:var(--tang-deep)}
.at-hand-back{border:0;cursor:pointer;font-family:var(--display);font-weight:800;font-size:.8rem;
  background:var(--tang);color:#fff;border-radius:var(--r-pill);padding:.5em 1.2em;
  transition:background var(--dur) var(--ease)}
.at-hand-back:hover{background:var(--tang-deep)}
.at-hand-back:focus-visible{outline:none;box-shadow:var(--ring-strong)}

/* ---- the one-take frame (JS only) ---------------------------------------- */
@media (min-width:1000px){
  .at.is-live .at-screen{aspect-ratio:16/8}
  /* A cut, not a dissolve. Whether an act is on screen must never depend on an
     animation or a transition reaching its end state — and between two acts of
     the same demo, a cut reads better than a cross-fade anyway. */
  .at.is-live .at-act{position:absolute;inset:0;border:0;visibility:hidden;
    pointer-events:none;display:grid;grid-template-rows:auto minmax(0,1fr) auto}
  .at.is-live .at-act.is-on{visibility:visible;pointer-events:auto}
  .at.is-live .at-work{min-height:0}
  .at.is-live .at-stages{overflow:hidden}
}
@media (max-width:999px){
  .at.is-live .at-act{display:none}
  .at.is-live .at-act.is-on{display:block}
  .at.is-live .at-act + .at-act{border-top:0}
}

/* ---- the pinned run (JS + wide + motion allowed) -------------------------
   The frame is 666px inside a 1315px section, so a reader at a normal scroll
   pace cleared the whole chapter in about ten seconds and never reached the
   projector. Pinned, the same frame holds still while scroll scrubs the run
   through it, and the head collapses to one line so the product and the claim
   it is proving are on screen together.
   `.is-pinned` is added by the entry script only when it can actually drive
   the pin; without it every rule below is inert and the stacked storyboard
   from `.is-live` is what renders. */
.at.is-pinned{display:grid;align-content:center;
  min-height:100vh;min-height:100dvh;margin-top:0;
  padding-block:calc(44px + 1.2rem) 1.2rem}
.at.is-pinned .at-head{display:flex;align-items:baseline;gap:.4rem 1rem;flex-wrap:wrap;
  margin-bottom:.7rem}
/* the chapter head is still an h2 in the document — it is only *set* smaller
   while pinned, so the outline never depends on a layout mode */
.at.is-pinned .at-h{font-size:clamp(1.05rem,2.1vw,1.5rem);margin-top:0;max-width:none}
.at.is-pinned .at-head__say{display:flex;align-items:baseline;gap:.35rem .8rem;flex-wrap:wrap;min-width:0}
.at.is-pinned .at-head__say .eyebrow{margin-bottom:0}
.at.is-pinned .at-head__say .line{display:none}
/* the four moves live in the stage bar's transport while pinned — one object,
   not two progress devices arguing with each other */
.at.is-pinned .at-steps{display:none}
.at.is-pinned .at-device{margin:0}
.at.is-pinned .at-screen{aspect-ratio:auto;height:min(76vh,780px)}
.at.is-pinned .at-foot{margin-top:.7rem}
.at.is-pinned .at-foot__acts [data-at-skip]{display:none}
@media (max-width:999px){ .at.is-pinned{display:block;min-height:0;padding-block:0} }

/* ---- narrow ---------------------------------------------------------------
   The four moves sit outside the frame, so they reflow like ordinary content.
   Everything *inside* the frame is the fit stage's job now (see FIT STAGE
   above): fitted, the phone gets the laptop arrangement scaled down, which is
   the only way the projector still reads as a projector. The rules below are
   what renders when there is no JS to measure the stage — the outline pane is
   dropped (the stage list carries the same information) and Pixie moves under
   the board, where the narration line still reads. */
@media (max-width:900px){
  .at-steps{grid-template-columns:repeat(2,minmax(0,1fr))}
  .fitstage:not(.is-fit) :is(.at-work,.at-stages,.at-receipt,.at-pmain,
    .at-board--intro,.at-board--expl,.at-board--poll){grid-template-columns:minmax(0,1fr)}
  .fitstage:not(.is-fit) .at-outline{display:none}
  .fitstage:not(.is-fit) :is(.at-fields,.at-more__body){grid-template-columns:repeat(2,minmax(0,1fr))}
  .fitstage:not(.is-fit) .at-receipt__stub{border-left:0;border-top:3px dashed var(--card);
    grid-auto-flow:column;justify-content:center;gap:.5rem;align-items:center;padding:.6rem}
  .fitstage:not(.is-fit) .at-face{max-width:4rem}
  .fitstage:not(.is-fit) .at-intro__img{justify-self:center}
  .fitstage:not(.is-fit) .at-seq__slots{grid-template-columns:repeat(3,minmax(0,1fr))}
  .fitstage:not(.is-fit) .at-pdock__note{display:none}
  .fitstage:not(.is-fit) .at-ptop{flex-wrap:wrap}
  .fitstage:not(.is-fit) .at-prog{flex:1 1 100%;order:3}
}
@media (max-width:560px){
  .at-steps{grid-template-columns:minmax(0,1fr)}
  .fitstage:not(.is-fit) :is(.at-fields,.at-more__body){grid-template-columns:minmax(0,1fr)}
}

@keyframes at-blink{0%,100%{opacity:1}50%{opacity:0}}
@keyframes at-spin{to{rotate:360deg}}
@keyframes at-pulse{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(.72);opacity:.55}}
@keyframes at-ring{0%{opacity:.55;transform:scale(1)}70%,100%{opacity:0;transform:scale(1.22)}}
@keyframes at-ghost{0%,100%{opacity:.55}50%{opacity:1}}
@keyframes at-talk{0%,100%{transform:scaleY(1)}50%{transform:scaleY(2.6)}}
@keyframes at-blinkeye{0%,96%,100%{ry:7}98%{ry:1}}

@media (prefers-reduced-motion:reduce){
  .at *,.at *::before,.at *::after{animation:none !important;transition-duration:.01ms !important}
  .at-caret{display:none !important}
}

/* The old .bridge line lived here. The week's timestamps now do that job —
   Tuesday is the room, Wednesday is one student's own device — so the reader
   never has to be told the two are different systems. */

/* ==========================================================================
   2 · LEARNING OS — one chapter, four panels
   ========================================================================== */
/* ==========================================================================
   THE WEEK — six moments from one class's week, in order. Each moment is a
   top-level section carrying its own timestamp.
   ========================================================================== */
.moment{padding:clamp(3.5rem,7vw,6rem) 0}
.moment--alt{background:var(--fill-soft)}
/* the chips carry --fill-soft, which is also the tinted section's own ground */
.moment--alt .proof-chips li{background:var(--card)}
/* pinned, the flagship supplies its own vertical rhythm */
.moment--flagship:has(.at.is-pinned){padding:0}

/* A way out of the page at the point interest peaks, not only at the bottom.
   This band is warm on purpose: it is the first place the page asks the
   visitor to do something, and orange is what marks a human acting. */
.cta-band{padding:var(--space-5) 0 var(--space-6)}
.cta-band__in{display:flex;flex-wrap:wrap;gap:1.2rem 2.4rem;align-items:center;
  justify-content:space-between;border-radius:var(--r-lg);box-shadow:var(--lift);
  background:linear-gradient(105deg, oklch(97% 0.038 78), oklch(96% 0.055 62));
  padding:clamp(1.4rem,3.2vw,2.4rem)}
.cta-band__say{min-width:0}
.cta-band p{font-family:var(--display);font-weight:800;line-height:1.15;color:oklch(28% .06 55);
  font-size:clamp(1.15rem,2.4vw,1.6rem);max-width:24ch}
.cta-band__what{margin-top:.5rem;font-family:var(--body);font-size:.88rem;font-weight:700;
  color:oklch(42% .06 55);max-width:34ch}
.cta-band .hero-cta{margin-top:0;justify-content:flex-start}
.cta-band .chip-btn--card{background:#fff}

/* panel A — create */
.gatestrip{list-style:none;padding:0;display:grid;grid-template-columns:repeat(4,1fr);gap:.8rem;flex:1}
.gate{background:var(--card);border-radius:var(--r-md);padding:.8rem .9rem;display:grid;gap:.3rem;
  align-content:start;justify-items:start;box-shadow:var(--lift);position:relative}
.gate + .gate::before{content:"→";position:absolute;left:-.75rem;top:1.1rem;color:var(--violet);
  font-weight:800;font-family:var(--display)}
.gate-n{font-family:var(--display);font-weight:800;font-size:.72rem;color:white;background:var(--violet);
  border-radius:var(--r-pill);padding:.25em .8em}
.gate b{font-family:var(--display);font-weight:800;font-size:1.02rem}
.gate p{color:var(--soft);font-weight:600;font-size:.82rem;line-height:1.4}

.feature-list{list-style:none;padding:0;display:grid;gap:1rem}
.feature-list li{font-weight:600;color:var(--soft);font-size:1rem;line-height:1.5;
  padding-left:1.4rem;position:relative}
.feature-list li::before{content:"";position:absolute;left:0;top:.5em;width:.6rem;height:.6rem;
  border-radius:3px;background:var(--violet)}
.feature-list b{color:var(--ink);font-family:var(--display);font-weight:800}
.feature-list--tight li{font-size:.86rem;line-height:1.45}

/* icon-led card variant: each fact is its own scannable chunk (icon + lead +
   sentence) in a grid, instead of a bullet stacked in a paragraph-like list. */
.feature-list--grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:.9rem}
.feature-list--grid li{background:var(--card);box-shadow:var(--lift);border-radius:var(--r-lg);
  padding:1rem 1.1rem;display:flex;gap:.7rem;align-items:flex-start}
.feature-list--grid li::before{content:none}
.feature-list--grid .feat-ico{flex:none;width:2.1rem;height:2.1rem;border-radius:50%;
  display:grid;place-items:center;background:var(--fill-soft);color:var(--violet)}
.feature-list--grid .feat-ico svg{width:1.15rem;height:1.15rem}
@media (max-width:640px){.feature-list--grid{grid-template-columns:1fr}}

/* ==========================================================================
   3 · CANVAS STUDIO — board theater + capability rows
   ========================================================================== */
.canvas-scene{padding-bottom:var(--space-8)}

/* --- subject switcher: one board, four real lessons -----------------------
   A segmented control, not a nav: the four options are peers and the board
   below is the only thing that changes. */
.subject-switch{display:flex;align-items:center;justify-content:center;gap:.9rem;
  flex-wrap:wrap;margin-bottom:1.5rem}
.subject-switch__lbl{font-weight:700;font-size:.88rem;color:var(--soft)}
.subject-switch__set{display:inline-flex;gap:.25rem;background:var(--fill-soft);
  border-radius:var(--r-pill);padding:.3rem;max-width:100%;
  overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none}
.subject-switch__set::-webkit-scrollbar{display:none}
.subj{scroll-snap-align:center}
.subj{font-family:var(--display);font-weight:800;font-size:.86rem;border:0;background:transparent;
  color:var(--soft);border-radius:var(--r-pill);padding:.5em 1.05em;cursor:pointer;white-space:nowrap;
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease)}
.subj:hover{color:var(--ink)}
.subj.is-on{background:var(--card);color:var(--ink);box-shadow:0 1px 2px rgb(40 20 80 / .08),0 4px 10px -4px rgb(40 20 80 / .2)}
.subj:focus-visible{outline:none;box-shadow:var(--ring-strong)}

.board-bar{display:flex;align-items:center;gap:.45rem;padding:.2rem .4rem .8rem;flex-wrap:wrap}
.board-title{font-family:var(--display);font-weight:800;font-size:.9rem;margin-right:auto}
.board-chip{font-weight:700;font-size:.78rem;color:var(--soft);background:var(--fill-soft);
  border-radius:var(--r-pill);padding:.32em .9em;display:inline-flex;align-items:center;gap:.4em;
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease)}
.board-chip.is-active{background:var(--violet);color:#fff}
.board-chip--go{background:var(--violet);color:white}
.board-chip--go[role="button"]{cursor:pointer}
.board-chip--go[role="button"]:hover{background:var(--violet-deep)}
.board-chip--go[role="button"]:active{transform:translateY(1px)}
.board-chip--go[role="button"]:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.present-counter{font-family:var(--display);font-weight:800;font-size:.78rem;color:var(--soft);
  background:var(--card);border:2px solid var(--border);border-radius:var(--r-pill);padding:.25em .8em}
/* --- the palette rail + canvas, side by side ----------------------------
   Mirrors the editor's own chrome (#edRail in canvas_studio): a dark petrol
   palette against a paper canvas. Cards are dragged out of it one at a time,
   so the demo answers "where did that card come from?" instead of having a
   finished board simply appear. */
.board-shell{position:relative;display:grid;grid-template-columns:11.5rem minmax(0,1fr);
  gap:.55rem;align-items:stretch}
.board-rail{background:oklch(30% .026 235);color:oklch(88% .012 235);border-radius:var(--r-md);
  padding:.7rem .55rem;display:flex;flex-direction:column;gap:.1rem;overflow:hidden}
.rail-search{display:flex;align-items:center;justify-content:space-between;
  background:oklch(25% .022 235);border-radius:var(--r-sm);padding:.4em .55em;margin-bottom:.55rem;
  font-size:.66rem;font-weight:600;color:oklch(64% .018 235)}
.rail-search kbd{background:oklch(36% .024 235);border-radius:4px;padding:.1em .35em;font-size:.6rem}
.rail-cat{display:flex;align-items:center;gap:.4em;margin:.5rem 0 .25rem;font-family:var(--display);
  font-weight:800;font-size:.55rem;letter-spacing:.12em;text-transform:uppercase;
  color:oklch(66% .02 235)}
.rail-cat::before{content:"";width:.5rem;height:.5rem;border-radius:2px;background:var(--c)}
.rail-cat:first-child{margin-top:0}
.rail-btn{display:block;width:100%;text-align:start;border:0;background:transparent;
  color:oklch(90% .012 235);border-radius:6px;padding:.32em .45em;font-family:var(--body);
  font-size:.7rem;font-weight:500;line-height:1.25;cursor:default;
  transition:background var(--dur-fast) linear}
/* the row lights up at the moment its card is picked off the palette */
.rail-btn.is-picked{background:oklch(100% 0 0 / .14);color:#fff;
  box-shadow:inset 0 0 0 1px oklch(82% .15 85)}
.rail-more{margin:.5rem 0 .6rem;font-size:.62rem;font-weight:700;color:oklch(60% .02 235)}
.rail-ai{margin-top:auto;display:block;border:1px dashed oklch(82% .15 85 / .45);border-radius:8px;
  background:oklch(82% .15 85 / .07);color:oklch(86% .1 85);padding:.5em .55em;
  font-family:var(--display);font-weight:800;font-size:.68rem;text-align:center}

/* the card in flight: a lightweight stand-in, not a clone of the real card —
   what is being dragged out of a palette is a card *type*, not its content */
.drag-card{position:absolute;left:0;top:0;z-index:4;opacity:0;pointer-events:none;
  background:var(--card);border-radius:var(--r-sm);box-shadow:var(--lift);
  border:2px dashed var(--violet);padding:.5em .7em;display:grid;place-items:center;
  transform:rotate(-3deg)}
.drag-card b{font-family:var(--display);font-weight:800;font-size:.62rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--violet-deep);white-space:nowrap}

/* --- narration transport -------------------------------------------------
   Deliberately a player, not a generator: the audio already exists by the
   time a class sees it, so there is no spinner and no "generating…" state. */
.narrate-bar{display:flex;align-items:center;gap:.7rem;margin-top:.6rem;padding:.5rem .8rem;
  background:var(--card);border-radius:var(--r-pill);box-shadow:var(--lift)}
.nb-play{flex:none;width:1.7rem;height:1.7rem;border-radius:50%;background:var(--violet);
  display:grid;place-items:center}
.nb-play::before{content:"";width:0;height:0;margin-left:.15em;
  border-left:.5em solid #fff;border-top:.32em solid transparent;border-bottom:.32em solid transparent}
.nb-wave{flex:none;display:flex;align-items:center;gap:.11rem;height:1.1rem;width:5.5rem}
.nb-wave i{flex:1;border-radius:2px;background:var(--border);height:34%}
.nb-wave i:nth-child(3n){height:100%}
.nb-wave i:nth-child(4n){height:62%}
.nb-wave i:nth-child(5n){height:80%}
/* only the bars the playhead has passed are inked — a scrubber, not a meter */
.nb-wave i.is-played{background:var(--violet)}
.nb-line{flex:1 1 auto;min-width:0;font-size:.8rem;font-weight:600;line-height:1.3;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nb-voice{flex:none;font-family:var(--display);font-weight:800;font-size:.66rem;color:var(--soft);
  background:var(--fill-soft);border-radius:var(--r-pill);padding:.25em .7em}

.board{position:relative;aspect-ratio:16/9.9;min-height:27rem;border-radius:var(--r-md);overflow:hidden;
  background-color:var(--bg);background-image:radial-gradient(circle, var(--border) 1.4px, transparent 1.4px);
  background-position:0 0;background-size:26px 26px;
  /* the frame fades before it cuts, so the board reads as a window onto a
     bigger canvas rather than a bounded card */
  -webkit-mask-image:radial-gradient(ellipse at center, #000 68%, transparent 100%);
  mask-image:radial-gradient(ellipse at center, #000 68%, transparent 100%)}
/* one lesson layer per subject, stacked in the same coordinate space so the
   Present camera and the edge cards are shared, not duplicated four times */
.lesson{position:absolute;inset:0}
.bcard{position:absolute;left:var(--x);top:var(--y);width:var(--w);background:var(--card);
  border-radius:var(--r-sm);box-shadow:var(--lift);padding:.65rem .7rem .7rem;display:grid;gap:.4rem;
  align-content:start;transition:opacity var(--dur) var(--ease)}

/* --- card families ------------------------------------------------------
   Colour is not decoration here: it says what kind of teaching the card
   does. Neutral = the lesson's own frame (objective), then one accent per
   family, and rose reserved entirely for "this is where they get checked".
   Mixed against literal white, not var(--card), because these classes are
   landing-only and the marketing brand is light by design (see the theme
   note at the top of this file). */
.bcard{--cat:var(--fill-soft);--cat-ink:var(--soft)}
.bcard--plan {--cat:var(--ink);                                  --cat-ink:var(--card)}
.bcard--sci  {--cat:color-mix(in oklch, var(--lime) 42%, white);  --cat-ink:var(--lime-ink)}
.bcard--math {--cat:color-mix(in oklch, var(--cyan) 60%, white);  --cat-ink:var(--cyan-ink)}
.bcard--lang {--cat:color-mix(in oklch, var(--violet) 24%, white);--cat-ink:var(--violet-deep)}
.bcard--dia  {--cat:color-mix(in oklch, var(--tang) 34%, white);  --cat-ink:oklch(38% .11 55)}
.bcard--check{--cat:color-mix(in oklch, var(--rose) 26%, white);  --cat-ink:oklch(40% .13 10)}

/* the canvas's category tab, translated into the toy-box pill vocabulary */
.bcard__k{justify-self:start;background:var(--cat);color:var(--cat-ink);border-radius:var(--r-pill);
  padding:.3em .75em;font-family:var(--display);font-weight:800;font-size:.58rem;letter-spacing:.06em;
  text-transform:uppercase;line-height:1.3}
.bcard b{font-weight:800;font-size:.8rem;font-family:var(--display);line-height:1.2}
.bcard p{font-size:.72rem;line-height:1.4;color:var(--soft)}
.bk-cap{font-size:.66rem;line-height:1.35;color:var(--soft);font-style:italic}
.bk-ipa{font-weight:600;font-size:.68rem;color:var(--soft);font-family:var(--body)}

/* success criteria under an objective */
.bk-crit{list-style:none;padding:0;display:grid;gap:.2rem;font-size:.68rem;color:var(--soft);font-weight:600}
.bk-crit li{padding-left:.85em;position:relative}
.bk-crit li::before{content:"✓";position:absolute;left:0;color:var(--lime-ink);font-weight:800}

/* a labelled axis: AU distances, a 0–1 number line, a timeline */
.bk-scale{position:relative;height:2.6rem;margin-top:.5rem}
.bk-scale__axis{position:absolute;left:0;right:0;top:.35rem;height:3px;border-radius:2px;background:var(--border)}
.bk-scale__dot{position:absolute;left:var(--p);top:0;width:.55rem;height:.55rem;margin-left:-.275rem;
  border-radius:50%;background:var(--cat-ink);box-shadow:0 0 0 2px var(--card)}
/* a run of the axis rather than a point on it: several values so close
   together that individual dots would merge into one thick smudge */
.bk-scale__band{position:absolute;left:var(--a);width:calc(var(--b) - var(--a));top:-.02rem;
  height:.59rem;border-radius:var(--r-pill);background:var(--cat-ink);
  box-shadow:0 0 0 2px var(--card)}
.bk-scale__tick{position:absolute;left:var(--p);top:1.15rem;font-size:.62rem;font-weight:700;
  color:var(--soft);white-space:nowrap}
.bk-scale__tick--end{transform:translateX(-100%)}
.bk-scale--time .bk-scale__axis{background:var(--cat)}

/* a → b → c chain: cause & effect, and any short causal read */
.bk-flow{display:flex;align-items:stretch;gap:1.1rem;flex-wrap:wrap}
.bk-flow span{position:relative;flex:1 1 0;min-width:4.5rem;background:var(--fill-soft);border-radius:var(--r-sm);
  padding:.45em .6em;font-size:.7rem;font-weight:700;line-height:1.25}
.bk-flow span + span::before{content:"";position:absolute;left:-.85rem;top:50%;width:.5rem;height:.5rem;
  border-top:2px solid var(--cat-ink);border-right:2px solid var(--cat-ink);
  transform:translateY(-50%) rotate(45deg)}
.bk-flow .is-end{background:var(--cat);color:var(--cat-ink)}

/* two-column comparison with the criterion spanning both */
.bk-duo{display:grid;grid-template-columns:1fr 1fr;gap:.25rem .5rem;font-size:.7rem;line-height:1.3}
.bk-duo__h{font-family:var(--display);font-weight:800;font-size:.72rem;background:var(--fill-soft);
  border-radius:var(--r-sm);padding:.25em .6em;text-align:center}
.bk-duo__h--b{background:var(--cat);color:var(--cat-ink)}
.bk-duo__c{grid-column:1/-1;font-style:normal;font-weight:800;font-size:.58rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--soft);margin-top:.25rem}

/* multiple choice, with the key square the real quiz node uses */
.bk-opts{list-style:none;padding:0;display:grid;gap:.25rem}
.bk-opts li{display:flex;align-items:center;gap:.45rem;background:var(--fill-soft);border-radius:var(--r-sm);
  padding:.3em .5em;font-size:.72rem;font-weight:600}
.bk-opts i{flex:none;width:1.15rem;height:1.15rem;display:grid;place-items:center;border-radius:6px;
  background:var(--card);font-family:var(--display);font-weight:800;font-size:.62rem;font-style:normal}
.bk-opts .is-right{background:var(--lime);color:var(--lime-ink)}
.bk-opts .is-right i{background:var(--card);color:var(--lime-ink)}

/* numbered steps: worked example, lab protocol, exit ticket */
.bk-steps{list-style:none;padding:0;display:grid;gap:.3rem}
.bk-steps li{display:flex;align-items:flex-start;gap:.45rem;font-size:.7rem;line-height:1.3;font-weight:600}
.bk-steps i{flex:none;width:1.05rem;height:1.05rem;display:grid;place-items:center;border-radius:50%;
  background:var(--cat);color:var(--cat-ink);font-family:var(--display);font-weight:800;font-size:.6rem;
  font-style:normal;margin-top:.05rem}
.bk-ans{background:var(--lime);color:var(--lime-ink);border-radius:var(--r-sm);padding:.35em .7em;
  font-family:var(--display);font-weight:800;font-size:.78rem;text-align:center}

/* chip rows: synonyms, sorted cards */
.bk-chips{list-style:none;padding:0;display:flex;flex-wrap:wrap;gap:.25rem}
.bk-chips li{background:var(--fill-soft);color:var(--soft);border-radius:var(--r-pill);
  padding:.2em .65em;font-size:.64rem;font-weight:700}
.bk-sort{display:grid;grid-template-columns:1fr 1fr;gap:.4rem}
.bk-sort div{background:var(--fill-soft);border-radius:var(--r-sm);padding:.4rem;display:flex;
  flex-wrap:wrap;gap:.25rem;align-content:start}
.bk-sort b{flex:1 0 100%;font-family:var(--display);font-weight:800;font-size:.6rem;letter-spacing:.05em;
  text-transform:uppercase;color:var(--soft)}
.bk-sort span{background:var(--card);border-radius:var(--r-pill);padding:.2em .6em;font-size:.68rem;font-weight:700}

/* true/false, matched pairs, verb tables — three flavours of a two-part row */
.bk-tf{list-style:none;padding:0;display:grid;gap:.28rem}
.bk-tf li{display:flex;align-items:flex-start;gap:.45rem;font-size:.7rem;line-height:1.3;font-weight:600}
.bk-tf i{flex:none;width:1.05rem;height:1.05rem;display:grid;place-items:center;border-radius:6px;
  font-size:.62rem;font-style:normal;font-weight:800}
.bk-tf .y{background:var(--lime);color:var(--lime-ink)}
.bk-tf .n{background:var(--rose);color:#fff}
.bk-match{list-style:none;padding:0;display:grid;gap:.28rem}
.bk-match li{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:.4rem;font-size:.72rem}
.bk-match li::before{content:"→";grid-column:2;color:var(--cat-ink);font-weight:800;font-size:.7rem}
.bk-match span{background:var(--fill-soft);border-radius:var(--r-pill);padding:.22em .6em;text-align:center;font-weight:600}
.bk-match b{background:var(--cat);color:var(--cat-ink);border-radius:var(--r-pill);padding:.22em .6em;
  text-align:center;font-size:.72rem}
.bk-verbs{list-style:none;padding:0;display:grid;gap:.28rem}
.bk-verbs li{display:grid;grid-template-columns:1fr 1fr 1fr;gap:.25rem;font-size:.7rem;text-align:center}
.bk-verbs span{background:var(--fill-soft);border-radius:var(--r-sm);padding:.25em .3em;font-weight:600;color:var(--soft)}
.bk-verbs b{background:var(--cat);color:var(--cat-ink);border-radius:var(--r-sm);padding:.25em .3em;font-size:.72rem}

/* a real data table: planet facts, lab results */
.bk-table{width:100%;border-collapse:collapse;font-size:.68rem}
.bk-table th{font-family:var(--display);font-weight:800;font-size:.56rem;letter-spacing:.05em;
  text-transform:uppercase;color:var(--soft);text-align:start;padding:.2em .3em .3em}
.bk-table td{padding:.24em .3em;border-top:1px solid var(--border);font-weight:600}
.bk-table tr td:first-child{font-family:var(--display);font-weight:800}
.bk-table td:not(:first-child){text-align:end;font-variant-numeric:tabular-nums}
.bk-table .is-blank{color:var(--cat-ink);background:var(--cat);border-radius:5px}

/* label-the-diagram: targets on top, a bank of names underneath, one in hand */
.bk-label{display:flex;align-items:flex-end;justify-content:space-around;gap:.4rem;
  height:2.4rem;padding:0 .3rem;border-radius:var(--r-sm);background:var(--fill-soft)}
.bk-label i{width:var(--d);height:var(--d);border-radius:50%;background:var(--c);
  margin-bottom:.45rem;box-shadow:0 0 0 3px var(--card)}
.bk-chips--bank li{background:var(--card);box-shadow:var(--lift);color:var(--ink);font-size:.66rem}
.bk-chips--bank .is-held{background:var(--cat);color:var(--cat-ink);transform:rotate(-4deg)}

/* put these in order — the numbers are the answer, so they carry the accent */
.bk-seq{list-style:none;padding:0;display:flex;gap:.3rem;flex-wrap:wrap}
.bk-seq li{flex:1 1 3rem;display:flex;align-items:center;justify-content:center;gap:.3rem;
  background:var(--fill-soft);border-radius:var(--r-sm);padding:.3em .35em;
  font-size:.72rem;font-weight:700}
.bk-seq i{width:.95rem;height:.95rem;flex:none;display:grid;place-items:center;border-radius:50%;
  background:var(--cat);color:var(--cat-ink);font-family:var(--display);font-weight:800;
  font-size:.56rem;font-style:normal}

/* a two-speaker exchange */
.bk-talk{list-style:none;padding:0;display:grid;gap:.25rem}
.bk-talk li{display:flex;align-items:flex-start;gap:.4rem;font-size:.7rem;line-height:1.3}
.bk-talk b{flex:none;width:1.05rem;height:1.05rem;display:grid;place-items:center;border-radius:50%;
  background:var(--fill-soft);color:var(--soft);font-family:var(--display);font-size:.58rem}
.bk-talk span{background:var(--fill-soft);border-radius:var(--r-sm);padding:.28em .5em;font-weight:600}
.bk-talk .is-b b{background:var(--cat);color:var(--cat-ink)}
.bk-talk .is-b span{background:var(--cat);color:var(--cat-ink)}

/* claim · evidence · reasoning — three tinted panels, left-barred */
.bk-cer{display:grid;gap:.3rem;margin:0}
.bk-cer dt{font-family:var(--display);font-weight:800;font-size:.56rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--cat-ink)}
.bk-cer dd{margin:0 0 .1rem;padding-left:.55rem;border-left:3px solid var(--cat);
  font-size:.69rem;line-height:1.3;font-weight:600}

/* what goes into a system, what comes out */
.bk-sys{display:grid;grid-template-columns:1fr auto 1fr;align-items:stretch;gap:.45rem}
.bk-sys ul{list-style:none;padding:0;display:grid;gap:.2rem;font-size:.65rem;font-weight:700}
.bk-sys li{background:var(--fill-soft);border-radius:var(--r-pill);padding:.2em .55em;text-align:center}
.bk-sys__out li{background:var(--cat);color:var(--cat-ink)}
.bk-sys__core{background:var(--ink);color:var(--card);border-radius:var(--r-sm);padding:.5em .55em;
  font-family:var(--display);font-weight:800;font-size:.66rem;writing-mode:vertical-rl;text-orientation:mixed}

/* cloze blanks and the transform sentence. Two classes deep so these beat
   `.bcard p` on specificity rather than on !important. */
.bcard .bk-cloze{font-size:.74rem;line-height:1.7;color:var(--ink);font-weight:600}
.bk-cloze i{display:inline-block;min-width:2.6rem;border-bottom:2px solid var(--cat-ink);
  margin:0 .12rem;vertical-align:-.1em}
.bcard .bk-tx{font-size:.78rem;line-height:1.6;color:var(--ink);font-weight:600}
.bk-tag{justify-self:start;background:var(--cat);color:var(--cat-ink);border-radius:var(--r-pill);
  padding:.2em .7em;font-family:var(--display);font-weight:800;font-size:.6rem;letter-spacing:.05em;
  text-transform:uppercase}
/* a still waveform: this is a Listen affordance, not a playing one */
.bk-wave{display:flex;align-items:center;gap:.16rem;height:1.4rem}
.bk-wave i{flex:1;border-radius:2px;background:var(--cat)}
.bk-wave i:nth-child(odd){height:45%}
.bk-wave i:nth-child(3n){height:100%}
.bk-wave i:nth-child(even){height:70%}

/* --- one live element per lesson ---------------------------------------
   Each subject gets exactly one thing that moves, and it is always the thing
   the lesson is actually about. Everything else on the board holds still. */

/* solar system — planets on true relative periods */
.bk-orbit{display:grid;place-items:center}
.bk-orbit svg{width:100%;max-height:8.2rem}
.bk-orbit__ring{fill:none;stroke:var(--border-dash);stroke-width:1.2}
.bk-orbit__sun{fill:var(--tang)}
.bk-orbit__pl circle{fill:var(--cyan-ink)}
.bk-orbit__pl{transform-box:view-box;transform-origin:60px 50px;
  animation:bk-spin var(--t) linear infinite}
@keyframes bk-spin{to{transform:rotate(360deg)}}

/* fractions — the same two bars re-cut into twelfths, on a loop */
.bk-fr{position:relative;height:1.5rem;border-radius:var(--r-sm);overflow:hidden;background:var(--fill-soft)}
.bk-fr__fill{position:absolute;inset:0 auto 0 0;width:var(--f);
  background:color-mix(in oklch, var(--cyan) 75%, white)}
.bk-fr__split{position:absolute;inset:0;opacity:0;
  background:repeating-linear-gradient(90deg, transparent 0, transparent calc(100% / 12 - 1.5px),
    var(--card) calc(100% / 12 - 1.5px), var(--card) calc(100% / 12));
  animation:bk-recut 6s var(--ease) infinite}
.bk-fr__lab{position:absolute;inset:0;display:grid;place-items:center;font-family:var(--display);
  font-weight:800;font-size:.76rem;color:var(--cyan-ink)}
.bk-fr__lab b{grid-area:1/1;font-size:inherit}
.bk-fr__lab .a{animation:bk-fade-out 6s var(--ease) infinite}
.bk-fr__lab .b{opacity:0;animation:bk-fade-in 6s var(--ease) infinite}
@keyframes bk-recut{0%,18%{opacity:0}32%,68%{opacity:1}82%,100%{opacity:0}}
@keyframes bk-fade-out{0%,18%{opacity:1}32%,68%{opacity:0}82%,100%{opacity:1}}
@keyframes bk-fade-in{0%,18%{opacity:0}32%,68%{opacity:1}82%,100%{opacity:0}}

/* photosynthesis — light crosses the arrow, then the products land */
.bk-eq{display:flex;align-items:center;justify-content:center;gap:.3rem;flex-wrap:wrap;
  font-family:var(--display);font-weight:800;font-size:.74rem}
.bk-eq span{background:var(--fill-soft);border-radius:var(--r-sm);padding:.3em .5em}
.bk-eq i{font-style:normal;color:var(--soft)}
.bk-eq .is-out{background:var(--cat);color:var(--cat-ink);animation:bk-land 4.5s var(--ease) infinite}
.bk-eq .is-out:last-child{animation-delay:.25s}
.bk-eq__arrow{position:relative;overflow:hidden;background:var(--ink);color:var(--card);
  border-radius:var(--r-pill);padding:.25em .7em;font-size:.6rem;letter-spacing:.06em;text-transform:uppercase}
.bk-eq__arrow::after{content:"";position:absolute;inset:0;
  background:linear-gradient(90deg, transparent, oklch(95% .16 95 / .85), transparent);
  transform:translateX(-100%);animation:bk-sweep 4.5s var(--ease) infinite}
@keyframes bk-sweep{0%{transform:translateX(-100%)}45%,100%{transform:translateX(100%)}}
@keyframes bk-land{0%,42%{opacity:.35}58%,100%{opacity:1}}

/* past tense — the sentence changes tense in place. The slot is sized to the
   longer of the two words and tinted, so the spare width reads as a slot
   rather than as a stray gap in the sentence. */
.bk-swap{position:relative;display:inline-grid;justify-items:center;background:var(--cat);
  border-radius:5px;padding:0 .3em}
.bk-swap > span{grid-area:1/1;white-space:nowrap}
.bk-swap .a{animation:bk-fade-out 5s var(--ease) infinite}
.bk-swap .b{opacity:0;animation:bk-fade-in 5s var(--ease) infinite}
.bk-swap--key .b{color:var(--violet-deep);text-decoration:underline;text-decoration-thickness:2px;
  text-underline-offset:3px}

/* cards that hang off the frame on purpose — the lesson keeps going past
   what's in view, this demo just isn't showing all of it */
.bcard--edge{opacity:.4;box-shadow:none;pointer-events:none}
.bcard--edge .bcard__k{background:var(--fill-soft);color:var(--soft)}
.focus-ring{position:absolute;border-radius:var(--r-md);border:3px solid var(--violet);opacity:0;
  box-shadow:0 0 0 9999px color-mix(in oklch, var(--ink) 22%, transparent);pointer-events:none}
/* the second teacher's cursor: a name pill that taps a card, then leaves —
   the only way "two teachers, no silent overwrites" reads as real rather
   than an unillustrated claim in the proof-chip list below the board */
.collab-cursor{position:absolute;left:var(--x);top:var(--y);opacity:0;pointer-events:none;
  display:flex;align-items:center;gap:.4em;font-family:var(--display);font-weight:800;font-size:.7rem;
  color:var(--cyan-ink);background:var(--card);box-shadow:var(--lift);border-radius:var(--r-pill);
  padding:.3em .8em .3em .5em;white-space:nowrap}
.collab-cursor__dot{width:.6em;height:.6em;border-radius:50%;background:var(--cyan);flex:none}

/* one capability row now, not two: "upload a page" and "turn a figure into a
   walk-through" were the same promise told twice, and the second is a clause
   in the board's caption instead */
.cap-rows{display:grid;gap:var(--space-8);margin-top:var(--space-8)}
.cap-row{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);gap:clamp(1.6rem,4vw,3.5rem);
  align-items:center}
.cap-row__art .art-img{box-shadow:var(--lift)}
.cap-row__copy h3{font-size:var(--t-panel);margin-bottom:.8rem}
/* a caption belonging to the surface above it, not a column of its own */
.board-caption{margin-top:1.2rem;text-align:center;color:var(--soft);font-weight:700;font-size:.94rem;
  max-width:58ch;margin-inline:auto;line-height:1.5}
.board-caption b{color:var(--ink);font-family:var(--display);font-weight:800}

/* shared art */
.art-img{border-radius:var(--r-md);width:100%;height:auto;display:block}

/* ==========================================================================
   4 · CONTENT STUDIO — the ring, and the two seats hanging off it.

   The other two chapters are a run (Auto-Teach: one frame, one recorded run)
   and a switch (Canvas: one board, four subjects). This one is a round trip,
   so its structural device is a literal circuit rather than a second tab or a
   numbered pipeline: numbering would claim "then, then", and the true shape
   is that seat two's output is seat one's input. The SVG path draws that
   loop; stations sit on it as nodes; the return label rides the bottom arc.

   Each seat keyed to one accent, from the station through the seat kicker and
   nowhere else: violet = the maker (and the class behind them), cyan = what
   comes back.
   ========================================================================== */
.course-scene{padding-bottom:var(--space-6)}

/* tinted band: claim left, circuit right - the chapter's signature ground */
.cs-band{background:var(--fill-soft);padding:clamp(1.8rem,3.5vw,2.8rem) 0;margin-bottom:.5rem}
.cs-intro{display:grid;grid-template-columns:minmax(0,.92fr) minmax(0,1.18fr);
  gap:clamp(1.4rem,3vw,2.4rem) clamp(1.6rem,3.5vw,2.8rem);align-items:center}
.cs-intro__claim{text-align:start;padding-block:.2rem}
.cs-intro__claim .eyebrow{margin-bottom:.7rem}
.cs-intro__claim h2{font-size:var(--t-chapter);max-width:16ch}
.cs-intro__claim .line{margin:1rem 0 0;max-width:38ch}

/* the loop: SVG track under nodes; display:contents lets stations join the grid */
.cs-intro__loop{position:relative;display:grid;
  grid-template-columns:1fr 1fr;grid-template-rows:auto auto;
  gap:1.1rem 1.6rem;padding:1.4rem .8rem 1.8rem 1.7rem;isolation:isolate}
.cs-circuit{position:absolute;inset:0;width:100%;height:100%;z-index:0;
  color:var(--violet);pointer-events:none;overflow:visible}
.cs-circuit__track{stroke:var(--border-dash);stroke-width:2.5;stroke-dasharray:7 8}
.cs-circuit__draw{stroke:var(--violet);stroke-width:2.5;
  stroke-dasharray:1;stroke-dashoffset:1;
  transition:stroke-dashoffset 1.15s var(--ease)}
.cs-intro__loop.is-drawn .cs-circuit__draw{stroke-dashoffset:0}

.cs-ring{list-style:none;padding:0;margin:0;display:contents}
.cs-ring__node{position:relative;z-index:1;min-width:0}
.cs-ring__node--make{grid-column:1;grid-row:1}
.cs-ring__node--read{grid-column:2;grid-row:1}

/* nodes on the path - flatter than lifted cards so the circuit carries weight */
.cs-station{--k:var(--violet);display:grid;gap:.28rem;justify-items:start;height:100%;
  align-content:start;text-decoration:none;color:inherit;
  background:var(--card);border-radius:var(--r-md);
  border:2px solid color-mix(in oklch, var(--k) 28%, var(--border));
  padding:1.05rem 1.1rem 1.15rem;
  transition:translate var(--dur) var(--ease), border-color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease), background var(--dur) var(--ease)}
.cs-station--make{--k:var(--violet)}
.cs-station--read{--k:var(--cyan)}
.cs-station__who{font-family:var(--display);font-weight:800;font-size:.68rem;letter-spacing:.08em;
  text-transform:uppercase;border-radius:var(--r-pill);padding:.28em .85em;
  background:color-mix(in oklch, var(--k) 28%, var(--card));color:var(--ink)}
.cs-station b{font-family:var(--display);font-weight:800;font-size:clamp(1.05rem,1.6vw,1.22rem);
  line-height:1.15;margin-top:.15rem}
.cs-station em{font-style:normal;color:var(--soft);font-weight:600;font-size:.86rem;line-height:1.4}
.cs-station:hover{translate:0 -3px;border-color:color-mix(in oklch, var(--k) 55%, var(--border))}
.cs-station:active{translate:0 -1px;scale:.99}
.cs-station:focus-visible{outline:none;box-shadow:var(--ring-strong)}
/* lit while its seat is the one on screen; with no JS nothing is lit and the
   two read as a plain list, which is the honest fallback */
.cs-station.is-on{border-color:var(--k);
  box-shadow:0 0 0 3px color-mix(in oklch, var(--k) 32%, transparent)}
.cs-station.is-on .cs-station__who{background:var(--k);color:var(--card)}
.cs-station--read.is-on .cs-station__who{color:var(--cyan-ink)}

/* return label rides the bottom arc of the circuit */
.cs-ring__return{position:relative;z-index:1;grid-column:1 / -1;grid-row:2;
  margin:0;padding:.55rem .8rem;text-align:center;
  color:var(--ink);font-weight:700;font-size:.86rem;line-height:1.35;
  background:color-mix(in oklch, var(--fill-soft) 55%, var(--card));
  border-radius:var(--r-pill);border:1.5px dashed var(--border-dash);
  justify-self:center;max-width:36ch}

/* ghost tick: where the loop re-enters seat one as the next draft */
.cs-circuit__ghost{position:absolute;z-index:1;left:.2rem;top:40%;
  translate:0 -50%;font-family:var(--display);font-weight:800;font-size:.62rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--violet-deep);
  writing-mode:vertical-rl;rotate:180deg;opacity:.72;pointer-events:none}

@media (prefers-reduced-motion:reduce){
  .cs-circuit__draw{transition:none;stroke-dashoffset:0}
  .cs-station:hover,.cs-station:active{translate:none;scale:none}
}

/* --- a seat --------------------------------------------------------------
   Claim once in the head, prove it on the surface below. Both seats share the
   manifesto head; seat one adds a three-verb trip strip that lights the
   matching step in the run (the essay lives in the demo, not beside the claim). */
.cs-act{padding-top:var(--space-8)}
.cs-act__head{margin-bottom:1.2rem}
.cs-act__head h3{font-size:var(--t-panel);max-width:22ch;margin-top:.5rem}
.split-text-reveal{animation:split-reveal .8s cubic-bezier(.16,1,.3,1) forwards;opacity:0;transform:translateY(10px)}
@keyframes split-reveal{to{opacity:1;transform:translateY(0)}}
@media (prefers-reduced-motion:reduce){
  .split-text-reveal{animation:none;opacity:1;transform:none}
}
.cs-act__head .line{margin-top:1rem;max-width:52ch}
.cs-act__head--manifesto{display:block;max-width:48ch;margin-bottom:2.8rem}
.cs-act__head--manifesto h3{max-width:20ch}
.cs-act__head--manifesto .line{max-width:40ch}
.cs-act:has(.cs-trip) .cs-act__head--manifesto{margin-bottom:1.2rem}

/* Seat One trip: one worksheet, three hands.
   Three frames of the SAME object (a teacher's page → the draft behind the
   four gates → a student's answered question), bottom-aligned on one straight
   rail. The rail's ghost track is the whole route; the saturated fill and the
   token riding it are the live demo beat, read off --trip-draw (set by the
   trip script on the board, 1 = nothing run, 0 = all of it).

   Two things this replaced, both deliberate: a drawn bezier that connected
   none of the cards and mixed violet→tang in oklch (which lands on magenta),
   and a second numbered step list duplicating .csr-steps directly below. The
   frames are keyed by hand, not by step number, so the two never restate
   each other. Accent per frame is the page's existing station mapping:
   violet = you, tang = your call, lime = the class. */
.cs-trip-board{position:relative;margin:0 0 2.4rem;isolation:isolate}

.cs-trip{list-style:none;margin:0;padding:0;position:relative;z-index:1;
  display:grid;grid-template-columns:1.12fr .93fr 1.05fr;
  gap:clamp(.85rem,1.9vw,1.6rem);align-items:end}
.cs-trip__stop{margin:0;position:relative;--k:var(--violet);--k-deep:var(--violet-deep);--k-ink:#fff}
.cs-trip__stop--approve{--k:var(--tang);--k-deep:var(--tang-deep);--k-ink:var(--tang-deep)}
.cs-trip__stop--finish{--k:var(--lime);--k-deep:var(--lime-ink);--k-ink:var(--lime-ink)}

.cs-trip__cell{width:100%;text-align:start;font:inherit;cursor:pointer;position:relative;
  display:grid;grid-template-rows:1fr auto;gap:.9rem;
  padding:clamp(.85rem,1.5vw,1.1rem);
  background:var(--card);border-radius:var(--r-md);box-shadow:var(--lift);
  border:1px solid color-mix(in srgb,var(--border) 75%,transparent);
  transition:transform .35s var(--ease),box-shadow .35s var(--ease),border-color .28s var(--ease)}

/* The artifact stage. Each frame gets its own tinted ground so the strip is
   three different objects at a glance, not three cards with text in them. */
.cs-trip__art{position:relative;display:block;overflow:hidden;
  min-height:var(--art-h,10.5rem);border-radius:var(--r-sm);
  background:color-mix(in srgb,var(--k) 8%,var(--bg));
  border:1px solid color-mix(in srgb,var(--k) 20%,var(--border))}
.cs-trip__stop--attach .cs-trip__cell{--art-h:12.25rem}
.cs-trip__stop--approve .cs-trip__cell{--art-h:10.25rem}
.cs-trip__stop--finish .cs-trip__cell{--art-h:11.25rem}

/* 1 · paper. Three sheets on the desk, the top one open at the worked
   example the quiz in frame three is built from. */
.cs-trip__art--paper{display:grid;place-items:center}
.cs-trip__sheet{position:absolute;width:60%;height:76%;border-radius:4px;background:var(--card);
  border:1px solid color-mix(in srgb,var(--violet) 20%,var(--border));
  box-shadow:0 4px 12px rgb(24 22 70 / .08);
  transition:transform .45s var(--ease)}
.cs-trip__sheet--back{transform:rotate(-8deg) translate(-9%,3%)}
.cs-trip__sheet--mid{transform:rotate(4.5deg) translate(7%,-1%)}
.cs-trip__page{position:relative;z-index:2;width:64%;height:81%;
  border-radius:4px;background:var(--card);
  border:1px solid color-mix(in srgb,var(--violet) 26%,var(--border));
  box-shadow:0 6px 18px rgb(24 22 70 / .13);transform:rotate(-1.6deg);
  padding:.7rem .65rem;display:flex;flex-direction:column;justify-content:center;gap:.42rem;
  transition:transform .45s var(--ease)}
.cs-trip__rule{display:block;height:2px;border-radius:2px;
  background:color-mix(in srgb,var(--violet) 15%,var(--border))}
.cs-trip__rule--short{width:56%}
.cs-trip__ink{font-family:var(--display);font-weight:800;font-size:.95rem;line-height:1;
  color:var(--violet-deep);letter-spacing:.01em;transform:rotate(-1.8deg);
  margin:.2rem 0;white-space:nowrap}
.cs-trip__file{position:absolute;z-index:3;inset-inline-start:.6rem;bottom:.6rem;
  display:inline-flex;align-items:center;gap:.35rem;padding:.28rem .5rem;
  border-radius:var(--r-pill);background:var(--card);
  border:1px solid color-mix(in srgb,var(--violet) 28%,var(--border));
  box-shadow:0 2px 7px rgb(24 22 70 / .1);
  font-family:var(--display);font-weight:800;font-size:.58rem;color:var(--violet-deep)}
.cs-trip__file::before{content:"";width:.5rem;height:.5rem;border-radius:2px;flex:none;
  background:color-mix(in srgb,var(--violet) 60%,var(--card))}

/* 2 · the approval gate. The four checkpoints are the real ones the run
   below stamps, in order. */
.cs-trip__art--gate{padding:.7rem;display:flex;flex-direction:column;gap:.42rem}
.cs-trip__gate-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem;
  padding-bottom:.5rem;margin-bottom:.18rem;
  border-bottom:1px solid color-mix(in srgb,var(--tang) 22%,var(--border))}
.cs-trip__gate-title{font-family:var(--display);font-weight:800;font-size:.8rem;
  color:var(--ink);letter-spacing:-.01em}
.cs-trip__gate-state{font-family:var(--display);font-weight:800;font-size:.55rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--tang-deep);flex:none;
  padding:.2rem .45rem;border-radius:var(--r-pill);
  background:color-mix(in srgb,var(--tang) 22%,var(--card))}
.cs-trip__check{display:flex;align-items:center;gap:.5rem;
  font-weight:700;font-size:.74rem;line-height:1.2;color:var(--soft);
  transition:color .3s var(--ease)}
.cs-trip__check i{position:relative;flex:none;width:.95rem;height:.95rem;border-radius:4px;
  background:var(--card);border:1.5px solid color-mix(in srgb,var(--tang) 42%,var(--border));
  transition:background .3s var(--ease),border-color .3s var(--ease)}
.cs-trip__check i::after{content:"";position:absolute;left:.29rem;top:.09rem;
  width:.2rem;height:.42rem;border:solid var(--card);border-width:0 2px 2px 0;
  transform:rotate(45deg) scale(.5);opacity:0;
  transition:opacity .22s var(--ease),transform .22s var(--ease)}

/* 3 · the answered question, exactly the quiz the run below plays. */
.cs-trip__art--answer{padding:.7rem;display:flex;flex-direction:column;gap:.36rem}
.cs-trip__q{font-family:var(--display);font-weight:800;font-size:.78rem;line-height:1.25;
  color:var(--ink);letter-spacing:-.01em;margin-bottom:.14rem}
.cs-trip__opt{display:flex;align-items:center;gap:.5rem;padding:.34rem .5rem;
  border-radius:8px;background:var(--card);font-weight:700;font-size:.73rem;color:var(--soft);
  border:1.5px solid color-mix(in srgb,var(--border) 85%,transparent);
  transition:background .3s var(--ease),border-color .3s var(--ease),color .3s var(--ease)}
.cs-trip__opt--pick{color:var(--lime-ink);
  background:color-mix(in srgb,var(--lime) 18%,var(--card));
  border-color:color-mix(in srgb,var(--lime) 58%,var(--border))}
.cs-trip__ok{position:relative;margin-inline-start:auto;flex:none;
  width:.95rem;height:.95rem;border-radius:50%;background:var(--lime)}
.cs-trip__ok::after{content:"";position:absolute;left:.31rem;top:.15rem;
  width:.2rem;height:.4rem;border:solid var(--lime-ink);border-width:0 2px 2px 0;
  transform:rotate(45deg)}
.cs-trip__xp{align-self:flex-start;margin-top:auto;
  font-family:var(--display);font-weight:800;font-size:.64rem;letter-spacing:.04em;
  padding:.3rem .55rem;border-radius:var(--r-pill);color:var(--lime-ink);
  background:color-mix(in srgb,var(--lime) 30%,var(--card));
  border:1px solid color-mix(in srgb,var(--lime) 45%,var(--border));
  transition:transform .35s cubic-bezier(.175,.885,.32,1.275),box-shadow .3s var(--ease)}

/* Caption. Two text elements per frame, and the left-to-right order is the
   step number, so no badge and no uppercase kicker. */
.cs-trip__cap{display:flex;flex-direction:column;gap:.28rem}
.cs-trip__cap b{font-family:var(--display);font-weight:800;line-height:1.12;
  font-size:clamp(1.15rem,1.9vw,1.35rem);color:var(--ink);letter-spacing:-.02em;
  transition:color .28s var(--ease)}
.cs-trip__cap em{font-style:normal;font-weight:600;font-size:.83rem;line-height:1.45;
  color:var(--soft);max-width:30ch}

/* Station pin. Lives on the <li> so it tracks its own column whatever the
   grid fractions are, and drops onto the rail below. */
.cs-trip__pin{position:absolute;inset-inline-start:50%;bottom:calc(-1.35rem - 1px);
  transform:translate(-50%,50%);z-index:2;width:.7rem;height:.7rem;border-radius:50%;
  background:var(--card);border:2px solid color-mix(in srgb,var(--k) 40%,var(--border));
  transition:background .35s var(--ease),border-color .35s var(--ease)}
.cs-trip__stop:has(.is-trip-live) .cs-trip__pin,
.cs-trip__stop:has(.is-trip-done) .cs-trip__pin{background:var(--k);border-color:var(--k)}
.cs-trip__stop:has(.is-trip-live) .cs-trip__pin::after{content:"";position:absolute;inset:-5px;
  border-radius:50%;border:2px solid color-mix(in oklch,var(--k) 55%,transparent);
  animation:cs-trip-ring 1.7s var(--ease) infinite}

/* The rail. Ghost track = the whole route, always legible with no JS; the
   fill is clipped from the right so the gradient stays anchored to the
   stations instead of squashing. */
.cs-trip__rail{position:relative;height:3px;margin:1.35rem 0 0;border-radius:3px;
  background:color-mix(in srgb,var(--border) 60%,transparent)}
.cs-trip__rail::before{content:"";position:absolute;inset:0;border-radius:inherit;opacity:.28;
  background:linear-gradient(90deg,var(--violet) 6%,var(--cyan) 50%,var(--lime) 94%)}
.cs-trip__rail-fill{position:absolute;inset:0;border-radius:inherit;
  background:linear-gradient(90deg,var(--violet) 6%,var(--cyan) 50%,var(--lime) 94%);
  clip-path:inset(0 calc(var(--trip-draw,1) * 100%) 0 0);
  transition:clip-path .75s var(--ease)}
.cs-trip__token{position:absolute;top:50%;z-index:2;white-space:nowrap;
  inset-inline-start:calc(1.9rem + (1 - var(--trip-draw,1)) * (100% - 3.8rem));
  transform:translate(-50%,-50%);
  font-family:var(--display);font-weight:800;font-size:.62rem;letter-spacing:.05em;
  padding:.3rem .52rem;border-radius:var(--r-pill);
  background:var(--card);color:var(--violet-deep);
  border:1px solid color-mix(in srgb,var(--violet) 34%,var(--border));
  box-shadow:0 3px 10px rgb(24 22 70 / .14);
  transition:inset-inline-start .75s var(--ease),color .35s var(--ease),
    border-color .35s var(--ease)}
.cs-trip[data-trip-at="approve"] ~ .cs-trip__rail .cs-trip__token{color:var(--tang-deep);
  border-color:color-mix(in srgb,var(--tang) 45%,var(--border))}
.cs-trip[data-trip-at="learn"] ~ .cs-trip__rail .cs-trip__token{color:var(--lime-ink);
  border-color:color-mix(in srgb,var(--lime) 52%,var(--border))}

.cs-trip__caption{margin:1.4rem 0 0;max-width:58ch}

/* Hover / focus: the frame lifts and its artifact opens a little. */
.cs-trip__cell:hover,.cs-trip__cell:focus-visible{transform:translateY(-5px);
  border-color:color-mix(in srgb,var(--k) 42%,var(--border));
  box-shadow:var(--lift),0 0 0 1px color-mix(in oklch,var(--k) 30%,transparent)}
.cs-trip__cell:hover .cs-trip__cap b,.cs-trip__cell:focus-visible .cs-trip__cap b{color:var(--k-deep)}
.cs-trip__cell:hover .cs-trip__page{transform:rotate(-3.4deg) translateY(-3px)}
.cs-trip__cell:hover .cs-trip__sheet--back{transform:rotate(-11deg) translate(-13%,4%)}
.cs-trip__cell:hover .cs-trip__sheet--mid{transform:rotate(7.5deg) translate(11%,-2%)}
.cs-trip__cell:active{transform:translateY(-1px)}
.cs-trip__cell:focus-visible{outline:none;box-shadow:var(--ring-strong),var(--lift)}

/* Live / done, mirrored off the demo beat below. */
.cs-trip__cell.is-trip-on,.cs-trip__cell.is-trip-live{
  border-color:color-mix(in srgb,var(--k) 45%,var(--border))}
.cs-trip__cell.is-trip-live{box-shadow:var(--lift),0 0 0 2px color-mix(in oklch,var(--k) 32%,transparent)}
.cs-trip__cell.is-trip-on .cs-trip__cap b,
.cs-trip__cell.is-trip-live .cs-trip__cap b{color:var(--k-deep)}
/* checkpoints stamp in order, not all at once */
.cs-trip__cell.is-trip-on .cs-trip__check i,
.cs-trip__cell.is-trip-live .cs-trip__check i,
.cs-trip__cell.is-trip-done .cs-trip__check i{background:var(--tang);border-color:var(--tang-deep)}
.cs-trip__cell.is-trip-on .cs-trip__check i::after,
.cs-trip__cell.is-trip-live .cs-trip__check i::after,
.cs-trip__cell.is-trip-done .cs-trip__check i::after{opacity:1;transform:rotate(45deg) scale(1)}
.cs-trip__cell.is-trip-on .cs-trip__check,
.cs-trip__cell.is-trip-live .cs-trip__check,
.cs-trip__cell.is-trip-done .cs-trip__check{color:var(--ink)}
.cs-trip__check:nth-of-type(2) i,.cs-trip__check:nth-of-type(2) i::after{transition-delay:.1s}
.cs-trip__check:nth-of-type(3) i,.cs-trip__check:nth-of-type(3) i::after{transition-delay:.2s}
.cs-trip__check:nth-of-type(4) i,.cs-trip__check:nth-of-type(4) i::after{transition-delay:.3s}
.cs-trip__cell.is-trip-done .cs-trip__check i{background:var(--lime);border-color:var(--lime-ink)}
.cs-trip__cell.is-trip-done .cs-trip__check i::after{border-color:var(--lime-ink)}
/* the reward landing */
.cs-trip__cell.is-trip-on .cs-trip__xp,
.cs-trip__cell.is-trip-live .cs-trip__xp{transform:translateY(-2px) scale(1.06);
  box-shadow:0 5px 14px color-mix(in oklch,var(--lime) 45%,transparent)}

.csr-step.is-trip-on i{background:color-mix(in srgb,var(--violet) 22%,var(--fill-soft));
  color:var(--violet-deep);transform:scale(1.06)}
.csr-step.is-trip-on b{color:var(--violet-deep)}
.csr-step.is-trip-on span{transform:translateX(2px)}

@keyframes cs-trip-ring{0%{opacity:.55;transform:scale(1)}70%,100%{opacity:0;transform:scale(1.22)}}
@keyframes cs-trip-in{from{opacity:0;transform:translateY(24px)}to{opacity:1;transform:none}}
/* Enter is CSS-only and opt-in via .is-in, so the default state is fully
   readable with no JS. Do not add a GSAP reveal on top of this. */
@media (prefers-reduced-motion:no-preference){
  .cs-trip.is-in .cs-trip__stop:nth-child(1) .cs-trip__cell{animation:cs-trip-in .62s var(--ease) both}
  .cs-trip.is-in .cs-trip__stop:nth-child(2) .cs-trip__cell{animation:cs-trip-in .62s var(--ease) .09s both}
  .cs-trip.is-in .cs-trip__stop:nth-child(3) .cs-trip__cell{animation:cs-trip-in .62s var(--ease) .18s both}
}
@media (prefers-reduced-motion:reduce){
  .cs-trip__cell:hover,.cs-trip__cell:focus-visible,.cs-trip__cell:active{transform:none}
  .cs-trip__cell:hover .cs-trip__page,
  .cs-trip__cell:hover .cs-trip__sheet--back,
  .cs-trip__cell:hover .cs-trip__sheet--mid{transform:none}
  .cs-trip__stop:has(.is-trip-live) .cs-trip__pin::after{animation:none;opacity:.45}
  .cs-trip__rail-fill,.cs-trip__token{transition:none}
  .cs-trip__cell.is-trip-on .cs-trip__xp,
  .cs-trip__cell.is-trip-live .cs-trip__xp{transform:none}
}

/* Fitted, the strip keeps all three stations side by side on the one rail —
   the whole point of the drawing is that the paper, the gate and the answer
   are one route, and a column of three cards is not a route. These are the
   no-JS fallback: one column, and the pins go with the columns they pinned. */
@media (max-width:880px){
  .fitstage:not(.is-fit) .cs-trip{grid-template-columns:1fr;gap:.9rem}
  .fitstage:not(.is-fit) .cs-trip__cell{--art-h:9rem !important;gap:.8rem}
  .fitstage:not(.is-fit) .cs-trip__pin{display:none}
  .fitstage:not(.is-fit) .cs-trip__rail{margin-top:1.1rem}
  .fitstage:not(.is-fit) .cs-trip__cap em{max-width:46ch}
}
@media (max-width:560px){
  .fitstage:not(.is-fit) .cs-trip__cell{--art-h:8.25rem !important}
  .fitstage:not(.is-fit) .cs-trip__ink{font-size:.85rem}
}

/* the seat kicker, keyed to its station by the leading square. Deliberately
   not an .eyebrow: two eyebrows already name the two products. */
.cs-seat{--k:var(--violet);display:flex;align-items:center;gap:.55rem;
  font-family:var(--display);font-weight:800;font-size:var(--t-meta);letter-spacing:.07em;
  text-transform:uppercase;color:var(--soft)}
.cs-seat::before{content:"";width:.75rem;height:.75rem;border-radius:4px;background:var(--k)}
.cs-seat--make{--k:var(--violet)}
.cs-seat--read{--k:var(--cyan)}

/* the seat's one surface. Inside a chapter these need plain rhythm, not the
   whole-section padding each of them used to carry. */
.cs-act > .csr-run,
.cs-act > .desk-stack{margin-top:1.4rem}

/* --- seat one's run: one frame, three acts --------------------------------
   The drafting seat used to be a still picture of a staged course, which could
   show that the Studio exists but not that a prompt and two attachments become
   something a thirteen-year-old finishes. So it is a run now, built exactly
   like the flagship: a flat list of beats, one renderer that always sets the
   whole frame, and a fallback that stacks every act complete.

   Three temperatures inside one chassis, and each one belongs to a different
   person: the generator keeps the site's cool card, the lesson act goes to the
   runtime's warm paper, and the reward slide takes the violet the real
   completion screen tints itself with. "We left the tool and someone else
   picked it up" is felt before it is read.

   Everything that hides an act is scoped to .csr.is-live, which the entry
   script adds only once it can drive the frame.

   The four beats sit as a vertical spine beside the frame: the journey is a
   sequence, so the rail reads top-to-bottom and the lime fill climbs with it.
   ------------------------------------------------------------------------- */
.csr-run{--csr-p:0;display:grid;gap:1.5rem 2rem;align-items:start;margin-top:2.5rem}
@media (min-width:1000px){
  .csr-run{grid-template-columns:minmax(13.5rem,17rem) minmax(0,1fr);
    grid-template-areas:"steps device" "foot foot";gap:1.25rem 2.25rem}
  .csr-steps-container{grid-area:steps;position:sticky;top:6.5rem}
  /* the fit stage wrapping the TV is the grid item, not the TV itself */
  .csr-fit{grid-area:device}
  .csr-foot{grid-area:foot}
  /* Same clearance the flagship earns: the pin docks under the stage bar, not
     into it. Sticky offset is dropped while pinned — the padding already clears
     the chrome, and sticky-top was what made the spine sit lower than the TV. */
  .csr.is-pinned{min-height:100vh;min-height:100dvh;margin-top:0;box-sizing:border-box;
    align-content:center;padding-block:calc(44px + 1.25rem) 1.25rem}
  .csr.is-pinned .csr-steps-container{position:relative;top:auto;align-self:center}
  .csr.is-pinned .csr-screen{aspect-ratio:auto;height:min(68vh,700px)}
  .csr.is-pinned .csr-foot{margin-top:.35rem}
}
.csr-device{--csr-paper:oklch(98.4% 0.012 95);width:100%;margin-top:0}
.csr-device svg{width:1em;height:1em;display:block;flex:none}
.csr-device .csr-sprite{position:absolute;width:0;height:0;overflow:hidden}
.csr-device .csr-narr__face svg{width:100%;height:100%}
/* the renderer drives this scene with [hidden], and half the elements it hides
   carry a display of their own — so hidden wins outright */
[data-csr] [hidden]{display:none !important}

/* vertical journey spine: four beats the demo can jump to */
.csr-steps-container{position:relative;padding:0 0 0 .15rem;margin:0}
.csr-steps-spine{position:absolute;left:.9rem;top:1.05rem;bottom:1.05rem;width:2px;
  pointer-events:none;z-index:0}
.csr-steps-spine__rail{display:block;position:absolute;inset:0;border-radius:2px;
  background:repeating-linear-gradient(180deg,var(--border-dash) 0 5px,transparent 5px 9px)}
.csr-steps-spine__fill{display:block;position:absolute;left:0;top:0;width:100%;
  height:calc(var(--csr-p,0) * 100%);border-radius:2px;
  background:linear-gradient(180deg,var(--violet),var(--lime));
  transform-origin:top center;
  transition:height .55s cubic-bezier(.22,1,.36,1);
  box-shadow:0 0 12px color-mix(in oklch,var(--violet) 35%,transparent)}
.csr-steps{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;
  gap:0;position:relative;z-index:1}
.csr-steps > li{margin:0}
.csr-step{width:100%;text-align:start;font:inherit;border:0;cursor:pointer;
  background:transparent;padding:.7rem 0;margin:0;
  display:grid;grid-template-columns:1.85rem minmax(0,1fr);gap:.85rem;align-items:start;
  position:relative;
  transition:background var(--dur) var(--ease)}
@media (prefers-reduced-motion:no-preference){
  .csr.is-live .csr-step{animation:csr-step-in .55s var(--ease) both}
  .csr.is-live .csr-steps > li:nth-child(1) .csr-step{animation-delay:.04s}
  .csr.is-live .csr-steps > li:nth-child(2) .csr-step{animation-delay:.12s}
  .csr.is-live .csr-steps > li:nth-child(3) .csr-step{animation-delay:.2s}
  .csr.is-live .csr-steps > li:nth-child(4) .csr-step{animation-delay:.28s}
}
@keyframes csr-step-in{
  from{opacity:0;transform:translateX(-12px)}
  to{opacity:1;transform:none}
}
.csr-step:hover{background:transparent}
.csr-step:hover span{color:var(--ink)}
.csr-step:focus-visible{outline:none}
.csr-step:focus-visible i{box-shadow:var(--ring-strong)}
.csr-step i{position:relative;z-index:2;font-style:normal;font-family:var(--display);font-weight:800;font-size:.78rem;
  width:1.85rem;height:1.85rem;flex:none;display:grid;place-items:center;border-radius:50%;
  background:var(--fill-soft);color:var(--soft);justify-self:center;
  transition:transform .35s cubic-bezier(.175,.885,.32,1.275),background var(--dur) var(--ease),color var(--dur) var(--ease),box-shadow var(--dur) var(--ease)}
.csr-step:hover i{transform:scale(1.1);background:var(--violet);color:#fff}
.csr-step:active i{transform:scale(0.95)}
.csr-step span{min-width:0;padding-top:.15rem;transition:transform .35s var(--ease)}
.csr-step b{font-family:var(--display);font-weight:800;font-size:.98rem;display:block;line-height:1.2}
.csr-step em{font-style:normal;display:block;color:var(--soft);font-weight:600;font-size:.78rem;line-height:1.35;margin-top:.2rem}
.csr-step.is-done i{background:var(--lime);color:var(--lime-ink)}
.csr-step.is-on{background:transparent}
.csr-step.is-on i{background:var(--violet);color:#fff;transform:scale(1.12);box-shadow:var(--lift)}
.csr-step.is-on i::after{content:"";position:absolute;inset:-5px;border-radius:50%;
  border:2px solid color-mix(in oklch,var(--violet) 55%,transparent);
  animation:csr-ring 1.6s var(--ease) infinite}
.csr-step.is-on b{color:var(--violet-deep)}
.csr-step.is-on span{transform:translateX(2px)}

.csr-screen{background:var(--card)}
.csr-act{display:block}
.csr-act + .csr-act{border-top:2px dashed var(--border-dash)}

/* ---- act one · the generator --------------------------------------------- */
.csr-bar{display:flex;align-items:center;gap:.5rem;padding:.5rem .8rem;
  border-bottom:1px solid var(--border);background:var(--card);font-size:.78rem}
.csr-brand{display:inline-flex;align-items:center;gap:.35rem;font-family:var(--display);font-weight:800}
.csr-brand i{display:grid;place-items:center;width:1.35rem;height:1.35rem;border-radius:7px;
  background:var(--violet);color:#fff;font-size:.8rem}
.csr-bar__sep{width:1px;height:1.1rem;background:var(--border)}
.csr-bar__title{font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  border-bottom:1px dashed var(--border);padding-bottom:1px}
.csr-bar__right{margin-left:auto;flex:none}
.csr-save{font-size:.68rem;font-weight:700;color:var(--soft);display:inline-flex;align-items:center;gap:.35rem}
.csr-save::before{content:"";width:.42rem;height:.42rem;border-radius:50%;background:var(--border);flex:none}
.csr-save.is-busy::before{background:var(--tang);animation:csr-pulse 1.1s ease-in-out infinite}
.csr-save.is-check::before{background:var(--tang)}
.csr-save.is-live::before{background:var(--lime)}

.csr-stage{padding:clamp(.8rem,1.8vw,1.2rem);min-height:0}
.csr-view{min-height:0;display:grid;align-content:start;gap:.7rem}

/* the modal, on the veiled Studio it opens over */
.csr-view--brief{background:color-mix(in oklch,var(--ink) 5%,transparent);
  border-radius:var(--r-md);padding:clamp(.4rem,1.4vw,1rem)}
.csr-modal{background:var(--card);border:1px solid var(--border);border-radius:var(--r-md);
  box-shadow:var(--lift);overflow:hidden;display:grid;align-content:start}
.csr-modal__head{display:flex;align-items:center;gap:.6rem;padding:.65rem .8rem;
  border-bottom:1px solid var(--border);
  background:linear-gradient(100deg,color-mix(in oklch,var(--tang) 16%,transparent),
                                    color-mix(in oklch,var(--cyan) 14%,transparent))}
.csr-modal__icon{display:grid;place-items:center;width:2rem;height:2rem;flex:none;border-radius:9px;
  background:var(--violet);color:#fff;font-size:1.05rem}
.csr-modal__say{min-width:0}
.csr-modal__t{font-family:var(--display);font-weight:800;font-size:.92rem;line-height:1.2}
.csr-modal__s{font-size:.7rem;font-weight:600;color:var(--soft)}
.csr-modal__x{margin-left:auto;color:var(--soft);font-size:.95rem;flex:none}

/* Configure → Generate → Create, the modal's own step rail */
.csr-rail{list-style:none;padding:.55rem .8rem;margin:0;display:flex;align-items:center;
  justify-content:center;gap:.4rem;border-bottom:1px solid var(--border);background:var(--bg)}
.csr-rail li{display:flex;align-items:center;gap:.35rem;font-size:.7rem;font-weight:700;color:var(--soft)}
.csr-rail li + li::before{content:"";width:clamp(1rem,3vw,2.4rem);height:2px;border-radius:2px;
  background:var(--border);margin-right:.4rem;transition:background var(--dur) var(--ease)}
.csr-rail li i{font-style:normal;font-family:var(--display);font-weight:800;font-size:.66rem;
  width:1.35rem;height:1.35rem;flex:none;display:grid;place-items:center;border-radius:50%;
  background:var(--fill-soft);color:var(--soft);
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease)}
.csr-rail li.is-doing{color:var(--ink)}
.csr-rail li.is-doing i{background:var(--violet);color:#fff}
.csr-rail li.is-done{color:var(--ink)}
.csr-rail li.is-done i{background:var(--lime);color:var(--lime-ink)}
.csr-rail li.is-done + li::before,.csr-rail li.is-doing + li::before{background:var(--lime)}

.csr-modal__body{padding:.75rem .8rem;display:grid;gap:.6rem}
.csr-lbl{font-size:.76rem;font-weight:800;font-family:var(--display)}
.csr-prompt{position:relative;background:var(--surface-sunk);border:2px solid var(--border);
  border-radius:var(--r-sm);padding:.6rem .7rem .5rem;min-height:4.2rem;display:grid;gap:.5rem;align-content:start}
.csr.is-live .csr-prompt{border-color:var(--violet);box-shadow:var(--ring)}
.csr-prompt__txt{font-size:.82rem;font-weight:600;line-height:1.5}
.csr-caret{display:none;width:2px;height:1.05em;background:var(--violet);vertical-align:-3px;margin-left:1px}
.csr.is-typing .csr-caret{display:inline-block;animation:csr-blink 1s steps(2,end) infinite}
.csr-prompt__ph{position:absolute;inset:.6rem .7rem auto;font-size:.82rem;font-weight:600;color:var(--soft);opacity:.7}
.csr-prompt__toggles{display:flex;flex-wrap:wrap;gap:.35rem}
.csr-toggle{display:inline-flex;align-items:center;gap:.3rem;font-size:.65rem;font-weight:700;
  color:var(--soft);background:var(--card);border:1px solid var(--border);
  border-radius:var(--r-pill);padding:.25em .7em}
.csr-toggle.is-on{border-color:var(--cyan);background:color-mix(in oklch,var(--cyan) 22%,var(--card));
  color:var(--cyan-ink)}

/* the attachments — the claim this seat is built on, so it is shown */
.csr-drop{border:2px dashed var(--border-dash);border-radius:var(--r-sm);padding:.55rem .65rem;
  display:grid;gap:.45rem;transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease)}
.csr-drop.is-hot{border-color:var(--violet);background:color-mix(in oklch,var(--violet) 6%,transparent)}
.csr-drop__h{display:flex;align-items:center;gap:.4rem;font-size:.7rem;font-weight:700;color:var(--soft)}
.csr-drop__h > span{color:var(--violet-deep);font-size:.95rem;flex:none;display:grid;place-items:center}
.csr-files{list-style:none;padding:0;display:grid;gap:.3rem}
.csr-file{display:flex;align-items:center;gap:.45rem;background:var(--fill-soft);border-radius:9px;
  padding:.35rem .55rem;font-size:.72rem;min-width:0}
.csr-file__i{display:grid;place-items:center;width:1.5rem;height:1.5rem;flex:none;border-radius:6px;
  background:var(--card);color:var(--rose);font-size:.85rem}
.csr-file__i--img{color:var(--cyan-ink)}
.csr-file b{font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.csr-file em{font-style:normal;color:var(--soft);font-weight:600;font-size:.66rem;flex:none}
.csr-file__ok{margin-left:auto;flex:none;display:grid;place-items:center;width:1.15rem;height:1.15rem;
  border-radius:50%;background:var(--lime);color:var(--lime-ink);font-size:.62rem}
/* they land one at a time, and only while the script is driving */
.csr.is-live .csr-file{opacity:0;transform:translateY(6px);
  transition:opacity .3s var(--ease),transform .3s var(--ease)}
.csr.is-live .csr-file.is-in{opacity:1;transform:none}

.csr-fields{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:.4rem}
.csr-field{display:grid;gap:.1rem;background:var(--fill-soft);border-radius:9px;padding:.35rem .55rem;min-width:0}
.csr-field > span{font-family:var(--display);font-weight:800;font-size:.56rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--soft)}
.csr-field > b{font-size:.74rem;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.csr.is-live .csr-field{opacity:0;transition:opacity .3s var(--ease)}
.csr.is-live .csr-field.is-in{opacity:1}

.csr-modal__foot{display:flex;align-items:center;gap:.8rem;flex-wrap:wrap;
  padding:.65rem .8rem;border-top:1px solid var(--border);background:var(--bg)}
.csr-hint{display:inline-flex;align-items:center;gap:.35rem;font-size:.68rem;font-weight:600;color:var(--soft)}
.csr-hint > span{color:var(--tang-deep);font-size:.9rem;display:grid;place-items:center}
.csr-go{position:relative;margin-left:auto;display:inline-flex;align-items:center;gap:.45rem;
  font-family:var(--display);font-weight:800;font-size:.85rem;color:#fff;background:var(--violet);
  border:0;border-radius:var(--r-pill);padding:.55em 1.4em;cursor:pointer;box-shadow:var(--lift);
  transition:transform var(--dur) var(--ease),filter var(--dur) var(--ease)}
.csr-go:hover{filter:brightness(1.1)}
.csr-go:active{transform:translateY(1px)}
.csr-go:focus-visible{outline:none;box-shadow:var(--ring-strong)}
/* one ring while the button is the thing to press — an invitation, not a firework */
.csr.is-live .csr-go.is-cue::after{content:"";position:absolute;inset:-4px;border-radius:inherit;
  border:2px solid var(--violet);animation:csr-ring 2.6s var(--ease) infinite}

/* generating */
.csr-view--gen{align-content:center;justify-items:center;min-height:13rem}
.csr-gen{width:min(32rem,100%);background:var(--card);border-radius:var(--r-md);box-shadow:var(--lift);
  padding:1.1rem 1.3rem;display:grid;gap:.8rem}
.csr-gen__h{display:flex;align-items:center;gap:.6rem}
.csr-gen__h b{font-family:var(--display);font-weight:800;font-size:1rem}
.csr-gen__h i{margin-left:auto;font-style:normal;font-weight:700;font-size:.76rem;color:var(--soft);
  font-variant-numeric:tabular-nums}
.csr-gen__spin{width:1.9rem;height:1.9rem;flex:none;border-radius:50%;background:var(--violet);color:#fff;
  display:grid;place-items:center;font-size:.95rem;animation:csr-spin 3s linear infinite}
.csr-gen__phases{list-style:none;padding:0;display:grid;gap:.4rem}
.csr-gen__phases li{display:flex;align-items:center;gap:.55rem;font-size:.83rem;font-weight:700;
  color:var(--soft);opacity:.5;transition:opacity var(--dur) var(--ease),color var(--dur) var(--ease)}
.csr-gen__phases li::before{content:"";width:.8rem;height:.8rem;flex:none;border-radius:50%;
  box-shadow:inset 0 0 0 2px var(--border)}
.csr-gen__phases li.is-doing{opacity:1;color:var(--ink)}
.csr-gen__phases li.is-doing::before{box-shadow:inset 0 0 0 2px var(--violet);animation:csr-pulse 1.1s ease-in-out infinite}
.csr-gen__phases li.is-done{opacity:1}
.csr-gen__phases li.is-done::before{background:var(--lime);box-shadow:none}
.csr-gen__status{font-size:.72rem;font-weight:600;color:var(--soft)}

/* the staged course + the four checkpoints */
.csr-work{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);gap:1rem;align-items:start}
.csr-tree .st-row{font-size:.78rem;padding:.4em .7em}
.csr.is-live .csr-tree .st-row{opacity:0;transform:translateY(5px);
  transition:opacity .28s var(--ease),transform .28s var(--ease)}
.csr.is-live .csr-tree .st-row.is-in{opacity:1;transform:none}
.csr-pane{grid-template-rows:auto minmax(84px,1fr) auto}
.csr-src{display:flex;align-items:center;gap:.35rem;font-size:.68rem;font-weight:700;color:var(--soft)}
.csr-src > span{color:var(--rose);font-size:.85rem;display:grid;place-items:center}
.csr-gates{gap:.55rem}
.csr-gates .gate{padding:.6rem .7rem}
.csr-gates .gate b{font-size:.88rem}
.csr-gates .gate p{font-size:.72rem}
.csr-gates .stamp-ok{font-size:.7rem;padding:.25em .8em}
.csr.is-live .csr-gates .gate{opacity:.45;transition:opacity .3s var(--ease)}
.csr.is-live .csr-gates .gate.is-in{opacity:1}
.csr.is-live .csr-gates .stamp-ok{opacity:0;transform:scale(.7);
  transition:opacity .25s var(--ease),transform .25s var(--ease)}
.csr.is-live .csr-gates .gate.is-stamped .stamp-ok{opacity:1;transform:none}
.csr-applied{display:flex;align-items:center;gap:.5rem;font-family:var(--display);font-weight:800;
  font-size:.86rem;background:color-mix(in oklch,var(--lime) 20%,var(--card));color:var(--lime-ink);
  border-radius:var(--r-pill);padding:.5em 1em;justify-self:start}
.csr-applied__ok{display:grid;place-items:center;width:1.2rem;height:1.2rem;flex:none;border-radius:50%;
  background:var(--lime);color:var(--lime-ink);font-size:.65rem}

/* ---- act two · the student's lesson --------------------------------------
   The runtime's own layout: a fixed bar with the exit, the narration control,
   the progress track and the points chip; the section card; a footer with Back
   and Continue. Warm paper, because this is not the teacher's screen. */
.csr-act--lesson{background:var(--csr-paper)}
.csr-lbar{display:flex;align-items:center;gap:.6rem;padding:.55rem .9rem;
  border-bottom:1px solid color-mix(in oklch,var(--ink) 7%,transparent)}
.csr-lbar__x,.csr-lbar__snd{display:grid;place-items:center;width:1.8rem;height:1.8rem;flex:none;
  border-radius:9px;color:var(--soft);font-size:.9rem}
.csr-lbar__snd{background:var(--card);color:var(--violet-deep);box-shadow:var(--lift)}
.csr-lbar__snd.is-on{background:var(--violet);color:#fff;animation:csr-pulse 1.4s ease-in-out infinite}
.csr-lprog{flex:1;height:.7rem;border-radius:var(--r-pill);background:var(--fill-soft);overflow:hidden;
  box-shadow:inset 0 1px 2px color-mix(in oklch,var(--ink) 9%,transparent)}
.csr-lprog i{display:block;height:100%;width:var(--p,0%);border-radius:var(--r-pill);background:var(--lime);
  transition:width .5s var(--ease)}
.csr-lpts{display:inline-flex;align-items:center;gap:.3rem;flex:none;font-size:.78rem;
  border-radius:var(--r-pill);padding:.3em .8em;background:var(--fill-soft);color:var(--soft);
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease)}
.csr-lpts b{font-family:var(--display);font-weight:800;font-variant-numeric:tabular-nums}
.csr-lpts.is-hit{background:var(--rose);color:#fff}

.csr-lbody{padding:clamp(.8rem,2vw,1.3rem);display:grid;gap:.7rem;align-content:start;min-height:0}
.csr-adapt{display:flex;align-items:flex-start;gap:.5rem;font-size:.74rem;font-weight:700;
  background:color-mix(in oklch,var(--cyan) 20%,var(--card));color:var(--cyan-ink);
  border-radius:var(--r-md);padding:.5rem .75rem;line-height:1.4}
.csr-adapt > span{font-size:1rem;flex:none;display:grid;place-items:center;margin-top:.05em}
.csr-card{background:var(--card);border-radius:var(--r-md);box-shadow:var(--lift);
  padding:clamp(.9rem,2vw,1.4rem);display:grid;gap:.7rem;justify-items:center;text-align:center}
.csr-narr{display:flex;align-items:center;gap:.55rem;font-size:.75rem;font-weight:600;color:var(--soft);
  background:var(--fill-soft);border-radius:var(--r-pill);padding:.35rem .9rem .35rem .4rem;
  text-align:start;max-width:100%}
.csr-narr__face{width:1.7rem;height:1.7rem;flex:none;border-radius:50%;background:var(--violet);
  fill:#fff;stroke:#fff;padding:.15rem}
.csr-q{font-family:var(--display);font-weight:800;font-size:clamp(1rem,2vw,1.35rem);line-height:1.15}
.csr-choices{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.5rem;width:min(30rem,100%)}
.csr-choice{padding:.6em .8em;font-size:.82rem}
.csr-choice .tb-choice__label{font-size:.82rem}
.csr-choice .tb-choice-radio{width:1.15em;height:1.15em;border-width:2px}
.csr-choice:hover{transform:none}
.csr-choice.is-picked{border-color:var(--violet);background:var(--fill-soft)}
.csr-choice.is-picked .tb-choice-radio{border-color:var(--violet);background:var(--violet)}
.csr-choice.is-picked .tb-choice-radio::after{opacity:1}
.csr-choice.is-right{border-color:var(--lime);background:oklch(94% 0.08 130)}
.csr-choice.is-right .tb-choice-radio{border-color:var(--lime);background:var(--lime)}
.csr-choice.is-right .tb-choice-radio::after{opacity:1}
.csr-check{display:inline-flex;align-items:center;gap:.4rem;font-family:var(--display);font-weight:800;
  font-size:.82rem;color:#fff;background:var(--violet);border-radius:var(--r-pill);padding:.5em 1.4em;
  box-shadow:var(--lift);transition:background var(--dur) var(--ease),opacity var(--dur) var(--ease)}
.csr-check.is-off{opacity:.45}
.csr-check.is-hit{background:var(--lime);color:var(--lime-ink)}
.csr-fb{position:relative;width:min(30rem,100%)}
.csr-fb .tb-feedback__icon{font-size:.95rem}
.csr-xp{position:absolute;top:-.7rem;inset-inline-end:-.4rem;font-family:var(--display);font-weight:800;
  font-size:.76rem;background:var(--lime);color:var(--lime-ink);border-radius:var(--r-pill);
  padding:.25em .8em;box-shadow:var(--lift)}
.csr.is-live .csr-xp{opacity:0;transform:scale(.6) translateY(8px);
  transition:opacity .3s var(--ease),transform .35s var(--ease)}
.csr.is-live .csr-xp.is-in{opacity:1;transform:none}

.csr-lfoot{display:flex;align-items:center;gap:.8rem;padding:.6rem .9rem;
  border-top:1px solid color-mix(in oklch,var(--ink) 7%,transparent)}
.csr-lbtn{display:inline-flex;align-items:center;gap:.35rem;font-family:var(--display);font-weight:800;
  font-size:.76rem;border-radius:var(--r-pill);padding:.5em 1.1em}
.csr-lbtn--ghost{background:var(--card);color:var(--soft);box-shadow:var(--lift)}
.csr-lbtn--go{margin-left:auto;background:var(--lime);color:var(--lime-ink);box-shadow:var(--lift);
  transition:filter var(--dur) var(--ease)}
.csr-lbtn--go.is-hit{filter:brightness(1.15)}
.csr-ldots{display:inline-flex;align-items:center;gap:.3rem}
.csr-ldots i{width:.42rem;height:.42rem;border-radius:var(--r-pill);
  background:color-mix(in oklch,var(--ink) 18%,transparent);transition:width var(--dur) var(--ease)}
.csr-ldots i.is-on{width:1rem;background:var(--violet)}

/* ---- act three · what finishing is worth ---------------------------------
   The reward slide the runtime throws on the completion screen, at the shape
   it actually has. Violet, because the real quest slide is. */
.csr-act--done{position:relative;overflow:hidden;
  background:color-mix(in oklch,var(--violet) 10%,var(--card));
  display:grid;place-items:center;padding:clamp(1rem,3vw,2.2rem)}
.csr-confetti{position:absolute;inset:0;pointer-events:none;overflow:hidden}
.csr-confetti i{position:absolute;top:-6%;width:.5rem;height:.75rem;border-radius:2px;opacity:0}
.csr.is-live .csr-confetti i{animation:csr-fall var(--d,2.6s) var(--ease) var(--delay,0s) forwards}
.csr-slide{position:relative;z-index:1;width:min(26rem,100%);text-align:center;
  background:var(--card);border-radius:var(--r-lg);box-shadow:var(--lift);
  padding:clamp(1.1rem,2.6vw,1.8rem);display:grid;justify-items:center;gap:.55rem}
.csr-slide__kick{font-family:var(--display);font-weight:800;font-size:.76rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--violet-deep)}
.csr-slide__disc{position:relative;display:grid;place-items:center;width:5.2rem;height:5.2rem;
  border-radius:50%;background:var(--violet);color:#fff;font-size:2.2rem;margin:.2rem 0;
  box-shadow:var(--lift),0 0 0 6px color-mix(in oklch,var(--violet) 18%,transparent)}
.csr-slide__stamp{position:absolute;right:-.3rem;bottom:-.2rem;display:grid;place-items:center;
  width:1.7rem;height:1.7rem;border-radius:50%;background:var(--lime);color:var(--lime-ink);
  font-size:.8rem;border:3px solid var(--card)}
.csr.is-live .csr-slide__disc{transform:scale(.55);opacity:0;
  transition:transform .45s cubic-bezier(.34,1.56,.64,1),opacity .3s var(--ease)}
.csr.is-live .csr-act--done.is-pop .csr-slide__disc{transform:none;opacity:1}
.csr-slide__t{font-family:var(--display);font-weight:800;font-size:clamp(1.3rem,3vw,1.9rem);line-height:1.1}
.csr-slide__s{color:var(--soft);font-weight:600;font-size:.84rem;line-height:1.45;max-width:32ch}
.csr-slide__xp{display:inline-flex;align-items:center;gap:.4rem;font-family:var(--display);font-weight:800;
  font-size:.95rem;background:var(--lime);color:var(--lime-ink);border-radius:var(--r-pill);
  padding:.4em 1.1em;margin-top:.2rem}
.csr-slide__dots{display:inline-flex;align-items:center;gap:.3rem;margin-top:.3rem}
.csr-slide__dots i{width:.42rem;height:.42rem;border-radius:var(--r-pill);
  background:color-mix(in oklch,var(--ink) 16%,transparent)}
.csr-slide__dots i.is-on{width:1.1rem;background:var(--violet)}
.csr-slide__go{font-family:var(--display);font-weight:800;font-size:.82rem;color:var(--violet-deep)}

/* ---- the caption under the frame ----------------------------------------- */
.csr-foot{display:flex;align-items:baseline;gap:1rem;flex-wrap:wrap;margin-top:.9rem}
.csr-cap{flex:1 1 24rem;color:var(--soft);font-weight:600;font-size:.92rem;line-height:1.5;max-width:62ch}
.csr-replay{flex:none}

/* ---- the one-take frame (JS only) ---------------------------------------- */
@media (min-width:1000px){
  .csr.is-live:not(.is-pinned) .csr-screen{aspect-ratio:16/9}
  /* A cut, not a dissolve — whether an act is on screen must never depend on a
     transition reaching its end state. Which act is on is carried by [hidden]
     alone, so the renderer has exactly one switch to set. */
  .csr.is-live .csr-act{position:absolute;inset:0;border:0;
    display:grid;grid-template-rows:auto minmax(0,1fr) auto}
  .csr.is-live .csr-act--done{grid-template-rows:minmax(0,1fr)}
  .csr.is-live .csr-stage{overflow:hidden}
}
@media (max-width:999px){
  .csr.is-live .csr-act + .csr-act{border-top:0}
}

/* The spine sits outside the TV, so it reflows normally. Inside the TV the fit
   stage takes over (see FIT STAGE); these are the no-JS fallback. */
@media (max-width:900px){
  .fitstage:not(.is-fit) .csr-fields{grid-template-columns:repeat(2,minmax(0,1fr))}
  .fitstage:not(.is-fit) .csr-work{grid-template-columns:minmax(0,1fr)}
}
@media (max-width:560px){
  .fitstage:not(.is-fit) :is(.csr-fields,.csr-choices){grid-template-columns:minmax(0,1fr)}
  .fitstage:not(.is-fit) .csr-rail li span{display:none}
  .fitstage:not(.is-fit) .csr-modal__foot{gap:.5rem}
  .fitstage:not(.is-fit) .csr-hint{display:none}
  .fitstage:not(.is-fit) .csr-go{margin-left:0;width:100%;justify-content:center}
  .csr-step{padding:.55rem 0;gap:.7rem}
  .csr-step em{font-size:.72rem}
}

@keyframes csr-blink{0%,100%{opacity:1}50%{opacity:0}}
@keyframes csr-spin{to{rotate:360deg}}
@keyframes csr-pulse{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(.72);opacity:.55}}
@keyframes csr-ring{0%{opacity:.55;transform:scale(1)}70%,100%{opacity:0;transform:scale(1.22)}}
@keyframes csr-fall{
  0%{opacity:0;transform:translateY(0) rotate(0)}
  12%{opacity:1}
  100%{opacity:0;transform:translateY(115%) translateX(var(--x,0)) rotate(var(--r,540deg))}
}

@media (prefers-reduced-motion:reduce){
  .csr *,.csr *::before,.csr *::after{animation:none !important;transition-duration:.01ms !important}
  .csr-caret{display:none !important}
  .csr-confetti{display:none}
  .csr-steps-spine__fill{transition:none}
}

/* the leg that closes the ring, in words */
.cs-close{margin-top:var(--space-6);padding-top:var(--space-5);border-top:2px dashed var(--border-dash);
  display:flex;flex-wrap:wrap;gap:1rem 2rem;align-items:center;justify-content:space-between}
.cs-close p{font-family:var(--display);font-weight:800;line-height:1.2;
  font-size:clamp(1.05rem,2.2vw,1.4rem);max-width:34ch}

/* ==========================================================================
   WHAT IT WILL AND WON'T DO — the proof layer.
   Not a systems disclosure and not a disclaimer: four paired stipulations
   (kept promise | hard refusal) about behaviour in a classroom. Solid = a
   promise the product keeps; dashed = something it refuses — the same
   solid/dashed vocabulary the board uses for a real card versus a ghost.
   A page that names its own limits is the kind a head of department forwards.
   ========================================================================== */
.proof{padding:var(--space-8) 0;overflow-x:clip}
.proof-head{text-align:center;margin-bottom:var(--space-5)}
.proof-head h2{font-size:var(--t-chapter)}
.proof-head .line{margin:1rem auto 0}

.proof-pairs{display:grid;gap:0;max-width:56rem;margin-inline:auto}
.proof-pairs__head,
.proof-pair{display:grid;grid-template-columns:1fr 1fr;gap:.75rem;align-items:stretch}
.proof-pairs__head{margin-bottom:.55rem;padding:0 .15rem}
.proof-pairs__lbl{font-family:var(--display);font-weight:800;font-size:.92rem;letter-spacing:-.01em}
.proof-pairs__lbl--yes{color:var(--lime-ink)}
.proof-pairs__lbl--no{color:var(--soft)}

.proof-pair{padding:.55rem 0}
/* header is child 1; tint every other pair (children 3 and 5) for row rhythm */
.proof-pair:nth-child(odd) .proof-clause--yes{background:color-mix(in oklch, var(--fill-soft) 55%, var(--card))}

.proof-clause{margin:0;padding:clamp(1rem,2.2vw,1.25rem) clamp(1.05rem,2.4vw,1.4rem);
  border-radius:var(--r-md);font-weight:600;font-size:.98rem;line-height:1.45;color:var(--ink);
  display:grid;align-content:center;min-height:100%;transition:box-shadow .25s cubic-bezier(.16,1,.3,1)}
.proof-clause--yes{background:var(--card);box-shadow:var(--lift)}
.proof-clause--no{background:transparent;box-shadow:none;border:2px dashed var(--border-dash)}
/* Shadow only — transform is owned by the scroll scrub in toybox-entry.js */
@media (hover:hover) and (pointer:fine){
  .proof-pair:hover .proof-clause--yes{
    box-shadow:0 4px 8px rgb(40 20 80/.08),0 16px 36px -8px rgb(40 20 80/.2),0 36px 72px -24px rgb(40 20 80/.26)}
}

/* /for-it/ still uses .proof-list for its limits block */
.proof-list{list-style:none;padding:0;display:grid;gap:1rem}
.proof-list li{color:var(--ink);font-weight:600;font-size:.98rem;line-height:1.5;
  padding-left:1.5rem;position:relative}
.proof-list li::before{content:"";position:absolute;left:0;top:.55em;width:.6rem;height:.6rem;
  border-radius:3px;background:var(--lime)}

/* the section's real work: the sentence that says what is not ready yet */
.proof-say{margin-top:var(--space-6);padding-top:var(--space-5);
  border-top:2px dashed var(--border-dash);
  font-family:var(--display);font-weight:800;font-size:clamp(1rem,1.9vw,1.2rem);line-height:1.4;
  text-align:center;max-width:70ch;margin-inline:auto}
.proof-say span{display:block;font-family:var(--body);font-weight:600;font-size:.9rem;
  color:var(--soft);margin-top:.5rem;line-height:1.5}

@media (max-width:767px){
  .proof-pairs__head,
  .proof-pair{grid-template-columns:1fr;gap:.55rem}
  .proof-pairs__head{display:none} /* per-clause data-lbl takes over */
  .proof-clause::before{content:attr(data-lbl);display:block;font-family:var(--display);
    font-weight:800;font-size:.78rem;letter-spacing:-.01em;margin-bottom:.35rem}
  .proof-clause--yes::before{color:var(--lime-ink)}
  .proof-clause--no::before{color:var(--soft)}
  .proof-pair:nth-child(odd) .proof-clause--yes{background:var(--card)}
}

@media (prefers-reduced-motion:reduce){
  .proof-clause{transition:none}
}

/* ==========================================================================
   WHO IT'S FOR + FAQ — the last objections, cleared.
   Three audiences, three different doors, and six questions every school asks.
   The disclosures are <details> because the answers must be readable with no
   script at all, like every other scene here.
   ========================================================================== */
.audience{padding:var(--space-8) 0}
.audience-head{text-align:center;margin-bottom:var(--space-5)}
.audience-head h2{font-size:var(--t-chapter)}
.audience-head .line{margin:1rem auto 0}
.who-grid{list-style:none;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1.2rem}
.who-card{--k:var(--violet);display:grid;gap:.5rem;align-content:start;height:100%;
  background:var(--card);border-radius:var(--r-lg);box-shadow:var(--lift);
  padding:1.4rem 1.4rem 1.5rem}
.who-card--dept{--k:var(--cyan)}
.who-card--it{--k:var(--lime)}
.who-card__who{justify-self:start;font-family:var(--display);font-weight:800;font-size:.72rem;
  letter-spacing:.08em;text-transform:uppercase;border-radius:var(--r-pill);padding:.32em .9em;
  background:color-mix(in oklch, var(--k) 32%, var(--card));color:var(--ink)}
.who-card p{font-family:var(--display);font-weight:800;font-size:1.12rem;line-height:1.25;margin-top:.2rem}
.who-card a{margin-top:auto;padding-top:.6rem;justify-self:start;font-weight:700;font-size:.9rem;
  color:var(--violet-deep);text-decoration:none}
.who-card a:hover{text-decoration:underline}
.who-card a:focus-visible{outline:none;box-shadow:var(--ring-strong);border-radius:6px}

.faq{margin-top:var(--space-6);max-width:74ch;margin-inline:auto}
.faq h3{font-size:var(--t-panel);text-align:center;margin-bottom:1.4rem}
.faq details{border-top:2px dashed var(--border-dash)}
.faq details:last-of-type{border-bottom:2px dashed var(--border-dash)}
.faq summary{list-style:none;cursor:pointer;display:flex;align-items:baseline;gap:1rem;
  padding:.9rem .4rem;font-family:var(--display);font-weight:800;font-size:1.02rem;line-height:1.3;
  border-radius:var(--r-sm);transition:background var(--dur) var(--ease)}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{background:var(--hover)}
.faq summary:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.faq summary::after{content:"+";margin-inline-start:auto;flex:none;color:var(--violet);
  font-size:1.3rem;line-height:1;transition:rotate var(--dur) var(--ease)}
.faq details[open] summary::after{rotate:45deg}
.faq details > p{padding:0 .4rem 1rem;color:var(--soft);font-weight:600;font-size:.98rem;line-height:1.6}
.faq details > p a{color:var(--violet-deep);font-weight:700}

@media (max-width:880px){
  .who-grid{grid-template-columns:1fr}
}

/* finale — booking destination: run-of-show, then one form */
.finale{padding:var(--space-10) 0 var(--space-8);text-align:start;position:relative;overflow:hidden;
  padding-bottom:max(var(--space-8), env(safe-area-inset-bottom) + var(--space-6));
  scroll-margin-top:7.5rem;
  background:
    radial-gradient(ellipse 70% 55% at 12% 18%, color-mix(in oklch, var(--tang) 14%, transparent), transparent 62%),
    radial-gradient(ellipse 55% 45% at 92% 72%, color-mix(in oklch, var(--lime) 12%, transparent), transparent 58%)}
.finale-inner{position:relative;z-index:2;max-width:760px;margin-inline:auto}
.finale-head{max-width:36ch}
.finale-head h2{font-size:var(--t-chapter);line-height:1.12}
.finale-head .line{margin:1rem 0 0;max-width:42ch;color:var(--soft);font-weight:600;line-height:1.45}
.confetti{position:absolute;width:14px;height:14px;border-radius:4px;top:-20px;pointer-events:none}

/* Call arc as time markers — not three equal feature cards.
   Pills sit on column centers so the connector (::before) threads them evenly. */
.finale-run{list-style:none;padding:0;margin:var(--space-6) 0 0;
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0 1.25rem;
  position:relative}
.finale-run::before{content:"";position:absolute;left:calc(100% / 6);right:calc(100% / 6);
  top:calc(.28 * .78rem + .39rem + 1px);height:2px;background:var(--border);border-radius:2px;pointer-events:none}
.finale-run li{display:grid;gap:.55rem;justify-items:center;text-align:center;
  position:relative;z-index:1;min-width:0;padding:0}
.finale-run__t{font-family:var(--display);font-weight:800;font-size:.78rem;letter-spacing:.02em;
  color:var(--tang-deep);background:var(--card);border:2px solid color-mix(in oklch, var(--tang) 35%, var(--border));
  border-radius:var(--r-pill);padding:.28em .7em;line-height:1;
  position:relative;z-index:1}
.finale-run__body{display:grid;gap:.2rem;width:100%;max-width:22ch}
.finale-run__body b{display:block;font-family:var(--display);font-weight:800;font-size:1.05rem;
  color:var(--ink);line-height:1.2}
.finale-run__body em{font-style:normal;display:block;color:var(--soft);font-weight:600;
  font-size:.88rem;line-height:1.4}
/* Sit under step 1: left edge matches the centered 22ch body in column 1. */
.finale-run__note{margin:.9rem 0 0;color:var(--soft);font-weight:600;font-size:.84rem;line-height:1.4;
  margin-inline-start:max(0px, calc(100% / 6 - 11ch))}

.finale-form{position:relative;z-index:2;margin-top:var(--space-6)}
.finale-form .tb-form{margin-top:0;transition:box-shadow .5s var(--ease)}
.finale-form.is-landed .tb-form{box-shadow:0 18px 48px color-mix(in oklch, var(--ink) 10%, transparent)}
.finale-form .tb-form h3{text-align:start}
.finale-form .tb-form .chip-btn{justify-self:start}
.finale-form .tb-form-note{text-align:start}
.finale-run.is-done .finale-run__t{background:var(--lime);border-color:var(--lime);color:var(--lime-ink)}

.finale-alt{margin:1.8rem 0 0;position:relative;z-index:2}
.finale-alt__label{display:block;color:var(--soft);font-weight:700;font-size:.82rem;margin-bottom:.55rem}
.finale-alt__links{display:flex;flex-wrap:wrap;gap:.35rem 1.25rem}
.finale-alt__links a{color:var(--ink);font-weight:700;font-size:.92rem;text-decoration:underline;
  text-underline-offset:.18em;text-decoration-thickness:2px;text-decoration-color:color-mix(in oklch, var(--ink) 28%, transparent)}
.finale-alt__links a:hover{text-decoration-color:var(--tang);color:var(--tang-deep)}
.finale-alt__links a:focus-visible{outline:none;box-shadow:var(--ring-strong);border-radius:4px}

@media (max-width:720px){
  .finale-run{grid-template-columns:1fr;gap:1rem}
  .finale-run::before{left:.55rem;right:auto;top:.4rem;bottom:.4rem;width:2px;height:auto}
  .finale-run li{grid-template-columns:auto 1fr;gap:.75rem .9rem;align-items:start;
    justify-items:start;text-align:start;padding:0}
  .finale-run__t{grid-row:1 / span 2}
  .finale-run__body{grid-column:2;max-width:none}
  .finale-run__note{margin-inline-start:0}
}

/* demo request form (htmx partial) */
.tb-form{padding:1.8rem;margin-top:1.6rem;text-align:left}
.tb-form h3{font-size:1.5rem;margin-bottom:1.1rem;text-align:center}
.tb-form form{display:grid;gap:.9rem}
.tb-form label{display:grid;gap:.35rem;font-weight:700;font-size:.88rem;color:var(--soft)}
.tb-form input, .tb-form textarea{
  font:inherit;font-weight:600;color:var(--ink);width:100%;
  background:var(--surface-sunk);border:2px solid var(--border);border-radius:14px;
  padding:.65em .9em;outline:none;transition:border-color .15s, box-shadow .15s;
}
.tb-form input:focus, .tb-form textarea:focus{border-color:var(--violet);box-shadow:var(--ring)}
.tb-form textarea{min-height:96px;resize:vertical}
.tb-form-row{display:grid;grid-template-columns:1fr 1fr;gap:.9rem}
.tb-form .chip-btn{justify-self:center;margin-top:.4rem}
.tb-form .chip-btn[disabled]{opacity:.7;cursor:wait;translate:0 0}
/* what happens after they press it — expectation-setting belongs next to the
   button, not two screens away */
.tb-form-note{text-align:center;color:var(--soft);font-weight:600;font-size:.82rem;line-height:1.45}
.tb-form--success{text-align:center;display:grid;gap:.5rem;justify-items:center}
.tb-form--success .tb-form-check{width:56px;height:56px;display:grid;place-items:center;border-radius:50%;
  background:var(--lime);color:var(--lime-ink);font-size:1.8rem;font-weight:800}
.tb-form--success p{color:var(--soft);font-weight:600}
@media (max-width:560px){ .tb-form-row{grid-template-columns:1fr} }

/* ==========================================================================
   FOOTER. Was one line — "© 2026 teloriva · Blog" — on a page selling into
   schools. It is now the place the inventory, the technical page and the
   language switch are reachable from, plus the honest note about what is not
   published yet. Every link here points at something that exists.
   ========================================================================== */
.tb-foot{background:var(--fill-soft);padding:var(--space-8) 0 var(--space-6);
  color:var(--soft);font-weight:600;font-size:.9rem;margin-top:var(--space-6)}
.tb-foot a{color:inherit;text-decoration:none}
.tb-foot a:hover{color:var(--ink);text-decoration:underline}
.tb-foot a:focus-visible{outline:none;box-shadow:var(--ring-strong);border-radius:6px}
.foot-grid{display:grid;grid-template-columns:minmax(0,1.4fr) repeat(3,minmax(0,1fr));
  gap:2rem clamp(1.4rem,3vw,2.6rem);align-items:start}
.foot-brand{display:grid;gap:.9rem;justify-items:start}
.foot-brand img{height:24px;width:auto;display:block}
.foot-brand p{max-width:32ch;line-height:1.55}
.foot-col{display:grid;gap:.6rem;align-content:start}
.foot-col h2{font-family:var(--display);font-weight:800;font-size:.74rem;letter-spacing:.09em;
  text-transform:uppercase;color:var(--ink);line-height:1.2}
.foot-col ul{list-style:none;padding:0;display:grid;gap:.5rem}
.foot-bar{margin-top:var(--space-6);padding-top:1.2rem;border-top:2px dashed var(--border-dash);
  display:flex;flex-wrap:wrap;gap:.6rem 1.6rem;align-items:baseline;justify-content:space-between;
  font-size:.84rem}
.foot-note{max-width:62ch;line-height:1.5}
@media (max-width:880px){
  .foot-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .foot-brand{grid-column:1/-1}
}
@media (max-width:520px){
  .foot-grid{grid-template-columns:1fr}
}

/* ==========================================================================
   TEACHER DESK (panel D) — a collage of the desk's real screens: the
   dashboard, the mastery heatmap, an intervention queue you can actually
   clear, and a filled-in assignment. The queue buttons work: promoting or
   dismissing writes a line to the audit note underneath, which is what the
   real screen does.
   ========================================================================== */
.stat-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:.7rem}
.stat-tile{background:var(--fill-soft);border-radius:var(--r-md);padding:.9rem .7rem;text-align:center;
  display:grid;gap:.15rem;align-content:center}
.stat-tile b{font-family:var(--display);font-weight:800;font-size:clamp(1.3rem,2.4vw,1.6rem);color:var(--violet-deep)}
.stat-tile span{font-weight:700;font-size:.76rem;color:var(--soft);line-height:1.3}

.heat{display:grid;gap:.3rem}
.heat-head,.heat-row{display:grid;grid-template-columns:5.4rem repeat(5,minmax(0,1fr));gap:.3rem;align-items:center}
.heat-head span{font-weight:700;font-size:.7rem;color:var(--soft);text-align:center}
.heat-who{font-weight:700;font-size:.82rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.heat-row i{--m:0;height:1.9rem;border-radius:8px;
  background:color-mix(in oklch, var(--violet) calc(var(--m) * 100%), var(--fill-soft))}
.heat-row i[data-heat-cue].is-cue{outline:2px solid var(--cyan);outline-offset:2px}
.heat-key{display:flex;align-items:center;gap:.7rem;font-weight:700;font-size:.74rem;color:var(--soft)}
.heat-ramp{flex:1;height:.55rem;border-radius:4px;background:linear-gradient(90deg,var(--fill-soft),var(--violet))}

.queue{list-style:none;padding:0;display:grid;gap:.55rem;margin:0}
.qrow{display:flex;gap:1rem;align-items:center;justify-content:space-between;flex-wrap:wrap;
  background:var(--card);border-radius:var(--r-md);padding:.85rem 1rem;
  box-shadow:0 1px 0 color-mix(in oklch, var(--ink) 6%, transparent);
  transition:opacity var(--dur) var(--ease), transform var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease);opacity:1}
.qrow.is-cleared{opacity:0;transform:translateX(1.5rem);pointer-events:none}
.qrow__what{min-width:0;flex:1 1 12rem}
.qrow__what b{display:block;font-family:var(--display);font-weight:800;font-size:.95rem;color:var(--ink)}
.qrow__what span{color:var(--soft);font-weight:600;font-size:.82rem;line-height:1.4}
.qrow__acts{display:flex;gap:.4rem;flex:none}
.qbtn{font-family:var(--body);font-weight:700;font-size:.78rem;border:0;cursor:pointer;
  border-radius:var(--r-pill);padding:.45em 1.05em;background:var(--fill-soft);color:var(--soft);
  box-shadow:none;border:1.5px solid var(--border);transition:color var(--dur) var(--ease),
    background-color var(--dur) var(--ease),transform var(--dur) var(--ease),border-color var(--dur) var(--ease)}
.qbtn:hover{color:var(--ink);border-color:color-mix(in oklch, var(--ink) 22%, var(--border))}
.qbtn:active{transform:translateY(1px)}
.qbtn:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.qbtn--go{background:var(--violet);color:#fff;border-color:transparent}
.qbtn--go:hover{background:var(--violet-deep);color:#fff;border-color:transparent}
.q-audit{color:var(--soft);font-weight:600;font-size:.84rem;line-height:1.45;margin:0}
.q-audit.is-done{color:var(--lime-ink);font-weight:700}
.q-reset{justify-self:start}

/* --- the desk as a causal sticky-stack ------------------------------------
   Seat two used to be a four-tile collage (equal white windows). The ring's
   claim is a return, so the desk is now one student through four beats:
   risk → pale heat cell → promote/dismiss → assignment. Each beat is a
   full-viewport moment; GSAP pins them on wide viewports. Captions stay
   outside the device (claim → proof), keyed cyan like the read seat.
   Mocks still live only inside .tb-device. -------------------------------- */
.desk-stack{position:relative;margin-top:1.4rem}
.desk-beat{position:relative;min-height:100dvh;display:flex;align-items:center;
  padding:clamp(2rem,6vh,4rem) 0;will-change:transform;transform-origin:center top;
  background:var(--bg);isolation:isolate}
.desk-beat__in{width:100%;max-width:42rem;margin-inline:auto;display:grid;gap:1rem;
  position:relative;z-index:1}
.desk-caption{margin:0;max-width:42ch;padding:.35rem .2rem .35rem .85rem;
  border-inline-start:3px solid var(--cyan);color:var(--soft);font-weight:600;
  font-size:.9rem;line-height:1.45;background:var(--bg);position:relative;z-index:2}
.desk-caption b{color:var(--ink);font-weight:800}
.desk-sprite{position:absolute;width:0;height:0}
.desk-ico{display:grid;place-items:center;width:1.5rem;height:1.5rem;border-radius:7px;
  background:var(--violet);color:#fff;flex:none}
.desk-ico svg{width:.95rem;height:.95rem}
.desk-win--mastery .desk-ico{background:var(--cyan);color:var(--cyan-ink)}
.desk-win--queue .desk-ico{background:var(--rose)}
.desk-win--assign .desk-ico{background:var(--tang)}
.desk-win{background:var(--card)}
.desk-screen{padding:1.1rem;display:flex;flex-direction:column;gap:1rem;overflow:visible}
.desk-screen > .mock-bar,
.desk-screen > .mock-lbl{position:relative;z-index:1;background:inherit}

/* per-beat surface tints so the stack is not four cream cards */
.desk-beat--risk .desk-screen{
  background:color-mix(in oklch, var(--fill-soft) 70%, oklch(94% 0.03 250))}
.desk-beat--mastery .desk-screen{
  background:color-mix(in oklch, var(--bg) 55%, oklch(93% 0.04 220))}
.desk-beat--queue .desk-screen{
  background:color-mix(in oklch, var(--bg) 60%, oklch(95% 0.035 15))}
.desk-beat--assign .desk-screen{
  background:color-mix(in oklch, var(--bg) 55%, oklch(95% 0.04 70))}

/* beat 1: one student risk strip */
.risk-strip{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:.8rem 1.2rem;background:var(--card);border-radius:var(--r-md);padding:1rem 1.1rem;
  box-shadow:var(--lift)}
.risk-strip__who{display:grid;gap:.2rem;min-width:0}
.risk-strip__who b{font-family:var(--display);font-weight:800;font-size:1.15rem;color:var(--ink)}
.risk-strip__who span{font-weight:700;font-size:.78rem;color:var(--soft)}
.risk-strip__tags{display:flex;flex-wrap:wrap;gap:.4rem}

/* thread continuity across beats */
.heat-row.is-thread .heat-who{color:var(--cyan-ink);font-weight:800}
.qrow.is-thread{box-shadow:inset 3px 0 0 var(--cyan);background:var(--card)}
.desk-thread-chip.is-awaiting{opacity:0;transform:translateY(.4rem)}
.desk-thread-chip.is-in{opacity:1;transform:none;
  outline:2px solid var(--cyan);outline-offset:2px;
  transition:opacity .35s var(--ease), transform .35s var(--ease), outline-color .35s var(--ease)}

.dform{display:grid;gap:.7rem}
.dform-row{display:grid;gap:.3rem}
.dform-row--split{grid-template-columns:1fr 1fr;gap:1rem}
.dform-field{display:grid;gap:.3rem;min-width:0}
.dform-lbl{font-weight:700;font-size:.68rem;text-transform:uppercase;letter-spacing:.04em;color:var(--soft)}
.dform-val{background:var(--fill-soft);border-radius:var(--r-sm);padding:.5em .8em;font-weight:700;
  font-size:.88rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.dstudents{display:flex;flex-wrap:wrap;align-items:center;gap:.4rem}
.dstudents__more{font-weight:700;font-size:.78rem;color:var(--soft)}

.dform-go{margin-top:.1rem;justify-self:start;pointer-events:none}

/* ==========================================================================
   /for-it/ — where the homepage's inventory went.
   One audience, and it is the opposite of the homepage's: this reader wants
   the numbers and the algorithm names, so the page gives them plainly and
   quietly. No product mocks, no theater — a specification sheet.
   ========================================================================== */
.spec-block{padding-top:var(--space-8);margin-top:var(--space-6);border-top:2px dashed var(--border-dash)}
.spec-block > h2{font-size:var(--t-panel);margin-bottom:.7rem}
.spec-block > .line{margin-bottom:var(--space-5)}
.spec-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:1.2rem;margin:0}
.spec-grid > div{background:var(--card);border-radius:var(--r-lg);box-shadow:var(--lift);
  padding:1.4rem;display:grid;gap:.5rem;align-content:start}
.spec-grid dt{font-family:var(--display);font-weight:800;font-size:2.6rem;line-height:1;
  color:var(--violet);font-variant-numeric:tabular-nums}
.spec-grid dd{margin:0;color:var(--soft);font-weight:600;font-size:.94rem;line-height:1.5}
.spec-list{display:grid;grid-template-columns:repeat(auto-fit,minmax(21rem,1fr));
  gap:0 clamp(1.6rem,4vw,3.4rem);margin:0}
.spec-list > div{padding:1.15rem 0;border-top:2px dashed var(--border-dash);display:grid;gap:.35rem}
.spec-list dt{font-family:var(--display);font-weight:800;font-size:1.02rem}
.spec-list dd{margin:0;color:var(--soft);font-weight:600;font-size:.94rem;line-height:1.55}
/* the limits use the refused-column marker from the homepage's proof section,
   because they are the same kind of statement */
.proof-list--limits li::before{background:transparent;box-shadow:inset 0 0 0 2px var(--tang)}
.proof-list--limits{max-width:74ch}

/* ==========================================================================
   Blog (index + article) — same toy-box card language
   ========================================================================== */
.tb-page{padding:8rem 0 4rem}
.tb-page-head{text-align:center;margin-bottom:3rem}
.tb-page-head h1{font-size:clamp(2.2rem, 5vw, 3.8rem)}
.tb-page-head .line{margin:1rem auto 0}
.cat-chips{display:flex;gap:.5rem;justify-content:center;flex-wrap:wrap;margin-top:1.4rem}
.cat-chip{font-family:var(--display);font-weight:700;font-size:.82rem;border-radius:999px;padding:.4em 1.1em;box-shadow:var(--lift);background:var(--card)}
.cat-chip:nth-child(5n+1){background:var(--violet);color:white}
.cat-chip:nth-child(5n+2){background:var(--lime);color:var(--lime-ink)}
.cat-chip:nth-child(5n+3){background:var(--tang);color:white}
.cat-chip:nth-child(5n+4){background:var(--cyan);color:var(--cyan-ink)}
.cat-chip:nth-child(5n+5){background:var(--rose);color:white}

.post-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:1.6rem}
.post-hero{width:100%;height:170px;object-fit:cover;border-radius:var(--r-md);display:block}
.post-hero--article{height:auto;max-height:340px;border-radius:var(--r-lg);box-shadow:var(--lift);margin-bottom:1.8rem}
.post-card{padding:1.6rem;display:flex;flex-direction:column;gap:.7rem;text-decoration:none;rotate:var(--r,0deg);transition:rotate .25s, translate .25s}
.post-card:hover{rotate:0deg;translate:0 -6px}
.post-card h2{font-size:1.45rem;line-height:1.15}
.post-card .dek{color:var(--soft);font-weight:600;font-size:.95rem;line-height:1.5}
.post-meta{display:flex;gap:.8em;align-items:center;flex-wrap:wrap;font-size:.8rem;font-weight:700;color:var(--soft);margin-top:auto}
.post-meta .cat-chip{font-size:.72rem;box-shadow:none}
.post-more{font-family:var(--display);font-weight:700;color:var(--violet)}

/* article */
.tb-article{width:min(720px, 92vw);margin-inline:auto;padding-bottom:4rem}
.tb-article-head{text-align:center;margin-bottom:2.5rem}
.tb-article-head h1{font-size:clamp(1.9rem, 4.2vw, 3rem)}
.tb-article-head .post-meta{justify-content:center;margin-top:1.2rem}
.article-body{background:var(--card);border-radius:var(--r-lg);box-shadow:var(--lift);padding:clamp(1.4rem, 4vw, 3rem);font-size:1.05rem;line-height:1.7}
.article-body h2, .article-body h3{font-family:var(--display);margin:1.6em 0 .5em}
.article-body h2{font-size:1.6rem}
.article-body h3{font-size:1.25rem}
.article-body p{margin-block:1em}
.article-body a{color:var(--violet-deep);font-weight:700}
.article-body code{font-size:.9em;background:oklch(95.5% 0.012 var(--ground-h));padding:.12em .4em;border-radius:6px}
.article-body pre{overflow-x:auto;background:oklch(95.5% 0.012 var(--ground-h));padding:1em;border-radius:var(--r-md)}
.article-body pre code{background:none;padding:0}
.article-body blockquote{margin:1.4em 0;padding:1em 1.3em;background:oklch(96% 0.014 var(--ground-h));border-radius:var(--r-md);color:var(--soft);font-weight:600}
.article-body img{max-width:100%;height:auto;border-radius:var(--r-md)}
.article-body ul, .article-body ol{padding-left:1.4em}
.article-body table{display:block;overflow-x:auto;border-collapse:collapse}
.article-body th, .article-body td{border:1px solid oklch(88% 0.015 var(--ground-h));padding:.4em .7em;text-align:left}
.tb-article-nav{display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin-top:2.4rem}

/* ==========================================================================
   Auth (login / signup) — one centered toy-box card on the light field.
   Same card language, tokens and chip button as the rest of the system.
   ========================================================================== */
.tb-auth{min-height:100vh;min-height:100dvh;display:grid;place-items:center;
  padding:6.5rem 1rem 3rem;position:relative;overflow:hidden}

/* decorative floating tiles echoing the hero, kept behind the card */
.auth-toy{position:absolute;z-index:0;width:66px;height:66px;border-radius:var(--r-md);
  box-shadow:var(--lift);display:grid;place-items:center;font-size:1.7rem;background:var(--card);
  animation:auth-bob 6s ease-in-out infinite}
.auth-toy--1{top:15%;left:9%;background:var(--lime);animation-delay:0s}
.auth-toy--2{top:22%;right:11%;background:var(--cyan);animation-delay:.9s}
.auth-toy--3{bottom:16%;left:14%;background:var(--tang);animation-delay:1.6s}
.auth-toy--4{bottom:22%;right:9%;background:var(--rose);animation-delay:.4s}
@keyframes auth-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-12px)}}
@media (max-width:820px){ .auth-toy{display:none} }

.auth-card{width:min(460px, 100%);padding:clamp(1.6rem, 4vw, 2.6rem);
  position:relative;z-index:2;display:grid;gap:1.25rem}
.auth-brand{display:grid;justify-items:center;text-align:center;gap:.55rem}
.auth-brand .mark{width:56px;height:56px;border-radius:var(--r-md);display:grid;place-items:center;
  background:var(--violet);color:#fff;box-shadow:var(--lift)}
.auth-brand .mark svg{width:30px;height:30px;display:block}
.auth-card h1{font-size:clamp(1.7rem, 4vw, 2.2rem)}
.auth-card .line{margin:0 auto;text-align:center;font-size:.98rem;max-width:34ch}

/* language segmented control */
.auth-lang{display:inline-flex;gap:.25rem;padding:.28rem;border-radius:999px;
  background:var(--fill-soft);justify-self:center;flex-wrap:wrap;justify-content:center}
.auth-lang button{font-family:var(--display);font-weight:700;font-size:.82rem;border:0;background:none;
  cursor:pointer;color:var(--soft);padding:.42em 1.05em;border-radius:999px;
  transition:color .15s, background .15s}
.auth-lang button:hover{color:var(--ink)}
.auth-lang button.is-active{background:var(--card);color:var(--violet-deep);box-shadow:var(--lift)}
.auth-lang button:focus-visible{outline:none;box-shadow:var(--ring-strong)}

/* form fields — same input contract as .tb-form */
.auth-form{display:grid;gap:1rem}
.auth-fld{display:grid;gap:.35rem;font-weight:700;font-size:.88rem;color:var(--soft)}
.auth-fld .note{font-weight:600;color:var(--soft);opacity:.85}
.auth-form input:not([type="checkbox"]), .auth-form select{
  font:inherit;font-weight:600;color:var(--ink);width:100%;
  background:var(--surface-sunk);border:2px solid var(--border);border-radius:14px;
  padding:.7em .9em;outline:none;transition:border-color .15s, box-shadow .15s;
}
.auth-form select{appearance:none;-webkit-appearance:none;cursor:pointer;padding-inline-end:2.6em;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%237a7488' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right .9em center}
[dir="rtl"] .auth-form select{background-position:left .9em center}
.auth-form input:focus, .auth-form select:focus{border-color:var(--violet);
  box-shadow:var(--ring)}
.auth-form input::placeholder{color:var(--soft);opacity:.6;font-weight:600}

/* password field + show/hide toggle */
.auth-pw{position:relative}
.auth-pw input{padding-inline-end:2.9em}
.auth-pw-toggle{position:absolute;top:50%;inset-inline-end:.45em;transform:translateY(-50%);
  width:2.1em;height:2.1em;display:grid;place-items:center;border:0;background:none;cursor:pointer;
  color:var(--soft);border-radius:9px;transition:color .15s, background .15s}
.auth-pw-toggle:hover{color:var(--violet-deep);background:var(--hover)}
.auth-pw-toggle:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.auth-pw-toggle svg{width:20px;height:20px;display:block}

.auth-check{display:flex;align-items:center;gap:.55rem;font-weight:600;font-size:.92rem;color:var(--soft);cursor:pointer}
.auth-check input{width:1.15em;height:1.15em;accent-color:var(--violet);cursor:pointer;flex-shrink:0}

.auth-form .chip-btn{width:100%;text-align:center;margin-top:.35rem}
.auth-form .chip-btn[disabled]{opacity:.7;cursor:wait}
.auth-hint{font-size:.8rem;font-weight:600;color:var(--soft);line-height:1.4}
.auth-err{font-size:.82rem;font-weight:700;color:oklch(52% 0.16 10)}

.auth-foot{text-align:center;font-weight:600;color:var(--soft);font-size:.92rem}
.auth-foot a{color:var(--violet-deep);font-weight:700}
.auth-foot a:hover{text-decoration:underline}

/* flash messages */
.auth-msgs{display:grid;gap:.5rem}
.auth-msg{border-radius:14px;padding:.7em 1em;font-weight:700;font-size:.9rem}
.auth-msg--error{background:oklch(94% 0.05 10);color:oklch(48% 0.16 10)}
.auth-msg--warning{background:oklch(94% 0.07 70);color:oklch(44% 0.12 70)}
.auth-msg--success{background:oklch(94% 0.08 130);color:var(--lime-ink)}

@media (prefers-reduced-motion: reduce){
  .auth-toy{animation:none}
}

/* ==========================================================================
   APP COMPONENTS (Phase 2) — data + shell primitives for logged-in pages.
   Built ONLY on Layer-1 tokens. Same toy-box language: light card surface,
   --lift, rounded, no borders except inputs/hairlines, paired -ink on accent
   fills, visible focus rings, RTL via logical properties, reduced-motion safe.
   Class names are the API (mirror of the marketing components above).
   ========================================================================== */

/* --- Status badge: small pill, one accent family per variant --- */
.tb-badge{display:inline-flex;align-items:center;gap:.4em;font-family:var(--display);
  font-weight:700;font-size:.75rem;line-height:1;padding:.4em .8em;border-radius:var(--r-pill);
  background:var(--fill-soft);color:var(--soft)}
.tb-badge--violet{background:var(--violet);color:#fff}
.tb-badge--lime{background:var(--lime);color:var(--lime-ink)}
.tb-badge--tang{background:var(--tang);color:#fff}
.tb-badge--cyan{background:var(--cyan);color:var(--cyan-ink)}
.tb-badge--rose{background:var(--rose);color:#fff}
.tb-badge .dot{width:.5em;height:.5em;border-radius:50%;background:currentColor}

/* --- Form fields (standalone; for app forms outside .tb-form / .auth-form) ---
   Selectors are element+class (not just .tb-input/.tb-select) on purpose: the
   vendored Tailwind runtime bundles the @tailwindcss/forms plugin, which injects
   its own base styles for input[type=...]/select via plain attribute selectors
   AFTER this stylesheet loads. Equal-specificity rules let the later one win, so
   these need the extra element tie-breaker to reliably beat it regardless of
   injection order (see .tbm input[type=...] in edu_management/_base_list.html
   for the same workaround). */
input.tb-input,select.tb-select,textarea.tb-input{font:inherit;font-weight:600;color:var(--ink);width:100%;
  background:var(--surface-sunk);border:2px solid var(--border);border-radius:var(--r-sm);
  padding:.6em .85em;outline:none;transition:border-color var(--dur-fast),box-shadow var(--dur-fast);
  appearance:none;-webkit-appearance:none}
input.tb-input[type="search"]::-webkit-search-decoration,
input.tb-input[type="search"]::-webkit-search-cancel-button,
input.tb-input[type="search"]::-webkit-search-results-button,
input.tb-input[type="search"]::-webkit-search-results-decoration{-webkit-appearance:none}
input.tb-input:focus,select.tb-select:focus,textarea.tb-input:focus{border-color:var(--violet);box-shadow:var(--ring)}
input.tb-input::placeholder,textarea.tb-input::placeholder{color:var(--soft);opacity:.6;font-weight:600}
input.tb-input--sm,select.tb-select--sm{padding:.4em .65em;font-size:.9rem}
select.tb-select{appearance:none;-webkit-appearance:none;cursor:pointer;padding-inline-end:2.4em;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%237a7488' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right .8em center}
[dir="rtl"] .tb-select{background-position:left .8em center}

/* --- Table: card-wrapped, scrolls on overflow, sticky head, row hover --- */
.tb-table-wrap{background:var(--surface);border-radius:var(--r-lg);box-shadow:var(--lift);
  overflow:auto;max-width:100%}
.tb-table{width:100%;border-collapse:collapse;font-weight:600;font-size:.95rem}
.tb-table th,.tb-table td{padding:.85em 1.1em;text-align:start;white-space:nowrap}
.tb-table thead th{position:sticky;top:0;background:var(--surface);z-index:1;
  font-family:var(--display);font-weight:700;font-size:.8rem;letter-spacing:.04em;
  color:var(--soft);border-bottom:2px solid var(--border)}
.tb-table tbody tr+tr td{border-top:1px solid var(--border)}
.tb-table tbody tr:hover td{background:var(--hover)}

/* --- .tb-table--stack: rows become cards below 720px, using each <td>'s
   data-label as the row caption. Add data-label="..." (reuse the column's
   header text, wrapped in {% trans %}) to every <td>; no JS required. --- */
@media (max-width:720px){
  .tb-table--stack thead{display:none}
  .tb-table--stack,.tb-table--stack tbody,.tb-table--stack tr,.tb-table--stack td{display:block;width:100%}
  .tb-table-wrap:has(.tb-table--stack){overflow:visible}
  .tb-table--stack tbody tr{background:var(--surface);border-radius:var(--r-md);box-shadow:var(--lift);
    margin:0 0 .9rem;padding:.3rem .9rem}
  .tb-table--stack tbody tr:hover td{background:none}
  .tb-table--stack td{display:flex;align-items:center;justify-content:space-between;gap:1rem;
    padding:.6em 0;border-top:1px solid var(--border);text-align:end;white-space:normal}
  .tb-table--stack td:first-child{border-top:0}
  .tb-table--stack td::before{content:attr(data-label);font-family:var(--display);font-weight:700;
    font-size:.72rem;letter-spacing:.03em;color:var(--soft);text-align:start;flex-shrink:0}
  .tb-table--stack td:empty::before{content:none}
}

/* --- Tabs: pill tablist on a soft track + panels --- */
.tb-tabs{display:inline-flex;gap:.25rem;padding:.3rem;border-radius:var(--r-pill);
  background:var(--fill-soft);flex-wrap:wrap}
.tb-tabs button,.tb-tabs a{font-family:var(--display);font-weight:700;font-size:.85rem;
  border:0;background:none;cursor:pointer;color:var(--soft);padding:.5em 1.1em;
  border-radius:var(--r-pill);text-decoration:none;
  transition:color var(--dur-fast),background var(--dur-fast)}
.tb-tabs button:hover,.tb-tabs a:hover{color:var(--ink)}
.tb-tabs [aria-selected="true"],.tb-tabs .is-active{background:var(--surface);
  color:var(--violet-deep);box-shadow:var(--lift)}
.tb-tabs button:focus-visible,.tb-tabs a:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.tb-tabpanel{padding-top:1.4rem}

/* --- Dropdown menu: zero-JS via <details>, card popover --- */
.tb-menu{position:relative;display:inline-block}
.tb-menu>summary{list-style:none;cursor:pointer}
.tb-menu>summary::-webkit-details-marker{display:none}
.tb-menu__pop{position:absolute;top:calc(100% + .5rem);inset-inline-start:0;z-index:var(--z-nav);
  min-width:210px;background:var(--surface);border-radius:var(--r-md);box-shadow:var(--lift);
  padding:.5rem;display:grid;gap:.15rem}
.tb-menu[open]>.tb-menu__pop{animation:tb-pop .16s var(--ease)}
.tb-menu__item{display:flex;align-items:center;gap:.6em;font-weight:600;font-size:.92rem;
  text-decoration:none;color:var(--ink);padding:.55em .8em;border-radius:var(--r-sm);
  border:0;background:none;cursor:pointer;width:100%;text-align:start}
.tb-menu__item:hover{background:var(--hover)}
.tb-menu__item:focus-visible{outline:none;box-shadow:var(--ring-strong)}
.tb-menu__sep{height:1px;background:var(--border);margin:.3rem 0}
@keyframes tb-pop{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}

/* --- Selectable option row + checkbox indicator: the shared visual language
   for custom multi-selects / option lists (Alpine, htmx, or plain JS). Toggle
   `.is-selected` from script — never hardcode an accent color per instance. --- */
.tb-opt{display:flex;align-items:center;gap:.7em;font-weight:600;font-size:.92rem;
  color:var(--ink);padding:.55em .8em;border-radius:var(--r-sm);cursor:pointer;
  transition:background var(--dur-fast)}
.tb-opt:hover{background:var(--hover)}
.tb-opt.is-selected{background:var(--fill-soft)}
.tb-check{width:1.25em;height:1.25em;flex-shrink:0;border-radius:6px;border:2px solid var(--border);
  display:grid;place-items:center;transition:background var(--dur-fast),border-color var(--dur-fast)}
.tb-check .material-symbols-outlined{font-size:.9em;color:#fff}
.tb-opt.is-selected .tb-check,.tb-check.is-selected{background:var(--violet);border-color:var(--violet)}

/* --- Dropzone: file drag-and-drop target --- */
.tb-dropzone{border:2px dashed var(--border);border-radius:var(--r-md);background:var(--surface-sunk);
  padding:1.6rem;text-align:center;color:var(--soft);font-weight:600;transition:border-color var(--dur-fast),background var(--dur-fast)}
.tb-dropzone.is-dragover{border-color:var(--violet);background:var(--fill-soft);color:var(--violet-deep)}

/* --- Modal: native <dialog>, card surface, blurred ink backdrop --- */
dialog.tb-modal{border:0;padding:0;background:transparent;max-width:min(520px,92vw);color:var(--ink)}
dialog.tb-modal::backdrop{background:var(--scrim);backdrop-filter:blur(3px)}
.tb-modal__card{background:var(--surface);border-radius:var(--r-lg);box-shadow:var(--lift);
  padding:clamp(1.5rem,4vw,2.2rem);display:grid;gap:1rem}
.tb-modal__head{display:flex;align-items:start;justify-content:space-between;gap:1rem}
.tb-modal__head h3{font-family:var(--display);font-size:1.5rem}
.tb-modal__x{width:2.1em;height:2.1em;display:grid;place-items:center;border:0;cursor:pointer;
  border-radius:var(--r-sm);background:var(--fill-soft);color:var(--soft);font-size:1.1rem;flex-shrink:0}
.tb-modal__x:hover{background:var(--hover);color:var(--ink)}
.tb-modal__foot{display:flex;gap:.6rem;justify-content:flex-end;flex-wrap:wrap;margin-top:.4rem}
dialog.tb-modal[open]{animation:tb-pop .18s var(--ease)}

/* --- Toasts: stacked corner chips, accent icon circle (no side-stripes) --- */
.tb-toasts{position:fixed;inset-block-end:1.2rem;inset-inline-end:1.2rem;z-index:var(--z-toast);
  display:grid;gap:.7rem;max-width:min(360px,92vw)}
.tb-toast{display:flex;align-items:center;gap:.8rem;background:var(--surface);
  border-radius:var(--r-md);box-shadow:var(--lift);padding:.85rem 1rem;font-weight:600}
.tb-toast__ico{width:2em;height:2em;flex-shrink:0;border-radius:50%;display:grid;place-items:center;
  font-weight:800;font-family:var(--display);background:var(--fill-soft);color:var(--soft)}
.tb-toast__body{display:grid;gap:.1rem;font-size:.9rem}
.tb-toast__body b{font-family:var(--display)}
.tb-toast--success .tb-toast__ico{background:var(--lime);color:var(--lime-ink)}
.tb-toast--info .tb-toast__ico{background:var(--cyan);color:var(--cyan-ink)}
.tb-toast--warn .tb-toast__ico{background:var(--tang);color:#fff}
.tb-toast--error .tb-toast__ico{background:var(--rose);color:#fff}

/* --- Sidebar / nav rail for the app shell --- */
.tb-side{background:var(--surface);border-radius:var(--r-lg);box-shadow:var(--lift);
  padding:1rem;display:grid;gap:.2rem;align-content:start;width:min(260px,100%)}
.tb-side__label{font-family:var(--display);font-weight:700;font-size:.72rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--soft);padding:.6rem .8rem .3rem}
.tb-side__item{display:flex;align-items:center;gap:.7em;font-weight:600;font-size:.95rem;
  text-decoration:none;color:var(--ink);padding:.6em .8em;border-radius:var(--r-md);
  transition:background var(--dur-fast)}
.tb-side__item:hover{background:var(--hover)}
.tb-side__item[aria-current]{background:var(--violet);color:#fff}
.tb-side__item .tb-badge{margin-inline-start:auto}
.tb-side__item:focus-visible{outline:none;box-shadow:var(--ring-strong)}

/* --- Pagination --- */
.tb-pager{display:flex;gap:.4rem;align-items:center;flex-wrap:wrap}
.tb-pager a,.tb-pager button{font-family:var(--display);font-weight:700;font-size:.9rem;
  min-width:2.4em;height:2.4em;display:grid;place-items:center;padding:0 .6em;border:0;cursor:pointer;
  border-radius:var(--r-sm);background:var(--surface);box-shadow:var(--lift);color:var(--ink);text-decoration:none}
.tb-pager a:hover,.tb-pager button:hover{color:var(--violet-deep)}
.tb-pager [aria-current="page"]{background:var(--violet);color:#fff}
.tb-pager [aria-disabled="true"],.tb-pager :disabled{opacity:.45;pointer-events:none;box-shadow:none}
.tb-pager a:focus-visible,.tb-pager button:focus-visible{outline:none;box-shadow:var(--ring-strong)}

/* ==========================================================================
   LESSON RUNTIME COMPONENTS
   Shared vocabulary for interactive lesson content (quizzes, puzzles, math
   visuals) rendered inside core/partials/components/. These are included
   INSIDE an already-`.card` wrapper (core/partials/section_fragment.html),
   so partials should not wrap themselves in another `.card`. Buttons use
   the `.lc-cta` variants defined page-locally in lesson_content.html (the
   only host page these partials render into). Class names are the API —
   one definition, reused across every quiz/puzzle template.
   ========================================================================== */

/* --- Choice tile: quiz/puzzle answer option. Toggle state classes from
   Alpine — never hardcode a per-instance accent. --- */
.tb-choice{position:relative;display:flex;align-items:center;justify-content:space-between;gap:.8em;
  width:100%;padding:1em 1.2em;min-height:70px;background:var(--surface);border:2px solid var(--border);
  border-radius:var(--r-md);box-shadow:var(--lift);cursor:pointer;text-align:start;
  transition:border-color var(--dur-fast),background var(--dur-fast),transform var(--dur-fast)}
.tb-choice:hover{transform:translateY(-2px);border-color:var(--violet)}
.tb-choice.is-selected{border-color:var(--violet);background:var(--fill-soft)}
.tb-choice.is-correct{border-color:var(--lime);background:oklch(94% 0.08 130)}
.tb-choice.is-incorrect{border-color:var(--rose);background:oklch(94% 0.05 10)}
.tb-choice.is-disabled{opacity:.6;cursor:not-allowed;transform:none}
.tb-choice.is-disabled:hover{transform:none;border-color:var(--border)}
.tb-choice.is-incorrect.is-disabled{text-decoration:line-through}
.tb-choice__label{flex:1;font-weight:800;color:var(--ink)}

/* --- Choice radio indicator: small circle inside a .tb-choice --- */
.tb-choice-radio{flex-shrink:0;width:1.5em;height:1.5em;border-radius:50%;border:3px solid var(--border);
  background:var(--surface);display:grid;place-items:center;transition:border-color var(--dur-fast),background var(--dur-fast)}
.tb-choice-radio::after{content:"";width:.55em;height:.55em;border-radius:50%;background:#fff;
  opacity:0;transition:opacity var(--dur-fast)}
.tb-choice-radio.is-selected{border-color:var(--violet);background:var(--violet)}
.tb-choice-radio.is-selected::after,.tb-choice-radio.is-correct::after,.tb-choice-radio.is-incorrect::after{opacity:1}
.tb-choice-radio.is-correct{border-color:var(--lime);background:var(--lime)}
.tb-choice-radio.is-incorrect{border-color:var(--rose);background:var(--rose)}

/* --- Choice corner badge: "Correct" / "Your answer" flag on reveal --- */
.tb-choice-badge{position:absolute;top:-.6em;inset-inline-end:-.5em;display:inline-flex;align-items:center;gap:.3em;
  font-family:var(--display);font-weight:700;font-size:.7rem;padding:.35em .7em;border-radius:var(--r-pill);
  color:#fff;box-shadow:var(--lift);border:2px solid var(--card)}
.tb-choice-badge--correct{background:var(--lime);color:var(--lime-ink)}
.tb-choice-badge--incorrect{background:var(--rose)}

/* --- Feedback banner: "Not quite" / "Excellent!" panels under a quiz form --- */
.tb-feedback{border-radius:var(--r-md);padding:1rem 1.2rem;text-align:center}
.tb-feedback__icon{width:2.4rem;height:2.4rem;border-radius:50%;display:grid;place-items:center;margin:0 auto .5rem}
.tb-feedback__title{font-family:var(--display);font-weight:800;font-size:1.1rem;margin-bottom:.2rem}
.tb-feedback__body{color:var(--soft);font-weight:600;font-size:.9rem}
.tb-feedback--success{background:oklch(94% 0.08 130)}
.tb-feedback--success .tb-feedback__icon{background:var(--lime);color:var(--lime-ink)}
.tb-feedback--success .tb-feedback__title{color:var(--lime-ink)}
.tb-feedback--error{background:oklch(94% 0.05 10)}
.tb-feedback--error .tb-feedback__icon{background:var(--rose);color:#fff}
.tb-feedback--error .tb-feedback__title{color:oklch(48% 0.16 10)}
.tb-feedback--warn{background:oklch(94% 0.07 70)}
.tb-feedback--warn .tb-feedback__icon{background:var(--tang);color:#fff}
.tb-feedback--warn .tb-feedback__title{color:oklch(44% 0.12 70)}

/* --- Answer compare box: side-by-side "Your answer" / "Correct answer" --- */
.tb-answer{border-radius:var(--r-md);padding:.7em .9em;min-height:50px;display:flex;
  align-items:center;justify-content:center;text-align:center;font-weight:800;border:2px solid var(--border)}
.tb-answer.is-correct{border-color:var(--lime);background:oklch(94% 0.08 130);color:var(--lime-ink)}
.tb-answer.is-incorrect{border-color:var(--rose);background:oklch(94% 0.05 10);color:oklch(48% 0.16 10)}
.tb-answer.is-empty{color:var(--soft);font-weight:600;font-size:.85rem;border-style:dashed}

@media (prefers-reduced-motion: reduce){
  .tb-menu[open]>.tb-menu__pop,dialog.tb-modal[open]{animation:none}
}

/* cross-page view transitions */
@view-transition { navigation: auto; }
::view-transition-old(root){animation-duration:200ms}
::view-transition-new(root){animation-duration:300ms;animation-timing-function:cubic-bezier(0.22,1,0.36,1)}

/* --- landing: narrow viewports get the stacked storyboard, never the film --- */
@media (max-width:980px){
  .ar-split,.cap-row,.mock--studio .mock-body{grid-template-columns:1fr}
  .cap-row--flip .cap-row__art{order:0}
  .gatestrip{grid-template-columns:repeat(2,1fr)}
  .gate + .gate::before{display:none}
  /* sticky-stack becomes a plain vertical storyboard; pin is desktop-only */
  .desk-beat{min-height:0;padding:1.6rem 0}
  .desk-beat__in{max-width:none}
  /* Content Studio circuit: claim stacks above a vertical spine; the oval SVG
     only reads as a loop when stations sit side by side, so it drops */
  .cs-intro{grid-template-columns:1fr;gap:1.4rem}
  .cs-intro__claim h2{max-width:none}
  .cs-intro__claim .line{max-width:48ch}
  .cs-intro__loop{grid-template-columns:1fr;grid-template-rows:auto;gap:.9rem;
    padding:0}
  .cs-circuit{display:none}
  .cs-ring{display:grid;grid-template-columns:1fr;gap:.9rem}
  .cs-ring__node--make,.cs-ring__node--read{grid-column:auto;grid-row:auto}
  .cs-ring__node--read{position:relative;padding-top:1.1rem}
  .cs-ring__node--read::before{content:"↓";position:absolute;left:50%;top:0;
    translate:-50% 0;color:var(--violet);font-family:var(--display);font-weight:800;
    line-height:1}
  .cs-ring__return{grid-column:auto;grid-row:auto;justify-self:stretch;
    max-width:none;border-radius:var(--r-md)}
  .cs-ring__return::before{content:"↑ ";color:var(--violet);font-weight:800}
  .cs-circuit__ghost{position:static;writing-mode:horizontal-tb;rotate:none;
    translate:none;text-align:center;letter-spacing:.08em;padding-top:.15rem}
  .cs-row{grid-template-columns:1fr}
  .cs-row--flip .cs-row__art{order:0}
  .cs-act__head h3,.cs-close p{max-width:none}
}
@media (max-width:880px){
  .heat-head,.heat-row{grid-template-columns:4.2rem repeat(5,minmax(0,1fr))}
  .heat-row i{height:1.6rem}
  .dform-row--split{grid-template-columns:1fr}
  /* Fitted, the board keeps its --x/--y canvas, its palette and its Present
     camera — an infinite board that reflows into a column is not an infinite
     board, it is a list. Everything below is the no-JS fallback: the absolute
     layout collapses to a plain stack, the lesson layer goes with it, and the
     visible subject reads as one column of real cards. */
  .fitstage:not(.is-fit) .board{aspect-ratio:auto;min-height:0;height:auto;padding:.8rem;
    display:grid;gap:.7rem;-webkit-mask-image:none;mask-image:none}
  .fitstage:not(.is-fit) .lesson{position:static;display:grid;gap:.7rem}
  .fitstage:not(.is-fit) .bcard{position:static;width:auto}
  /* the palette and the drag it feeds are an authoring story that needs the
     canvas beside it; with no canvas the cards are the whole point of the space */
  .fitstage:not(.is-fit) .board-shell{grid-template-columns:minmax(0,1fr)}
  .fitstage:not(.is-fit) :is(.board-rail,.drag-card){display:none}
  .fitstage:not(.is-fit) :is(.bcard--edge,.focus-ring,.collab-cursor){display:none}
  .fitstage:not(.is-fit) .narrate-bar{flex-wrap:wrap;border-radius:var(--r-md)}
  .fitstage:not(.is-fit) .nb-line{flex:1 0 100%;white-space:normal;order:3}
  /* a cut-off option has to read as scrollable rather than as broken: the
     track fades at its trailing edge instead of being clipped by
     body{overflow-x:hidden} with no affordance at all */
  .subject-switch{gap:.6rem;display:grid;justify-items:center}
  .subject-switch__set{justify-self:stretch;
    -webkit-mask-image:linear-gradient(90deg,#000 0,#000 88%,transparent 100%);
    mask-image:linear-gradient(90deg,#000 0,#000 88%,transparent 100%)}
  .tile-strip{flex-wrap:nowrap;overflow-x:auto;justify-content:flex-start;padding-bottom:.6rem;
    -webkit-mask-image:linear-gradient(90deg,#000 0,#000 90%,transparent 100%);
    mask-image:linear-gradient(90deg,#000 0,#000 90%,transparent 100%)}
  .tile-strip li{flex:none}
  /* "all 4 rocky" and "Jupiter" sat 17% apart on a 300px card and rendered as
     "all 4 rockyJupiter". Where the card is not held at its design width the
     ticks stack instead of colliding. */
  .fitstage:not(.is-fit) .bk-scale{height:3.6rem}
  .fitstage:not(.is-fit) .bk-scale__tick{font-size:.58rem}
  .fitstage:not(.is-fit) .bk-scale__tick:nth-of-type(even){top:2.1rem}
}
@media (max-width:560px){
  /* one row, always. Wrapping turned the bar into a three-row block that sat
     over the content at every scroll position. */
  .tb-nav{flex-wrap:nowrap;gap:.15rem;padding:.35rem .45rem;top:.6rem;max-width:calc(100vw - 1rem)}
  .tb-nav a{font-size:.78rem;padding:.45em .65em;white-space:nowrap}
  /* flex:none, or the single row squeezes the wordmark to an unreadable sliver */
  .tb-nav .logo-img{padding:.3em .4em;flex:none}
  .tb-nav .logo-img img{height:18px;max-width:none}
  .tb-nav__minor{display:none}
  .gatestrip{grid-template-columns:1fr}
  .qrow__acts{width:100%}
  .qbtn{flex:1}
}
/* ==========================================================================
   THE FITTED TIER — the four product surfaces, on a phone.

   Each block declares the width it is *drawn* at. These are not the widths it
   uses on a laptop (the Auto-Teach frame is ~1300px there): they are the
   narrowest width at which the arrangement still holds, because the narrower
   the drawing, the less the fit stage has to shrink it and the bigger the
   type ends up on the phone. Anything that reads off the viewport inside
   these blocks — every `clamp(x, Nvw, y)` — lands on its minimum here, which
   is exactly the compact end of each scale. That is intended.

   Heights are set here rather than inherited from the 16:8 / 16:9 one-take
   frames: a 16:8 box scaled onto a phone is a 170px-tall letterbox with a
   whole lesson inside it. Squarer frames use the portrait screen. JS measures
   everything else.
   ========================================================================== */
@media (max-width:899px){
  /* 1 · the Auto-Teach projector. One take, two acts, cutting inside a fixed
     box — the same frame a laptop pins, minus the pin. */
  .at-fit{--fit-w:760px}
  /* the fixed box and the absolute acts are one decision: only the renderer
     shows a single act at a time, so without it the frame must stay auto-height
     or the second act would be clipped by tb-device__screen's overflow */
  .at.is-live .at-fit.is-fit .at-screen{height:540px}
  .at.is-live .at-fit.is-fit .at-act{position:absolute;inset:0;border:0;
    grid-template-rows:auto minmax(0,1fr) auto}
  .at.is-live .at-fit.is-fit .at-act.is-on{display:grid}
  .at.is-live .at-fit.is-fit .at-work{min-height:0}
  .at.is-live .at-fit.is-fit .at-stages{overflow:hidden}

  /* 2 · the Canvas board. Palette rail and canvas side by side, cards on
     their own --x/--y coordinates, Present gliding between them.

     This one is sized by a proportion, not by taste. Card widths are a
     percentage of the canvas while the type inside them is in rem, so the
     canvas cannot be *relatively* narrower here than on a laptop without the
     cards' contents outgrowing their boxes and being cut off by the board's
     own overflow. Two things were doing exactly that at 800px:
       · the rail is a fixed 11.5rem at any width, so it ate 23% of the device
         instead of the 16% it takes at 1140. 10.5rem of 1000 is 16.8%.
       · min-height:27rem beat the 16/9.9 ratio, which stretched the canvas
         vertically and squeezed it horizontally — the cards lost a third of
         their width while their text kept its size.
     At 1000 with a 10.5rem rail the canvas is 798px against the laptop's
     921px and the ratio is the authored one again, so the cards hold
     together. The wider drawing costs a little type size (the scale drops
     from ~.50 to ~.40) but buys back almost as much on-screen card size —
     that is roughly fixed by the phone either way — so the trade is nearly
     free. Do not narrow --fit-w here without re-checking the cards. */
  .board-fit{--fit-w:1000px}
  .board-fit.is-fit .board-shell{grid-template-columns:10.5rem minmax(0,1fr);
    /* the drag card parks off the right of the shell with autoAlpha:0 between
       runs; unclipped it would extend the stage's scrollable width */
    overflow:hidden}
  /* min-height off, so the authored ratio governs. The edge fade is a hint
     that the canvas continues, and at laptop size it costs nothing; scaled
     down it was washing out the last card in each row, which is half of what
     "nodes run off the right" looked like. Same gesture, later start. */
  .board-fit.is-fit .board{min-height:0;
    -webkit-mask-image:radial-gradient(ellipse at center, #000 90%, transparent 100%);
    mask-image:radial-gradient(ellipse at center, #000 90%, transparent 100%)}

  /* 3 · the trip strip. Three stations on one rail, which is the drawing. */
  .trip-fit{--fit-w:700px}

  /* 4 · the Content Studio run. Same one-take treatment as the flagship. */
  .csr-fit{--fit-w:760px}
  .csr.is-live .csr-fit.is-fit .csr-screen{height:520px}
  .csr.is-live .csr-fit.is-fit .csr-act{position:absolute;inset:0;border:0;display:grid;
    grid-template-rows:auto minmax(0,1fr) auto}
  .csr.is-live .csr-fit.is-fit .csr-act--done{grid-template-rows:minmax(0,1fr)}
  .csr.is-live .csr-fit.is-fit .csr-stage{overflow:hidden}
}

@media (prefers-reduced-motion: reduce){
  html{scroll-behavior:auto}
  ::view-transition-old(root), ::view-transition-new(root){animation:none}
  .post-card, .chip-btn{transition:none}
  .log-row-new{animation:none}
  .qrow,.qbtn,.cs-station,.stagebar__dots a,.sb-cmd,.desk-thread-chip{transition:none}
  /* the per-lesson live element stops moving; each one is legible frozen —
     orbits become a diagram, the fraction bar keeps its thirds, the sentence
     holds the present tense it started in */
  .bk-orbit__pl,.bk-fr__split,.bk-fr__lab b,.bk-eq .is-out,.bk-eq__arrow::after,.bk-swap > span{animation:none}
  .bk-fr__split,.bk-swap .b,.bk-fr__lab .b{opacity:0}
  .subj{transition:none}
  /* the nav still tucks — that is layout, not decoration — it just snaps */
  .tb-nav,.skip-link{transition:none}
}
[hidden]{display:none !important}
