/* layer: shared
   is:    what every lesson looks like — the ground, the voice, the count
          track, and the two ways she answers
   owns:  the palette, and that anything which must stay distinguishable is
          measured in units of the count and never in pixels */

/* What every lesson looks like: the ground, the voice, the count track,
   and the two ways she answers. Nothing here belongs to one lesson. */

:root {
  /* Two worlds, two temperatures: the things are warm, the number is cool. */
  --ground: #f2efe8;
  --ink: #23262a;
  --ink-soft: #5d6067; /* what is said beside the point, never instead of it */


  --count: #1c6b72;
  --count-soft: #b7d3d4;
  --count-pale: #e2eded;

  --tray: #ece5d7;
  --tray-rim: #ddd3c0;

  --step: 0.32s;
  --calm: 1.8s; /* the beckon's breath — an invitation, never a jolt */
  --jump: 0.52s; /* one unit of travel on the track — marker and trace share it */

  /* A RÉGUA DA MOLDURA: every fluid token below measures the screen
     through this indirection — 1vw/1vh by default (the real app), and
     whoever frames the screen in a smaller glass (the workshop's device
     frame) refeeds it the frame's own size. A bench that kept the
     window's vw drew a desktop's margins inside a 390px phone — the
     cramped-whiteboard scar (2026-08-29). */
  --vw: 1vw;
  --vh: 1vh;

  /* THE SIZES, IN ONE PLACE. --unit is how wide one unit of the count is
     allowed to be — what stops a short track from being stretched across a
     wide screen; everything on the track is a fraction of it. */
  /* the canonical breath: the minimum air between a thing and its
     neighbour, kept whenever there is room for it */
  --breath: clamp(10px, calc(1.6 * var(--vw)), 20px);
  /* The ceiling the content stops growing at, and the margin it keeps. */
  --ceiling: 1180px;
  --edge: clamp(24px, calc(5 * var(--vw)), 72px);

  /* The room a screen actually has for its mathematics. */
  --room: calc(min(calc(100 * var(--vw)), var(--ceiling)) - 2 * var(--edge));

  /* A unit is the room divided by how many units must be shown — not a
     fraction of the viewport. Deriving it from the viewport made the count
     shrink faster than the screen did and leave the sides empty; deriving it
     from the room means a count of ten fills the same width a count of
     twenty-five does, and the drawings on it grow with it.
     The floor keeps a unit touchable; the ceiling keeps it from becoming
     scenery on a wide screen. */
  /* THE DIGNITY: the ceiling of one countable thing, past which it turns
     into scenery. The unit's ceiling, and the seat's (stage.js seat()) —
     one number for the house, never one per family. */
  --dignity: 96px;
  --unit: clamp(22px, calc(var(--room) / var(--total, 20)), var(--dignity));
  /* how far a pressed thing sinks — the platform's answer to a finger */
  --sink: 2px;

  /* ---------- the type scale: a size is a ROLE, never a number.
     A thing's PIGMENT (a cherry's red) is not a token — it lives with the
     thing; these are the platform's own voice, paper and ink. ---------- */
  --type-hero: clamp(34px, calc(6 * var(--vw)), 58px); /* the number being learned */
  --type-numeral: clamp(30px, calc(4.4 * var(--vw)), 50px); /* numbers standing in a chain */
  --type-title: clamp(28px, calc(4.4 * var(--vw)), 44px); /* what names the screen */
  --type-say: clamp(21px, calc(2.6 * var(--vw)), 31px); /* what the voice is saying */
  --type-lead: clamp(19px, calc(2.4 * var(--vw)), 26px); /* what asks or answers */
  --type-body: clamp(16px, calc(2.1 * var(--vw)), 21px); /* what accompanies */
  --type-note: clamp(15px, calc(1.7 * var(--vw)), 19px); /* what explains quietly */
  --type-label: clamp(12px, calc(1.4 * var(--vw)), 14px); /* what tags */

  /* ---------- the space scale: rhythm is a ROLE too. Three vertical
     breaths, one horizontal air beside --breath, and the 4px grid for
     fixed seams. A component's content-fitting metric (the chain's own
     squeeze) stays with the component, like pigment. ---------- */
  --row: clamp(14px, calc(2.5 * var(--vh)), 36px); /* between the screen's rows */
  --stack: clamp(10px, calc(2 * var(--vh)), 26px); /* between a block's parts */
  --rest: clamp(10px, calc(1.6 * var(--vh)), 18px); /* the card's quiet stack */
  --air: clamp(14px, calc(3 * var(--vw)), 34px); /* between standing terms */
  --hush: clamp(30px, calc(6 * var(--vh)), 70px); /* the index's tall quiet */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;

  /* the strip: the lesson's one permanent band — never a tight target */
  --strip: clamp(44px, calc(5.5 * var(--vh)), 54px);
  /* a key of the number pad: 48px of design, shrinking on a narrow frame
     so the row of ten wraps ONCE, never twice — eleven fixed keys broke
     into THREE rows on a phone and the footer ate the scene's room */
  --key: clamp(38px, calc(11 * var(--vw)), 48px);
  /* a alternativa é uma LAJE de largura fixa: a FILEIRA dá a largura
     (meia para 2 e 4; terça para 3, 5 e 6) e o RÓTULO dá o passo da
     fonte — a escada desce no engine (dressChoices) até o chão de 14px;
     desktop veste 27px único. A prosa longa sobe à laje ALTA (duas
     linhas, só na meia); a matemática nunca quebra. Tetos em unidades
     no script-gate; a válvula é `aperto:` declarado no roteiro. */
  --choices-measure: 620px;
  --choice: clamp(52px, calc(9 * var(--vh)), 64px);
  --choice-tall: 96px;
  --type-choice: clamp(19px, calc(2.4 * var(--vw)), 27px);
  /* a beginning reader follows the voice; her line never runs the screen */
  --say-measure: 46ch;
  /* the numbers she reads TO ANSWER — never the smallest text on screen */
  --type-answer: clamp(24px, calc(3.2 * var(--vw)), 36px);

  /* ---------- corners ---------- */
  --round-dish: clamp(18px, calc(2.2 * var(--vw)), 30px);
  --round-card: 22px;
  --round-slab: 14px;
  --round-pill: 999px;

  /* ---------- paper, and the inks the light leaves ---------- */
  --paper: #fbf9f5;
  --paper-bright: #fff;
  --shade-whisper: rgba(35, 38, 42, 0.06);
  --shade-soft: rgba(35, 38, 42, 0.09);
  --shade-deep: rgba(35, 38, 42, 0.14);
  --press-count: rgba(28, 107, 114, 0.28);
  --halo-count: rgba(28, 107, 114, 0.16);
  /* the one warm judgement ink: a desaturated terracotta the ground
     already inhabits — used ONLY where the screen says "not this" (the
     error verdict's frame, the struck choice). Right stays teal: the
     counting world rewarding the counting. */
  --amiss: #a9705a;
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: ui-rounded, "SF Pro Rounded", "Nunito", system-ui, -apple-system,
    "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* ---------- the screen ---------- */
.screen {
  height: 100dvh;
  overflow: hidden;
  display: grid;
  grid-template-rows: auto 1fr;
  gap: var(--stack);
  /* the strip sits tight; the sheet reaches near the bottom — the lesson
     gets the room, and the sheet's own ceiling stops ballooning on very
     tall screens */
  padding: clamp(8px, calc(1.2 * var(--vh)), 14px) var(--edge) clamp(18px, calc(2.6 * var(--vh)), 32px);
  max-width: var(--ceiling);
  margin: 0 auto;
}

@media (max-width: 620px) {
  .screen {
    padding-inline: var(--space-3);
    gap: var(--rest);
  }

  /* the sheet keeps a narrower margin on a phone: its desk respiro of
     24px a side, with the screen's own, ate a quarter of the width before
     the scene began (2026-09-02) */
  .sheet {
    padding-inline: var(--space-4);
  }

  .stage {
    padding-inline: var(--space-2);
  }
}

/* ---------- the strip ---------- */
/* One band, at the top, and nothing at the bottom — the footer belongs to
   the answering hand. The strip holds what floats above a lesson: where
   she is (title), what she has done (the practice trail), the way back to
   a movement she missed, and the way out. Nothing in it ever CALLS for a
   press — that is its signature, and it holds for the two ways alike:
   they are available, never asked for. */
.strip {
  height: var(--strip);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
}

.strip-mid {
  display: grid;
  justify-items: center;
  gap: var(--space-1);
}

.strip-title {
  font-size: var(--type-note);
  font-weight: 700;
  color: var(--ink-soft);
  letter-spacing: 0.02em;
  white-space: nowrap;
}

/* where she is: dots walk the Learn; the trail tells the Practice; the
   phase names the half. A pool has no denominator — the forms differ on
   purpose: here you walk, there you show. */
.strip-where {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 18px;
}

.strip-where .dots {
  display: flex;
  gap: var(--space-1);
}

.strip-where .dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--count-soft);
}

