/* Moojam (P8.2 visual polish, on "Creative Studio"): playful, friendly, airy. A few large white panels on a soft warm
   canvas, with the canvas visible around and between them. Colour is selective: blue for the primary action and the
   prompt, Moojam purple for the brand and selection, tangerine only for activity, neutrals for everything else.
   One typeface, Gabarito, with hierarchy from size and weight: 900 is rare, 800 for major titles, 700 for primary
   buttons and selection, 600 for secondary headings and strong labels, 500 for most UI, 400 for longer text.
   Every value below the tokens comes from the tokens; a one-off colour or size is a bug. */
/* the typeface, self-hosted (dogfood/public/fonts, SIL Open Font License; variable, 400-900, latin): no request leaves our own server */
@font-face { font-family: "Gabarito"; src: url("/fonts/gabarito.woff2") format("woff2"); font-weight: 400 900; font-style: normal; font-display: swap; }
:root {
  /* type: 13 / 15 / 16 / 17 / 20 / 26 / 28, body 16; weights 400 and 600 only.
     13 is for quiet metadata only; nothing a person must read is smaller than 15. */
  --font-ui: "Gabarito", "Segoe UI Variable Text", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-display: var(--font-ui);
  --font: var(--font-ui);
  --mono: ui-monospace, "Cascadia Mono", Consolas, Menlo, monospace;
  --fs-xs: 13px; --fs-sm: 15px; --fs-body: 16px; --fs-md: 17px; --fs-lg: 20px; --fs-xl: 26px; --fs-2xl: 28px;
  --lh: 1.5; --w-regular: 400; --w-medium: 500; --w-strong: 600; --w-bold: 700; --w-display: 800; --w-black: 900;
  /* spacing */
  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 24px; --s-6: 32px; --s-7: 48px;
  /* radius, one family: controls and inputs, cards and the stage, major panels and dialogs, pills (chips and tags only) */
  --r-control: 14px; --r-card: 16px; --r-panel: 24px; --r-pill: 999px;
  /* the canvas showing around and between the major panels. 12 px on a desktop: the calibrated stage widths (ui-check)
     leave no more, since the creation column is a fixed 42% and every gutter comes out of the stage */
  --gutter: 12px;
  /* surfaces */
  --bg: #F3F0F7; --surface: #FFFFFF; --surface-2: #F5F3F0; --surface-3: #EAE6E0; --stage-surround: #251A2E;
  /* text: about 15:1, 9:1 and 5.4:1 on white (never lighter than --text-3) */
  --text: #221A28; --text-2: #4D4554; --text-3: #6E6676; --text-on-dark: #F7F2FA; --text-on-dark-2: #D2C8DA;
  --ink: #2C1635;   /* headings: the logo's deep plum, softened */
  /* lines: dividers, and the edge of a soft (white) button */
  --line: #E7E2DB; --line-strong: #D5CFC6;
  /* primary: the one blue, for the main action (Send, Play, a dialog's main button) and the prompt (5.2:1 under white) */
  --primary: #2563EB; --primary-hover: #1D54D4; --primary-press: #1A45AE; --primary-ring: rgba(37, 99, 235, .32);
  /* accent: Moojam purple (the logo's jam), the brand and SELECTION only (a chosen card, chip or version), never every edge */
  --accent: #9235C5; --accent-hover: #7A28A8; --accent-press: #6A2192; --accent-soft: #F3E8FA; --accent-wash: #FAF5FD;
  --accent-ring: rgba(146, 53, 197, .35); --accent-light: #BB76E5;   /* the logo's lilac: purple on a dark surface */
  /* activity: tangerine, secondary. Fills only (3:1 on white): never text, and never the only carrier of a meaning */
  --activity: #E8691E; --activity-text: #A84A10; --activity-soft: #FDEEE3; --activity-on-dark: #FFB27A;
  /* status, each at least 4.5:1 on its soft background */
  --ok: #1E7A45; --ok-soft: #E6F4EC;
  --warn: #855600; --warn-soft: #FFF3D9;
  --err: #B3261E; --err-soft: #FCECEA;
  --info: #2557A7; --info-soft: #E8F0FB;
  /* elevation */
  --shadow-1: 0 1px 2px rgba(44, 22, 53, .05), 0 1px 3px rgba(44, 22, 53, .06);
  --shadow-2: 0 18px 44px rgba(44, 22, 53, .16), 0 3px 10px rgba(44, 22, 53, .08);
  /* tactile buttons: a primary sits on a darker blue lip, a secondary on a neutral one; both press flat on :active */
  --shadow-raise: 0 3px 0 var(--primary-press), 0 6px 14px rgba(26, 69, 174, .16);
  --shadow-lip: 0 2px 0 var(--line-strong);
  /* keyboard focus: always the same blue ring, distinct from selection (purple) */
  --ring: 0 0 0 3px var(--primary-ring);
  /* motion */
  --t-fast: 150ms; --t-med: 250ms; --ease: cubic-bezier(.2, .7, .2, 1);
  /* controls: primary 44, ordinary 40, small 36 */
  --h-big: 48px; --h-btn: 44px; --h-small: 36px;
  --topbar-h: 76px;
  /* the creation column: a first-class half of the page, never a sidebar; the stage keeps the larger share */
  --chat-w: clamp(420px, 42vw, 780px);
  /* prompt-first (prompt-first-ui-001): sizes the creation column scales up on a desktop (see the min-width 861px block) */
  --fs-prompt: var(--fs-body); --fs-panel-title: var(--fs-md); --fs-sentence: var(--fs-md); --fs-tile: var(--fs-sm); --fs-counter: 11px;
  --tile-min-h: 84px; --thumb-w: 60px; --thumb-h: 44px; --pair-thumb: 32px; --prompt-min-h: 80px;
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body { margin: 0; background: var(--bg); color: var(--text); font: var(--w-regular) var(--fs-body)/var(--lh) var(--font);
  -webkit-font-smoothing: antialiased; }
button, input, textarea { font: inherit; color: inherit; }
:where(h1, h2, h3):not(.blocks-view *), .display, .empty-title, .projects-empty-title, .vpb-sentence, .building-title, .play-title,
.ideas-title, .project-title, .fix-ask { font-family: var(--font-display); }
/* 800: major titles; 900 only for the two strongest moments (the start question, the sign-in name) */
:where(h1, h2):not(.blocks-view *), .vpb-sentence { font-weight: var(--w-display); letter-spacing: -.01em; }
.empty-title, .login-box h1 { font-weight: var(--w-black); letter-spacing: -.015em; }
/* 600-700: secondary headings */
:where(h3):not(.blocks-view *), .ideas-title, .project-title, .fix-ask { font-weight: var(--w-strong); }
.projects-empty-title { font-weight: var(--w-bold); }
/* most UI text is Medium; longer text inside it goes back to Regular */
.topbar, .chat, .stage-controls, .projects-box, .login-box, .menu-pop, .confirm-pop { font-weight: var(--w-medium); }
.req-text, .empty-sub, .projects-empty-sub, .confirm-pop p, .composer textarea, .vcard-meta, .pcard-meta, .chip-hint,
.wsub, .wait-note, .wait-time, .ideas-note, .pcard-confirm { font-weight: var(--w-regular); }
:where(h1, h2, h3):not(.blocks-view *), .empty-title, .projects-empty-title, .vpb-sentence { color: var(--ink); }
.hidden { display: none !important; }
/* The hidden attribute always wins (Product UX Polish 001): a class that sets display, such as .btn, used
   to override it, which kept "Back to latest" on screen at all times. */
[hidden] { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* Developer UI appears only in developer mode (npm run dogfood:dev). */
body:not(.dev-mode) .dev-only { display: none !important; }
:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* ---------- icons: one family, decorative beside a visible label ---------- */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.icon { width: 1.25em; height: 1.25em; flex: none; fill: none; stroke: currentColor; stroke-width: 2.25;
  stroke-linecap: round; stroke-linejoin: round; }

/* ---------- top bar ---------- */
.topbar {
  position: relative; height: var(--topbar-h); display: flex; align-items: center; gap: var(--s-5);
  padding: 0 calc(var(--gutter) + var(--s-3)); background: var(--surface); border-bottom: 1px solid var(--line);
}
.brand { display: flex; align-items: center; gap: var(--s-2); font-weight: var(--w-strong); font-size: var(--fs-md); white-space: nowrap; }
/* the Moojam logo (moojam-logo.js inlines the supplied SVGs; the box is reserved so nothing shifts when it arrives) */
.brand-logo { display: block; height: 46px; aspect-ratio: 1930 / 540; flex: none; }
.brand-icon { display: none; height: 40px; aspect-ratio: 1; flex: none; }
.brand-icon.big { display: block; height: 83px; }
.brand-logo svg, .brand-icon svg { display: block; width: 100%; height: 100%; }
.brand .tag { font-weight: var(--w-regular); font-size: var(--fs-xs); color: var(--text-3); background: var(--surface-2); border-radius: var(--r-pill); padding: 0 var(--s-2); }
/* the project's name: clearly the subject of the page, quieter than the game itself */
.project-title { flex: 0 1 auto; min-width: 0; margin-left: var(--s-1); padding-left: var(--s-5); border-left: 1px solid var(--line-strong);
  font-size: var(--fs-md); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.project-title:empty { border-left: 0; }
/* the project's own actions: a quiet ⋯ right after the title; its menu opens under it */
.project-actions { position: relative; flex: none; margin-left: calc(-1 * var(--s-3)); }
.project-title:empty + .project-actions { display: none; }
.project-actions:not([open]) > .project-menu { display: none; }   /* closed means gone: no box, no tab stop */
/* the free space sits after the title's group: the mode pill keeps its place beside the actions */
.mode-pill { margin-left: auto; }
.mode-pill:not([hidden]) ~ .topbar-actions { margin-left: 0; }
.project-actions > summary { list-style: none; width: var(--h-btn); padding: 0; color: var(--text-2); }
.project-actions > summary::-webkit-details-marker { display: none; }
.project-actions[open] > summary { background: var(--surface-2); color: var(--text); }
.project-actions .project-menu { top: calc(100% + var(--s-2)); left: 0; right: auto; }
.mode-pill { font-size: var(--fs-xs); font-weight: var(--w-strong); color: var(--text-2); background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-pill); padding: var(--s-1) var(--s-3); white-space: nowrap; }
.topbar-actions { display: flex; align-items: center; gap: var(--s-3); margin-left: auto; }
@media (min-width: 861px) {
  .topbar-actions { gap: var(--s-2); }
  .nav-item { flex-direction: column; gap: 2px; height: auto; min-height: 60px; min-width: 88px; padding: var(--s-1) var(--s-3);
    border-radius: var(--r-card); font-size: var(--fs-sm); font-weight: var(--w-strong); color: var(--text-2); }
  .nav-item .icon { width: 28px; height: 28px; stroke-width: 2; }
  .nav-item:hover:not(:disabled) { background: var(--surface-2); color: var(--text); }
  /* the open section: purple, the selection colour */
  body:has(#projectsPanel:not([hidden])) #myProjects { color: var(--accent); background: var(--accent-wash); font-weight: var(--w-bold); }
}
.menu-btn { flex: none; width: var(--h-btn); min-width: var(--h-btn); padding: 0; }
.menu-initial { flex: none; width: 32px; height: 32px; border-radius: 50%; background: var(--accent-soft); color: var(--accent);
  display: inline-flex; align-items: center; justify-content: center; font-size: var(--fs-sm); font-weight: var(--w-strong); }
.menu-initial:empty { display: none; }
.menu-btn.initial .icon { display: none; }

.menu-pop, .confirm-pop {
  position: absolute; top: calc(var(--topbar-h) - var(--s-2)); right: var(--gutter); z-index: 20;
  background: var(--surface); border-radius: var(--r-card); border: 1px solid var(--line); box-shadow: var(--shadow-2);
  animation: pop-in var(--t-fast) var(--ease);
}
.confirm-pop { width: 400px; max-width: calc(100vw - 2 * var(--s-4)); padding: var(--s-5); border-radius: var(--r-panel); }
.confirm-pop p { margin: 0 0 var(--s-4); }
.confirm-actions { display: flex; gap: var(--s-2); justify-content: flex-end; flex-wrap: wrap; }
.menu-pop { min-width: 240px; max-width: calc(100vw - 2 * var(--s-4)); padding: var(--s-2); }
.menu-pop p { margin: 0; }
.menu-project { display: none; }   /* phone only: the top bar hides the title, mode and download there */
.menu-title { font-size: var(--fs-md); font-weight: var(--w-strong); padding: var(--s-2) var(--s-3) 0; overflow-wrap: anywhere; }
.menu-mode { color: var(--text-3); font-size: var(--fs-sm); padding: 0 var(--s-3) var(--s-2); }
.tester-label { color: var(--text-2); font-size: var(--fs-sm); padding: var(--s-2) var(--s-3); }
.menu-plan { padding-top: 0; font-weight: var(--w-strong); }
.notice:not(.error) { background: var(--surface-2); color: var(--text); }
/* a notice with an action (P4: Get access) wraps, so its words keep the full width */
.notice.error:has(#composerNoticeAction:not([hidden])) { flex-wrap: wrap; }
.menu-item { display: flex; align-items: center; gap: var(--s-3); width: 100%; min-height: var(--h-big); padding: 0 var(--s-3); border: 0; border-radius: var(--r-control);
  background: none; color: var(--text); text-decoration: none; cursor: pointer; text-align: left; font-size: var(--fs-body); }
.menu-item .icon { color: var(--text-2); }
.menu-item { transition: background-color var(--t-fast) var(--ease); }
.menu-item:hover { background: var(--surface-2); }
.menu-item[aria-disabled="true"] { color: var(--text-3); pointer-events: none; }
@keyframes pop-in { from { opacity: 0; transform: translateY(-4px); } }

/* ---------- hosted beta sign-in (ADR-073) ---------- */
.login { position: fixed; inset: 0; z-index: 50; display: flex; align-items: center; justify-content: center; padding: var(--s-4);
  background: var(--bg); }
.login-box { width: 420px; max-width: 100%; background: var(--surface); border-radius: var(--r-panel); border: 1px solid var(--line);
  box-shadow: var(--shadow-1); padding: var(--s-7) var(--s-6) var(--s-6); display: flex; flex-direction: column; align-items: stretch; gap: var(--s-3);
  animation: pop-in var(--t-med) var(--ease); }
.login-box .brand-icon { align-self: center; }
/* P8.3 THE HOME PAGE (the waitlist, and /signin): the cow-print background behind a taller card that shows the full
   logo big. The card is the background's "window" (data-cow-window): the spots behind it are drawn Moojam purple and
   soft, and the card is translucent enough to let them through while the text stays on near-white. Never over the app
   ("Add an email" is the same card without .home). */
.login cow-background { display: none; }
.login.home cow-background { display: block; }
.login-box .home-logo { display: none; }
.login.home .login-box { width: 460px; min-height: min(620px, calc(100dvh - 2 * var(--s-4))); justify-content: center;
  gap: var(--s-4); background: rgba(255, 255, 255, .74); border-color: rgba(64, 16, 80, .14);
  box-shadow: 0 12px 40px rgba(64, 16, 80, .18); }
.login.home .login-box .brand-icon { display: none; }
.login.home .login-box .home-logo { display: block; align-self: center; width: min(340px, 86%); height: auto; aspect-ratio: 1930 / 540;
  margin-bottom: var(--s-2); }
.login.home .login-box h1 { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.login.home .login-pitch { font-size: var(--fs-lg); color: var(--text); font-weight: var(--w-strong); margin-bottom: var(--s-4); text-wrap: balance; }
/* the existing-user way in (P8.3): one quiet line, never a second button; Join Waitlist stays the only call to action */
.home-signin { margin: 0; font-size: var(--fs-sm); color: var(--text-2); text-align: center; }
.home-signin a { color: inherit; font-weight: var(--w-strong); text-decoration: underline; text-underline-offset: 2px; }
.home-signin a:hover { color: var(--text); }
.waitlist-done { margin: 0; padding: var(--s-4); border-radius: var(--r-control); background: var(--surface-2); color: var(--text);
  font-size: var(--fs-md); font-weight: var(--w-strong); text-align: center; }
.login-box h1 { margin: 0; font-size: var(--fs-2xl); line-height: 1.2; text-align: center; }
/* the code inputs share the control radius; focus is the purple border and ring */
.login-pitch { margin: 0 0 var(--s-3); color: var(--text-2); font-size: var(--fs-md); text-align: center; }
.login-label { font-size: var(--fs-sm); font-weight: var(--w-strong); color: var(--text-2); }
.login-box input { height: 52px; padding: 0 var(--s-4); border: 1.5px solid var(--line-strong); border-radius: var(--r-control);
  background: var(--surface); font-family: var(--mono); font-size: var(--fs-md); letter-spacing: .02em;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); }
.login-box input:hover:not(:focus) { border-color: var(--text-3); }
.login-box input::placeholder { font-family: var(--font); font-size: var(--fs-body); letter-spacing: 0; color: var(--text-3); }
.login-box input:focus { outline: none; border-color: var(--primary); box-shadow: var(--ring); }
.login-step { display: flex; flex-direction: column; align-items: stretch; gap: var(--s-3); }
.login-hint { margin: calc(-1 * var(--s-2)) 0 0; font-size: var(--fs-sm); color: var(--text-2); }
.login-links { margin: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-2) var(--s-4); }
.link-btn { background: none; border: 0; padding: var(--s-1); font: inherit; font-size: var(--fs-sm); font-weight: var(--w-strong);
  color: var(--accent); cursor: pointer; text-decoration: underline; text-underline-offset: 3px; border-radius: 6px; }
.link-btn:hover:not(:disabled) { color: var(--accent-hover); }
.link-btn:disabled { color: var(--text-3); cursor: default; }
/* the error line keeps its space, so the card does not grow when it appears */
.login-error { margin: 0; min-height: calc(var(--fs-sm) * var(--lh)); font-size: var(--fs-sm); color: var(--err); text-align: center; }
/* P6: the adult confirmation (a real checkbox, not the code inputs' style) and the legal links */
.login-check { display: flex; align-items: flex-start; gap: var(--s-2); font-size: var(--fs-sm); color: var(--text-2); text-align: left; cursor: pointer; }
.login-check[hidden] { display: none; }
.login-box .login-check input { flex: none; width: 20px; height: 20px; margin: 2px 0 0; padding: 0; border: 0; box-shadow: none; accent-color: var(--accent); }
.login-check a, .legal-links a { color: var(--accent); }
.legal-links { margin: 0; font-size: var(--fs-xs); color: var(--text-3); text-align: center; }
.menu-legal { padding: var(--s-2) var(--s-3) var(--s-1); text-align: left; }

/* ---------- My Projects (hosted, P2) ---------- */
.projects-layer { position: fixed; inset: 0; z-index: 40; display: flex; align-items: flex-start; justify-content: center;
  padding: var(--s-6) var(--s-4); background: rgba(37, 26, 46, .42); overflow-y: auto; }
.projects-box { width: 820px; max-width: 100%; background: var(--surface); border-radius: var(--r-panel); box-shadow: var(--shadow-2);
  padding: var(--s-6); display: flex; flex-direction: column; gap: var(--s-4); animation: pop-in var(--t-med) var(--ease); }
.projects-head { display: flex; align-items: center; gap: var(--s-3); }
.projects-head h2 { margin: 0 auto 0 0; font-size: var(--fs-xl); line-height: 1.2; }
.projects-status { margin: 0; min-height: 0; font-size: var(--fs-sm); color: var(--text-2); }
.projects-status:empty { display: none; }
.projects-empty { display: flex; flex-direction: column; align-items: center; gap: var(--s-2); padding: var(--s-6) var(--s-4); text-align: center; }
.projects-empty .empty-jar { width: 72px; height: 72px; margin-bottom: var(--s-2); }
.projects-empty-title { margin: 0; font-size: var(--fs-lg); }
.projects-empty-sub { margin: 0 0 var(--s-3); color: var(--text-2); }
.projects-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--s-5); }
.pcard { display: flex; flex-direction: column; min-width: 0; padding: var(--s-2); border: 1.5px solid var(--line); border-radius: var(--r-card);
  background: var(--surface); transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), transform var(--t-fast) var(--ease); }
