/* Sanskrit Setu — /start. Only what landing.css does not already carry.
   Every value is a token from design-system/tokens.css. No literals here by rule. */

/* ---- the stage: one region, two states (L918 §3.2d) ----------------------
   The nine and the taste occupy the same area. On selection the touched card
   grows into the taste and the others recede in place — no horizontal
   scroller, and no page scroll in either direction: only this box changes
   height, under the visitor's eye. */

.s-stage { position: relative; width: 100%; }
/* while the taste holds the stage, the receded grid is out of flow and clipped
   to the stage box, so it cannot spill past it into the continuation below */
.s-stage[data-state="receded"] { overflow: hidden; }
/* Once a choice is made the taste owns the region (§3.2d): the hero's opening
   padding was sized for a heading that has now receded, and left the lesson
   starting a third of the way down the viewport with its first line pushed
   past the fold. */
.l-hero[data-state="taste"] { padding-block-start: var(--space-7); }
.s-intro[hidden] { display: none; }

/* the movement is animated from script (§3.2d) — no transition here, and no
   from-state on the element that could be left latched */
.s-taste {
  position: absolute;
  inset: 0;
  background: var(--color-bg);
}
.s-taste[hidden] { display: none; }
.s-taste__inner { width: 100%; }

.s-back {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  min-height: var(--hit-target-min);
  padding: 0;
  background: transparent;
  color: var(--color-accent-text);
  border: none;
  border-bottom: var(--border-hair) solid var(--color-border);
  font-family: var(--font-ui);
  cursor: pointer;
}
.s-back:hover { color: var(--color-text); border-bottom-color: var(--color-border-strong); }
.s-back { gap: var(--space-3); white-space: nowrap; }
/* the arrow points back toward the nine, whichever way the text runs */
.s-back__icon { width: var(--space-5); height: var(--space-5); }
[dir="rtl"] .s-back__icon { transform: scaleX(-1); }

/* ---- 1 · the nine (L918 §3.2, §3.2c) ------------------------------------
   Equal weight, 3×3 from lg and narrowing below. No featured card. Each card
   is a two-second demonstration of its own domain rather than a title with a
   decoration: one motion, on hover or tap, never on load and never looping.
   The page at rest is still. */

.s-field { display: grid; gap: var(--space-7); width: 100%; }

.s-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(calc(var(--grid-min) + var(--space-9)), 1fr));
  gap: var(--space-5);
  width: 100%;
  transition: opacity var(--duration-base) var(--ease-standard);
}
@media (min-width: 1024px) {
  .s-cards { grid-template-columns: repeat(3, 1fr); gap: var(--space-6); }
}
/* the heading and the nine recede together: after a choice the taste owns
   the region (§3.2d), and nothing under an opaque panel holds keyboard focus */
.s-choosing[data-state="receded"] {
  position: absolute;
  inset-block-start: var(--space-0);
  inset-inline: var(--space-0);
  opacity: var(--opacity-disabled);
  pointer-events: none;
}

.s-card {
  display: grid;
  grid-template-rows: 1fr auto;
  align-items: start;
  justify-items: start;
  gap: var(--space-5);
  padding: var(--space-6);
  text-align: start;
  background: var(--color-surface);
  color: var(--color-text);
  border: var(--border-hair) solid var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-standard),
              border-color var(--duration-fast) var(--ease-standard),
              box-shadow var(--duration-fast) var(--ease-standard);
}
.s-card:hover {
  background: var(--color-surface-hover);
  border-color: var(--color-text-secondary);
  box-shadow: var(--shadow-1);
}
.s-card:focus { outline: none; }
.s-card:focus-visible {
  outline: var(--border-thick) solid var(--color-border-accent);
  outline-offset: var(--space-2);
}
.s-card[aria-pressed="true"] {
  background: var(--color-surface-pressed);
  border: var(--border-thick) solid var(--color-text);
  padding: calc(var(--space-6) - var(--border-hair));
}

.s-card__name { color: var(--color-text); text-wrap: pretty; }
.s-card__note {
  font-family: var(--font-ui);
  font-size: var(--type-ui-sm-size);
  line-height: var(--type-ui-sm-lh);
  font-weight: var(--type-ui-sm-weight);
  letter-spacing: var(--type-ui-sm-tracking);
  color: var(--color-text-secondary);
}

/* ---- the demonstrations -------------------------------------------------
   The script is the visual, so the glyph is set well above its own label. Each
   demo holds its own box so nothing reflows when the motion runs. */

.s-card__demo {
  display: grid;
  justify-items: start;
  gap: var(--space-2);
  direction: ltr;
  text-align: left;
  min-height: calc(var(--type-display-2-size) * 2 + var(--space-6));
  align-content: start;
}
.d-glyph, .s-card__deva {
  font-family: var(--font-deva);
  font-size: var(--type-display-2-size);
  line-height: var(--type-sanskrit-display-lh);
  font-weight: var(--type-sanskrit-weight);
  color: var(--color-text);
  /* no Devanagari word may break inside itself; lines break between words only */
  overflow-wrap: normal;
  word-break: keep-all;
}
.s-card__translit { color: var(--color-text-secondary); font-style: italic; }