.strip-where .dot[data-walked="true"] {
  background: var(--count);
}

.strip-where .phase {
  font-size: var(--type-label);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.strip-where .phase:empty {
  display: none;
}

.screen:not([data-practice="true"]) .strip .trail {
  display: none;
}

.screen[data-practice="true"] .strip .dots {
  display: none;
}

.strip .trail {
  gap: var(--space-2);
}

.strip .trail .mark {
  width: 12px;
  height: 12px;
}

.strip .leave {
  justify-self: end;
}

.strip .again {
  justify-self: start;
}

/* the held (ghost) surface reserves height and shows nothing */
.hold {
  visibility: hidden;
}

/* ---------- what the voice is saying ---------- */
.say {
  margin: 0;
  max-inline-size: var(--say-measure);
  margin-inline: auto;
  text-align: center;
  font-size: var(--type-say);
  line-height: 1.35;
  font-weight: 600;
  letter-spacing: -0.01em;
  /* two lines, always: 2 × the line-height above — the scene must not
     climb when a shorter line follows a longer one across screens */
  min-height: 2.7em;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity var(--step) ease;
}

.say[data-fading="true"] {
  opacity: 0;
}

/* a REAL frame change re-composes the screen the way an arrival does:
   the sheet dips out, the cycle refits, the sheet returns — numbers
   never slide across a screen she is watching */
.sheet[data-reframing="true"] {
  opacity: 0;
}

/* ---------- the card ---------- */
/*
   The one screen shape used whenever the platform speaks ABOUT the lesson
   rather than teaching it: the cover, the way into a session, the report.
   Deliberately quiet — an eyebrow that names where you are, one headline,
   and short asides. Everything is centred on the stage and its action lives
   in the answering band, so arriving and leaving move nothing.
*/
.card {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: var(--rest);
  text-align: center;
  max-width: 34ch;
  margin-inline: auto;
  padding-inline: var(--space-3);
}

.card .card-art {
  inline-size: clamp(64px, calc(12 * var(--vw)), 96px);
  display: block;
}

.card .eyebrow {
  margin: 0;
  font-size: var(--type-label);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--count);
}

.card .headline {
  margin: 0;
  font-size: var(--type-title);
  line-height: 1.12;
  font-weight: 800;
  letter-spacing: -0.015em;
  color: var(--ink);
  text-wrap: balance;
}

.card .aside {
  margin: 0;
  font-size: var(--type-body);
  line-height: 1.45;
  color: var(--ink-soft);
  text-wrap: balance;
}

/* what she did reads as a number, not as a sentence */
.card .figure {
  margin: 0;
  font-size: var(--type-lead);
  font-weight: 700;
  color: var(--count);
}

/* ---------- pressing ---------- */
/* Everything that can be touched sinks when it is. Hover says "this can be
   pressed"; only the sink says "you pressed it" — and on a tablet, where
   there is no hover at all, the sink is the only thing that answers.
   The platform owns the DEPTH (--sink) and its own surfaces; a lesson applies
   that depth to the things it invented, because the shared layer must not
   know what a dish or a pair is. */

.choice:active:not([data-spent="true"]),
.keys button:active,
.go:active {
  transform: translateY(var(--sink));
  box-shadow: none;
}

/* a family marks the thing of its own that sinks (data-sinks) — on the
   pressed element itself, or on the drawn thing inside a pressed button.
   The press stays the platform's: one depth, one rule. */
[data-sinks]:not(:disabled):active,
button:not(:disabled):active > [data-sinks] {
  transform: translateY(var(--sink));
  box-shadow: none;
}

