/* ScratchCreator — "Creative Studio" (Frontend Product Polish 002): Studio Calm's warm, restrained surfaces,
   with type, targets and a small icon family sized for people from about 7 to adult.
   Every value below the tokens comes from the tokens; a one-off colour or size is a bug. */
: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: "Segoe UI Variable Text", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", Arial, sans-serif;
  --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-strong: 600;
  /* spacing */
  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 24px; --s-6: 32px; --s-7: 48px;
  /* radius: controls, cards and the stage, pills */
  --r-control: 10px; --r-card: 14px; --r-pill: 999px;
  /* surfaces */
  --bg: #FAF8F5; --surface: #FFFFFF; --surface-2: #F3F0EB; --surface-3: #E9E4DC; --stage-surround: #1E1B2E;
  /* text: about 15:1, 9:1 and 5.4:1 on white (never lighter than --text-3) */
  --text: #1F1D24; --text-2: #4A4752; --text-3: #6B6874; --text-on-dark: #F2F0FA; --text-on-dark-2: #C9C5DA;
  /* lines: dividers, and the edge of a soft (white) button */
  --line: #E8E3DB; --line-strong: #D6D0C6;
  /* accent: primary action and selection only; the wash marks "current" without competing with the stage */
  --accent: #6B4EFF; --accent-hover: #5A3DEB; --accent-press: #4E33D6; --accent-soft: #EFEBFF; --accent-wash: #F8F6FF;
  --accent-ring: rgba(107, 78, 255, .38);
  /* 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(30, 27, 46, .06), 0 1px 3px rgba(30, 27, 46, .07);
  --shadow-2: 0 14px 36px rgba(30, 27, 46, .20), 0 2px 8px rgba(30, 27, 46, .10);
  /* motion */
  --t-fast: 150ms; --t-med: 250ms; --ease: cubic-bezier(.2, .7, .2, 1);
  /* controls: primary 44, ordinary 40, small 36 */
  --h-big: 44px; --h-btn: 40px; --h-small: 36px;
  --topbar-h: 60px;
  /* 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; }
.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(--accent); 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-4); padding: 0 var(--s-5);
  background: var(--bg); 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: 39px; aspect-ratio: 1930 / 540; flex: none; }
.brand-icon { display: none; height: 39px; 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: 1; min-width: 0; margin-left: var(--s-2); padding-left: var(--s-4); border-left: 1px solid var(--line-strong);
  font-size: var(--fs-md); font-weight: var(--w-strong); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.project-title:empty { border-left: 0; }
.mode-pill { font-size: var(--fs-xs); font-weight: var(--w-strong); color: var(--text-2); background: var(--surface-2); 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-2); margin-left: auto; }
.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-1)); right: var(--s-4); z-index: 20;
  background: var(--surface); border-radius: var(--r-card); 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-4) var(--s-5) var(--s-5); }
.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(--accent-soft); 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: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: linear-gradient(180deg, var(--stage-surround) 0 38%, var(--bg) 38% 100%); }
.login-box { width: 420px; max-width: 100%; background: var(--surface); border-radius: var(--r-card); box-shadow: var(--shadow-2);
  padding: var(--s-6); display: flex; flex-direction: column; align-items: stretch; gap: var(--s-3); }
.login-box .brand-icon { align-self: center; }
.login-box h1 { margin: 0; font-size: var(--fs-2xl); line-height: 1.2; text-align: center; }
.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; }
.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(--accent); box-shadow: 0 0 0 3px var(--accent-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); color: var(--accent); cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px; }
.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(20, 18, 40, .45); overflow-y: auto; }
.projects-box { width: 760px; max-width: 100%; background: var(--surface); border-radius: var(--r-card); box-shadow: var(--shadow-2);
  padding: var(--s-5); display: flex; flex-direction: column; gap: var(--s-3); }
.projects-head { display: flex; align-items: center; gap: var(--s-3); }
.projects-head h2 { margin: 0 auto 0 0; font-size: var(--fs-xl); }
.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-title { margin: 0; font-size: var(--fs-lg); font-weight: var(--w-strong); }
.projects-empty-sub { margin: 0 0 var(--s-3); color: var(--text-2); }
.projects-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-2); }
.pcard { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-2); border: 1.5px solid var(--line); border-radius: var(--r-control); }
.pcard.current { border-color: var(--accent); }
.pcard-open { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--s-3); background: none; border: 0; padding: var(--s-1);
  text-align: left; font: inherit; color: inherit; cursor: pointer; border-radius: var(--r-control); }
.pcard-open:hover { background: var(--surface-2); }
.pcard-pic { flex: none; width: 48px; height: 48px; display: grid; place-items: center; font-size: 26px; border-radius: 12px; background: var(--surface-2); }
.pcard-text { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.pcard-title { font-weight: var(--w-strong); font-size: var(--fs-md); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pcard-meta { font-size: var(--fs-sm); color: var(--text-2); }
.pcard-actions { flex: none; display: flex; align-items: center; gap: var(--s-2); }
.pcard-confirm { margin: 0; font-size: var(--fs-sm); max-width: 260px; }

/* ---------- 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);
  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: 0 0 0 3px var(--accent-ring); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: default; pointer-events: none; }
.btn.primary { background: var(--accent); color: #fff; box-shadow: 0 1px 2px rgba(78, 51, 214, .25); }
.btn.primary:hover:not(:disabled) { background: var(--accent-hover); }
.btn.primary:active:not(:disabled) { background: var(--accent-press); }
.btn.primary:focus-visible { box-shadow: 0 0 0 3px var(--accent-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); }
.btn.soft:hover:not(:disabled) { background: var(--surface-2); }
.btn.soft:focus-visible { box-shadow: inset 0 0 0 1.5px var(--line-strong), 0 0 0 3px var(--accent-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.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); height: calc(100vh - var(--topbar-h)); height: calc(100dvh - var(--topbar-h)); }
.chat { display: flex; flex-direction: column; min-height: 0; min-width: 0; background: var(--surface); border-right: 1px solid var(--line); }
.stage-panel { display: flex; flex-direction: column; min-height: 0; min-width: 0; padding: var(--s-5) var(--s-6); overflow: auto; }
/* The stage and its head and controls share one centred column, as wide as the stage. */
/* 168px: the panel's padding, the stage frame and the controls under it. 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) - 168px) * 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(--accent-soft); }
.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(--bg); }
/* "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(--accent-wash); box-shadow: inset 0 0 0 1.5px var(--accent-soft); }
.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(--accent); outline-offset: -2px; }
.vtitle { font-size: var(--fs-md); font-weight: var(--w-strong); 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-3);
  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-strong); }
.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(--accent); font-weight: var(--w-strong); }
.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; }
.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); font-weight: var(--w-strong); 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-strong); 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); font-weight: var(--w-strong); line-height: 1.3; color: var(--text); }
.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); }
.tile:active { transform: translateY(1px); }
.tile:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent), 0 0 0 3px var(--accent-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(--accent-wash);
  box-shadow: inset 0 0 0 1.5px var(--accent-soft); }
.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: var(--surface); }
.composer textarea {
  display: block; width: 100%; resize: none; border: 1.5px solid var(--line-strong); border-radius: var(--r-card); 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(--accent); box-shadow: 0 0 0 4px var(--accent-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(--accent); box-shadow: 0 0 0 3px var(--accent-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); }
.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(--accent-soft); color: var(--accent); box-shadow: inset 0 0 0 1.5px 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); font-weight: var(--w-strong); color: var(--text); }
.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(--accent-wash); box-shadow: inset 0 0 0 1.5px var(--accent-soft); 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); font-weight: var(--w-strong); line-height: 1.3; }
.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), 0 0 0 3px var(--accent-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(--accent); }
.chips { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-2); }
.chip { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-height: 64px;
  padding: var(--s-2) var(--s-1); 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-strong); color: var(--text); line-height: 1.25; }
.chip-hint { font-size: var(--fs-xs); color: var(--text-3); line-height: 1.3; }
.chip:has(input:checked) { background: var(--accent-soft); box-shadow: inset 0 0 0 2px var(--accent); }
.chip:has(input:checked) .chip-name { color: var(--accent); }
.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: 0 0 0 3px var(--accent-ring), inset 0 0 0 2px var(--accent); }
.mode-lock { font-size: var(--fs-xs); font-weight: var(--w-regular); color: var(--text-3); }

/* ---------- 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: var(--shadow-2);
  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: #6B4EFF !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(107, 78, 255, .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: #4E33D6; stroke-width: 2; stroke-linejoin: round; filter: drop-shadow(0 2px 0 rgba(78, 51, 214, .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 #6B4EFF; 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: 0 0 0 3px var(--accent-ring), var(--shadow-2); }
.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; }
/* 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: #A996FF; margin-bottom: var(--s-3); }
.building-title { font-size: 22px; font-weight: var(--w-strong); 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: #9C97B3; }
.stage-overlay.building .phase-steps .done { color: var(--text-on-dark-2); }
.stage-overlay.building .phase-steps .now { color: #C4B8FF; }
.stage-overlay.building .wait-time { color: #A8A3BF; 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 #C4B8FF; outline-offset: -3px; }
.play-title { max-width: 90%; font-size: 22px; font-weight: var(--w-strong); 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(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center; padding-left: 5px; box-shadow: 0 6px 20px 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(--accent-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; } }

/* Two groups under the stage: playing it (Play/Replay first), then taking it away (Download, Open Scratch). */
.stage-controls { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3) var(--s-4); margin-top: var(--s-5); flex-wrap: wrap; }
.ctl-group { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
/* [ Play | Blocks ]: one compact segmented control, left of Play / Stop */
.view-toggle { flex-wrap: nowrap; gap: 2px; padding: 3px; border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--surface-2); }
.view-toggle .seg { height: calc(var(--h-btn) - 8px); padding: 0 var(--s-4); border: 0; border-radius: var(--r-pill); background: transparent;
  color: var(--text-2); font: inherit; font-weight: var(--w-strong); cursor: pointer; }