.pcard:hover { border-color: var(--line-strong); box-shadow: var(--shadow-1); }
.pcard.current { border-color: var(--accent); }
.pcard-open { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: stretch; gap: var(--s-2); background: none; border: 0; padding: 0;
  text-align: left; font: inherit; color: inherit; cursor: pointer; border-radius: var(--r-control); }
.pcard-open:focus-visible { outline: none; box-shadow: var(--ring); }
.pcard-pic { display: grid; place-items: center; aspect-ratio: 16 / 10; font-size: 44px; border-radius: var(--r-control); background: var(--surface-2);
  transition: background-color var(--t-fast) var(--ease); }
.pcard-open:hover .pcard-pic { background: var(--surface-3); }
.pcard-text { min-width: 0; display: flex; flex-direction: column; gap: 2px; padding: 0 var(--s-1); }
.pcard-title { font-family: var(--font-display); font-weight: var(--w-bold); font-size: var(--fs-md); color: var(--ink); line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pcard-meta { font-size: var(--fs-xs); color: var(--text-3); }
.pcard-actions { flex: none; display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--s-2); margin-top: var(--s-1); }
.pcard-actions .btn.small { height: 32px; padding: 0 var(--s-2); }
.pcard-confirm { margin: 0; flex-basis: 100%; font-size: var(--fs-sm); color: var(--text); }
/* the confirmed delete is destructive: the error colour, never the brand's primary purple */
.pcard-confirm ~ .btn.primary { background: var(--err); box-shadow: 0 2px 0 #7F1A15; }
.pcard-confirm ~ .btn.primary:hover:not(:disabled) { background: #93201A; }

/* ---------- buttons: soft, tactile, icon + words ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2); height: var(--h-btn); padding: 0 var(--s-4);
  border: 0; border-radius: var(--r-control); background: var(--surface-2); color: var(--text);
  cursor: pointer; text-decoration: none; white-space: nowrap; font-weight: var(--w-strong); font-size: var(--fs-sm); letter-spacing: .01em;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.btn:hover:not(:disabled) { background: var(--surface-3); }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:focus-visible { outline: none; box-shadow: var(--ring); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: default; pointer-events: none; }
.btn.primary { background: var(--primary); color: #fff; font-weight: var(--w-bold); box-shadow: var(--shadow-raise); }
.btn.primary:hover:not(:disabled) { background: var(--primary-hover); }
.btn.primary:active:not(:disabled) { background: var(--primary-press); box-shadow: 0 0 0 var(--primary-press); transform: translateY(3px); }
.btn.primary:focus-visible { box-shadow: var(--shadow-raise), var(--ring); }
/* a white button with a soft edge: secondary actions that should still be easy to find */
.btn.soft { background: var(--surface); box-shadow: inset 0 0 0 1.5px var(--line-strong), var(--shadow-lip); }
.btn.soft:hover:not(:disabled) { background: var(--surface-2); }
.btn.soft:active:not(:disabled) { box-shadow: inset 0 0 0 1.5px var(--line-strong); transform: translateY(2px); }
.btn.soft:focus-visible { box-shadow: inset 0 0 0 1.5px var(--line-strong), var(--shadow-lip), var(--ring); }
.btn.ghost { background: transparent; color: var(--text-2); }
.btn.ghost:hover:not(:disabled) { background: var(--surface-2); color: var(--text); }
.btn.link { background: none; color: var(--accent); height: auto; padding: 0; }
.btn.link:hover:not(:disabled) { background: none; color: var(--accent-hover); text-decoration: underline; text-underline-offset: 3px; }
.btn.big { height: var(--h-big); padding: 0 var(--s-5); font-size: var(--fs-body); }
.btn.small { height: var(--h-small); padding: 0 var(--s-3); }
.btn.block { width: 100%; height: 52px; font-size: var(--fs-md); }

/* ---------- layout ---------- */
.layout { display: grid; grid-template-columns: var(--chat-w) minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); gap: var(--gutter);
  padding: var(--gutter);
  height: calc(100vh - var(--topbar-h)); height: calc(100dvh - var(--topbar-h)); }
/* the two major panels: white, rounded, a quiet edge, no shadow; the content inside them stays open */
.chat, .stage-panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-panel); }
/* never overflow: hidden on the column: a phone's open Ideas can be taller than the column, and Send must stay reachable */
.chat { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.stage-panel { display: flex; flex-direction: column; min-height: 0; min-width: 0; padding: var(--s-3); overflow: auto; }
/* The stage and its head and controls share one centred column, as wide as the stage. */
/* 112px: the panel's padding and edges, the stage frame and the controls under it (the gutters are added separately). Nothing sits above the stage on a desktop: the
   head row (an earlier version, an edit's "keep playing") floats just above it and takes no height (prompt-first-ui-001). */
.stage-column { position: relative; width: 100%; max-width: calc((100dvh - var(--topbar-h) - 2 * var(--gutter) - 112px) * 4 / 3); min-width: 320px; margin: auto; }

/* ---------- timeline: one turn = the request, quoted, and what came of it ---------- */
.timeline { flex: 1; overflow-y: auto; padding: var(--s-5) var(--s-5); display: flex; flex-direction: column; gap: var(--s-5); overscroll-behavior: contain; }
.turn { display: flex; flex-direction: column; gap: var(--s-2); }
.turn-request { align-self: flex-end; max-width: 90%; background: var(--surface-2); border-radius: var(--r-card) var(--r-card) var(--s-1) var(--r-card);
  padding: var(--s-3) var(--s-4); color: var(--text); }
.req-text { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.req-text.clamp { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.req-more { display: inline-flex; align-items: center; min-height: 32px; border: 0; background: none; padding: 0 var(--s-2); margin: var(--s-1) 0 0 calc(-1 * var(--s-2));
  border-radius: var(--r-control); color: var(--accent); font-size: var(--fs-sm); font-weight: var(--w-strong); cursor: pointer; }
.req-more:hover { background: var(--surface-2); }
.msg-meta { font-size: var(--fs-xs); color: var(--text-3); text-align: right; }

.earlier-toggle { align-self: center; }

/* A history card: what changed (the headline), then quiet context. Selecting shows it on the stage. */
.vcard {
  width: 100%; border-radius: var(--r-card); background: var(--surface); box-shadow: var(--shadow-1), inset 0 0 0 1px var(--line);
  display: flex; align-items: center; gap: var(--s-2); padding-right: var(--s-3);
  transition: box-shadow var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.vcard:hover { background: var(--surface-2); }
/* "latest" is a faint wash and a check; selection is an outline: two different cues, neither louder than the stage */
.vcard.is-latest { background: var(--surface); box-shadow: inset 0 0 0 1.5px var(--line-strong); }
.vcard.selected, .vcard.is-latest.selected { box-shadow: 0 0 0 2px var(--accent); }
.vcard-main {
  flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; text-align: left; cursor: pointer;
  border: 0; background: none; padding: var(--s-3) var(--s-4); min-height: 52px; justify-content: center;
  color: inherit; font: inherit; border-radius: var(--r-card);
}
.vcard-main:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.vtitle { font-size: var(--fs-md); font-weight: var(--w-medium); line-height: 1.4; overflow-wrap: anywhere; }
.vtitle .done { color: var(--ok); white-space: nowrap; }
.vcard-meta { color: var(--text-3); font-size: var(--fs-sm); }
.vcard-meta:empty { display: none; }
.vcard-side { display: flex; align-items: center; gap: var(--s-2); flex: none; }
.vcard.flash { animation: flash 1.6s var(--ease); }
@keyframes flash { 0%, 30% { box-shadow: 0 0 0 3px var(--accent), 0 0 0 9px var(--accent-ring); } 100% { box-shadow: none; } }

.badge { display: inline-flex; align-items: center; gap: var(--s-1); font-size: var(--fs-xs); font-weight: var(--w-strong);
  border-radius: var(--r-pill); padding: 3px 10px; white-space: nowrap; }
.badge .icon { width: 15px; height: 15px; stroke-width: 2.75; }
.badge.current { color: var(--ok); background: var(--ok-soft); }
.badge.old { color: var(--warn); background: var(--warn-soft); }

.fcard { border-radius: var(--r-card); background: var(--err-soft); padding: var(--s-3) var(--s-4); }
.fcard-text { color: var(--err); }
.fcard-dev { margin-top: var(--s-1); font-size: var(--fs-xs); color: var(--text-2); overflow-x: auto; }
.fcard-dev summary { cursor: pointer; color: var(--text-3); }

/* an edit's one progress indicator: in its own turn, while the stage stays playable */
.wcard { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: var(--s-1) var(--s-4);
  border-radius: var(--r-card); background: var(--surface); box-shadow: var(--shadow-1), inset 0 0 0 1px var(--line); padding: var(--s-3) var(--s-4); }
.wcard .wtext { font-size: var(--fs-md); font-weight: var(--w-bold); }
.wcard .status-jar { grid-row: 1 / span 3; align-self: start; width: 44px; height: 44px; }
.wcard .wsub, .wcard .phase-steps, .wcard .wait-time, .wcard .wait-note { grid-column: 2; }
.wsub { color: var(--text-2); font-size: var(--fs-sm); }
.wait-time { color: var(--text-3); font-size: var(--fs-sm); margin: 0; }
.wait-note { color: var(--text-2); font-size: var(--fs-sm); margin: 0; }
.wait-time:empty, .wait-note:empty { display: none; }
.phase-steps { display: flex; flex-wrap: wrap; gap: var(--s-1) var(--s-2); list-style: none; margin: 0; padding: 0; font-size: var(--fs-sm); color: var(--text-3); }
.phase-steps:empty { display: none; }
.phase-steps li + li::before { content: "·"; margin-right: var(--s-2); color: var(--text-3); }
.phase-steps .done { color: var(--text-2); }
.phase-steps .now { color: var(--activity-text); font-weight: var(--w-bold); }
.spinner { width: 20px; height: 20px; border: 2.5px solid var(--surface-3); border-top-color: var(--accent); border-radius: 50%; animation: spin .9s linear infinite; }
/* THE JAR AS STATUS (moojam-logo.js): purple and still at rest; while something is being made its blobs float and warm
   to tangerine, then settle back to purple. Decorative (aria-hidden): the words beside it carry the status. */
.status-jar, .empty-jar { display: block; flex: none; line-height: 0; }
.status-jar svg, .empty-jar svg { display: block; width: 100%; height: 100%; }
.mj-blob { transition: fill .9s var(--ease); }
.is-active .mj-blob { fill: var(--activity); }
.spinner.big { width: 36px; height: 36px; border-width: 3px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- empty project ---------- */
.empty { margin: auto 0; padding: 0 var(--s-1); }
.empty-title { font-size: var(--fs-xl); line-height: 1.25; margin: 0 0 var(--s-2); }
.empty-sub { color: var(--text-2); margin: 0 0 var(--s-4); }
.empty-sub:last-child { margin-bottom: 0; }
/* the start screen sits just above the box, so the question, the builder and the box read as one group */
.timeline > .empty { margin: auto 0 0; padding-bottom: var(--s-2); }

/* ---------- Visual Prompt Builder 001 (ADR-074): pictures that grow into a first request ----------
   One component in two homes: the empty stage on a desktop, the creation column on a narrow screen. The growing
   sentence is the only progress there is: no steps, no Next, no progress bar. */
.vpb { width: 100%; max-width: 600px; margin: 0 auto; text-align: left; color: var(--text); }
.vpb .vpb-label { margin: 0 0 var(--s-2); font-size: var(--fs-sm); font-weight: var(--w-bold); color: var(--accent); }
/* the sentence grows in place as pictures are picked; it is the hero of the builder */
.vpb .vpb-sentence { margin: 0 0 var(--s-4); font-size: var(--fs-xl); line-height: 1.3; }
.vpb .vpb-q { margin: 0 0 var(--s-3); font-size: var(--fs-body); font-weight: var(--w-strong); color: var(--text-2); }
.vpb-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-3); }
.tile { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s-2); min-height: 112px;
  padding: var(--s-3) var(--s-2); border: 0; border-radius: var(--r-card); background: var(--surface); color: var(--text); cursor: pointer;
  box-shadow: inset 0 0 0 1.5px var(--line-strong), var(--shadow-1); text-align: center;
  transition: background-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), transform var(--t-fast) var(--ease); }
.tile:hover { box-shadow: inset 0 0 0 2px var(--accent), var(--shadow-1); background: var(--accent-wash); transform: translateY(-1px); }
.tile:active { transform: translateY(1px); }
.tile:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent), var(--ring); }
.tile-pic { font-size: 40px; line-height: 1; }
.tile-label { font-size: var(--fs-body); font-weight: var(--w-strong); line-height: 1.25; }
.vpb-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin-top: var(--s-4); min-height: var(--h-big); }
.vpb-actions #vpbAgain { margin-left: auto; }
.vpb-done { display: inline-flex; align-items: center; gap: var(--s-2); margin: 0; font-size: var(--fs-body); font-weight: var(--w-strong); color: var(--ok); }
/* once copied, the idea stays, quieter: the box below is now the place to change it */
/* on the empty desktop stage: the placeholder words give way to the builder, which keeps its own height */
.stage-overlay.empty.has-builder { position: relative; inset: auto; width: 100%; align-items: stretch; padding: var(--s-6) var(--s-5); color: var(--text); font-size: var(--fs-body); }
.stage-overlay.empty.has-builder > p { display: none; }
.stage-wrap.is-empty .stage-box:has(.has-builder) { aspect-ratio: auto; min-height: min(60vh, 520px); display: flex; align-items: center; }
/* in the creation column (narrow screens): a soft card under the question */
.chat .vpb { margin: 0 0 var(--s-5); padding: var(--s-4); border-radius: var(--r-card); background: var(--surface-2); }
.chat .vpb .vpb-sentence { font-size: var(--fs-lg); }
.chat .tile { min-height: 96px; }
.chat .tile-pic { font-size: 34px; }