/* the press sinks the label without touching its centring — position is
   the box's; the transform channel carries state alone */
button.stop:not(:disabled):active {
  transform: translateY(var(--sink));
}

/* the ring is for the keyboard, not for the finger */
:focus {
  outline: none;
}

:focus-visible {
  outline: 3px solid var(--count-soft);
  outline-offset: 3px;
}

/* ---------- the stage ---------- */
/* the band is the room the stage was given; the stage scales to fit it */
.band {
  min-height: 0;
  display: grid;
  place-items: center;
  overflow: hidden;
  /* the band is the true measure of the scene's room. Its size comes from
     the sheet's grid, never from its content — so it can declare itself a
     container and let a family read 100cqh/100cqw: the room that actually
     remains after the voice and the answering hand took theirs. */
  container-type: size;
}

/* the WHITEBOARD, whole: the lesson — voice, scene and answer — lives on
   ONE sheet of paper; the strip stays light on the ground above it. The
   answering band gets a floor of its own inside the sheet: the GROUND
   comes in under the hand, so what she touches reads apart from what she
   watches. */
.sheet {
  min-height: 0;
  /* the sheet fills its cell but never past it, and never beyond the
     ceiling a very tall screen would grant */
  max-height: min(100%, 1080px);
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: var(--row);
  background: var(--paper);
  border: 1px solid var(--tray-rim);
  border-radius: var(--round-card);
  transition: opacity var(--step) ease;
  box-shadow: 0 2px 6px var(--shade-whisper);
  padding: var(--space-6) var(--space-5); /* the lesson breathes inside its board */
}

/* no slab behind the answer — what stands apart from the whiteboard is
   each CONTROL itself: keys, choices and the written number wear the
   ground as their own back (Tiago: buttons distinct, never a band) */

/* ---------- birth in a live screen ---------- */
/* An object that will enter a LIVE screen is composed early — data-unborn
   holds its place with its content invisible, so being born displaces
   nothing — and enters by the house fade when reveal() flips it. Opacity
   only: transform stays free for each thing's own travel. */
.stage [data-unborn] {
  transition: opacity calc(var(--calm) / 3) ease;
}

.stage [data-unborn="true"] {
  opacity: 0;
  pointer-events: none;
}

.stage {
  width: 100%;
  display: grid;
  gap: var(--stack);
  padding-inline: var(--space-3);
  transform: scale(var(--fit, 1));
  /* top, not center: the picture's top stays glued to the layout box and
     the whole surplus is returned below — visual box = layout box exactly */
  transform-origin: top center;
}


/* ---------- the count ---------- */
.track {
  position: relative;
  height: 118px;
  margin-top: var(--space-2);
  /* places are for walking, not for copying: a dragging finger must
     never turn the numbers into a text selection */
  user-select: none;
  -webkit-user-select: none;
  /* the last landing's numeral hangs half itself past the rail — what
     hangs reserves its own room (third appearance of the law): the track
     leaves its labels' reach free on both ends */
  --reach: 18px;
  /* one lane per unit: the band's room divided by the GAUGE (the ruler
     the lesson fixed — the window itself when none is), capped by the
     unit's own ceiling. A squeezed band squeezes the RULER, so every
     window of one lesson keeps the same rhythm. */
  width: calc(var(--total, 20) *
    min((100% - 2 * var(--reach)) / var(--gauge, var(--total, 20)), var(--unit)));
  margin-inline: auto;
}

/* a touchable track's end labels wear the finger's coat — the reach
   grows to keep the whole button inside the band */
.track[data-touch="true"] {
  --reach: 26px;
}

.rail {
  position: absolute;
  left: 0;
  right: 0;
  top: 52px;
  height: 3px;
  border-radius: 3px;
  background: var(--count-soft);
}

/* how far the count has come — a SCALE of the full lane: the walked
   share grows by transform alone (paint, never layout), so the labels
   stand perfectly still while the ball moves */
.rail.done {
  right: auto;
  width: 100%;
  transform-origin: left center;
  transform: scaleX(0);
  will-change: transform;
  background: var(--count);
}

.tick {
  position: absolute;
  top: 46px;
  width: 2px;
  height: 15px;
  border-radius: 2px;
  background: var(--count-soft);
  transform: translateX(-50%);
  transition: height var(--step) ease, top var(--step) ease,
    background var(--step) ease;
  pointer-events: none; /* a tick is paint — never the finger's target */
}

.tick[data-stop="true"] {
  top: 40px;
  height: 27px;
  width: 3px;
  background: var(--count);
}

.stop {
  position: absolute;
  top: 74px;
  transform: translate(-50%, 6px);
  color: var(--count);
  font-size: var(--type-lead);
  font-weight: 700;
  opacity: 0;
  transition: opacity var(--step) ease, transform var(--step) ease;
}

/* a touchable stop is a button wearing the label's own look — and it
   carries a finger-sized coat (padding pulled back by margin, and the
   30px floor of the touch law), so the place answers the touch even
   where units stand close */
/* a touchable stop's POSITION lives in its box, never in transform:
   one fixed width self-centred by margin, so no state rule that touches
   transform can ever move a label. The 34px box is also the finger's
   target (floor 30 — the frames harness collects it). */
button.stop,
button.stop[data-reached="true"] {
  /* the stop's own metric, like the tray's --cell: one box for every
     label, self-centred by half of itself */
  --stop: 34px;
  box-sizing: border-box;
  width: var(--stop);
  margin-left: calc(var(--stop) / -2);
  top: calc(74px - var(--space-2));
  padding: var(--space-2) 0;
  border: none;
  border-radius: var(--round-slab); /* any ring or halo wears the slab's corner */
  background: none;
  font: inherit;
  font-size: var(--type-lead);
  font-weight: 700;
  color: var(--count);
  cursor: default;
  transform: none;
}

button.stop[data-live="true"] {
  cursor: pointer;
}

.stop[data-reached="true"] {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* the marker: the thing that jumps */
/* smaller than one unit, always — so it never covers its neighbours */
.hop {
  position: absolute;
  top: 53px;
  left: 0;
  width: min(30px, calc(78% / var(--total, 20)));
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--count);
  box-shadow: 0 3px 0 var(--press-count);
  pointer-events: none;
  will-change: transform;
}