.d-row { display: flex; align-items: baseline; gap: var(--space-4); }
.d-row--tight { gap: var(--space-0); }
.d-stack { display: grid; }
.d-stack > * { grid-area: 1 / 1; }
.d-stack--inline { justify-items: start; }

/* One registered state, read by every layer (§3.2c). --reveal is 0 at rest
   and 1 while the card is hovered, focused or freshly tapped. It is registered
   as a number and interpolated itself: an unregistered custom property changes
   its inherited value without recomputing a descendant's transitioned property,
   which is why the layers must derive from an animatable variable rather than
   each carry a transition of their own. */
@property --reveal {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}
.s-card { --reveal: 0; transition: --reveal var(--duration-base) var(--ease-standard); }
.s-card:hover, .s-card:focus-visible, .s-card[data-shown="true"] { --reveal: 1; }

/* the a-layer is what the card shows at rest, the b-layer what the motion reveals */
.d-a { opacity: calc(1 - var(--reveal)); }
.d-b { opacity: var(--reveal); }

/* read and write — at rest the word stands as two separate signs, and the card
   writes them into one: the śirorekhā comes last and binds them, which is the
   thing the domain is about. The strokes are the shared module's; this only
   places the two states and cross-fades them on --reveal. */
[data-demo="script"] .d-stack { position: relative; }
[data-demo="script"] .d-parts {
  display: flex;
  gap: var(--space-5);
  opacity: calc(1 - var(--reveal));
}
[data-demo="script"] .d-write {
  position: absolute;
  inset-block-start: var(--space-0);
  inset-inline-start: var(--space-0);
  opacity: var(--reveal);
  pointer-events: none;
}
/* the word stays in the accessibility tree once its visible copies are decorative */
.s-card__sr {
  position: absolute;
  width: var(--border-hair);
  height: var(--border-hair);
  overflow: hidden;
  opacity: 0;
}

/* speak — the greeting lifts as it is offered */
[data-demo="speak"] .d-glyph { transform: translateY(calc(var(--reveal) * var(--space-2) * -1)); }

/* mantra — the one becomes three. The echoes are out of flow at rest, so the
   first copy keeps the same 40px step as the other eight cards, and they open
   on the demo box's second line: anchored to the row's inline end they would
   land outside the card, over its neighbour. */
/* mantra — the card holds one line and completes it: the opening is at the card's
   reading size and the completion follows it inline, one step smaller, appearing
   only while the card is looked at. Nothing is quoted from the other two lines. */
[data-demo="mantra"] .d-echo {
  font-size: var(--type-sanskrit-inline-size);
  white-space: nowrap;
  color: var(--color-accent-text);
  opacity: var(--reveal);
  transition: opacity var(--duration-base) var(--ease-standard);
}
[data-demo="mantra"] .d-row .s-card__deva {
  font-size: var(--type-sanskrit-size);
  white-space: nowrap;
}

/* story — the opening formula continues under अस्ति, at the smaller Sanskrit
   step so the card's own first fragment stays the largest thing on it */
[data-demo="story"] .d-follow {
  font-size: var(--type-sanskrit-inline-size);
  white-space: nowrap;
  /* marked, so what arrived is obvious against what was already there */
  color: var(--color-accent-text);
  opacity: var(--reveal);
  transform: translateY(calc((1 - var(--reveal)) * var(--space-2) * -1));
}

/* read a text — one word lifts out of the line and gives up its meaning under
   itself, which is what reading a text actually feels like */
[data-demo="text"] .d-lift {
  transform: translateY(calc(var(--reveal) * var(--space-3) * -1));
  transition: color var(--duration-base) var(--ease-standard);
}
.s-card:hover [data-demo="text"] .d-lift,
.s-card:focus-visible [data-demo="text"] .d-lift,
.s-card[data-shown="true"] [data-demo="text"] .d-lift { color: var(--color-accent-text); }

/* the header carries the returning learner's way in next to the language switch */
.l-header__end { display: flex; align-items: center; gap: var(--space-6); }
#signin[aria-disabled="true"] { color: var(--color-text-secondary); cursor: default; }

/* a subject whose taste is not open yet answers with its own Sanskrit, and has no
   boards to switch between */
.s-taste[data-pending="true"] .s-view { display: none; }
.s-waiting__k { color: var(--color-accent-text); }
.s-waiting__deva { color: var(--color-text); }

/* Two quiet indications under the card's name: where the subject starts a learner,
   and whether its taste is ready yet. Both are text, not badges — a coloured pill
   on nine cards would outshout the Devanagari the cards are built on. */