/* ---------- composer: the main creative surface ---------- */
.composer { padding: var(--s-4) var(--s-5) var(--s-5); border-top: 1px solid var(--line); background: transparent; }
.composer textarea {
  display: block; width: 100%; resize: none; border: 1.5px solid var(--line-strong); border-radius: 20px; padding: var(--s-3) var(--s-4);
  color: var(--text); background: var(--surface); font-size: var(--fs-prompt); line-height: var(--lh); min-height: var(--prompt-min-h); max-height: 260px;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
/* a picture tool just wrote into the box: the box is where it went, and it is the person's to change (no words needed) */
.composer textarea.filled { border-color: var(--primary); box-shadow: 0 0 0 4px var(--primary-ring); }
.composer textarea::placeholder { color: var(--text-3); }
.composer textarea:hover:not(:focus):not(:disabled) { border-color: var(--text-3); }
.composer textarea:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 4px var(--primary-ring); }
.composer textarea:disabled { background: var(--surface-2); }
body.no-project .composer textarea { min-height: 128px; }
.composer-row { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); margin-top: var(--s-3); }
/* Ideas, Fix something and Send in one row: tighter sides and gap, and no gap for an empty hint, so Send stays inside
   the panel (on main it ran 24 px past the column at 1280 px; the panel's edge made that visible) */
.composer-row { gap: 10px; flex-wrap: wrap; }
.composer-row #send { margin-left: auto; }   /* if the row wraps (a narrow desktop), Send keeps the right-hand edge */
.composer-row .composer-hint:empty { display: none; }
.composer-row .btn.soft { padding: 0 var(--s-3); }
.composer-row .btn.big { padding: 0 18px; }
.composer-hint { font-size: var(--fs-xs); color: var(--text-3); }
/* the hint gives way first: a long line never pushes Send out of the column (it shrinks, then ellipsizes) */
.composer-row .composer-hint { margin-right: auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ideas-btn.on { background: var(--surface); color: var(--text); box-shadow: inset 0 0 0 2px var(--accent); }
/* Fix something: a sibling of Ideas with its own warm colour, so "something is wrong" never reads as "an idea" */
.fix-btn.on { background: var(--warn-soft); color: var(--warn); box-shadow: inset 0 0 0 1.5px #E0A43A; }
.ideas.fix { background: #FFFBF2; box-shadow: inset 0 0 0 1.5px #F5D9A0; }
.ideas.fix .ideas-title { display: flex; align-items: center; gap: var(--s-2); }
.ideas.fix .ideas-title .icon { color: var(--warn); }
.fix-ask { margin: 0 0 var(--s-1); font-size: var(--fs-md); color: var(--ink); }
.fix-vague { margin: 0 0 var(--s-3); padding: var(--s-3); border-radius: var(--r-control); background: var(--surface); box-shadow: inset 0 0 0 1px #F5D9A0; }
.fix-follow { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); background: var(--warn-soft); }
.fix-follow p { margin: 0; }

/* Ideas (Visual Prompt Builder 001): a panel above the box; a suggestion fills the box, it never sends */
.ideas { margin-bottom: var(--s-3); padding: var(--s-3) var(--s-3) var(--s-4) var(--s-4); border-radius: var(--r-card);
  background: var(--surface-2); box-shadow: none; animation: fade-in var(--t-med) var(--ease);
  max-height: 46vh; max-height: 46dvh; overflow: auto; }
.ideas-head { display: flex; align-items: center; gap: var(--s-2); margin-bottom: var(--s-2); }
.ideas-title { flex: 1; margin: 0; font-size: var(--fs-panel-title); line-height: 1.3; color: var(--ink); }
.ideas-close { color: var(--text-2); }
.ideas-close:hover { background: var(--surface); }
.ideas-back { margin-left: calc(-1 * var(--s-2)); }
.ideas-note { margin: 0 0 var(--s-3); font-size: var(--fs-sm); color: var(--text-2); }
.idea-cats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2); }
.idea-cat { display: flex; align-items: center; gap: var(--s-3); min-height: 60px; padding: var(--s-2) var(--s-3); border: 0; text-align: left;
  border-radius: var(--r-control); background: var(--surface); color: var(--text); cursor: pointer; box-shadow: inset 0 0 0 1.5px var(--line);
  transition: box-shadow var(--t-fast) var(--ease), transform var(--t-fast) var(--ease); }
.idea-cat .tile-pic { font-size: 26px; }
.idea-cat:hover { box-shadow: inset 0 0 0 2px var(--accent); }
.idea-cat:active { transform: translateY(1px); }
.idea-cat:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent), var(--ring); }
.idea-cat-words { display: flex; flex-direction: column; min-width: 0; }
.idea-cat-label { font-size: var(--fs-sm); font-weight: var(--w-strong); line-height: 1.3; }
.idea-cat-hint { font-size: var(--fs-xs); color: var(--text-3); line-height: 1.3; }
/* the idea being built: the same grammar as the builder (a growing sentence, three picture tiles), smaller */
.ideas-sentence { margin: 0 0 var(--s-3); font-size: var(--fs-sentence); font-weight: var(--w-strong); line-height: 1.35; color: var(--text); }
.ideas.built .ideas-sentence { padding: var(--s-3) var(--s-4); border-radius: var(--r-control); background: var(--surface);
  box-shadow: inset 0 0 0 1.5px var(--accent-soft); color: var(--text-2); font-size: var(--fs-body); font-weight: var(--w-regular); }