.hop[data-look="true"] {
  animation: look 0.7s ease 2;
}

/* a walk not yet begun: the marker waits unseen until the start is hers */
.hop[data-off="true"] {
  visibility: hidden;
}

/* a draggable marker answers the hand: she takes the ball and walks it —
   the touch law's floor still rules its size */
.hop[data-drag="true"] {
  pointer-events: auto;
  touch-action: none;
  cursor: grab;
  min-width: 30px;
  min-height: 30px;
  z-index: 1; /* the ball rides above the paint — it IS the target */
}

.hop[data-held="true"] {
  cursor: grabbing;
}

/* ---------- the leap: one hop, drawn and kept ---------- */
/* each unit walked leaves its arc on the line — the road remembers, one
   +1 at a time. The arc REVEALS itself in the jump's own tempo. */

.leap {
  position: absolute;
  top: 24px;
  height: 28px;
  border: 2.5px solid var(--count-soft);
  border-bottom: none;
  border-top-left-radius: 50% 100%;
  border-top-right-radius: 50% 100%;
  clip-path: inset(-20px 100% 0 0);
  transition: clip-path var(--jump) ease;
  pointer-events: none;
}

.leap[data-drawn="true"] {
  clip-path: inset(-20px 0 0 0);
}

.leap-label {
  position: absolute;
  left: 50%;
  top: -4px;
  transform: translate(-50%, -100%);
  font-size: var(--type-note);
  font-weight: 700;
  color: var(--count);
  opacity: 0;
  transition: opacity var(--step) ease;
}

.leap[data-drawn="true"] .leap-label {
  opacity: 1;
  transition-delay: var(--jump);
}

@keyframes look {
  50% {
    box-shadow: 0 3px 0 var(--press-count),
      0 0 0 12px var(--halo-count);
  }
}

/* ---------- onward ---------- */
/* Two stacked layers in one cell: the held one is invisible and gives the
   footer the height of the tallest surface this moment will use; the live
   one is what she sees. The footer's height therefore never changes inside
   a moment — the room was reserved on arrival. */
.onward {
  display: grid;
  min-height: 62px;
  /* no raw margin: the sheet's own gap breathes equally above and below
     the scene — this margin alone broke the symmetry by 17 measured px */
}

.onward .hold,
.onward .answer {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: var(--space-4);
}

.onward .hold {
  visibility: hidden;
  pointer-events: none;
}

.go {
  border: 0;
  border-radius: var(--round-pill);
  padding: var(--space-4) var(--space-7);
  font: inherit;
  font-size: var(--type-lead);
  font-weight: 700;
  color: var(--paper-bright);
  background: var(--ink);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transform: translateY(6px);
  transition: opacity var(--step) ease, transform var(--step) ease;
}

.go[data-ready="true"] {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

/* ---------- where will it land: as lajes ---------- */
/* The slab's WIDTH follows the row's density, never the content: counts
   2 and 4 wear the MEIA (1×2, the 2×2 square of the standard four);
   counts 3, 5 and 6 wear the TERÇA (one row of three, 3+2, 3+3). Never
   three rows. The FONT is the modular part: dressChoices() walks the
   set down the ladder until its longest label fits (desktop: one
   canonical 27px), so "9" and "12 + 8 = 20" sit in identical frames. */
.choices {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
  justify-content: center;
  inline-size: 100%;
  max-inline-size: var(--choices-measure);
  margin-inline: auto;
  font-size: var(--type-choice);
}

.choice {
  inline-size: calc((100% - var(--space-3)) / 2);
  block-size: var(--choice);
  display: grid;
  place-items: center;
  padding-inline: var(--space-2);
  border-radius: var(--round-slab);
  border: 2px solid var(--count-soft);
  background: var(--ground);
  color: var(--count);
  font: inherit;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--step) ease, opacity var(--step) ease,
    border-color var(--step) ease;
}

.choices[data-count="3"] .choice,
.choices[data-count="5"] .choice,
.choices[data-count="6"] .choice {
  inline-size: calc((100% - 2 * var(--space-3)) / 3);
}

/* a laje ALTA: prose past the one-line ceiling rises to two lines —
   same width, doubled height, word-wrapped and balanced. Only the meia
   wears it, and mathematics never does (a broken sentence is not a
   sentence) — dressChoices() holds both laws. */
.choices[data-tall="true"] .choice {
  block-size: var(--choice-tall);
  white-space: normal;
  text-wrap: balance;
  text-align: center;
  line-height: 1.15;
}

.choice:hover:not([data-spent="true"]) {
  background: var(--count-pale);
}

.choice[data-spent="true"] {
  opacity: 0.55;
  border-color: var(--amiss);
  color: var(--amiss);
  text-decoration: line-through;
  cursor: default;
}

/* the right answer WEARS the judgement — the count's own ink, a breath of
   the beckon — and stays dressed while the screen lives; the choices
   beside it just go quiet. This is the whole of "Correct": the dress, the
   cue, and the screen moving on. */
.choice[data-won="true"] {
  border-color: var(--count);
  background: var(--count-pale);
  color: var(--count);
  animation: beckon var(--calm) ease-in-out 1;
}

.choice:disabled:not([data-won="true"]):not([data-spent="true"]) {
  opacity: 0.5;
  cursor: default;
}

/* a slot wears the miss for a breath, then clears for the next try (a
   family whose border rules are more specific restates this, as with the
   caret's waiting ink) */
[data-amiss="true"] {
  border-color: var(--amiss);
  color: var(--amiss);
}

/* ---------- how a session answers back ---------- */

/* The trail of a practice session, at the very top and fixed there: marks are
   only ever added to its end, so nothing already on the screen moves. */
.trail {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  justify-content: center;
  align-items: center;
}

.screen[data-practice="true"] .trail {
  min-height: 22px;
}

.mark {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid var(--count);
  transition: background var(--step) ease, border-color var(--step) ease;
}

.mark[data-got="true"] {
  background: var(--count);
  border-color: var(--count);
}

.mark {
  animation: land 0.3s ease;
}

/* the case stands at the exact centre, between two equal counterweights.
   The judgement reserves NOTHING here: it dresses the answer in place, or
   rises over a surface as the blade — a transitory state may have a
   guard, but it may not have rent. */