.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(--text); box-shadow: var(--shadow-1); }
.view-toggle .seg:disabled { opacity: .5; cursor: default; }
.view-toggle .seg:focus-visible { outline: 3px solid var(--accent-ring); outline-offset: 1px; }
.view-toggle + .ctl-group { margin-right: auto; }
.play-btn { height: var(--h-big); min-width: 128px; padding: 0 var(--s-5); font-size: var(--fs-body); }
#stop { height: var(--h-big); }
.ctl-group.secondary .btn { height: var(--h-btn); }   /* tertiary: under Ideas and Fix something in weight */
.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(107, 78, 255, .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(107, 78, 255, .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: 104px; }
  .composer textarea { padding: 14px var(--s-4); border-width: 2px; }
  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(30, 27, 46, .06), 0 8px 20px rgba(30, 27, 46, .08), inset 0 0 0 1.5px #DCD4FF; }
.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: #CFC4FF; }
.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(169, 150, 255, .35); }
.stage-overlay.building .piece-pic { font-size: 48px; }
.stage-overlay.building .piece-join { width: 22px; background: rgba(169, 150, 255, .25); }
.stage-overlay.building .piece.target { background: #6B4EFF; box-shadow: inset 0 0 0 2px #A996FF; 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 #A996FF, 0 0 0 0 rgba(169, 150, 255, .5); }
  60% { box-shadow: inset 0 0 0 2px #fff, 0 0 0 14px rgba(169, 150, 255, 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%, #C9BCFF 50%, transparent 70%) 0 0 / 200% 100% no-repeat,
    rgba(169, 150, 255, .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); }
  .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) - 168px - 68px * (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) {
  :root { --topbar-h: 56px; }
  .topbar { gap: var(--s-2); padding: 0 var(--s-3); }
  /* the title, mode and download move into the menu (app.js shows its button) */
  .topbar .project-title, .topbar .mode-pill { 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; }
  .stage-panel { order: -1; flex: none; padding: var(--s-2) var(--s-3) var(--s-3); overflow: visible; border-bottom: 1px solid var(--line); }
  .stage-panel .dev { display: none; }
  /* the stage takes at most about half the screen height, so the history and the box always have room */
  .stage-column { max-width: min(100%, calc((100dvh - var(--topbar-h)) * .44 * 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-top: var(--s-3); }
  .ctl-group.secondary { display: none; }
  .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; border-right: 0; }
  .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(--accent-wash); }
  .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: var(--s-2); }
  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-4); margin-left: auto; }
  .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; }
  .play-btn { min-width: 0; }
}

@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 { 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; }