.s-card__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-3) var(--space-4);
  color: var(--color-text-secondary);
}
.s-card__level::before {
  content: "";
  display: inline-block;
  width: var(--space-3);
  height: var(--space-3);
  margin-inline-end: var(--space-3);
  border: var(--border-hair) solid currentColor;
  border-radius: var(--radius-pill);
  vertical-align: baseline;
}
/* the mark fills by level: one outline, half, whole */
.s-card__level[data-level="b"]::before { background: linear-gradient(to right, currentColor 50%, transparent 50%); }
.s-card__level[data-level="c"]::before { background: currentColor; }
/* no separator glyph: the two marks wrap onto separate lines on a narrow card, and
   a dot left at the start of a line reads as debris */
.s-card__soon { color: var(--color-accent-text); }

/* Sanskrit and its transliteration are LTR runs sitting inside a page that may be
   RTL. Left-aligning them keeps every card's script and IAST on the same edge in
   both languages, and nowrap keeps a short Sanskrit fragment on one line — the
   Hebrew page's narrower text pushed the longer demos onto a second line. */
/* the demo box itself is the LTR column: aligning its items needs the direction
   on the container, since a right-to-left container puts its items on the right
   whatever the items themselves say */
[data-demo] {
  direction: ltr;
  text-align: left;
  justify-items: start;
  /* the box has to span the card, or an LTR column inside a right-to-left card
     still sits against the card's right edge */
  width: 100%;
}
[data-demo] .d-glyph, [data-demo] .s-card__translit { white-space: nowrap; }
/* the gloss is prose, not script — it wraps */
[data-demo] .d-gloss { white-space: normal; text-wrap: pretty; }
[data-demo] .d-row { justify-content: flex-start; }

/* grammar — the body stays quiet and only the ending is marked, so what moves is
   visible without a word of explanation */
[data-demo="grammar"] .d-end {
  color: var(--color-accent-text);
  transition: color var(--duration-base) var(--ease-standard);
}

/* read a text — the lifted word ties itself to what the line says, and the tie is
   drawn only while the card is being looked at */
[data-demo="text"] .d-gloss {
  opacity: var(--reveal);
  color: var(--color-accent-text);
}

/* vocabulary — जल gains द, and the meaning arrives with the sign */
[data-demo="vocabulary"] .d-add {
  opacity: var(--reveal);
  transform: translateX(calc((1 - var(--reveal)) * var(--space-3) * -1));
}

/* grammar — only the ending moves; both layers are complete words, never a
   fragment beginning with a matra, which would shape as a dotted circle */
[data-demo="grammar"] .d-glyph { white-space: nowrap; }

/* words — कर्म separates into its root */
[data-demo="words"] .d-b { transform: translateX(calc((1 - var(--reveal)) * var(--space-2) * -1)); }

@media (prefers-reduced-motion: reduce) {
  .s-card, [data-demo] .d-lift { transition: none; }
}

/* ---- 2 · the taste ------------------------------------------------------
   One thing at a time, at the visitor's pace. Nothing counted, nothing scored.
   The lesson's own shape follows its subject: speech is a conversation with
   layers that open, reading is a guided decoding with a moment of trying, a
   mantra is a sequence of utterance. */

/* §3.2a — not subjects but states of the learner, so they sit below a hairline of
   their own, quiet and separate from the nine */
.s-routes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4) var(--space-7);
  padding-top: var(--space-5);
  border-top: var(--border-hair) solid var(--color-border);
}
.s-route {
  display: inline-flex;
  align-items: center;
  min-height: var(--hit-target-min);
  padding: 0;
  background: transparent;
  color: var(--color-accent-text);
  border: none;
  border-bottom: var(--border-hair) solid var(--color-border);
  font-family: var(--font-ui);
  cursor: pointer;
}
.s-route:hover { color: var(--color-text); border-bottom-color: var(--color-border-strong); }
.s-route[aria-pressed="true"] { color: var(--color-text); border-bottom: var(--border-thick) solid var(--color-text); }

.s-handoff[hidden] { display: none; }
.s-promise { color: var(--color-text); max-width: var(--content-max); }

.s-build { display: grid; gap: var(--space-7); width: 100%; }
.s-build[hidden] { display: none; }

.s-step { display: grid; justify-items: start; gap: var(--space-4); width: 100%; }
.s-step[hidden] { display: none; }
.s-step__k { color: var(--color-text-secondary); }
.s-step__glyph {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  direction: ltr;
  font-family: var(--font-deva);
  font-size: var(--type-sanskrit-display-size);
  line-height: var(--type-sanskrit-display-lh);
  color: var(--color-text);
}
/* the sign or chunk, its transliteration and the way to hear it are one line of
   thought, so they sit together rather than as separate blocks */
.s-meta { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-4); }
.s-translit { color: var(--color-text-secondary); font-style: italic; }
.s-deva { color: var(--color-text); white-space: nowrap; }
.s-gloss { color: var(--color-text); }
.s-use { color: var(--color-text); max-width: var(--content-max); }