.case {
  display: grid;
  place-items: center;
}

.band .stage:has(> .case) {
  height: 100%;
  grid-template-rows: minmax(0, 1fr) auto minmax(0, 1fr);
  gap: 0;
}

.stage:has(> .case) > .case {
  grid-row: 2;
}

/* what she said, and what was true — the blade's written content. The
   right answer never gets a box: it dresses the thing she answered with
   (the won choice, the sealed slot) and the screen moves on. */
.verdict {
  display: grid;
  justify-items: center;
  gap: var(--space-1);
  min-width: clamp(200px, calc(34 * var(--vw)), 280px);
  padding: var(--space-4) var(--space-6) var(--space-4);
  border-radius: var(--round-card);
  font-weight: 700;
  animation: land 0.3s ease;
}

.verdict .said-so {
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--type-lead);
  letter-spacing: 0.01em;
}

.verdict[data-ok="false"] {
  background: var(--paper);
  border: 3px solid var(--amiss);
  color: var(--ink);
}

/* what she said, beside what was true — each one told apart by its label */
.verdict .two {
  display: flex;
  gap: var(--air);
  margin-top: 2px;
  /* an answer may be a whole WRITING (a sentence as one value): the pair
     wraps rather than bursting the box */
  flex-wrap: wrap;
  justify-content: center;
}

.verdict .two span {
  display: grid;
  justify-items: center;
  gap: 1px;
}

.verdict .two em {
  font-style: normal;
  font-size: var(--type-label);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  opacity: 0.6;
}

.verdict .two b {
  font-size: var(--type-title);
  line-height: 1.05;
}

/* how the case is solved — the method, not the mistake */
.verdict .how {
  margin: var(--space-2) 0 0;
  max-width: 22ch;
  text-align: center;
  font-size: var(--type-note);
  font-weight: 600;
  line-height: 1.35;
  opacity: 0.85;
}

.verdict .said {
  text-decoration: line-through;
  opacity: 0.5;
}

@keyframes land {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
}

/* ---------- writing how many ---------- */

/* answered: still there, so nothing moves, but no longer listening */
.keys[data-spent="true"],
.written[data-spent="true"],
.go[data-spent="true"] {
  opacity: 0.35;
  pointer-events: none;
}
.pad {
  display: grid;
  justify-items: center;
  /* a fixed seam, not a viewport breath: the pad lives in the reserved
     footer, and every extra pixel here is taken from the scene above —
     the phone's footer measured 239px with the breathing gap */
  gap: var(--space-3);
}

.written {
  min-width: 132px;
  background: var(--ground);
  border-radius: var(--round-slab) var(--round-slab) 0 0;
  min-height: 52px;
  padding: 0 var(--space-4);
  font-size: var(--type-answer);
  font-weight: 700;
  color: var(--count);
  text-align: center;
  line-height: 52px;
  border-bottom: 3px solid var(--count-soft);
}

.pad .go {
  margin-top: var(--space-2);
}

.keys {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  justify-content: center;
}

.keys button {
  width: var(--key);
  height: var(--key);
  border-radius: var(--round-slab);
  border: 2px solid var(--tray-rim);
  background: var(--ground);
  color: var(--ink);
  font: inherit;
  font-size: var(--type-lead);
  font-weight: 700;
  cursor: pointer;
}

.keys button:active {
  background: var(--tray);
}

/* A worked error replaces the spent answering hand, never the exercise.
   The message is deliberately compact enough to occupy the keypad's reserved
   room, but explicit enough to distinguish HER answer from the correct one.
   It stays through the whole reconstruction and until Continue. */
.review-verdict {
  inline-size: min(100%, 620px);
  min-block-size: var(--key);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  column-gap: var(--space-5);
  row-gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  border: 2px solid var(--amiss);
  border-radius: var(--round-slab);
  background: var(--paper);
  color: var(--ink);
  animation: land 0.3s ease;
}

.review-alert {
  margin: 0;
  color: var(--amiss);
  font-size: var(--type-note);
  line-height: 1.15;
  font-weight: 800;
  white-space: nowrap;
}

/* the judged question, quoted in the verdict: the repair line owns the
   voice band, so the comparison keeps its own reference in sight */
.review-ask {
  margin: 0;
  color: var(--ink);
  font-size: var(--type-note);
  line-height: 1.15;
  font-weight: 700;
}

.review-pair {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  /* an answer may be a whole WRITING (a sentence as one value): each value
     stays on one line, and the pair wraps into two rows only when two
     values cannot share one — never a sentence broken sign by sign down a
     column, never two numbers stacked that would sit side by side */
  flex-wrap: wrap;
  justify-content: center;
}

.review-pair span {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  min-block-size: 42px;
  padding: var(--space-2) var(--space-3);
  border-radius: 10px;
  /* the line is shared while both values fit at their narrowest (a label
     may wrap, a value never does); past that, one value per row */
  flex: 1 1 min-content;
  min-width: 0;
}

/* Her answer is evidence, not something to fade away. Its own warm block
   keeps the entered number legible after the equation has been repaired. */
.review-pair span[data-answer="said"] {
  padding-inline: var(--space-4);
  border: 3px solid var(--amiss);
  background: color-mix(in srgb, var(--amiss) 18%, var(--paper));
  box-shadow: 0 3px 0 color-mix(in srgb, var(--amiss) 35%, transparent);
}

.review-pair span[data-answer="said"] em {
  color: var(--amiss);
  opacity: 1;
}

.review-pair span[data-answer="correct"] {
  padding-inline: var(--space-4);
  border: 3px solid var(--count);
  background: color-mix(in srgb, var(--count-soft) 42%, var(--paper));
  box-shadow: 0 3px 0 color-mix(in srgb, var(--count) 28%, transparent);
}

.review-pair span[data-answer="correct"] em,
.review-pair span[data-answer="correct"] b {
  color: var(--count);
  opacity: 1;
}

.review-pair em {
  font-style: normal;
  font-size: var(--type-label);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  opacity: 0.62;
}

.review-pair b {
  font-size: var(--type-title);
  font-weight: 900;
  line-height: 1;
  white-space: nowrap;
}

.review-pair .said {
  font-size: var(--type-answer);
  color: var(--amiss);
  opacity: 1;
}