.ideas .vpb-q { margin: 0 0 var(--s-2); font-size: var(--fs-sm); font-weight: var(--w-strong); color: var(--text-2); }
.ideas .vpb-tiles { gap: var(--s-2); }
.chat .ideas .tile, .ideas .tile { min-height: var(--tile-min-h); padding: var(--s-2); }
.chat .ideas .tile-pic, .ideas .tile-pic { font-size: 28px; }
.ideas .tile-label { font-size: var(--fs-tile); }
/* a step: the question and Show me more on one line, the tiles below (DOM order: question, tiles, button) */
.idea-step { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: var(--s-2); }
.idea-step .vpb-q { grid-row: 1; grid-column: 1; }
.idea-step #ideaMore { grid-row: 1; grid-column: 2; margin-bottom: var(--s-2); }
.idea-step .idea-tiles { grid-row: 2; grid-column: 1 / -1; }
.ideas-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin-top: var(--s-3); }
.ideas-actions #ideaAgain { margin-left: auto; }
.vpb-keep { margin: 0 0 var(--s-2); font-size: var(--fs-sm); color: var(--text-2); }

/* notices above the box: one family (an earlier version, a refusal, a project that cannot be edited) */
.notice { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s-2) var(--s-3); margin-bottom: var(--s-3); padding: var(--s-3) var(--s-3) var(--s-3) var(--s-4);
  border-radius: var(--r-card); background: var(--warn-soft); color: var(--warn); font-size: var(--fs-sm); animation: fade-in var(--t-med) var(--ease); }
.notice p { margin: 0; flex: 1 1 220px; }
.notice.error { background: var(--err-soft); color: var(--err); flex-wrap: nowrap; }
.notice-actions { display: flex; gap: var(--s-2); flex-wrap: wrap; }
.notice .btn.small { background: var(--surface); color: var(--text); }
.notice .btn.small.ghost { background: transparent; color: inherit; }
.notice .btn.small.ghost:hover { background: rgba(255, 255, 255, .6); }
.notice-close { flex: none; display: inline-flex; align-items: center; justify-content: center; width: var(--h-btn); height: var(--h-btn);
  border: 0; border-radius: var(--r-control); background: none; color: inherit; cursor: pointer; }
.notice-close:hover { background: rgba(255, 255, 255, .6); }
@keyframes fade-in { from { opacity: 0; } }

/* the mode, chosen once, before Send: tactile chips (native radios), each with a measured time hint */
.mode-choice { border: 0; margin: var(--s-4) 0 0; padding: 0; min-width: 0; }
.mode-choice-label { display: flex; align-items: center; gap: var(--s-2); padding: 0; margin-bottom: var(--s-2);
  font-size: var(--fs-sm); font-weight: var(--w-strong); color: var(--text); }
.mode-choice-label .icon { color: var(--text-2); }
.chips { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.chip { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-height: 64px;
  padding: var(--s-2) 2px; border-radius: var(--r-control); background: var(--surface); box-shadow: inset 0 0 0 1.5px var(--line-strong);
  cursor: pointer; text-align: center; transition: background-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), transform var(--t-fast) var(--ease); }
.chip:hover { background: var(--surface-2); }
.chip:active { transform: translateY(1px); }
.chip input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }
.chip-name { font-size: var(--fs-body); font-weight: var(--w-medium); color: var(--text); line-height: 1.25; letter-spacing: -.01em; }
.chip-hint { font-size: var(--fs-xs); color: var(--text-3); line-height: 1.3; }
.chip:has(input:checked) { background: var(--surface); box-shadow: inset 0 0 0 2px var(--accent); }
.chip:has(input:checked) .chip-name { color: var(--ink); font-weight: var(--w-bold); }
.chip:has(input:disabled) { opacity: .45; cursor: not-allowed; }
.chip:has(input:disabled):hover { background: none; }
.chip:has(input:checked) .chip-hint { color: var(--text-2); }
.chip:has(input:focus-visible) { box-shadow: var(--ring), inset 0 0 0 2px var(--accent); }
.mode-lock { font-size: var(--fs-xs); font-weight: var(--w-regular); color: var(--text-3); }
/* the narrowest desktops (861-1100 px): the four chips' names step down to 15 px (the floor for anything read) rather
   than clip "Balanced" */
@media (min-width: 861px) and (max-width: 1100px) { .chip { padding-inline: 0; } .chip-name { font-size: 15px; } }

/* ---------- stage: the hero, a lit screen in a deep surround ---------- */
.stage-head { display: flex; align-items: center; gap: var(--s-3); margin-bottom: var(--s-3); min-height: var(--h-small); }
.version-label { display: flex; align-items: center; gap: var(--s-2); font-size: var(--fs-sm); }
.version-label .badge { font-size: var(--fs-xs); }
.version-label .v-num { font-size: var(--fs-xs); color: var(--text-3); }
.build-status { margin-left: auto; font-size: var(--fs-sm); color: var(--text-2); text-align: right; }
.stage-wrap { position: relative; width: 100%; padding: var(--s-2); border-radius: var(--r-card); background: var(--stage-surround); box-shadow: 0 6px 18px rgba(37, 26, 46, .14);
  transition: background-color var(--t-med) var(--ease), box-shadow var(--t-med) var(--ease); }