/* the discovery: one letter becoming another, shown rather than explained */
.s-discovery { color: var(--color-accent-text); }
.s-prompt { color: var(--color-text); max-width: var(--content-max); }
.s-tries { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4); }
.s-tries[hidden] { display: none; }
/* asking for the answer or for a hint is quieter than trying */
/* the lesson's own forward control: the one filled shape in a lesson */
.s-next {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--hit-target-min);
  padding-inline: var(--space-6);
  background: transparent;
  color: var(--color-text);
  border: var(--border-thick) solid var(--color-text);
  border-radius: var(--radius-sm);
  font-family: var(--font-ui);
  font-size: var(--type-ui-size);
  font-weight: var(--type-ui-strong-weight);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-standard);
}
.s-next:hover { background: var(--color-surface-hover); }
.s-next[hidden] { display: none; }

.s-quiet {
  display: inline-flex;
  align-items: center;
  min-height: var(--hit-target-min);
  padding: 0;
  background: transparent;
  color: var(--color-accent-text);
  border: none;
  border-bottom: var(--border-hair) solid var(--color-border);
  font-family: var(--font-ui);
  cursor: pointer;
}
.s-quiet:hover { color: var(--color-text); border-bottom-color: var(--color-border-strong); }
.s-hint, .s-verify { display: grid; justify-items: start; gap: var(--space-3); width: 100%; }
.s-hint[hidden], .s-verify[hidden] { display: none; }

/* the meaning of an utterance in three separate layers: what it is used for, what
   it is made of, and what it says literally (L918 §4.1a) — the pleasure is in the
   distance between them, and folding them into one sentence loses it */
/* the layer owns the label column, so every row's label shares one x — four rows
   of a word list are a column, not four staggered fragments */
.s-layer { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-3) var(--space-5); width: 100%; }
.s-layer[hidden] { display: none; }
.s-layer > :not(.s-row) { grid-column: 1 / -1; }
.s-row { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; align-items: baseline; }
.s-row__k { color: var(--color-text-secondary); }
.s-row__v { color: var(--color-text); }

/* the invitation: one thing to do, and no way to get it wrong */
.s-do { display: grid; justify-items: start; gap: var(--space-2); width: 100%; }
.s-do[hidden] { display: none; }
.s-do__k { color: var(--color-text-secondary); }
.s-do__v { color: var(--color-text); max-width: var(--content-max); }

/* the learner's own name goes in the open line: they are a party to the exchange,
   not a spectator of it */
.s-fill {
  min-width: var(--space-10);
  padding: 0 var(--space-2);
  background: transparent;
  color: var(--color-text);
  border: none;
  border-bottom: var(--border-thick) solid var(--color-border-strong);
  font-family: var(--font-deva);
  font-size: inherit;
  text-align: center;
}
.s-fill:focus-visible { outline: var(--border-thick) solid var(--color-focus); outline-offset: var(--space-1); }

/* hearing a line is a tap, and it stays small: an available layer, not the centre
   of attention */
.s-tap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--hit-target-min);
  height: var(--hit-target-min);
  padding: 0;
  background: transparent;
  color: var(--color-accent-text);
  border: none;
  border-radius: var(--radius-pill);
  cursor: pointer;
}
.s-tap:hover { background: var(--color-surface-hover); color: var(--color-text); }
.s-tap__icon, .s-tap__play, .s-tap__stop {
  width: var(--space-5);
  height: var(--space-5);
  flex: 0 0 auto;
  fill: currentColor;
}
.s-tap__stop { display: none; }
/* playing is visible but quiet: the button changes, and nothing animates */
.s-tap[data-playing="true"] .s-tap__play { display: none; }
.s-tap[data-playing="true"] .s-tap__stop { display: inline; }

/* ---- the conversation ----------------------------------------------------
   Two speakers, one to each side, as a thread reads. In Hebrew it mirrors on its
   own. Bubbles shrink to their content — a fixed width is what kills the sense of
   conversation — and stop at about 70% of the column so the alternation between
   sides stays visible. Vertical rhythm is tight and even; only a change of
   speaker gets a little more air. */
.s-thread { display: grid; gap: var(--space-3); width: 100%; }
.s-thread[hidden] { display: none; }
.s-turn { display: grid; gap: var(--space-0); justify-items: start; }
.s-turn[hidden] { display: none; }
.s-turn + .s-turn { margin-top: var(--space-2); }
.s-turn .s-bubble { width: fit-content; max-width: 70%; }
.s-turn[data-side="b"] { justify-items: end; }

.s-bubble {
  display: grid;
  justify-items: start;
  /* the Sanskrit, its transliteration and its meaning are one utterance, not
     three blocks — the spacing between them is tight */
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  background: var(--color-surface);
  border: var(--border-hair) solid var(--color-border);
  border-radius: var(--radius-lg);
}
/* a turn that is two sentences is two bubbles, one under the other */
.s-turn .s-bubble + .s-bubble { margin-top: var(--space-2); }
/* the visitor's own side is the marked one — they are a party to the exchange */
.s-turn[data-side="b"] .s-bubble {
  background: var(--color-surface-pressed);
  border-color: var(--color-border-strong);
}