/* The frame never changes shape. There is no special layout for the last
   screen of a lesson, because a screen that arranges itself differently makes
   everything jump on the way in and on the way out. */

@media (prefers-reduced-motion: reduce) {
  *,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}


/* THE BECKON: when a gesture is being conducted, the thing to touch
   calls — in the count's own ink, never the error's (the judgement keeps
   its temperature). A halo that breathes by paint alone: no layout
   moves. The FORM lives here, once, for every circumstance; WHEN it
   appears and falls is the family's attentionPlan (decisão *todo ato exigido
   é conduzido*): word and halo at a gesture's debut, halo alone the
   second time, then nothing — and her touch retires it. */
/* THE TOUCH WAVE: the house's one invitation to the hand, drawn by the
   platform as an overlay that follows the beckoned target (stage.js,
   waveFor) — two rings born at the centre that open and fade, in the
   target's inviting colour. The target itself wears nothing: a drawing is
   not boxed, a box is not haloed. Change the wave here, and it changes in
   every lesson (Tiago, 2026-09-05). */
.wave {
  position: fixed;
  left: var(--x);
  top: var(--y);
  width: var(--size, 48px);
  height: var(--size, 48px);
  translate: -50% -50%;
  pointer-events: none;
  z-index: 40;
  color: var(--invite, var(--count));
}
.wave::before,
.wave::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 3px solid currentColor;
  opacity: 0;
  animation: wave var(--calm) ease-out infinite;
}
.wave::after {
  animation-delay: calc(var(--calm) / 3);
}
@keyframes wave {
  0% { transform: scale(0.55); opacity: 0.85; }
  100% { transform: scale(1.9); opacity: 0; }
}

/* THE PULSE: the beckon's breath, once — the platform's way of POINTING
   at something already on screen (a figure read aloud, the tray it names).
   Paint alone, set and cleared by whoever is pointing. */
[data-pulse="true"] {
  animation: beckon var(--calm) ease-in-out 1;
}

@keyframes beckon {
  50% {
    box-shadow: 0 0 0 9px var(--halo-count);
  }
}

/* THE CARET: a slot that awaits her number blinks — one thin bar of the
   count's ink inside the waiting frame. Where the answer will LIVE is
   where the eye is invited; paint alone, no layout. */
/* THE RING: the one place that asks for her writing wears a firm ring, still,
   in the count's ink — "write here" — until her number lands (Tiago,
   2026-09-05; mockup option 2). */
[data-awaits="true"] {
  border-color: var(--count);
  outline: 3px solid var(--count);
  outline-offset: 4px;
  box-shadow: 0 0 0 8px var(--halo-count);
}

/* THE TELL ARMS WITH HER WRITING: dimmed while there is nothing to
   confirm, it lights the moment the first digit lands — so the eye is
   pulled to the confirm exactly when confirming becomes the next step,
   and an empty-handed "Done" never competes with the waiting slots. */
[data-tell]:not([data-armed="true"]) {
  opacity: 0.45;
}

[data-awaits="true"]:empty::after {
  content: "";
  display: block;
  width: 2.5px;
  height: 1.05em;
  border-radius: 2px;
  background: var(--count);
  animation: caret calc(var(--calm) * 0.6) steps(1) infinite;
}

@keyframes caret {
  50% {
    opacity: 0;
  }
}

/* THE FLYER: a number travelling from the scene to the writing (the
   genesis of the symbol, visible). A cloned messenger — fixed, above
   everything, gone on landing. The outer span carries it to its slot;
   the inner one rises and settles on the same clock — together, an arc:
   a thrown thing, never a dragged one. */
.flyer {
  position: fixed;
  z-index: 5;
  transform: translate(-50%, -50%);
  font-size: var(--type-answer);
  font-weight: 800;
  color: var(--count);
  pointer-events: none;
  transition: transform var(--flight, calc(var(--calm) / 2))
    cubic-bezier(0.45, 0, 0.55, 1);
  will-change: transform;
}

.flyer .lift {
  display: block;
  animation: flyer-arc var(--flight, calc(var(--calm) / 2))
    cubic-bezier(0.3, 0, 0.7, 1);
}

@keyframes flyer-arc {
  0% {
    transform: translateY(0) scale(0.9);
  }
  45% {
    transform: translateY(calc(-1 * var(--space-7))) scale(1.15);
  }
  100% {
    transform: translateY(0) scale(1);
  }
}

/* ---------- the writing ---------- */
/* a line that names an act the scene has shown (platform/notation.js):
   figures and signs, the signs in place from arrival — the frame of the
   writing complete before any number — and each figure a box that is
   empty, awaiting the finger, filled, or wearing a miss. The family gives
   a figure its part's ink (data-part) or its role's (data-role); the
   platform gives the line its shape and its states. Born in the join; the
   take's sentence made it shared (2026-09-03). */

.sentence {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  justify-content: center;
}

.sentence .sign {
  font-size: var(--type-title);
  font-weight: 700;
  color: var(--ink-soft);
}

.sentence .fig {
  /* the writing grows with the scene's own cell — the family's --cell when
     it declares one, the room's seat otherwise — never below its phone
     size, never past the ruler the room granted */
  --writing: var(--cell, var(--seat, 52px));
  min-width: max(52px, calc(var(--writing) * 0.85));
  min-height: max(52px, calc(var(--writing) * 0.85));
  display: grid;
  place-items: center;
  font-size: max(var(--type-answer), calc(var(--writing) * 0.5));
  font-weight: 800;
  color: var(--count);
  border: 2.5px dashed var(--count-soft);
  border-radius: var(--round-slab);
  transition: transform calc(var(--calm) / 2) ease,
    border-color var(--step) ease, background var(--step) ease,
    opacity var(--step) ease;
}

/* THE GRAMMAR OF THE SLOTS — only the one whose turn it is invites. The
   LIVE slot (data-awaits, the pad's caret inside it) is the single call to
   the finger; a DORMANT slot — empty, its question not yet asked — recedes,
   keeping the writing's structure readable without calling anyone; a
   filled slot stands as written. */
.sentence .fig:empty:not([data-awaits="true"]) {
  opacity: 0.4;
}

.sentence .fig[data-filled="true"],
.sentence .fig:not(:empty):not([data-awaits="true"]) {
  border-style: solid;
  border-color: var(--count);
  background: var(--ground);
}