.stage-box { position: relative; width: 100%; aspect-ratio: 4 / 3; background: #fff; border-radius: calc(var(--r-card) - var(--s-1)); overflow: hidden; }
.stage-box canvas { position: absolute; inset: 0; display: block; outline: none; }
/* Play | Blocks (play-blocks-phase1-001): the code sits exactly over the stage, which stays mounted (and sized) underneath */
.stage-wrap.show-blocks .stage-box { visibility: hidden; }
.blocks-view { position: absolute; inset: var(--s-2); z-index: 2; display: flex; flex-direction: column; overflow: hidden;
  background: #F9F9F9; border-radius: calc(var(--r-card) - var(--s-1)); }
.blocks-view[hidden] { display: none; }
.blocks-targets { flex: none; display: flex; gap: var(--s-2); padding: var(--s-2); overflow-x: auto; overscroll-behavior-x: contain;
  background: var(--surface); border-bottom: 1px solid var(--line); scrollbar-width: thin; }
.blocks-target { flex: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  width: 76px; min-height: 58px; padding: 4px 6px; border: 2px solid var(--line); border-radius: var(--r-control); background: var(--surface);
  color: var(--text-2); font: inherit; cursor: pointer; }
.blocks-target:hover { border-color: var(--line-strong); color: var(--text); }
.blocks-target[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-wash); color: var(--text); }
.blocks-target:focus-visible { outline: 3px solid var(--accent-ring); outline-offset: 1px; }
.blocks-target-pic { width: 44px; height: 30px; display: flex; align-items: center; justify-content: center; }
.blocks-target-pic img { max-width: 100%; max-height: 100%; object-fit: contain; }
.blocks-target-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-xs); line-height: 1.25; }
.blocks-area { position: relative; flex: 1; min-height: 0; }
.blocks-ws { position: absolute; inset: 0; }
.blocks-message { position: absolute; inset: 0; margin: 0; display: grid; place-items: center; padding: var(--s-5); text-align: center;
  color: var(--text-2); background: #F9F9F9; font-size: var(--fs-md); }
.blocks-message[hidden] { display: none; }
/* Blocks learning mode (blocks-learning-mode-001): ONE view. A caption above each script, quiet change tags, Before/After
   on request, and what an edit took away in a tray. Captions sit in an HTML layer that takes the block layer's transform. */
.blocks-target { position: relative; }
.blocks-target-badge { position: absolute; top: -1px; right: -1px; min-width: 18px; padding: 1px 5px; border-radius: var(--r-pill);
  font-size: 11px; font-weight: var(--w-strong); line-height: 16px; color: #fff; background: var(--info); }
.blocks-target-badge.is-added { background: var(--ok); }
.blocks-ws { overflow: hidden; }
.blocks-notes { position: absolute; left: 0; top: 0; width: 0; height: 0; transform-origin: 0 0; pointer-events: none; z-index: 1; }
/* The marks layer is placed in WORKSPACE units and takes the canvas transform; pills, edge bars and dots are
   counter-scaled by --inv (1 / scale) so they stay at UI size even when the overview is zoomed far out (ADR-081). */
.bk-mark { position: absolute; display: flex; gap: 4px; white-space: nowrap; transform-origin: 0 0; transform: scale(var(--inv, 1)) translateY(-100%); }
.bk-tags:empty { display: none; }
.bk-tag { display: inline-flex; align-items: center; gap: 4px; padding: 0 8px; border-radius: var(--r-pill); border: 1.5px solid currentColor;
  background: var(--surface); font: inherit; font-size: .8125rem; font-weight: var(--w-strong); line-height: 1.55; white-space: nowrap; }
.bk-tag.is-new { color: var(--ok); }
.bk-tag.is-changed { color: var(--info); cursor: pointer; pointer-events: auto; }
.bk-tag.is-changed::after { content: "\2197"; font-size: .9em; }
.bk-tag.is-changed:hover { background: var(--accent-wash); }
.bk-tag.is-changed:focus-visible { outline: 3px solid var(--accent-ring); outline-offset: 1px; }
.bk-tag.is-removed { color: var(--err); font-size: var(--fs-xs); line-height: 1.5; }
/* New / Changed down a stack's left edge: dashed = new, solid = changed (with the word in the pill: never colour alone) */
.bk-edge { position: absolute; width: calc(6px * var(--inv, 1)); margin-left: calc(-12px * var(--inv, 1)); border-radius: calc(3px * var(--inv, 1)); }
.bk-edge.is-added { background: repeating-linear-gradient(180deg, var(--ok) 0 calc(10px * var(--inv, 1)), transparent calc(10px * var(--inv, 1)) calc(15px * var(--inv, 1))); }
.bk-edge.is-changed { background: var(--info); }
/* THE DIRECT CHANGE MARKER (ADR-084), in focus only: "Changed" / "New" just right of one statement's own top row, at
   UI size (--inv), a button to the same Before -> After as the panel. Nothing is drawn on the block itself. */
.bk-atom-mark { position: absolute; transform-origin: 0 0; transform: scale(var(--inv, 1)) translate(8px, 7px); pointer-events: auto;
  display: inline-flex; align-items: center; gap: 3px; padding: 0 8px; border-radius: var(--r-pill); border: 1.5px solid currentColor;
  background: var(--surface); color: var(--info); font: inherit; font-size: .8125rem; font-weight: var(--w-strong); line-height: 1.55;
  white-space: nowrap; cursor: pointer; box-shadow: 0 1px 3px rgba(0, 0, 0, .12); transition: opacity 150ms ease-out; }
.bk-atom-mark[hidden] { display: none; }
.bk-atom-mark.is-new { color: var(--ok); }
.bk-atom-mark::after { content: "\2197"; font-size: .9em; }
.bk-atom-mark:hover { background: var(--accent-wash); }
.bk-atom-mark:focus-visible { outline: 3px solid var(--accent-ring); outline-offset: 1px; }
.bk-atom-mark.bk-shade { opacity: .25; }
.bk-atom-mark.bk-soft { opacity: .4; }
.bk-mark.is-quiet { display: none; }
/* a changed block in the Before -> After figures: a dark outline, Scratch's own colours kept (blue vanished on Motion) */
.sc-mark-fresh { stroke: #3B1F99 !important; stroke-width: 4px !important; }
/* ADR-086: a changed value (28 -> 40) gets a soft tint and a ring on both sides; its statement a quiet outline */
.sc-mark-value { stroke: var(--accent) !important; stroke-width: 3px !important; fill: #FFF3B0 !important; }
.sc-mark-stmt { stroke: #3B1F99 !important; stroke-width: 2.5px !important; }
.sc-mark-gone { stroke: #B3261E !important; stroke-width: 3px !important; stroke-dasharray: 6 4; }
/* setup scripts: shown, but quieter than the behaviour */
.blocklySvg .bk-setup { opacity: .78; }
/* THE SPOTLIGHT (ADR-082): nothing is drawn around code. What is selected, or what a click would select, stays as
   Scratch draws it, with the loops and conditions it sits in; everything else fades (no box, no outline, and no glow:
   a glow is Scratch's "this script is running").
   ADR-083 made it decisive: the containers a section merely sits in fade too (only its conditions stay).
     bk-dim   another script while one is selected          .15
     bk-shade unrelated code in the selected script         .15
     bk-wrap  a loop / the hat / compiler checks around it  .2
     bk-soft  everything but the hover's candidate          .3  (never brighter than the selection leaves it) */
.blocklySvg g.bk-dim, .bk-mark.bk-dim, .bk-edge.bk-dim { opacity: .15; }
.blocklySvg .bk-shade { opacity: .15; }
.blocklySvg .bk-wrap { opacity: .2; }
.blocklySvg g.bk-soft, .blocklySvg .bk-soft, .bk-mark.bk-soft, .bk-edge.bk-soft { opacity: .3; }
.blocklySvg g.bk-dim.bk-soft { opacity: .15; }
.blocklySvg g.bk-setup.bk-on { opacity: 1; }
/* the fade is quick and only ever opacity (Blockly's own moves are transforms and must never lag); none under reduced
   motion (see the reduced-motion block: .blocks-view * has no transition at all) */
.blocks-ws .blocklyBlockCanvas g, .blocks-ws .blocklyBlockCanvas path, .blocks-ws .blocklyBlockCanvas text,
.bk-mark, .bk-edge { transition: opacity 150ms ease-out; }
.bk-kb[hidden] { display: none; }
/* the keyboard's cursor: the focus indicator (focus must stay visible); the spotlight shows what Enter would pick */
.bk-kb { position: absolute; border: 3px dashed var(--accent); border-radius: 12px; box-sizing: border-box; }
.blocks-ws:focus { outline: none; }
.blocks-ws:focus-visible { box-shadow: inset 0 0 0 3px var(--accent-ring); }
.blocks-ws .blocklyBlockCanvas g[data-id] { cursor: pointer; }
/* the overview's one-line hint, over the top of the code (the overview keeps the whole area) */
.blocks-hint { position: absolute; left: var(--s-3); top: 6px; z-index: 1; margin: 0; padding: 1px 8px; border-radius: var(--r-pill);
  font-size: .8125rem; color: var(--text-3); background: rgba(255, 255, 255, .85); pointer-events: none; }
.blocks-hint[hidden] { display: none; }
/* FOCUS (ADR-081): the explanation panel on the LEFT, the code on the right. The panel is outside the camera: it never
   moves while the code reframes. A stack's left edge is straight, so meaning -> code reads cleanly side by side. */
/* NOT a size container: Chrome defers the style of a size container's descendants to layout, and the canvas then
   reported its old width for a frame after the panel opened (a second, corrective jump). The panel is the container. */
.blocks-area { --panel-w: clamp(220px, 38%, 460px); }
.is-focus .blocks-ws { left: var(--panel-w); }
.blocks-focus { position: absolute; left: 0; top: 0; bottom: 0; width: var(--panel-w); z-index: 2; box-sizing: border-box; overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--s-3); padding: var(--s-4) var(--s-5) var(--s-5) var(--s-4);
  background: var(--surface); border-right: 1px solid var(--line); container-type: inline-size; }
.blocks-focus[hidden] { display: none; }
.focus-top { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.focus-heading { margin: var(--s-2) 0 0; font-size: clamp(1.125rem, 7.5cqi, 1.3125rem); font-weight: var(--w-strong); line-height: 1.25; color: var(--text-2, var(--text)); }
.band-text { margin: 0; font-size: clamp(1.0625rem, 9.5cqi, 1.5rem); line-height: 1.4; color: var(--text); overflow-wrap: anywhere; }
.band-text strong { font-weight: var(--w-strong); }
.focus-hint { margin: auto 0 0; font-size: .875rem; color: var(--text-3); }
.band-tags:empty { display: none; }
.band-tags .bk-tag { font-size: .875rem; line-height: 1.7; padding: 0 10px; }
/* ADR-086: what changed HERE, under the explanation; a real change gets one large, friendly button to Before -> After */
.band-callout { display: flex; flex-direction: column; align-items: stretch; gap: var(--s-2); padding: 10px; border-radius: 14px;
  background: var(--accent-soft); border: 1.5px solid rgba(146, 53, 197, .25); }
.band-callout[hidden] { display: none; }
.band-callout.is-new { background: #EAF7EE; border-color: rgba(26, 127, 55, .25); }
.band-callout-text { margin: 0; font-size: 1.0625rem; font-weight: var(--w-strong); line-height: 1.35; color: var(--text); }
.band-see { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 48px; padding: 0 8px; border: 0; border-radius: var(--r-pill);
  background: var(--accent); color: #fff; font: inherit; font-size: clamp(.9375rem, 7cqi, 1.125rem); font-weight: var(--w-strong); white-space: nowrap; cursor: pointer;
  box-shadow: 0 3px 0 var(--accent-press); touch-action: manipulation; }
.band-see-icon { font-size: 1.15em; line-height: 1; }
.band-see:hover { background: var(--accent-hover); }
.band-see:active { background: var(--accent-press); box-shadow: 0 1px 0 var(--accent-press); transform: translateY(2px); }
.band-see:focus-visible { outline: 3px solid var(--accent-ring); outline-offset: 3px; }
.band-back, .band-more { flex: none; font: inherit; font-size: .9375rem; padding: 2px 12px; border-radius: var(--r-pill); border: 1.5px solid var(--info);
  background: var(--surface); color: var(--info); cursor: pointer; }
.band-back[hidden], .band-more[hidden] { display: none; }
.band-back::before { content: "\2190\00a0"; }
.band-back:focus-visible, .band-more:focus-visible { outline: 3px solid var(--accent-ring); outline-offset: 1px; }
.band-more { align-self: flex-start; }
@media (prefers-reduced-motion: no-preference) { .blocks-focus:not([hidden]) { animation: fade-in 150ms ease-out; } }
/* a narrow code area (phones, portrait tablets): the panel sits ABOVE the code as a card, two lines until More */
.is-narrow .blocks-area { --panel-w: 100%; }
.is-narrow.is-focus .blocks-ws { left: 0; }
.is-narrow .blocks-focus { bottom: auto; width: 100%; max-height: 60%; gap: 4px; padding: 6px var(--s-3);
  border-right: 0; border-bottom: 1px solid var(--line); }
.is-narrow .focus-heading, .is-narrow .focus-hint { display: none; }
/* the stacked card keeps one line for its actions: the button alone (its name still says "Changed in this version") */
/* the stacked card: the button alone, still 44 px (its name says what it does) */
.is-narrow .band-callout { padding: 0; background: none; border: 0; align-items: flex-start; }
.is-narrow .band-callout-text { display: none; }
.is-narrow .band-see { min-height: 44px; font-size: 1rem; padding: 0 16px; }
.is-narrow .band-text { font-size: 1rem; line-height: 1.35; }
.is-narrow .band-back, .is-narrow .band-more { font-size: .875rem; padding: 0 10px; }
.is-narrow .blocks-focus { position: absolute; }
.is-narrow .band-more { position: absolute; right: var(--s-3); top: 6px; }
.is-narrow .blocks-focus:not(.is-expanded) .band-text { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
/* with the 44 px "See what changed" in its top row the card keeps ONE line of explanation until More (the code keeps half the area) */
.is-narrow .blocks-focus.has-change:not(.is-expanded) .band-text { -webkit-line-clamp: 1; }
.blocks-live { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* Removed in this edit: one quiet line, opened on request */
.blocks-removed { flex: none; display: flex; flex-direction: column; max-height: 55%; background: var(--surface); border-bottom: 1px solid var(--line); }
.blocks-removed[hidden] { display: none; }
.blocks-removed-summary { display: flex; align-items: center; gap: 4px; min-height: 32px; padding: 0 var(--s-3); cursor: pointer;
  font-size: var(--fs-sm); color: var(--text-2); list-style: none; }
.blocks-removed-summary::-webkit-details-marker { display: none; }
.blocks-removed-summary::before { content: "\25B8"; color: var(--text-3); }
.blocks-removed[open] > .blocks-removed-summary::before { content: "\25BE"; }
.blocks-removed-summary:focus-visible { outline: 3px solid var(--accent-ring); outline-offset: -3px; }
.blocks-removed-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 0 var(--s-3) var(--s-3); display: flex; flex-direction: column; gap: var(--s-2);
  overscroll-behavior: contain; }
.removed-note { margin: 0; font-size: var(--fs-xs); color: var(--text-3); }
.removed-group { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-2); }
.removed-name { margin: 0; font-size: var(--fs-sm); color: var(--text-2); }
/* Before -> After for one Changed script: a dialog over the code, never a mode */
.blocks-detail { position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column; background: #F9F9F9; }
.blocks-detail[hidden] { display: none; }
.detail-head { flex: none; display: flex; align-items: center; gap: var(--s-2) var(--s-3); flex-wrap: wrap; padding: var(--s-2) var(--s-3);
  border-bottom: 1px solid var(--line); background: var(--surface); }
/* ADR-087: a child-friendly comparison. One big headline, a quiet version line, a friendly Close */
.detail-title { margin: 0; font-size: 1.625rem; font-weight: 800; line-height: 1.15; color: var(--text); }
.detail-versions { font-size: .75rem; color: var(--text-3); opacity: .8; }
.detail-close { margin-left: auto; min-height: 44px; padding: 0 var(--s-5); border: 2px solid var(--accent); border-radius: var(--r-pill); font-size: 1rem; color: var(--accent);
  background: var(--surface); color: var(--text); font: inherit; font-weight: var(--w-strong); cursor: pointer; }
.detail-close:focus-visible { outline: 3px solid var(--accent-ring); outline-offset: 1px; }
.detail-body { flex: 1; min-height: 0; overflow: auto; padding: var(--s-4); display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-3);
  overscroll-behavior: contain; }
.change-pair { display: flex; align-items: flex-start; gap: var(--s-4); max-width: 100%; }
.change-arrow { align-self: center; flex: none; display: inline-flex; line-height: 0; padding: 0 var(--s-1); }
.change-arrow svg { display: block; fill: var(--accent); stroke: var(--accent-press); stroke-width: 2; stroke-linejoin: round; filter: drop-shadow(0 2px 0 rgba(106, 33, 146, .35)); }
.change-pair.is-stacked .change-arrow { align-self: flex-start; margin: 0 0 0 var(--s-5); padding: var(--s-1) 0; }
.change-pair.is-stacked .change-arrow svg { transform: rotate(90deg); }
.change-pair + .change-pair { padding-top: var(--s-3); border-top: 1px dashed var(--line); }
.change-pair.is-stacked { flex-direction: column; align-items: flex-start; }

.change-fig { margin: 0; display: flex; flex-direction: column; gap: var(--s-2); max-width: 100%; }
.change-fig figcaption { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
/* Before / After: big bold chips; After in the accent colour (where the story ends) */
.fig-label { display: inline-flex; align-items: center; min-height: 32px; padding: 0 14px; border-radius: var(--r-pill); font-size: 1.125rem; font-weight: 800;
  background: #ECEAF2; color: var(--text-2); }
.fig-label.is-after { background: var(--accent); color: #fff; }
/* what happened on this side: one simple badge (its border style is the outline it names) */
.fig-badge { display: inline-flex; align-items: center; min-height: 26px; padding: 0 10px; border-radius: var(--r-pill); font-size: .8125rem; font-weight: 800;
  letter-spacing: .04em; text-transform: uppercase; background: var(--surface); }
.fig-badge.is-new { color: #3B1F99; border: 3px solid #3B1F99; }
.fig-badge.is-gone { color: #B3261E; border: 3px dashed #B3261E; }
.fig-badge.is-changed { color: #3B1F99; border: 3px solid var(--accent); background: #FFF3B0; }
/* each side is a white card: the code is the focal point */
.change-ws { flex: none; border-radius: 12px; }
.change-fig > .change-ws, .change-scroll { background: #fff; box-shadow: 0 0 0 1.5px var(--line), 0 2px 6px rgba(0, 0, 0, .06); border-radius: 12px; }
/* a values change lists one row per changed block: label the first row; the arrow and the tint carry the rest */
.detail-body .change-pair:not(:first-child):not(.is-stacked) figcaption { display: none; }
/* the first row's labels sit above the cards: the arrow centres on the cards, not on cards + labels */
.detail-body .change-pair:first-child:not(.is-stacked) .change-arrow { margin-top: 40px; }
.change-fig > .change-ws, .change-scroll { max-width: 100%; overflow-x: auto; }
.change-scroll { max-height: 340px; overflow-y: auto; border-radius: 6px; overscroll-behavior: contain; }
.change-ws.is-failed { padding: var(--s-2); color: var(--text-2); font-size: var(--fs-sm); }
/* removed code is drawn from the old version, faded but readable, never in the live workspace */
.change-fig.is-ghost .blocklyBlockCanvas { opacity: .62; filter: saturate(.55); }
@media (prefers-reduced-motion: no-preference) {
  .blocks-detail:not([hidden]) { animation: fade-in var(--t-med) var(--ease); }
  .blocks-removed-body { animation: fade-in var(--t-med) var(--ease); }
}
/* a phone: the code panel is the stage's size, so the strip takes as little height as it can */
@media (max-width: 480px) {
  .blocks-targets { padding: 4px var(--s-2); }
  .blocks-target { min-height: 44px; padding: 2px 4px; }
  .blocks-target-pic { height: 18px; }
  .blocks-removed-summary { min-height: 28px; padding: 0 var(--s-2); font-size: var(--fs-xs); }
  .detail-head { padding: 6px var(--s-2); }
  .detail-body { padding: var(--s-2); gap: var(--s-2); }
}
.stage-wrap:focus-within { box-shadow: var(--ring), 0 6px 18px rgba(37, 26, 46, .14); }
.stage-box.fade-in canvas { animation: fade-in var(--t-med) var(--ease); }
/* before anything exists: a quiet dashed frame, not a big grey box */
.stage-wrap.is-empty { background: transparent; box-shadow: none; border: 2px dashed var(--line-strong); padding: calc(var(--s-2) - 2px); }
.stage-wrap.is-empty .stage-box { background: transparent; }
.stage-wrap.is-empty:has(.has-builder) { border-color: transparent; }
/* no version yet: the renderer's blank canvas stays out of sight (it would show white through the frame) */
.stage-wrap.no-version canvas { visibility: hidden; }
.stage-wrap.no-version:not(.is-empty) .stage-box { background: var(--stage-surround); }
.monitors { position: absolute; left: 0; top: 0; width: 480px; height: 360px; transform-origin: 0 0; pointer-events: none; }
.monitor { position: absolute; display: inline-flex; align-items: center; gap: 5px; background: #e6f0ff; border: 1px solid #c3d1e8; border-radius: 4px; padding: 2px 5px; font: 11px/1.2 "Helvetica Neue", Helvetica, Arial, sans-serif; color: #575e75; white-space: nowrap; }
.monitor .m-label { font-weight: 700; }
.monitor .m-value { background: #ff8c1a; color: #fff; border-radius: 4px; padding: 1px 6px; min-width: 30px; text-align: center; }
.monitor.large { padding: 3px 7px; }
.monitor.large .m-label { display: none; }
.monitor.large .m-value { font-size: 15px; }
.stage-overlay { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: var(--s-4); text-align: center; }
.stage-overlay p { margin: 0; }
.stage-overlay.empty { color: var(--text-3); font-size: var(--fs-md); }
.stage-overlay.loading { background: rgba(30, 27, 46, .55); color: var(--text-on-dark); }
.stage-overlay.building { gap: var(--s-1); background: var(--stage-surround); color: var(--text-on-dark-2); animation: fade-in var(--t-med) var(--ease); }
.stage-overlay.building .spinner { border-color: rgba(255, 255, 255, .18); border-top-color: var(--accent-light); margin-bottom: var(--s-3); }
.building-title { font-size: 22px; font-weight: var(--w-display); color: var(--text-on-dark); }
.building-sub { font-size: var(--fs-sm); }
.building-sub:empty { display: none; }
.stage-overlay.building .phase-steps { margin-top: var(--s-3); justify-content: center; color: #A89BB3; }
.stage-overlay.building .phase-steps .done { color: var(--text-on-dark-2); }
.stage-overlay.building .phase-steps .now { color: var(--activity-on-dark); }
.stage-overlay.building .wait-time { color: #B2A6BC; margin-top: var(--s-2); }
.stage-overlay.building .wait-note { color: var(--text-on-dark-2); margin-top: var(--s-2); max-width: 440px; }
/* READY: the project's first frame under a dark veil, its title, and one Play button; nothing runs until it is pressed */
.play-overlay {
  position: absolute; inset: 0; z-index: 5; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s-3);
  border: 0; padding: var(--s-4); background: rgba(20, 18, 32, .55); cursor: pointer; font: inherit; color: #fff;
  animation: fade-in var(--t-med) var(--ease);
}
.play-overlay:focus-visible { outline: 3px solid #D9B3F2; outline-offset: -3px; }
.play-title { max-width: 90%; font-size: 22px; font-weight: var(--w-bold); line-height: 1.3; text-shadow: 0 1px 8px rgba(0, 0, 0, .35); overflow-wrap: anywhere; }
.play-title:empty { display: none; }
.play-disc { width: 84px; height: 84px; border-radius: 50%; background: var(--primary); color: #fff;
  display: flex; align-items: center; justify-content: center; padding-left: 5px; box-shadow: 0 4px 0 var(--primary-press), 0 8px 22px rgba(0, 0, 0, .3);
  transition: transform var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease); }
.play-disc .icon { width: 40px; height: 40px; }
.play-overlay:hover .play-disc { background: var(--primary-hover); transform: scale(1.05); }
.play-word { font-size: var(--fs-md); font-weight: var(--w-strong); }
.toast { position: absolute; left: 50%; bottom: var(--s-4); z-index: 6; transform: translateX(-50%); padding: var(--s-2) var(--s-4);
  border-radius: var(--r-pill); background: rgba(20, 18, 32, .88); color: #fff; font-size: var(--fs-sm); font-weight: var(--w-strong);
  white-space: nowrap; pointer-events: none; animation: toast 3.2s var(--ease) forwards; }
@keyframes toast { 0% { opacity: 0; transform: translate(-50%, 6px); } 8%, 85% { opacity: 1; transform: translate(-50%, 0); } 100% { opacity: 0; } }

/* THE STAGE TOOLBAR (P8.2), ABOVE the stage, which is the panel's endpoint. LEFT controls the project: run and stop, the
   flag and the octagon familiar from Scratch, in our own tactile style. RIGHT chooses what you look at: Stage | Blocks.
   Download and Open Scratch are the project's own actions: they live in the header, by the title. */
.stage-controls { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2) var(--s-3); margin: 0 0 var(--s-3); flex-wrap: wrap; }
.stage-controls .btn.soft { box-shadow: inset 0 0 0 1.5px var(--line-strong), var(--shadow-lip); }
.stage-controls .btn.soft:active:not(:disabled) { box-shadow: inset 0 0 0 1.5px var(--line-strong); }
.stage-controls .btn.soft:focus-visible { box-shadow: inset 0 0 0 1.5px var(--line-strong), var(--shadow-lip), var(--ring); }
.ctl-group { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
/* run and stop: square-ish icon buttons with a generous target; their words stay as their accessible names (sr-only) */
.run-stop { flex-wrap: nowrap; }
.run-btn, .stop-btn { width: 60px; min-width: 0; height: var(--h-big); padding: 0; }
.run-btn .icon { width: 28px; height: 28px; color: #2E7D3A; --flag-fill: #4CBF56; }   /* the flag: green, a darker green edge */
.stop-btn .icon { width: 24px; height: 24px; --stop-fill: #E5484D; }
/* while the project runs, the flag button is lit (as Scratch does), and Stop is the one that is enabled */
.stage-controls:has(#stop:not(:disabled)) .run-btn { background: #EAF7EC; box-shadow: inset 0 0 0 2px #4CBF56, var(--shadow-lip); }
.stage-controls:has(#stop:not(:disabled)) .run-btn:focus-visible { box-shadow: inset 0 0 0 2px #4CBF56, var(--shadow-lip), var(--ring); }
/* [ Stage | Blocks ]: two chunky segments, an icon and its word. The chosen one is white, raised, bold and edged in its
   own colour: Stage blue (the primary), Blocks tangerine (the activity colour, its text-safe tone on the icon) */
.view-toggle { margin-left: auto; flex-wrap: nowrap; gap: 4px; padding: 4px; border-radius: var(--r-card); background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line); }
.view-toggle .seg { display: inline-flex; align-items: center; gap: var(--s-2); height: calc(var(--h-big) - 8px); padding: 0 var(--s-4) 0 var(--s-3);
  border: 0; border-radius: var(--r-control); background: transparent; color: var(--text-2); font: inherit; font-size: var(--fs-body);
  font-weight: var(--w-strong); cursor: pointer; transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); }
.view-toggle .seg .icon { width: 22px; height: 22px; }
.view-toggle .seg:hover:not(:disabled):not([aria-pressed="true"]) { color: var(--text); background: var(--surface-3); }
.view-toggle .seg[aria-pressed="true"] { background: var(--surface); color: var(--ink); font-weight: var(--w-bold); }
#viewPlay[aria-pressed="true"] { box-shadow: inset 0 0 0 2px var(--primary), 0 2px 0 var(--line-strong); }
#viewPlay[aria-pressed="true"] .icon { color: var(--primary); }
#viewBlocks[aria-pressed="true"] { box-shadow: inset 0 0 0 2px var(--activity), 0 2px 0 var(--line-strong); }
#viewBlocks[aria-pressed="true"] .icon { color: var(--activity-text); }
.view-toggle .seg:disabled { opacity: .5; cursor: default; }
.view-toggle .seg:focus-visible { outline: 3px solid var(--primary-ring); outline-offset: 2px; }
.stage-hint { margin-left: auto; font-size: var(--fs-sm); color: var(--text-2); text-align: right; }
.touch-note { margin: var(--s-3) 0 0; font-size: var(--fs-sm); color: var(--info); background: var(--info-soft); border-radius: var(--r-control); padding: var(--s-2) var(--s-3); }

/* ---------- developer details (deliberately compact) ---------- */
.dev { margin-top: var(--s-6); border-top: 1px solid var(--line); padding-top: var(--s-3); font-size: 12.5px; color: var(--text-2); }
.dev > summary { cursor: pointer; color: var(--text-3); user-select: none; }
.dev-body { margin-top: var(--s-3); display: flex; flex-direction: column; gap: var(--s-3); }
.dev-row { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.dev-export { margin-top: var(--s-3); }
.dev-label { color: var(--text-2); }
.dev-note { color: var(--text-3); font-size: 12px; }
.dev-sub { font-weight: var(--w-strong); color: var(--text-2); margin: var(--s-1) 0; }
.dev-links a { color: var(--accent); }
.dev .btn.small { height: 32px; font-size: 12.5px; }
.seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: 8px; overflow: hidden; }
.seg button { border: 0; background: var(--surface); min-height: 32px; padding: 0 var(--s-3); cursor: pointer; color: var(--text-2); font-size: 12px; }
.seg button + button { border-left: 1px solid var(--line-strong); }
.seg button.on { background: var(--text); color: #fff; }
table.kv, table.calls { border-collapse: collapse; font: 12px var(--mono); }
table.kv th { text-align: left; font-weight: var(--w-regular); color: var(--text-3); padding: 1px var(--s-4) 1px 0; font-family: var(--font); white-space: nowrap; vertical-align: top; }
table.kv td { padding: 1px 0; word-break: break-all; }
table.calls { margin-top: var(--s-2); }
table.calls th { text-align: left; color: var(--text-3); font-weight: var(--w-regular); font-family: var(--font); padding: 2px var(--s-3) 2px 0; border-bottom: 1px solid var(--line); }
table.calls td { padding: 2px var(--s-3) 2px 0; }
pre.issues { max-height: 180px; overflow: auto; background: var(--surface-2); padding: var(--s-2); border-radius: var(--s-1); font-size: 11px; white-space: pre-wrap; }

/* ---------- session report ---------- */
.report-panel { margin-top: var(--s-3); border-top: 1px solid var(--line); padding-top: var(--s-2); }
.report-panel > summary { cursor: pointer; color: var(--text-2); font-weight: var(--w-strong); user-select: none; }
.report-body { margin-top: var(--s-2); }
.report-content { max-height: 400px; overflow-y: auto; font: 12px var(--mono); white-space: pre-wrap; background: var(--surface-2); border-radius: 8px; padding: var(--s-3); line-height: var(--lh); }
.report-content:empty { display: none; }
.report-actions { display: flex; align-items: center; gap: var(--s-2); margin-top: var(--s-2); }
.report-status { font-size: 12px; color: var(--ok); }
.analysis-section { margin-top: var(--s-3); padding-top: var(--s-2); border-top: 1px solid var(--line); }
.analysis-content { margin-top: var(--s-2); max-height: 500px; overflow-y: auto; font: 12.5px/1.55 var(--font); color: var(--text); background: var(--surface-2); border-radius: 8px; padding: var(--s-3); }
.analysis-content:empty { display: none; }
.analysis-loading { color: var(--text-3); font-size: 12px; margin-top: var(--s-1); }

/* ---------- narrow screens: sticky stage on top, history between, sticky composer at the bottom ---------- */
/* Ideas: an EXISTING thing's tile shows the project's own picture of it (stage-overlay.js thumbnail()), on a soft
   ground so a white sprite still shows; the backdrop fills its little frame. A new thing or an action keeps its emoji. */
.tile-pic.has-thumb { display: flex; align-items: center; justify-content: center; width: 52px; height: 40px; padding: 3px;
  border-radius: 8px; background: var(--surface-2); font-size: 0; }
.tile-thumb { display: block; max-width: 100%; max-height: 100%; object-fit: contain; }
.tile-pic.has-thumb:has(.tile-thumb.backdrop) { padding: 0; background: none; }
.tile-thumb.backdrop { width: 52px; height: 39px; object-fit: cover; border-radius: 6px; border: 1px solid var(--line, #E9E4DC); }
/* Ideas composite pictures (ideas-composite-visuals-001, app.js ideaPic): the project thing is the picture, the action a
   small corner annotation (not a button: no border, no shadow, no pointer); two things share one marker; a counter is
   its own name and value. One box size for every form, so a mixed hand lines up. */
.tile-pic.idea-vis { position: relative; pointer-events: none; }
/* the thing fills its box (scaled up or down, never cropped), so it stays the larger part of the picture */
.tile-pic.vis-entity, .tile-pic.vis-backdrop { width: var(--thumb-w); height: var(--thumb-h); }
.vis-entity .tile-thumb { width: 100%; height: 100%; object-fit: contain; }
.vis-backdrop .tile-thumb.backdrop { width: 100%; height: 100%; }
/* the action badge: one corner, mostly outside the thing's box; --optic evens out a thin or a boxed glyph (opticOf) */
.idea-badge { --glyph: 17px; --optic: 1; position: absolute; top: -8px; right: -13px; width: 25px; height: 25px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-size: calc(var(--glyph) * var(--optic)); line-height: 1;
  background: var(--surface, #fff); }
.idea-badge[data-optic="small"] { --optic: 1.2; }
.idea-badge[data-optic="large"] { --optic: .85; }
.tile-pic.vis-pair { width: calc(2 * var(--pair-thumb) + 12px); gap: 2px; }
.vis-pair .tile-thumb { width: var(--pair-thumb); height: var(--pair-thumb); }
.idea-marker { flex: none; font-size: 14px; line-height: 1; font-weight: var(--w-strong); color: var(--text-2, #6B645C); }
.tile-pic.vis-counter { display: flex; align-items: center; justify-content: center; height: 40px; max-width: 100%; }
.idea-counter { display: inline-flex; align-items: center; gap: 4px; max-width: 100%; padding: 3px 4px 3px 6px; border-radius: 6px;
  background: var(--surface-2); font-size: var(--fs-counter); line-height: 1.2; }
.idea-counter-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-2, #6B645C); font-weight: var(--w-strong); }
.idea-counter-value { flex: none; padding: 1px 5px; border-radius: 4px; background: #FF8C1A; color: #fff; font-weight: 700; }
.idea-counter-glyph { flex: none; font-size: 15px; line-height: 1; }
.ideas-retry { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin: 0 0 var(--s-3); }
.ideas-retry .ideas-note { margin: 0; }

/* Ideas' stage overlay (stage-overlay.js): light and temporary, over the canvas, never part of the project. It
   ignores the pointer, so Play and the project's own clicks still work. */
.idea-overlay { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 6; pointer-events: none; overflow: visible; }
/* the badge layer is the stage's size: badges scale with the STAGE (cqi), not the window */
.idea-badges { position: absolute; inset: 0; z-index: 7; pointer-events: none; container-type: inline-size; }
.ov-ring { fill: rgba(146, 53, 197, .10); stroke: var(--accent); stroke-width: 2.5; vector-effect: non-scaling-stroke; }
.ov-ring.target { fill: rgba(255, 255, 255, .10); }
.ov-ring.hidden { fill: rgba(255, 255, 255, .28); stroke-dasharray: 5 4; }
.ov-link { stroke: var(--accent); stroke-width: 2.5; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.ov-link.then { stroke-dasharray: 6 5; }
#ideaArrow path { fill: var(--accent); }
.stage-box.ov-backdrop::after { content: ''; position: absolute; inset: 0; z-index: 6; pointer-events: none; border-radius: inherit;
  box-shadow: inset 0 0 0 4px var(--accent), inset 0 0 0 9px rgba(146, 53, 197, .22); }
/* a badge is a strong part of the explanation, not a footnote: about 4% of the stage's width (15-27 px), its emoji
   a little larger than its word so the two read as one unit; everything else in em, so it all scales together.
   It is an ANNOTATION, never a button: no border, no lift, no pill; a dark see-through caption with a light halo,
   and a small tail that points at the thing it describes (above it: the tail points down; below it: up). */
.ov-badge { position: absolute; display: inline-flex; align-items: center; gap: .3em; max-width: 72%; padding: .16em .5em .18em .38em;
  border: 0; border-radius: .38em; background: rgba(24, 21, 38, .74); color: #fff; box-shadow: none; cursor: default; user-select: none;
  font-size: clamp(15px, 4cqi, 27px); font-weight: var(--w-strong); line-height: 1.15; letter-spacing: .005em;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .55); white-space: nowrap;
  transform: translate(-50%, calc(-100% - .42em - var(--stack, 0) * 1.6em)); }
.ov-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.ov-badge::after { content: ''; position: absolute; left: 50%; top: 100%; margin-left: -.36em; border: .36em solid transparent;
  border-top-color: rgba(24, 21, 38, .74); border-bottom-width: 0; }
.ov-badge:not(.above):not(.below)::after { display: none; }
.ov-badge.below { transform: translate(-50%, calc(.42em + var(--stack, 0) * 1.6em)); }
.ov-badge.below::after { top: auto; bottom: 100%; border-top-width: 0; border-bottom-width: .36em; border-top-color: transparent;
  border-bottom-color: rgba(24, 21, 38, .74); }
/* on a connector: a label sitting on its line */
.ov-badge.mid { transform: translate(-50%, -50%); background: rgba(24, 21, 38, .8); }
.ov-badge.frame { transform: translate(-50%, 0); }
/* a counter's change floats beside its monitor like score text in a game: no backing at all, a strong halo */
.ov-badge.right, .ov-badge.pill { background: none; color: #FFE45C; font-size: clamp(17px, 4.6cqi, 30px); font-weight: 800;
  text-shadow: 0 0 2px #1d1830, 0 0 2px #1d1830, 0 1px 3px rgba(0, 0, 0, .8), 0 0 8px rgba(0, 0, 0, .45); padding: 0 .1em; }
.ov-badge.right { transform: translate(0, -50%); }
.ov-badge.pill { transform: translate(-50%, -50%); }
.ov-ghost { opacity: .55; }
.ov-emoji { font-size: 1.15em; line-height: 1; }
@media (prefers-reduced-motion: no-preference) { .ov-badge, .ov-ring, .ov-link { animation: fade-in var(--t-med) var(--ease); } }
/* while an idea points at the stage, the ready veil lightens so the things it names can be seen (Play still works) */
.stage-box.has-idea-overlay .play-overlay { background: rgba(20, 18, 32, .16); }
.stage-box.has-idea-overlay .play-title, .stage-box.has-idea-overlay .play-word { display: none; }
.stage-box.has-idea-overlay .play-disc { width: 56px; height: 56px; }
.stage-box.has-idea-overlay .play-disc .icon { width: 28px; height: 28px; }

/* ---------- prompt-first (prompt-first-ui-001): on a desktop the creation column is READ, not glanced at ----------
   The prompt is the person's instruction and the strongest thing in the column; Ideas and Fix are tools that build it.
   The column's own tokens scale up here (never a zoom, never the stage); nothing a person must read is under 15px. */
@media (min-width: 861px) {
  .chat { --fs-xs: 15px; --fs-sm: 16px; --fs-md: 18px; --fs-prompt: 18px; --fs-panel-title: 20px; --fs-sentence: 20px; --fs-tile: 17px;
    --fs-counter: 14px; --h-btn: 44px; --h-big: 48px; --h-small: 44px;
    --tile-min-h: 120px; --thumb-w: 72px; --thumb-h: 54px; --pair-thumb: 40px; --prompt-min-h: 100px; }
  .composer textarea { padding: 14px 18px; border-width: 2px; }
  /* the white header and the canvas gutters above and below took the column's height: the box sits a little closer
     to its edges, so it and Send never leave the screen */
  .composer { padding-top: var(--s-3); padding-bottom: var(--s-3); }
  body.no-project .composer textarea { min-height: 140px; }
  /* the head row takes no height: it floats just above the stage, and only when it has something to say */
  .stage-head { position: absolute; left: 0; right: 0; bottom: calc(100% + var(--s-2)); margin: 0; }
}
/* ---------- The idea's pieces (right-panel-visual-001) ----------
   One picture card per builder choice. The finished builder shows them instead of repeating the sentence (the words are
   in the box on the left); a first build's waiting stage shows them flowing into the stage. Decorative: aria-hidden. */
.pieces { display: flex; align-items: center; justify-content: center; gap: var(--s-2); }
.piece { flex: 1 1 0; min-width: 64px; max-width: 124px; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--s-2); padding: var(--s-3) var(--s-2); border-radius: 20px; background: #fff;
  box-shadow: 0 1px 2px rgba(44, 22, 53, .06), 0 8px 20px rgba(44, 22, 53, .08), inset 0 0 0 1.5px #E9D7F5; }
.piece-pic { font-size: 46px; line-height: 1.1; }
.piece-label { font-size: 15px; font-weight: var(--w-strong); line-height: 1.2; color: var(--text); text-align: center; overflow-wrap: anywhere; }
.piece-join { flex: 0 0 auto; width: 14px; height: 4px; border-radius: 2px; background: #DDC2EF; }
.pieces.ready { justify-content: flex-start; align-items: stretch; margin: var(--s-1) 0 var(--s-4); }
.pieces.ready .piece-join { align-self: center; }
.pieces.ready .piece { min-height: 124px; transition: transform var(--t-fast, .15s) ease; }
.vpb.done .vpb-label { font-size: var(--fs-body); }
.vpb-done { color: var(--text-2); font-weight: var(--w-strong); }
/* the waiting stage: the pieces on the dark stage surround, flowing into a pulsing play target */
.building-pieces { margin-bottom: var(--s-4); }
.building-pieces:empty { display: none; }
.stage-overlay.building .pieces { gap: var(--s-2); }
.stage-overlay.building .piece { flex: 0 0 auto; width: 92px; height: 92px; min-width: 0; padding: 0; border-radius: 18px;
  background: rgba(255, 255, 255, .09); box-shadow: inset 0 0 0 1.5px rgba(187, 118, 229, .35); }
.stage-overlay.building .piece-pic { font-size: 48px; }
.stage-overlay.building .piece-join { width: 22px; background: rgba(187, 118, 229, .25); }
.stage-overlay.building .piece.target { background: var(--accent); box-shadow: inset 0 0 0 2px var(--accent-light); color: #fff; }
.stage-overlay.building .piece.target .icon { width: 34px; height: 34px; }
@media (max-width: 860px) {
  .stage-overlay.building .pieces { gap: 4px; }
  .stage-overlay.building .piece { width: 46px; height: 46px; border-radius: 12px; }
  .stage-overlay.building .piece-pic { font-size: 26px; }
  .stage-overlay.building .piece-join { width: 8px; }
  .stage-overlay.building .piece.target .icon { width: 22px; height: 22px; }
}
@keyframes piece-in { from { opacity: 0; transform: translateY(12px) scale(.86); } }
@keyframes piece-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }
@keyframes piece-flow { from { background-position: 100% 0, 0 0; } to { background-position: -100% 0, 0 0; } }
@keyframes target-pulse { 0%, 100% { box-shadow: inset 0 0 0 2px var(--accent-light), 0 0 0 0 rgba(187, 118, 229, .5); }
  60% { box-shadow: inset 0 0 0 2px #fff, 0 0 0 14px rgba(187, 118, 229, 0); } }
@media (prefers-reduced-motion: no-preference) {
  .pieces.ready .piece, .pieces.ready .piece-join { animation: piece-in .45s var(--ease) both; animation-delay: calc(var(--i) * 110ms); }
  .pieces.ready .piece:hover { transform: translateY(-3px); }
  .pieces.assembling .piece { animation: piece-in .5s var(--ease) both, piece-bob 2.6s ease-in-out infinite;
    animation-delay: calc(var(--i) * 160ms), calc(.6s + var(--i) * 260ms); }
  .pieces.assembling .piece-join { background: linear-gradient(90deg, transparent 30%, var(--activity-on-dark) 50%, transparent 70%) 0 0 / 200% 100% no-repeat,
    rgba(187, 118, 229, .22); animation: piece-in .4s var(--ease) both, piece-flow 1.3s linear infinite;
    animation-delay: calc(var(--i) * 160ms), calc(var(--i) * 200ms); }
  .pieces.assembling .piece.target { animation: piece-in .5s var(--ease) both, target-pulse 1.8s ease-out infinite;
    animation-delay: calc(var(--i) * 160ms), .8s; }
}

/* ---------- Desktop scale (chosen by dogfooding with the calibration tool, ui-calibration-controls-001) ----------
   The creation column is zoomed as a whole (its own tokens stay as they are), the prompt's text is larger again inside
   it, and the Starting Builder, which stands in for the EMPTY stage, is zoomed too. The stage, its canvas, overlays and
   pointer mapping are never zoomed: the column's width is the grid track (--chat-w) and the stage takes the rest. */
:root { --ui-zoom: 1.3; --prompt-scale: 1.4; --builder-zoom: 1.4; --controls-zoom: 1; }
/* the TEMPORARY developer tool: dev-calibration.js sets --cal-* on <html> from this browser's localStorage; they act
   only in developer mode, and each falls back to the production value above */
body.dev-mode { --ui-zoom: var(--cal-zoom, 1.3); --prompt-scale: var(--cal-prompt, 1.4); --builder-zoom: var(--cal-builder, 1.4);
  --controls-zoom: var(--cal-controls, 1); }
@media (min-width: 861px) {
  body.dev-mode { --chat-w: var(--cal-chat-w, clamp(420px, 42vw, 780px)); }
  .chat { zoom: var(--ui-zoom); border-radius: calc(var(--r-panel) / var(--ui-zoom)); border-width: calc(1px / var(--ui-zoom)); }
  .chat .composer textarea { font-size: calc(var(--fs-prompt) * var(--prompt-scale)); }
  /* a viewport-relative height inside a zoomed column is zoomed too: keep the panel at its share of the screen */
  .chat .ideas { max-height: calc(54dvh / var(--ui-zoom)); }
  .stage-overlay.empty.has-builder .vpb { zoom: var(--builder-zoom); }
  /* the Play/Download row and the head line; the stage gives up only the row's extra height (a 68 px row: 44 px
     controls and their 24 px gap), so it is resized exactly as a window resize would, never zoomed */
  .stage-controls, .stage-head { zoom: var(--controls-zoom); }
  .stage-column { max-width: calc((100dvh - var(--topbar-h) - 2 * var(--gutter) - 112px - 72px * (var(--controls-zoom) - 1)) * 4 / 3); }
}
.dev-cal { display: flex; flex-direction: column; gap: var(--s-2); padding-bottom: var(--s-3); border-bottom: 1px solid var(--line); }
.dev-cal-row { display: grid; grid-template-columns: 150px minmax(120px, 260px) auto; align-items: center; gap: var(--s-3); }
.dev-cal-row output { font-family: var(--mono); color: var(--text); }

/* a tablet keeps readable tile labels and counters (the phone keeps its tighter grid) */
@media (min-width: 481px) and (max-width: 860px) {
  .chat { --fs-counter: 13px; }
  /* with the history set aside, an open panel takes the column's whole remaining height (not a guessed share), so a
     step's Start over is not cut off at the bottom */
  .chat:has(.ideas:not([hidden])) .composer { flex: 1; min-height: 0; display: flex; flex-direction: column; justify-content: flex-end; }
  .chat .composer > .ideas { flex: 0 1 auto; min-height: 0; max-height: none; }
}
@media (max-width: 860px) {
  /* tablets and phones keep the denser control heights (44 / 40): the box, Ideas and the stage share one screen */
  :root { --topbar-h: 56px; --gutter: 8px; --h-big: 44px; --h-btn: 40px; }
  .topbar { gap: var(--s-3); padding: 0 calc(var(--gutter) + var(--s-2)); }
  /* the title, mode and download move into the menu (app.js shows its button) */
  .topbar .project-title, .topbar .mode-pill, .topbar .project-actions { display: none; }
  .menu-project { display: block; }
  .menu-project:has(.menu-title:empty) { display: none; }
  .menu-project:not(:has(.menu-title:empty)) + .menu-account { border-top: 1px solid var(--line); padding-top: var(--s-1); margin-top: var(--s-1); }
  .layout { display: flex; flex-direction: column; }
  .chat, .stage-panel { border-radius: 20px; }
  .stage-panel { order: -1; flex: none; padding: var(--s-2); overflow: visible; }
  .stage-panel .dev { display: none; }
  /* the stage takes at most about half the screen height, so the history and the box always have room */
  /* .41 (was .44): the panels' gutters and edges come out of the stage, not out of the box and Ideas below it */
  .stage-column { max-width: min(100%, calc((100dvh - var(--topbar-h)) * .41 * 4 / 3)); min-width: 0; }
  .stage-head { margin-bottom: var(--s-2); min-height: 0; }
  .stage-head:has(.version-label:empty):has(.build-status:empty) { display: none; }
  .stage-controls { margin: 0 0 var(--s-2); }
  .stage-hint { display: none; }
  .touch-note { margin-top: var(--s-2); }
  .stage-wrap.is-empty .stage-box { aspect-ratio: auto; height: 72px; }
  /* nothing to show on the stage yet (no project, no build): the builder in the column has the room instead */
  body.no-project:not(.has-job) .stage-panel { display: none; }
  .chat .vpb { margin-top: var(--s-3); }
  .chat { flex: 1; }
  .timeline { padding: var(--s-4) var(--s-3); gap: var(--s-4); }
  .composer { padding: var(--s-3) var(--s-3) calc(var(--s-3) + env(safe-area-inset-bottom)); }
  body.no-project .composer textarea { min-height: 76px; }
  .composer textarea { min-height: 56px; }
  .btn, .menu-item { min-height: var(--h-big); }
  .btn.small { min-height: 40px; }
  /* Ideas shares the column under the stage with the box: while it is open the history steps aside, and the
     panel takes what is left and scrolls inside, so the box and Send stay on screen. The stage panel is about
     44% of the height plus ~114 px of head and controls (.stage-column); the box, Send and padding ~170 px. */
  .chat:has(.ideas:not([hidden])) .timeline { display: none; }
  .ideas { max-height: max(120px, calc((100dvh - var(--topbar-h)) * .56 - 290px)); padding: var(--s-2) var(--s-2) var(--s-3) var(--s-3); }
  .ideas-head { position: sticky; top: calc(-1 * var(--s-2)); z-index: 1; margin: calc(-1 * var(--s-2)) 0 var(--s-2); padding-top: var(--s-2);
    background: var(--surface-2); }
  .ideas.fix .ideas-head { background: #FFFBF2; }
  .ideas-note:not(.keep) { display: none; }
  .idea-cat { min-height: 52px; gap: var(--s-2); }
  .chat .ideas .tile, .ideas .tile { min-height: 64px; gap: var(--s-1); padding: var(--s-2) var(--s-1); }
  .chat .ideas .tile-pic, .ideas .tile-pic { font-size: 22px; }
  .ideas .tile-label { font-size: var(--fs-xs); }
}
@media (min-width: 481px) and (max-width: 860px) {
  .ideas .tile-label { font-size: var(--fs-sm); }
}
@media (max-width: 480px) {
  .ideas .tile-pic.has-thumb { width: 40px; height: 30px; }
  .tile-thumb.backdrop { width: 40px; height: 30px; }
  .ideas .tile-pic.vis-pair { width: 64px; }
  .ideas .tile-pic.vis-entity, .ideas .tile-pic.vis-backdrop { width: 50px; height: 38px; }
  .vis-pair .tile-thumb { width: 26px; height: 26px; }
  .tile-pic.vis-counter { height: 30px; }
  .idea-counter { font-size: 12px; padding: 2px 3px 2px 4px; }
  .idea-badge { --glyph: 16px; width: 23px; height: 23px; top: -7px; right: -12px; }
  .brand-logo { display: none; }    /* the jar alone on a phone; its accessible name is the same */
  .brand-icon { display: block; }
  .chips { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .chip { min-height: 56px; }
  .composer-hint { display: none; }
  .composer-row { justify-content: flex-end; margin-top: var(--s-2); }
  /* once a project exists (no picker), Send sits beside the box to save height */
  body:not(.no-project) .composer { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0 var(--s-2); }
  body:not(.no-project) .composer .notice, body:not(.no-project) .composer .ideas { flex-basis: 100%; }
  .idea-cat .tile-pic { font-size: 22px; }
  /* with Ideas offered, the box keeps the whole width and Ideas and Send sit in a row below it */
  body:not(.no-project) .composer:has(#ideasBtn:not([hidden])) textarea { flex-basis: 100%; }
  body:not(.no-project) .composer:has(#ideasBtn:not([hidden])) .composer-row { flex: 1; margin-top: var(--s-2); justify-content: space-between; }
  /* Ideas, Fix something and Send share that row: tighter sides, the same height and words, Send on the right */
  body:not(.no-project) .composer-row { gap: 6px; }
  body:not(.no-project) .composer-row .btn.soft { padding: 0 var(--s-3); gap: 6px; }
  body:not(.no-project) .composer-row .btn.big { padding: 0 var(--s-3); margin-left: auto; }
  /* the panel's gutters cost the row 16 px: the box's sides give a little back so Send stays inside the panel */
  .composer { padding-left: var(--s-2); padding-right: var(--s-2); }
  .ideas { max-height: max(100px, calc((100dvh - var(--topbar-h)) * .56 - 220px)); }
  /* a construction step fits the panel: the question, the growing sentence, three tiles and Show me more stay in
     view together (ui-check U18 measures it) - tighter gaps, never smaller targets or text */
  .ideas-head { margin-bottom: var(--s-1); }
  .ideas-sentence { margin-bottom: var(--s-2); font-size: var(--fs-body); }
  .ideas .vpb-q { margin-bottom: var(--s-1); }
  .ideas-actions { margin-top: var(--s-2); }
  .ideas-actions .btn.small { min-height: 44px; }
  .chat .tile { min-height: 84px; }
  .chat .tile-pic { font-size: 30px; }
  body:not(.no-project) .composer textarea { flex: 1 1 0; min-width: 0; min-height: var(--h-big); }
  body:not(.no-project) .composer-row { margin-top: 0; }
  /* a phone: the view switch takes its own row, run and stop share the next, each half */
  /* a phone: run and stop on the left, Stage | Blocks taking the rest of the row (it wraps under them only if it must) */
  .view-toggle { flex: 1 1 auto; }
  .view-toggle .seg { flex: 1; justify-content: center; padding: 0 var(--s-2); }
  .run-btn, .stop-btn { width: 52px; }
  /* phones: panels nearly edge-to-edge with the canvas still showing; dialogs a slightly smaller radius; one strong
     column of project cards (two to a row was squeezed) */
  :root { --gutter: 6px; }
  /* Ideas keeps the tile width it had before the gutters (a label never wraps to a third line) */
  .ideas { padding-left: 6px; padding-right: 6px; }
  .chat, .stage-panel { border-radius: var(--r-card); }
  .projects-layer { padding: var(--s-3) var(--s-2); }
  .projects-box, .login-box { padding: var(--s-5) var(--s-4); border-radius: 20px; }
  .projects-list { grid-template-columns: minmax(0, 1fr); gap: var(--s-3); }
  .pcard-pic { aspect-ratio: 2 / 1; }
  .confirm-pop { border-radius: var(--r-card); }
  .composer textarea { border-radius: var(--r-card); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 1ms !important; animation-iteration-count: 1 !important; transition-duration: 1ms !important; scroll-behavior: auto !important; }
  .spinner { animation: none; border-top-color: var(--accent); opacity: .8; }
  .toast { animation: none; }
  /* the 1 ms above turns EVERY property change into a transition (transition-property defaults to all): the code
     canvas then reported its old place and width for a frame after the focus panel opened, and the camera framed
     the script for the old width and jumped again a frame later. SVG transform and width attributes are style too,
     so Blockly's own canvas moves became transitions as well. Nothing in the Blocks view may lag a frame. */
  .blocks-view, .blocks-view * { transition-duration: 0s !important; }
  .btn:active, .chip:active, .tile:active, .idea-cat:active, .tile:hover { transform: none; }
  .btn.primary:active:not(:disabled) { transform: none; }
}
/* Windows high contrast / forced colours: icons follow the text colour, chips and cards keep a visible edge */
@media (forced-colors: active) {
  .icon { stroke: CanvasText; }
  .chip, .vcard, .btn.soft, .composer textarea, .tile, .idea, .idea-cat, .vpb, .ideas { border: 1px solid CanvasText; }
  .chip:has(input:checked) { outline: 3px solid Highlight; }
}

/* Scratch's "ask and wait" prompt (player.js attachAsk), along the bottom of the stage. */
.ask-prompt { position: absolute; left: 8px; right: 8px; bottom: 8px; background: #fff; border: 2px solid #4c97ff; border-radius: 8px; padding: 6px 8px; box-shadow: 0 2px 6px rgba(0,0,0,.15); font: 13px/1.3 "Helvetica Neue", Helvetica, Arial, sans-serif; color: #575e75; }
.ask-prompt.hidden, .ask-question.hidden { display: none; }
.ask-question { font-weight: 700; margin-bottom: 4px; }
.ask-row { display: flex; gap: 6px; }
.ask-input { flex: 1; min-width: 0; border: 1px solid #c3d1e8; border-radius: 16px; padding: 4px 10px; font: inherit; color: inherit; outline: none; }
.ask-input:focus { border-color: #4c97ff; }
.ask-submit { border: 0; border-radius: 50%; width: 26px; height: 26px; background: #4c97ff; color: #fff; font-weight: 700; cursor: pointer; }
/* THE CURIOUS HELPER (ADR-083): decorative, beside the heading so the explanation keeps the panel's whole width.
   Sized from the panel (it is the inline-size container), about 72-96 px tall; gone on the stacked phone card, where
   every line goes to the explanation. Its own animation (rock, blink) stops under reduced motion (its own rule). */
.focus-head { display: flex; align-items: center; gap: var(--s-3); margin-top: var(--s-1); }
.focus-head .focus-heading { margin: 0; }
.curious-helper { display: inline-block; flex: none; line-height: 0; }
.curious-helper svg { display: block; width: 100%; height: 100%; overflow: visible; }
.curious-helper.is-panel { width: clamp(72px, 28cqi, 92px); aspect-ratio: 400 / 480; }
.is-narrow .curious-helper.is-panel, .is-narrow .focus-head { display: none; }