/* speech is read at reading size: the display step is for a word put up to be
   looked at, and at that step an ordinary sentence breaks over three lines and
   the bubble becomes a page. A short sentence never wraps. */
.s-line__sa { display: flex; align-items: baseline; gap: var(--space-3); direction: ltr; min-height: 0; }
.s-bubble .s-line__sa, .s-bubble .s-meta, .s-bubble .s-use { min-height: 0; }
/* speech is read at reading size, 2.0 leading, never at display size (§4.2a) */
.s-bubble .s-deva {
  font-family: var(--font-deva);
  font-size: var(--type-sanskrit-size);
  line-height: var(--type-sanskrit-lh);
  font-weight: var(--type-sanskrit-weight);
}

/* ---- the writing figures (L2601) ---------------------------------------
   The animation teaches the movement and the finished form teaches the shape, so
   the two stand together: the form first, where reading starts, and the movement
   after it. The glyph layers, the numbers and the arrows are the shared module's
   (/assets/deva-write/) — this stylesheet only places them. */
/* a writing step carries two readings at once, so it breathes wider than a
   reading step */
.s-step--write { gap: var(--space-6); }
.s-figs { display: grid; grid-template-columns: 1fr; gap: var(--space-8); width: 100%; }
.s-fig { display: grid; justify-items: start; gap: var(--space-5); }
.s-fig__row {
  display: flex;
  flex-wrap: wrap;
  direction: inherit;
  flex-direction: row;
  align-items: flex-start;
  gap: var(--space-7);
}
/* Devanagari runs set their own direction, but the direction belongs on the runs
   themselves, not on the row: forcing the row ltr also forced its flex order
   left-to-right, so on the Hebrew page the pair came out the English way round. */
.s-fig__row .s-write, .s-fig__row .s-ref { direction: ltr; }
/* the phrase's two words are one script run, and script order never mirrors */
.s-fig--whole .s-fig__row:not(:has(.s-ref)) { direction: ltr; }
.s-fig__row > .s-quiet--row, .s-fig__row .s-ref__k { direction: inherit; }
/* the finished form comes first and the movement follows, in both views */
.s-fig__row > .s-ref { order: 1; }
.s-fig__row > .s-write { order: 2; }
.s-fig__row > .s-quiet--row { order: 3; }
.s-ref { display: grid; justify-items: start; gap: var(--space-2); flex: 0 0 auto; }
.s-fig--whole .s-ref { flex: 0 1 auto; }
.s-ref__k { color: var(--color-text-secondary); }
/* the replay sits beside the row it belongs to */
.s-quiet--row { align-self: flex-start; margin-block-start: var(--space-6); }
.s-write { padding: var(--space-6) var(--space-7) var(--space-9); flex: 0 0 auto; }
/* the placeholder the module reads its text from and then replaces: styled so it
   never flashes at a default size before the mount */
.s-write__glyph { position: relative; display: block; }
.s-write__sizer {
  display: block;
  font-family: var(--font-deva);
  font-size: var(--type-sanskrit-display-size);
  line-height: 1;
  white-space: nowrap;
  color: var(--color-text);
}
.s-write__sr { position: absolute; width: var(--border-hair); height: var(--border-hair); overflow: hidden; opacity: 0; }

/* A mantra line is longer than the single word the display size was made for, so
   it fills the board's width instead of being set at a fixed size: display size is
   the ceiling, and the line shrinks only as far as the width demands. That keeps a
   line, a chunk and the two dictionary forms all reading at one visual weight. */
#taste-mantra .s-step__glyph.t-sanskrit-display {
  font-size: min(var(--type-sanskrit-display-size), 9cqw);
  line-height: var(--type-sanskrit-display-lh);
  width: 100%;
  text-align: center;
  text-wrap: nowrap;
}

/* ---- the feedback page --------------------------------------------------
   One column, fields the width of the reading measure, no card chrome — the
   page is a page and not a form widget. */
.f-form { display: grid; gap: var(--space-6); width: 100%; max-width: var(--content-max); }
.f-field { display: grid; gap: var(--space-3); margin: 0; }
.f-label { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-3); color: var(--color-text); }
.f-hint { color: var(--color-text-secondary); }
.f-input {
  box-sizing: border-box;
  width: 100%;
  min-height: var(--hit-target-min);
  padding: var(--space-4) var(--space-5);
  background: var(--color-surface);
  color: var(--color-text);
  border: var(--border-hair) solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  font-family: var(--font-ui);
  font-size: var(--type-body-size);
  transition: border-color var(--duration-fast) var(--ease-standard);
}
.f-input:hover { border-color: var(--color-text-secondary); }
.f-input:focus-visible { outline: var(--border-thick) solid var(--color-accent); outline-offset: var(--space-1); }
.f-area { min-height: calc(var(--space-11) + var(--space-8)); resize: vertical; line-height: var(--type-body-lh); }
.f-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-5) var(--space-7); }
.f-about { color: var(--color-text-secondary); }
.f-about[hidden] { display: none; }