.sentence .fig[data-awaits="true"] {
  border-style: dashed;
  border-color: var(--count);
}

.sentence .fig[data-amiss="true"] {
  border-color: var(--amiss);
  color: var(--amiss);
}

/* a writing that steps back, still readable */
.sentence[data-stale="true"] {
  opacity: 0.35;
  transition: opacity calc(var(--calm) / 2) ease;
}

/* a touchable figure or writing says so to the hand */
.fig[data-touch="true"],
.sentence[data-touch="true"] {
  cursor: pointer;
}

/* ---------- the way in ---------- */
/*
   For a child this is a list of lessons. For whoever is building one it is
   also a panel of doors: every screen of every lesson is one click away, so
   reviewing the fourth moment never means playing the first three.
*/
.screen.index {
  display: block;
  align-content: start;
  padding-block: var(--hush);
  overflow-y: auto;
}

.index h1 {
  margin: 0 0 var(--row);
  font-size: var(--type-title);
  font-weight: 800;
  letter-spacing: -0.015em;
  color: var(--ink);
}

.index nav section {
  margin-bottom: var(--row);
}

.index nav h2 {
  margin: 0 0 var(--space-3);
  font-size: var(--type-label);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--count);
}

.index nav a {
  display: inline-block;
  margin: 0 var(--space-2) var(--space-2) 0;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--round-pill);
  background: var(--tray);
  border: 1.5px solid var(--tray-rim);
  color: var(--ink);
  font-size: var(--type-note);
  font-weight: 600;
  text-decoration: none;
  transition: transform var(--step) ease, border-color var(--step) ease,
    background var(--step) ease;
}

/* the two ways in that a child would take — of-type, because the h2 is
   the container's first CHILD and the old selector never matched */
.index nav a:first-of-type,
.index nav a:last-of-type {
  background: var(--count-pale);
  border-color: var(--count-soft);
  color: var(--count);
}

.index nav a:hover {
  border-color: var(--count-soft);
  transform: translateY(-2px);
}

.index nav a:active {
  transform: translateY(1px);
}

/* ---------- the catalogue ---------- */
/*
   The official way in: ONE course, its themes, and every lesson as one
   typographic LINE — a book's table of contents, not a wall of cards.
   Quiet paper, the count keeps the teal, nothing casts a shadow. The
   platform, not this page, will point at the next lesson when progression
   exists; the technical panel of doors lives in panel.html.
*/
.screen.catalog {
  display: block;
  padding-block: 0 var(--hush);
  overflow-y: auto;
}

.catalog .masthead {
  min-height: var(--strip);
  padding-block: var(--rest);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--air);
}

.catalog .wordmark {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--type-lead);
  font-weight: 800;
  letter-spacing: 0.02em;
  color: var(--ink);
}

.catalog .wordmark::after {
  content: "";
  width: var(--space-2);
  height: var(--space-2);
  border-radius: var(--round-pill);
  background: var(--count);
}

.catalog .masthead a {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--round-pill);
  color: var(--ink-soft);
  font-size: var(--type-note);
  font-weight: 600;
  text-decoration: none;
  transition: color var(--step) ease;
}

.catalog .masthead a:hover {
  color: var(--count);
}

/* the leaf: one narrow editorial column — the measure IS the refinement */
.catalog .leaf {
  max-width: 880px;
  margin: 0 auto;
  padding-block: var(--row) 0;
  display: grid;
  gap: var(--row);
}

.catalog .course {
  display: grid;
  gap: var(--space-3);
}

.catalog .grade {
  margin: 0;
  font-size: var(--type-label);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--count);
}

.catalog h1 {
  margin: 0;
  font-size: var(--type-title);
  font-weight: 800;
  letter-spacing: -0.015em;
  color: var(--ink);
}

.catalog .course .note {
  margin: 0;
  font-size: var(--type-note);
  line-height: 1.6;
  color: var(--ink-soft);
}

.catalog section {
  display: grid;
  gap: var(--space-4);
}

.catalog section > header {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
}

.catalog .no {
  font-size: var(--type-label);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--count-soft);
}

.catalog h2 {
  margin: 0;
  font-size: var(--type-lead);
  font-weight: 800;
  color: var(--ink);
}

.catalog section > p {
  margin: 0;
  font-size: var(--type-note);
  color: var(--ink-soft);
}

/* ONE sheet of paper per theme — not a card per lesson, not bare text.
   Inside it a lesson is a slim row; the ground shows through between
   rows as a hairline seam, and the whole row is the finger's target. */
.catalog .panel {
  background: var(--paper-bright);
  border-radius: var(--round-card);
  box-shadow: 0 1px 2px var(--shade-whisper), 0 6px 16px var(--shade-whisper);
  overflow: hidden;
}

.catalog .line {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  color: var(--ink);
  text-decoration: none;
  transition: background var(--step) ease;
}

.catalog .line + .line {
  border-top: 1.5px solid var(--ground);
}

.catalog .line:hover {
  background: var(--paper);
}

.catalog .line:active .name {
  color: var(--count);
}

.catalog .line .n {
  min-width: 2ch;
  text-align: right;
  font-size: var(--type-note);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--count);
}

.catalog .line .name {
  flex: 1;
  font-size: var(--type-body);
  font-weight: 700;
}

.catalog .line .meta {
  font-size: var(--type-note);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  white-space: nowrap;
}

.catalog .line svg {
  flex-shrink: 0;
  color: var(--count-soft);
  transition: color var(--step) ease;
}

.catalog .line:hover svg {
  color: var(--count);
}

@media (max-width: 620px) {
  .catalog .line {
    padding-inline: var(--space-4);
  }

  .catalog .line .meta {
    display: none;
  }
}

/* ---------- the turn, and the arrival ---------- */

/* while the voice speaks in the Learn, ONLY WHAT SHOWS THE WAIT waits:
   the footer's controls and the scene's marked action buttons — the same
   surfaces the dim below names. The touchable scene itself never waits:
   a well, a seat, a gap has no face to show a wait, and a touch it
   swallows in silence reads as a broken screen (the cross's dead cuts,
   measured 2026-08-31). Her touch on the scene IS the learning — the
   voice follows her: a gesture's own line simply takes the turn from
   the line it interrupts. Cards and the practice keep her pace hers. */
/* pointer-events alone holds the wait: with no press there is no sink to
   undo — and a blanket transform:none would ERASE POSITION from any
   button placed by transform (the line's labels leapt 15px on every
   spoken line until this was measured, 2026-08-30). State must never
   overwrite position. */
/* The voice expresses interaction and advance waits independently. A recoverable
   state leaves only its dedicated visible recovery control available, so the
   same utterance can be resumed or explicitly acknowledged without treating
   the failure as completion. */
[data-screen][data-voice-advance="wait"] .onward button[data-go],
[data-screen][data-voice-interaction="wait"] .onward [data-choices] button,
[data-screen][data-voice-interaction="wait"] .band button[data-acts],
[data-screen][data-voice-interaction="wait"] .answer .keys,
[data-screen][data-voice-interaction="wait"] .answer [data-tell] {
  pointer-events: none;
  opacity: 0.45;
}

[data-screen][data-voice-advance="wait"][data-voice-state="blocked"] .onward button[data-go][data-voice-recovery],
[data-screen][data-voice-advance="wait"][data-voice-state="missing"] .onward button[data-go][data-voice-recovery],
[data-screen][data-voice-advance="wait"][data-voice-state="error"] .onward button[data-go][data-voice-recovery] {
  pointer-events: auto;
  opacity: 1;
}

/* buttons ease back in when the voice finishes */
[data-screen] button {
  transition: opacity 0.25s ease;
}

/* a screen arrives, it does not pop */
[data-screen] .say,
[data-screen] .band,
[data-screen] .onward {
  transition: opacity 0.3s ease, translate 0.3s ease;
}

[data-screen].arriving .say,
[data-screen].arriving .band,
[data-screen].arriving .onward {
  opacity: 0;
  translate: 0 10px;
  transition: none;
}

@media (prefers-reduced-motion: reduce) {
  [data-screen] .say,
  [data-screen] .band,
  [data-screen] .onward {
    transition: none;
  }
}

/* ---------- the blade ---------- */
/* The judgement's written content rises OVER a surface and owns no
   layout. Two homes: over the CASE (the practice's reveal — the case is
   the one thing she no longer needs) and over the HAND (the Learn's why —
   the scene stays whole above it for her next try; her next gesture,
   anywhere, sheds it). */
.band,
.onward {
  position: relative;
}

.veil {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: color-mix(in srgb, var(--ground) 88%, transparent);
  z-index: 2;
}

.veil[data-home="hand"] {
  /* over the keys the ground goes near-solid: a why is read, not peered
     at through a lattice of buttons. It never becomes a dead first tap:
     the next target underneath receives the gesture while the window's
     capture listener sheds this explanation. */
  background: color-mix(in srgb, var(--ground) 96%, transparent);
  pointer-events: none;
}

.veil .verdict {
  max-width: min(92%, 420px);
  /* solid over the veil: what she reads must not be read THROUGH */
  background: var(--ground);
  border: 2px solid var(--count-soft);
  box-shadow: 0 18px 44px var(--shade-deep);
}


/* ---------- the way out ---------- */
/* Every screen carries its exit, top right — not ornament, navigation. An
   anchor, not a button, so it never waits for the voice and never dies. */
.screen {
  position: relative;
}

.leave {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: var(--round-pill);
  color: var(--ink-soft);
  z-index: 3;
  transition: background 0.2s ease, transform 0.2s ease;
}

.leave svg {
  width: 17px;
  height: 17px;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
  fill: none;
}

.leave:hover {
  background: var(--tray);
}

.leave:active {
  transform: translateY(var(--sink));
}

/* ---------- the way back ---------- */
/* The same quiet face as the way out, on the other end of the strip: the two
   things that are always available and never asked for. Dim while there is
   nothing to see again (or while the scene is busy being it), so the button
   is never born into a live screen — it only wakes. */
.again {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 0;
  padding: 0;
  background: none;
  border-radius: var(--round-pill);
  color: var(--ink-soft);
  z-index: 3;
  transition: background 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
}

.again svg {
  width: 18px;
  height: 18px;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
}

.again[data-live="false"] {
  opacity: 0.22;
  cursor: default;
}

.again[data-live="true"]:hover {
  background: var(--tray);
}

.again[data-live="true"]:active {
  transform: translateY(var(--sink));
}

/* the scene put back is not a scene moving: while a photograph is being
   restored, nothing on the stage animates its way there */
.screen[data-revisit-cut="true"] .stage,
.screen[data-revisit-cut="true"] .stage * {
  transition: none !important;
  animation: none !important;
}

/* ---------- the frame gate ---------- */
/* The lesson lives in the tall way ("a aula vive no modo alto").
   Sideways without height
   asks for a turn; absurdly small upright is told, gently. The gate covers
   the screen whole — the scene beneath stays put, ready for the turn. */
.frame-gate {
  position: fixed;
  inset: 0;
  z-index: 9;
  display: none;
  place-items: center;
  background: var(--ground);
  padding: var(--edge);
  text-align: center;
}

[data-frame="turn"] .frame-gate,
[data-frame="small"] .frame-gate,
[data-frame="sound"] .frame-gate {
  display: grid;
}

.frame-gate .plea {
  display: none;
  justify-items: center;
  gap: var(--rest);
  max-width: 34ch;
}

.frame-gate .sound-plea {
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

[data-frame="turn"] .frame-gate .plea[data-when="turn"],
[data-frame="small"] .frame-gate .plea[data-when="small"],
[data-frame="sound"] .frame-gate .plea[data-when="sound"] {
  display: grid;
}

.frame-gate .headline {
  margin: 0;
  font-size: var(--type-title);
  font-weight: 800;
  letter-spacing: -0.015em;
}

.frame-gate .aside {
  margin: 0;
  font-size: var(--type-body);
  line-height: 1.45;
  color: var(--ink-soft);
}

/* a little device, turning the way the hand should */
.frame-gate .device {
  width: 64px;
  height: 40px;
  border: 3px solid var(--count);
  border-radius: 10px;
  animation: turn-tall 1.8s ease-in-out infinite;
}

@keyframes turn-tall {
  0%, 25% { transform: rotate(0); }
  60%, 100% { transform: rotate(-90deg); }
}