/* a taste says what it is before it says which subject it is: a preview of a
   lesson, not the lesson */
.s-taste__k { color: var(--color-accent-text); }
.s-taste__k[hidden] { display: none; }

/* the quiet way out of the handoff is a button, and carries the link's manners */
.s-onward__back {
  min-height: var(--hit-target-min);
  padding: 0;
  background: transparent;
  border: none;
  cursor: pointer;
}

/* the thumb. The buttons themselves are the landing page's .l-vote, unchanged —
   this only places them and keeps the question quiet. */
.s-vote { display: grid; justify-items: start; gap: var(--space-2); width: 100%; }
.s-vote[hidden] { display: none; }
.s-vote__q { color: var(--color-text-secondary); }
.s-vote__thanks { color: var(--color-accent-text); }
.s-vote__thanks[hidden] { display: none; }
/* the optional note beside the thumb — the same offer the landing page makes
   after its own vote, kept to two rows so it never becomes a second form */
.s-vote__more { display: grid; justify-items: start; gap: var(--space-3); width: 100%; max-width: var(--content-max); }
.s-vote__more[hidden] { display: none; }
.s-vote__note {
  width: 100%;
  padding: var(--space-4);
  font: inherit;
  color: var(--color-text);
  background: var(--color-surface);
  border: var(--border-hair) solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  resize: vertical;
}
.s-vote__note:focus-visible { outline: var(--border-thick) solid var(--color-border-accent); outline-offset: var(--space-1); }

/* inside the form it sits as one field among the others */
.f-field .l-vote { margin-top: var(--space-0); }

/* the line that ties two tastes together. It is the quietest thing in the
   lesson: secondary text above a hairline, at the very end, never in the flow. */
.s-bridge {
  width: 100%;
  padding-top: var(--space-5);
  color: var(--color-text-secondary);
  border-top: var(--border-hair) solid var(--color-border);
  max-width: var(--content-max);
}
.s-bridge[hidden] { display: none; }
/* in one-board-at-a-time it belongs to the lesson, below the controls */
.s-board .s-bridge { grid-row: 5; }

/* a card the visitor has already opened. The quietest mark on the card — it
   sits beside the level, in secondary text, and says only that they have been
   here. No count and no score. */
.s-card__tasted { color: var(--color-text-secondary); }
.s-card__tasted::before {
  content: '';
  display: inline-block;
  width: var(--space-2);
  height: var(--space-2);
  margin-inline-end: var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-accent);
  vertical-align: middle;
}

/* the complete mantra: three lines as context and destination, each with its
   transliteration under it. The line the visitor learns is marked without the
   other two being hidden (L270 §10.5 step 9). */
.s-whole { display: grid; gap: var(--space-4); width: 100%; }
.s-whole__line { display: grid; gap: var(--space-1); justify-items: start; direction: ltr; }
.s-board .s-step { container-type: inline-size; }
.s-board .s-step .s-whole { justify-items: center; }
.s-board .s-step .s-whole__line { justify-items: center; }
.s-whole__line .s-translit { color: var(--color-text-secondary); font-style: italic; }
.s-whole__line.is-learned .s-deva { color: var(--color-accent-text); }
/* a peel control names what it opens, so meaning is visibly available and not a
   mystery icon */
.s-tap__label { color: var(--color-text-secondary); }

/* the lesson's closing lines, and what is still provisional about them */
.s-close { color: var(--color-text); max-width: var(--content-max); }
.s-note { color: var(--color-text-secondary); max-width: var(--content-max); }

.s-order { display: grid; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }
.s-order__item { display: flex; align-items: baseline; gap: var(--space-3); color: var(--color-text-secondary); }
.s-order__item::before {
  content: attr(data-stroke-label);
  color: var(--color-accent-text);
  font-variant-numeric: tabular-nums;
}

/* the eight awaiting philological verification: one sentence, no skeleton —
   empty boxes read as a failed load rather than as content on its way */
.s-waiting { color: var(--color-text); max-width: var(--content-max); }
.s-beats { display: grid; gap: var(--space-7); width: 100%; }
.s-beats[hidden] { display: none; }

/* ---- 3 · continue ------------------------------------------------------- */

.s-onward { display: grid; justify-items: start; gap: var(--space-5); width: 100%; }
.s-onward__lead { color: var(--color-text); max-width: var(--content-max); }
.s-onward__row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-5) var(--space-7); }
.s-status { color: var(--color-text-secondary); }
.s-status[hidden] { display: none; }
.l-btn[aria-disabled="true"] { opacity: var(--opacity-disabled); cursor: default; }

/* ---- the layout switch (owner request) -----------------------------------
   Two ways to read the same lesson, chosen before working through it and
   remembered: continuous, where each step joins the ones before it, or one board
   at a time, which holds the eye in one place. */

.s-view { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); }
.s-view__k { color: var(--color-text-secondary); }
/* the switcher speaks in shapes — stacked lines for the continuous lesson, one
   plate for one board at a time — so it reads at a glance and needs no label */
.s-view__icon { width: var(--space-5); height: var(--space-5); display: block; }
.s-view__opt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--hit-target-min);
  min-height: var(--hit-target-min);
  padding: 0 var(--space-4);
  background: transparent;
  color: var(--color-accent-text);
  border: none;
  border-bottom: var(--border-hair) solid var(--color-border);
  font-family: var(--font-ui);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-standard),
              border-bottom-color var(--duration-fast) var(--ease-standard);
}
.s-view__opt:hover { color: var(--color-text); border-bottom-color: var(--color-border-strong); }
.s-view__opt[aria-pressed="true"] { color: var(--color-text); border-bottom: var(--border-thick) solid var(--color-text); }

/* the way back and forward, and a row of dots saying how many boards there are
   and which one this is */
.s-nav { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-5); }
.s-nav[hidden] { display: none; }
.s-nav__back[hidden] { display: none; }
.s-dots { display: flex; align-items: center; gap: var(--space-3); }
.s-dots[hidden] { display: none; }
.s-dots__dot {
  width: var(--space-3);
  height: var(--space-3);
  border-radius: var(--radius-pill);
  background: transparent;
  border: var(--border-hair) solid var(--color-border-strong);
}
.s-dots__dot.is-seen { background: var(--color-border-strong); }
.s-dots__dot.is-at { background: var(--color-accent-text); border-color: var(--color-accent-text); }

/* Continuous reading still has parts: each step keeps a frame of its own so the
   visitor can see what was done in which piece. The board's plate is the same
   idea for one step at a time. */
.s-build:not(.s-board *) > .s-step,
.s-thread:not(.s-board *) > .s-exchange,
.s-thread:not(.s-board *) > .s-do {
  padding: var(--space-6);
  background: var(--color-surface);
  border: var(--border-hair) solid var(--color-border);
  border-radius: var(--radius-md);
}

/* The plate is the lesson's own frame: one row for the lesson's promise, one
   board row of a fixed height, one row for the controls — matching the plate's
   real children, so the board can no longer stretch that row and carry the
   controls with it. Everything a board recurs with holds a slot of its own, in a
   fixed order, so nothing moves as the visitor steps through. */
.s-board .s-build:not([hidden]),
.s-board .s-thread:not([hidden]) {
  box-sizing: border-box;
  display: grid;
  /* one explicit column, always: two children sharing an explicit row in a
     column-less grid create an implicit second column, and every other row then
     inherits it — which halved the board's width */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto var(--board-h) auto auto auto;
  gap: var(--space-6);
  width: 100%;
  padding: var(--space-7);
  background: var(--color-surface);
  border: var(--border-hair) solid var(--color-border);
  border-radius: var(--radius-lg);
}
/* the board row is sized to the tallest board of its lesson: large enough that
   none is cut off, no larger than the lesson actually uses */
.s-board .s-build { --board-h: calc(var(--space-11) * 4 + var(--space-8)); }
/* the conversation's tallest turn is the split utterance — two bubbles in one
   turn (L918 §4.2a) — so the row is sized for that, not for a single bubble */
/* a thread board now holds a whole exchange, and its tallest case is the split
   two-bubble utterance answered by a reply */
.s-board .s-thread { --board-h: calc(var(--space-11) * 4 + var(--space-9)); }

/* On a board the figure has the plate's width, not the page's, so the writing
   sits at a size that keeps the animation, the finished form and the replay on
   one line — a wrapped row is what pulled the glyphs off a common line. The
   stroke names stay below the letters, where they read as a caption. */
.s-board .s-fig { display: grid; justify-items: center; gap: var(--space-4); }
/* The finished form reads first and the movement below it: the shape is what the
   eye needs in order to follow the hand, and it stays legible while the writing
   is still blank. */
/* A single sign needs no second row: the finished form sits where reading starts
   and the movement follows it, which is left-then-right in English and
   right-then-left in Hebrew — flex row order is logical, so the same rule serves
   both. Only the two-word phrase stacks, since it cannot sit beside its form. */
.s-board .s-fig__row {
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: flex-start;
  justify-content: center;
  gap: var(--space-7);
  min-height: 0;
}
.s-board .s-fig__row > .s-ref { order: 1; }
.s-board .s-fig__row > .s-write { order: 2; }
.s-board .s-fig__row > .s-quiet--row { order: 3; margin-block-start: 0; align-self: center; }
/* the whole phrase keeps its two words side by side, and its finished form is the
   row above them */
.s-board .s-fig--whole .s-fig__row { flex-direction: row; flex-wrap: wrap; }
.s-fig--whole .s-fig__row:has(.s-ref) { order: 1; }
.s-fig--whole .s-fig__row:not(:has(.s-ref)) { order: 2; }
.s-fig--whole { display: grid; }
/* the padding belongs to the glyph box alone: on the finished-form side the
   wrapper and the box would both pay it, and the two letters could not share a
   line however the row is aligned */
/* the bottom is set per figure once its marks are placed (see measureWrite) */
.s-board .s-write { padding: var(--space-5) var(--space-6) var(--space-5); }
.s-board .s-ref { padding: 0; }
.s-board .s-order { justify-items: start; }

/* the promise heads the plate, the boards share the middle row, the controls close it */
.s-board .s-promise { grid-row: 1; }
/* an exchange is one board: its turns stack inside it */
.s-exchange { display: grid; gap: var(--space-5); width: 100%; }
.s-exchange[hidden] { display: none; }
.s-board .s-build > .s-step:not([hidden]),
.s-board .s-thread > .s-exchange:not([hidden]),
.s-board .s-thread > .s-do:not([hidden]) {
  grid-row: 2;
  align-self: stretch;
  min-height: 0;
  overflow: hidden;
}
.s-board .s-nav { grid-row: 3; align-self: end; }
/* One board at a time means one thing on screen: the lesson's closing lines are
   part of the continuous reading, not of any single board. */
.s-board .s-build > .s-close, .s-board .s-build > .s-note { display: none; }

/* the controls read back · where you are · onward, so the dots hold the middle */
.s-board .s-nav {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  width: 100%;
}
/* all three share row 1: the dots come first in source, and pinning columns
   alone let auto-placement push the buttons onto a second row */
.s-board .s-nav .s-nav__back { grid-area: 1 / 1; justify-self: start; }
.s-board .s-nav .s-dots { grid-area: 1 / 2; justify-self: center; }
.s-board .s-nav .s-next { grid-area: 1 / 3; justify-self: end; }
/* the caption sits under the form it labels, not at the row's edge */
.s-board .s-ref { justify-items: center; }

/* the slots inside a board, in one order on every board */
.s-board .s-step:not([hidden]) {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  width: 100%;
}
.s-board .s-step__k { order: 1; min-height: var(--space-6); }
/* The figure is a child of the step, its row a grandchild: the glyph slot must be
   claimed by the figure itself, or the row's order applies inside the figure and
   the whole block sorts ahead of the label. */
.s-board .s-step > .s-fig { order: 2; width: 100%; }
.s-board .s-step__glyph,
.s-board .s-step .s-line__sa {
  order: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(var(--space-11) + var(--space-5));
  width: 100%;
}
.s-board .s-step .s-meta { order: 3; min-height: var(--hit-target-min); justify-content: center; }
.s-board .s-step .s-use, .s-board .s-prompt { order: 4; text-align: center; width: 100%; }
.s-board .s-discovery, .s-board .s-step > .s-note { order: 5; text-align: center; }
/* inside a figure the stroke names and the note follow the letters */
.s-board .s-fig > .s-fig__row { order: 1; }
/* except in the phrase, whose finished form is a row of its own and comes first */
.s-board .s-fig--whole > .s-fig__row:has(.s-ref) { order: 1; }
.s-board .s-fig--whole > .s-fig__row:not(:has(.s-ref)) { order: 2; }
.s-board .s-fig > .s-order, .s-board .s-fig > .s-note { order: 2; }
.s-board .s-fig > .s-step__k { order: 0; }
/* Centring is the boards' arrangement for the lessons built of steps; a bubble is
   a conversation and reads start-aligned, with its meaning layers in one label
   column (§4.1a). Every rule here is scoped to a step for that reason. */
.s-board .s-step .s-tries, .s-board .s-step .s-verify,
.s-board .s-step .s-layer, .s-board .s-step .s-hint {
  order: 6;
  width: 100%;
  text-align: center;
}
.s-board .s-step .s-hint, .s-board .s-step .s-verify { justify-items: center; }
.s-board .s-step .s-layer { justify-self: center; justify-items: start; text-align: start; width: auto; max-width: 100%; }
.s-board .s-step .s-hint .s-line, .s-board .s-step .s-verify .s-line,
.s-board .s-step .s-layer .s-line { justify-content: center; }
.s-board .s-step .s-tries { justify-content: center; }
.s-board .s-turn:not([hidden]) { width: 100%; }

/* the navigation sits in the plate's last row, at the same place on every board */
/* the step fills the plate's content row — hugging its own content is what made
   align-content a no-op and let each board sit at a different height */
/* The board row is a fixed height, so an exchange placed in it must pack from the
   top rather than divide the row between its turns: stretch cascaded all the way
   into the bubbles and spread one short line over hundreds of pixels. */
.s-board .s-exchange:not([hidden]) { align-content: start; gap: var(--space-4); }
/* the exchange packs from the top of the fixed row: without this its auto rows
   divide the row between the two speakers, so a short bubble becomes a tall box */
.s-board .s-thread > .s-exchange:not([hidden]) { align-content: start; gap: var(--space-4); }
.s-board .s-exchange .s-turn { align-content: start; }
.s-board .s-exchange .s-bubble { align-self: start; align-content: start; }
