/* ============================================================
   OBI FRONT: the front page a signed-out visitor meets first: what
   Obi does, in about a minute, and Sign in for the teachers who
   already use it (Pass 6, Stage 6f; R55 to R57).
   The words: plans/FRONT-PAGE.md §2 (nothing else may appear). The
   behaviour: tools/FRONT-CONTRACT.md. The look: plans/WEB-EXTENSIONS.md
   §19, inside Obi v2 (tokens only, and Obi's own component values).
   obi-front.js builds the page (#obiFront) inside Thabo's sign-in
   overlay (#authOverlay) and puts the overlay in front mode
   (.ov-front); this file styles both. Every selector is scoped under
   #obiFront or #authOverlay.ov-front, so nothing reaches the app.
   The signature is the drawn apricot full stop (.obf-stop, §19.1) that
   ends the h1 and every section heading; everything else stays quiet.
   Every value that is not a token says why, beside it (a "keep" note).
   Spacing that grows with the window is a clamp between two of Obi's
   spacing tokens; its middle term (a vw rate) is not a size, only how
   fast it moves from the smaller token to the larger, and its keep
   note says where each end is reached.
   ============================================================ */

/* ---- 1. The overlay in front mode (FRONT-CONTRACT "DOM in front mode") ----
   The overlay is the scroll container; the page fits it, it is never clipped (no overflow-x:hidden). Two ids outrank
   ovation-loginfx.js's #authOverlay#authOverlay rule (its flex centring, its padding). While the page shows, every other
   child of the overlay (the card, the carousel, a splash) is hidden; outside front mode the page is. */
#obiFront { display: none; }
#authOverlay#authOverlay.ov-front { display: block; padding: 0; overflow-y: auto; }
#authOverlay.ov-front > :not(#obiFront) { display: none; }
#authOverlay.ov-front > #obiFront { display: block; }

/* ---- 2. Inter's stand-in (6.VB). Inter comes from Google Fonts (font-display:swap), so the first frame is set in a fallback
   face and Inter replaces it about 100ms later on a cold load. With an ordinary fallback the 96px headline re-wrapped at that
   moment. These faces are the computer's own Arial (local(): no request), scaled to Inter's widths as the page sets them
   (evidence/pass-6/6vb-fix/fontfit.mjs) and given Inter's ascent and descent (0.96875 and 0.2412 of the em, each divided by
   the size-adjust), so the swap changes the letterforms, not the lines. "Display" is for the h1 and the h2s (Inter's optical
   size makes it about 4.5% narrower than Arial Bold there); the other face serves the rest of the page's text (Regular for 400
   and 500, Bold for 600 and 700). Each element a local face sets in a frame costs the browser about 2ms before that frame
   (evidence/pass-6/6vb-fix/paint-variants3.mjs), so in the first frame (the bar and the hero) only the h1 uses one: the lede,
   the buttons and the wordmark stay on Obi's own stack, where they keep their lines when Inter arrives (linebreaks.mjs), and the
   h1 is drawn as soon as before (G21). Where Arial is missing the stack goes on to Obi's own fallbacks as before. ---- */
@font-face { font-family: "Obi Inter Fallback"; src: local("Arial"), local("ArialMT"); font-weight: 400; font-style: normal; font-display: swap;
  size-adjust: 104.5%; ascent-override: 92.70%; descent-override: 23.08%; line-gap-override: 0%; } /*keep: Inter Regular at 17 to 19px is 4.1 to 5.4% wider than Arial*/
@font-face { font-family: "Obi Inter Fallback"; src: local("Arial Bold"), local("Arial-BoldMT"); font-weight: 700; font-style: normal; font-display: swap;
  size-adjust: 98%; ascent-override: 98.85%; descent-override: 24.61%; line-gap-override: 0%; } /*keep: Inter SemiBold and Bold at 15 to 21px against Arial Bold, 0.98 to 1.01*/
@font-face { font-family: "Obi Inter Display Fallback"; src: local("Arial Bold"), local("Arial-BoldMT"); font-weight: 700; font-style: normal; font-display: swap;
  size-adjust: 95.5%; ascent-override: 101.44%; descent-override: 25.26%; line-gap-override: 0%; } /*keep: Inter Bold at 32px and up (its display optical size) is 0.955 of Arial Bold*/

/* ---- 3. The page ---- */
#obiFront {
  --obf-gutter: clamp(var(--space-4), 5vw, var(--space-7));       /*keep: §19.4, the 5vw rate: 16px up to 320 (§6's gutter), 48px from 960*/
  --obf-section: clamp(var(--space-8), 9vw, var(--space-9));      /*keep: §19.4, the space between sections; the 9vw rate: 64px up to about 710, 96px from about 1070*/
  --obf-bar: var(--space-8);                                      /* the top bar's height: a 40px button and 12px above and below */
  box-sizing: border-box; min-height: 100%; margin: 0;
  background: var(--bg-page); color: var(--ink);
  font-family: "Inter", "Obi Inter Fallback", var(--font-sans); /* Obi's Inter, then its stand-in (§2), then Obi's own stack */
  font-size: var(--text-body); line-height: var(--lh-body); text-align: left;
  overflow-wrap: anywhere; /* a word longer than its line (300% text, 320px) wraps inside itself rather than running off the side */
}
#obiFront *, #obiFront *::before, #obiFront *::after { box-sizing: border-box; }
#obiFront .obf-wrap {
  width: 100%; margin-inline: auto; padding-inline: var(--obf-gutter);
  max-width: calc(1200px/*keep: §19.4, a reading page's width, narrower than the app's 1780px grids*/ + 2 * var(--obf-gutter));
}
#obiFront p { margin: 0; }
#obiFront :focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; } /* Obi's ring, whatever the app's rules say */

/* Headings. ovation.css and obi-web.css style bare h1, h2 and h3 for the app's views: every property they set is set here. */
#obiFront :is(.obf-h1, .obf-h2, .obf-h3) { margin: 0; max-width: none; font-family: inherit; color: var(--ink); overflow-wrap: anywhere; text-wrap: balance; }
#obiFront :is(.obf-h1, .obf-h2) { font-family: "Inter", "Obi Inter Display Fallback", var(--font-sans); } /* §2: the display stand-in */
@media (max-width: 559px/*keep: below this the h2s are under about 28px, where Inter's optical size is near its text size and the text stand-in matches it better (linebreaks.mjs)*/) {
  #obiFront .obf-h2 { font-family: "Inter", "Obi Inter Fallback", var(--font-sans); }
}
/* The closing promise is two sentences: each starts its own line, so a line never ends on "Record" (obi-front.js wraps each in .obf-line). */
#obiFront .obf-line { display: block; }
#obiFront .obf-h1 {
  font-size: clamp(2.25rem, 1.6rem + 5.2vw, 6rem); /*keep: §19.3, the one bend: about 42px at 320, 96px from about 1354; rem, so it follows the reader's text size*/
  font-weight: var(--fw-bold);
  line-height: 1.02;           /*keep: §19.3, two lines of 96px type set solid read as one statement*/
  letter-spacing: -.035em;     /*keep: §19.3, Inter this large reads loose at Obi's -0.02em*/
  text-wrap: balance;
}
#obiFront .obf-h2 {
  font-size: clamp(var(--text-h2), 1rem + 2.2vw, var(--text-display)); /*keep: §19.3, between Obi's h2 and display steps, never above display; the 1rem + 2.2vw rate: 26px up to about 455, 40px from about 1090*/
  font-weight: var(--fw-bold); line-height: var(--lh-h2); letter-spacing: var(--ls-tight); text-wrap: balance;
  scroll-margin-top: var(--space-5);
}
#obiFront .obf-h3 { font-size: var(--text-h3); font-weight: var(--fw-semibold); line-height: var(--lh-h3); letter-spacing: var(--ls-tight); }
#obiFront .obf-h2[tabindex="-1"]:focus:not(:focus-visible) { outline: none; } /* "See how it works" moves focus here; a mouse user gets no ring */

/* The signature (§19.1): the wordmark's apricot full stop, drawn (0.19em, sitting on the baseline) rather than typed, because an
   apricot glyph on bone (2.50:1) would count as text; drawn and aria-hidden it is decoration. .obf-end holds the heading's last
   letter and the stop together, so the stop never wraps onto a line of its own. */
#obiFront .obf-end { white-space: nowrap; }
#obiFront .obf-stop {
  display: inline-block; width: .19em; height: .19em; /*keep: §19.1, the drawn full stop, the size of Inter's own (0.18 to 0.21em)*/
  margin-left: .03em; /*keep: §19.1, with the letter's own side and the tracking, the 0.04em gap a typed full stop leaves (6.VB)*/
  vertical-align: baseline; border-radius: var(--radius-full); background: var(--apricot);
}

/* ---- 4. Buttons: Obi's Button (primary, secondary, ghost), as real <button>s ---- */
#obiFront .obf-btn {
  appearance: none; display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: var(--tap-min); margin: 0;
  padding: var(--space-2) 20px/*keep: Obi Button md's own padding*/;
  font-family: var(--font-sans); /* Obi's own stack, not a stand-in (§2: the first frame sets only the h1 in one) */
  font-size: var(--text-body); font-weight: var(--fw-semibold); line-height: var(--lh-label); letter-spacing: normal;
  text-align: center; text-decoration: none; overflow-wrap: anywhere; cursor: pointer;
  border: 1px solid transparent; border-radius: var(--radius-control); box-shadow: none;
  transition: background-color var(--motion-fast) var(--ease-out), border-color var(--motion-fast) var(--ease-out);
}
#obiFront .obf-primary { background: var(--apricot); color: var(--apricot-ink-strong); }
#obiFront .obf-primary:hover { background: #DA762C; }  /*keep: Obi Button primary's own hover*/
#obiFront .obf-primary:active { background: #C96A26; } /*keep: Obi Button primary's own pressed*/
#obiFront .obf-secondary { background: var(--cream); color: var(--ink); border-color: var(--warm-grey); }
#obiFront :is(.obf-secondary, .obf-ghost):hover { background: var(--sand); }
#obiFront :is(.obf-secondary, .obf-ghost):active { background: #EAE1CF; } /*keep: Obi Button's own pressed secondary (and ghost), obi-v2 components/web/forms/Button.jsx*/
#obiFront .obf-ghost { background: transparent; color: var(--ink); }
#obiFront .obf-btn.obf-btn-bar { min-height: var(--row-dense); padding-inline: var(--space-4); } /* §19.4: 40px, the page's main action in a bar */

/* ---- 5. The top bar (banner): the icon and wordmark, and Sign in. Sticky only in a window at least 480px tall (§19.4). ---- */
#obiFront > .obf-bar {
  position: relative; top: auto; z-index: 3/*keep: the sticky bar stays over everything that scrolls under it (the scenes' frames and shadows); 3, the level of the web layer's pinned grid corner (§4); inside the overlay, so the app's own sticky header (30) never meets it*/;
  display: block; min-height: 0; margin: 0; padding: 0; gap: 0; font-size: inherit;
  background: var(--bg-page); border: 0; backdrop-filter: none; /* ovation.css styles every <header> as the app's */
}
#obiFront .obf-bar-fill { border-bottom: 1px solid transparent; }
#obiFront .obf-bar-in { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2) var(--space-3);
  min-height: var(--obf-bar); padding-block: var(--space-3); }
#obiFront .obf-mark { display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; }
#obiFront .obf-logo { display: block; flex: none; width: auto; height: 28px; /*keep: §19.4, the logo in a bar; 100px wide, above its 96px minimum*/
  max-width: 100%; user-select: none; -webkit-user-drag: none; } /* the Obi logo, assets/obi-logo-horizontal-primary.svg (brand/obi-logo) */
@media (min-height: 480px/*keep: §19.4, at 400% zoom (320x200) a sticky bar would take a quarter of the screen for good*/) {
  #obiFront > .obf-bar { position: sticky; top: 0; container-type: scroll-state; }
  /* A hairline under the bar only while it is stuck over the page (a scroll-state query; none where it is not supported). */
  @container scroll-state(stuck: top) { #obiFront .obf-bar-fill { border-bottom-color: var(--line); } } /*keep: §19.4, Obi's 1px hairline in --line, shown only while the bar is stuck so the page and the bar part where they overlap; not an Obi component*/
  #obiFront .obf-h2 { scroll-margin-top: calc(var(--obf-bar) + var(--space-5)); }
}

/* ---- 6. The hero: the h1 across the content width, then the lede and two buttons, left-aligned (§19.4) ---- */
#obiFront > .obf-main { display: block; max-width: none; margin: 0; padding: 0; animation: none; } /* ovation.css animates every <main> in */
#obiFront .obf-hero { padding-top: clamp(var(--space-7), 8vw, var(--space-9)); } /*keep: §19.4, the 8vw rate: 48px up to 600, 96px from 1200*/
/* The first frame draws the top bar and the hero only; obi-front.js takes .obf-later off after that frame, and the rest of the page
   follows in the next one (G21: the h1 reaches the screen as soon as the old sign-in screen's first frame did). */
#obiFront.obf-later :is(.obf-main > :not(.obf-hero), .obf-foot) { display: none; }
#obiFront .obf-lede { font-family: var(--font-sans); /* Obi's own stack, not a stand-in (§2) */
  max-width: 36em/*keep: §19.3, a comfortable reading line for the lede, about 70 characters*/;
  margin-top: clamp(var(--space-5), 3vw, var(--space-6))/*keep: the 3vw rate: 24px up to 800, 32px from about 1070*/;
  font-size: var(--text-body-lg); line-height: var(--lh-body); color: var(--ink-70); text-wrap: pretty; }
#obiFront .obf-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-6); }
@media (max-width: 359px/*keep: §19.6*/) {
  #obiFront .obf-actions { flex-direction: column; align-items: stretch; }
}

/* ---- 7. How Obi fits your day: the day's two halves, each with its scene at its foot (§19.4, §19.5) ---- */
#obiFront .obf-sec { padding-top: var(--obf-section); }
#obiFront .obf-halves { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-5);
  margin-top: clamp(var(--space-5), 4vw, var(--space-7)); } /*keep: the 4vw rate: 24px up to 600, 48px from 1200*/
#obiFront .obf-half {
  display: flex; flex-direction: column; min-width: 0;
  padding: clamp(var(--space-4), 5vw, var(--space-7)) clamp(var(--space-4), 5vw, var(--space-7)) 0; /*keep: the gutter's 5vw rate: 16px up to 320, 48px from 960*/
  border-radius: var(--radius-pill);
  overflow: visible clip; /* the device rises from the panel's foot: its shadow stops at the panel's edge; nothing is cut sideways */
}
#obiFront .obf-day { background: var(--sage-tint); }
#obiFront .obf-after { background: var(--sky-tint); }
#obiFront .obf-half-text { margin-bottom: clamp(var(--space-6), 4vw, var(--space-7)); } /*keep: the 4vw rate: 32px up to 800, 48px from 1200*/
#obiFront .obf-half-text p { max-width: 30em/*keep: a reading line inside a panel, about 60 characters*/; margin-top: var(--space-2); color: var(--ink-70); }
/* Side by side, each half spans two shared rows (a subgrid): its text, then its scene. So both scenes start on the same line
   under the taller text (the two "Example" tags level), and both run to the panels' common foot: the phone and the browser
   frame grow to fill it (6.VB, 6.VB-2). Stacked, each half is its own height. */
@media (min-width: 960px/*keep: §19.4, the two halves side by side*/) {
  #obiFront .obf-halves { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #obiFront .obf-half { display: grid; grid-row: span 2; grid-template-rows: subgrid; row-gap: 0; }
  #obiFront .obf-half > .obf-scene { margin: 0; }
  #obiFront .obf-half > .obf-phone { align-self: stretch; justify-self: center; } /* in the grid, centred across and full height */
  #obiFront .obf-phone, #obiFront .obf-device, #obiFront .obf-screen { flex: 1 0 auto; }
  #obiFront .obf-browser > .obf-window { display: flex; flex-direction: column; flex: 1 0 auto; }
  #obiFront .obf-browser .obf-page { flex: 1 0 auto; }
}

/* The scenes (§19.5): drawings made of Obi's components. figure[role=img] with an aria-label; spans only (nothing focusable,
   no form control). Sizes in rem, never transform: scale, so the text keeps its real size and follows the reader's text size. */
#obiFront .obf-scene { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-3); margin: auto 0 0; min-width: 0;
  font-size: var(--text-label); line-height: var(--lh-label); overflow-wrap: anywhere; }
#obiFront .obf-scene span { min-width: 0; }
/* In a narrow scene a row's parts move to the next line whole before any of them is squeezed (with overflow-wrap:anywhere a
   part's least width is one letter, so without this a name would shrink to a column of letters beside its neighbour); a part
   wider than the whole line keeps to the line and wraps inside itself. */
#obiFront :is(.obf-lc-head, .obf-row, .obf-rc, .obf-note, .obf-chips) > * { flex: 0 0 auto; max-width: 100%; }
#obiFront :is(.obf-who, .obf-note-body) { flex: 1 1 8em; } /*keep: a name or a note keeps about 8em beside its avatar or tile, then moves under it whole*/
#obiFront .obf-tag { display: inline-block; padding: var(--space-1) var(--space-3); border: 1px solid transparent; border-radius: var(--radius-pill);
  background: var(--cream); color: var(--text-muted); font-size: var(--text-caption); font-weight: var(--fw-medium); line-height: var(--lh-caption); }
#obiFront .obf-scene .brand .word { font-size: var(--text-body); }

/* The phone (the day): a simple frame, at most 17.5rem wide, rising from the panel's foot. Stacked, it is its own height (its
   screen at least 19rem); side by side it fills its panel to the common foot (the 960px rule above). Its screen is never empty: the note
   being written, then "Earlier today" and two notes (6.VB-2). */
#obiFront .obf-phone { align-self: center; width: min(100%, 17.5rem/*keep: §19.5, a phone's width beside the page's text*/); }
#obiFront .obf-device { display: flex; flex-direction: column; width: 100%; background: var(--ink);
  border: 6px solid var(--ink); border-bottom: 0;       /*keep: §19.5, the bezel*/
  border-radius: 32px 32px 0 0; }                       /*keep: §19.5, a phone's corner (not an Obi token)*/
#obiFront .obf-screen { display: flex; flex-direction: column; gap: var(--space-5);
  min-height: 19rem; /*keep: the screen reads as a phone, taller than it is wide; rem, so it grows with the text*/
  padding: var(--space-5) var(--space-4); background: var(--bg-page);
  border-radius: 26px 26px 0 0; } /*keep: §19.5, the screen's corner inside the bezel*/
/* Obi's VoiceInput, drawn: the label, the field (cream, warm-grey border, the field's height) and the 44px apricot mic. */
#obiFront .obf-vi { display: flex; flex-direction: column; gap: var(--space-2); }
#obiFront .obf-vi-label { font-weight: var(--fw-semibold); color: var(--ink); }
#obiFront .obf-field { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--space-3);
  min-height: var(--field-height); padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
  background: var(--cream); border: 1px solid var(--warm-grey); border-radius: var(--radius-control); }
#obiFront .obf-field-text { flex: 1 1 6em; color: var(--ink); } /*keep: the note keeps about 6em beside the mic, then the mic moves under it*/
#obiFront .obf-mic { display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 2.75rem; height: 2.75rem; /*keep: Obi VoiceInput's 44px mic, in rem*/
  border: 1px solid transparent; border-radius: var(--radius-full); background: var(--apricot); color: var(--apricot-ink-strong); }
/* Obi's Chip: a learner (neutral) and a subject (sky). */
#obiFront .obf-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
#obiFront .obf-chip { display: inline-flex; align-items: center; min-height: var(--control-dense); padding: var(--space-1) var(--space-3);
  border: 1px solid transparent; border-radius: var(--radius-pill); background: var(--sand); color: var(--ink); font-weight: var(--fw-medium); }
#obiFront .obf-chip-subject { background: var(--sky-tint); color: var(--sky-ink); }
/* Earlier today: a caption, then Obi's ListRow without its leading and trailing parts (a learner's name above the note, at
   least the tap height, 12px above and below, a --line hairline between rows); in a phone's screen, so no side padding. */
#obiFront .obf-earlier { display: flex; flex-direction: column; }
#obiFront .obf-earlier-cap { font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--text-muted); margin-bottom: var(--space-1); }
#obiFront .obf-li { display: flex; flex-direction: column; justify-content: center; min-height: var(--tap-min); padding-block: var(--space-3); }
#obiFront .obf-li + .obf-li { border-top: 1px solid var(--line); }
#obiFront .obf-li-name { font-weight: var(--fw-semibold); color: var(--ink); }
#obiFront .obf-li-note { margin-top: 2px/*keep: Obi ListRow's own gap between title and subtitle*/; color: var(--ink-70); text-wrap: pretty; } /* no lone last word */

/* The browser (afterwards): a cream frame with a sand strip and an empty address pill; inside, the page's own bone, and
   Obi's LearnerCard, ProgressBar, RatingChips and an observation. Its learner and note are not the phone's (6.VB): the page
   never shows a note moving from the phone to the website. */
#obiFront .obf-browser { width: 100%; }
#obiFront .obf-window { display: block; width: 100%; overflow: hidden; background: var(--cream);
  border: 1px solid var(--line); border-bottom: 0; border-radius: var(--radius-card) var(--radius-card) 0 0; box-shadow: var(--elev-2); }
#obiFront .obf-strip { display: flex; align-items: center; justify-content: center; padding: var(--space-2) var(--space-3);
  background: var(--sand); border-bottom: 1px solid var(--line); } /*keep (the strip as a whole): §19.5, a browser frame is not an Obi component*/
#obiFront .obf-address { display: block; width: min(100%, 22rem/*keep: §19.7, an address pill reads as one at most about 350px wide, whatever the frame's width*/);
  height: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-full); background: var(--cream); }
#obiFront .obf-page { display: flex; flex-direction: column; gap: var(--space-4);
  padding: clamp(var(--space-3), 4vw, var(--space-5)) clamp(var(--space-3), 4vw, var(--space-5)) var(--space-6); /*keep: the 4vw rate: 12px up to 300, 24px from 600*/
  background: var(--bg-page); }
#obiFront .obf-card-s { display: flex; flex-direction: column; background: var(--cream); border: 1px solid var(--line);
  border-radius: var(--radius-card); box-shadow: var(--elev-1); }
#obiFront .obf-lc { gap: var(--space-4); padding: clamp(var(--space-4), 4vw/*keep: the rate: 16px up to 400, 20px from 500*/, 20px/*keep: Obi LearnerCard's own padding, where there is room*/); }
#obiFront .obf-lc-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
#obiFront .obf-avatar { display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 3rem; height: 3rem; /*keep: Obi Avatar md's 48px, in rem*/
  border: 1px solid transparent; border-radius: var(--radius-full); background: var(--sage-tint); color: var(--sage-ink);
  font-size: var(--text-body); font-weight: var(--fw-bold); line-height: 1; }
#obiFront .obf-who { display: flex; flex-direction: column; flex: 1 1 8em; } /*keep: as above, the name's 8em beside the avatar*/
#obiFront .obf-name { font-size: var(--text-body-lg); font-weight: var(--fw-semibold); line-height: var(--lh-h3); color: var(--ink); }
#obiFront .obf-grade { margin-top: 2px/*keep: Obi LearnerCard's own gap under the name*/; color: var(--text-muted); }
#obiFront .obf-pb { display: flex; flex-direction: column; gap: 6px; } /*keep: Obi ProgressBar's own gap*/
#obiFront .obf-pb-label { font-weight: var(--fw-medium); color: var(--ink); }
#obiFront .obf-pb-track { display: block; height: 10px/*keep: Obi ProgressBar's track*/; overflow: hidden; border-radius: var(--radius-full); background: var(--sand); }
#obiFront .obf-pb-fill { display: block; width: 62%/*keep: an example's fill; no value is shown, so nothing is claimed*/; height: 100%;
  border-radius: var(--radius-full); background: var(--sage); }
/* The two rating rows: a subject, then its RatingChip. Where the row holds the longest subject word and the widest chip side by side,
   it is two columns (the subject wraps inside its own, the chip never wraps); narrower, the chip goes under its subject, in both
   rows alike. The step is a container query in rem, so it follows the reader's text size. */
#obiFront .obf-rows { container: obf-rows / inline-size; padding: 0 var(--space-4); }
#obiFront .obf-row { display: grid; grid-template-columns: minmax(0, 1fr); align-items: center; gap: var(--space-1) var(--space-3);
  min-height: var(--row-dense); padding-block: var(--space-2); }
@container obf-rows (min-width: calc(11.9rem + 36px)) { /*keep: "Mathematics" (5.26rem + 8px), the 12px gap and the widest chip, "5 Substantial" (6.57rem + 14px), measured by evidence/pass-6/6vb-fix/chipfit.mjs at 100, 200 and 300% text*/
  #obiFront .obf-row { grid-template-columns: minmax(0, 1fr) auto; }
  #obiFront .obf-row > .obf-rc { flex-wrap: nowrap; }
}
#obiFront .obf-row + .obf-row { border-top: 1px solid var(--line); }
#obiFront .obf-subject { font-weight: var(--fw-medium); color: var(--ink); }
#obiFront .obf-note { flex-direction: row; flex-wrap: wrap; align-items: flex-start; gap: var(--space-3); padding: var(--space-4); }
#obiFront .obf-note-tile { display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: var(--space-6); height: var(--space-6); border: 1px solid transparent; border-radius: var(--radius-control);
  background: var(--apricot-tint); color: var(--apricot-ink); }
#obiFront .obf-note-body { display: flex; flex-direction: column; gap: var(--space-1); flex: 1 1 8em; } /*keep: as above, the note's 8em beside its tile*/
#obiFront .obf-note-text { color: var(--ink); }
#obiFront .obf-note-cap { font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--text-muted); }

/* Obi's RatingChip: a 30px circle in --caps-N with its number in --caps-N-ink, bold, then the word, semibold. Never colour alone. */
#obiFront .obf-rc { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); font-size: var(--text-label); font-weight: var(--fw-semibold); color: var(--ink); }
#obiFront .obf-lv { display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 1.875rem; height: 1.875rem; /*keep: Obi RatingChip md's 30px circle, in rem*/
  border-radius: var(--radius-full); font-size: 1rem/*keep: Obi RatingChip md's 16px number, in rem*/; font-weight: var(--fw-bold); line-height: 1; }
#obiFront .obf-lv1 { background: var(--caps-1); color: var(--caps-1-ink); }
#obiFront .obf-lv2 { background: var(--caps-2); color: var(--caps-2-ink); }
#obiFront .obf-lv3 { background: var(--caps-3); color: var(--caps-3-ink); }
#obiFront .obf-lv4 { background: var(--caps-4); color: var(--caps-4-ink); }
#obiFront .obf-lv5 { background: var(--caps-5); color: var(--caps-5-ink); }
#obiFront .obf-lv6 { background: var(--caps-6); color: var(--caps-6-ink); }
#obiFront .obf-lv7 { background: var(--caps-7); color: var(--caps-7-ink); }

/* The CAPS band: a quiet change of ground (sand), one line and the seven levels as a real sequence (an ol). */
#obiFront .obf-caps { margin-top: var(--obf-section); background: var(--sand);
  padding-block: clamp(var(--space-7), 6vw, var(--space-8)); } /*keep: the 6vw rate: 48px up to 800, 64px from about 1070*/
#obiFront .obf-caps-line { max-width: 30em/*keep: one or two balanced lines, never a long single line across a wide band*/;
  font-size: clamp(var(--text-h3), 1rem + 1vw, var(--text-h2))/*keep: §19.7, between Obi's h3 and h2 steps; the 1rem + 1vw rate: 21px up to 500, 26px from 1000*/;
  font-weight: var(--fw-semibold); line-height: var(--lh-h3); letter-spacing: var(--ls-tight); color: var(--ink); text-wrap: balance; }
/* The seven levels: a grid of equal columns, one, then two (2, 2, 2, 1), four (4 and 3) and all seven in a row. Each step comes
   only when the widest level, "Not achieved" (its 30px circle, 8px gap and word: 7.3rem + 18px), fits every column; the steps
   are container queries in rem, so they follow the reader's text size (a media query's em would not), and no level is ever cut. */
#obiFront .obf-caps > .obf-wrap { container: obf-caps / inline-size; }
#obiFront .obf-levels { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-4) var(--space-3); margin: var(--space-6) 0 0; padding: 0; list-style: none; font-size: var(--text-label); }
#obiFront .obf-levels > li { min-width: 0; margin: 0; }
@container obf-caps (min-width: calc(14.6rem + 48px)) { /*keep: two columns of 7.3rem + 18px and one 12px gap (about 282px: two to a row at 320)*/
  #obiFront .obf-levels { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@container obf-caps (min-width: calc(29.2rem + 108px)) { /*keep: four columns and three gaps (about 575px: from about 640 wide)*/
  #obiFront .obf-levels { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@container obf-caps (min-width: calc(51.1rem + 198px)) { /*keep: seven columns and six gaps (about 1016px: from about 1112 wide)*/
  #obiFront .obf-levels { grid-template-columns: repeat(7, minmax(0, 1fr)); } }

/* ---- 8. What's inside: six cards, three columns from 1080px, two from 640px, one below (§19.4) ---- */
#obiFront .obf-inside { padding-bottom: var(--obf-section); } /* the last section before the closing band: the same space below as above */
#obiFront .obf-cards { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-4); padding: 0; list-style: none;
  margin: clamp(var(--space-5), 4vw, var(--space-7)) 0 0; } /*keep: the 4vw rate: 24px up to 600, 48px from 1200*/
#obiFront .obf-card { display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; margin: 0; padding: var(--space-5);
  background: var(--cream); border: 1px solid var(--line); border-radius: var(--radius-card); box-shadow: var(--elev-1); }
#obiFront .obf-card p { color: var(--ink-70); }
#obiFront .obf-tile { display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: var(--row-dense); height: var(--row-dense); margin-bottom: var(--space-1);
  border: 1px solid transparent; border-radius: var(--radius-control); }
#obiFront .obf-t-apricot { background: var(--apricot-tint); color: var(--apricot-ink); }
#obiFront .obf-t-sage { background: var(--sage-tint); color: var(--sage-ink); }
#obiFront .obf-t-sky { background: var(--sky-tint); color: var(--sky-ink); }
#obiFront .obf-t-clay { background: var(--clay-tint); color: var(--clay-ink); }
@media (min-width: 640px/*keep: §19.4*/) { #obiFront .obf-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1080px/*keep: §19.4*/) { #obiFront .obf-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-5); } }

/* ---- 9. The closing band (sand) and the footer (contentinfo) ---- */
#obiFront .obf-close { background: var(--sand);
  padding-block: clamp(var(--space-7), 8vw, var(--space-9)); } /*keep: the hero's 8vw rate: 48px up to 600, 96px from 1200*/
#obiFront .obf-close-in { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-5) var(--space-7); }
#obiFront .obf-close .obf-h2 { flex: 1 1 18em/*keep: the promise keeps about 18em beside Sign in, then Sign in moves under it*/;
  max-width: 22em/*keep: the promise's two sentences break into two lines, not one long one*/; }
#obiFront > .obf-foot { display: block; max-width: none; margin: 0; padding: var(--space-6) 0; background: var(--bg-page); color: var(--text-muted); font-size: var(--text-label); }
#obiFront .obf-foot-in { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3) var(--space-5); }
#obiFront .obf-foot-brand { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-4); min-width: 0; }
#obiFront .obf-foot-brand { align-items: center; }
/* The ghost button's label lines up with the content's edge, whichever side of the row it ends up on (its padding reaches into the gutter). */
#obiFront .obf-foot .obf-ghost { padding-inline: var(--space-3); margin-inline: calc(-1 * var(--space-3)); }
/* Terms of Use and Privacy Policy (terms.html, privacy.html): quiet links like "About Obi", each a 24px target. */
#obiFront .obf-legal { display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--space-4); }
#obiFront .obf-legal a { display: inline-flex; align-items: center; min-height: var(--control-dense); color: var(--text-muted);
  text-decoration: underline; text-underline-offset: 2px; } /*keep: Obi's own link offset, as on #obiAbout*/
#obiFront .obf-legal a:hover { color: var(--ink); }

/* ---- 10. The "About Obi" link on the sign-in card (FRONT-CONTRACT "Going back"): quiet, under everything, a 24px target.
   Only on the sign-in card: obi-front.js never puts it on "Choose your password". ---- */
#authOverlay .auth-card #obiAbout { display: block; width: fit-content; max-width: 100%; margin: var(--space-4) auto 0; padding: var(--space-1) var(--space-2);
  font-size: var(--text-label); color: var(--text-muted); text-decoration: underline; overflow-wrap: anywhere;
  text-underline-offset: 2px; } /*keep: Obi's own link offset (obi-v2 tokens base.css, a), restated so it holds whatever the app's unlayered rules say*/
#authOverlay .auth-card #obiAbout:hover { color: var(--ink); }

/* ---- 11. Durability (§19.6): below 240px the panels and cards step down to --space-3, and long words wrap ---- */
@media (max-width: 239px/*keep: the board's and §20.4's own step*/) {
  #obiFront :is(.obf-half, .obf-card, .obf-lc, .obf-note) { padding: var(--space-3); }
  #obiFront .obf-half { padding-bottom: 0; }
  #obiFront :is(.obf-screen, .obf-page) { padding: var(--space-3) var(--space-2); }
  #obiFront .obf-rows { padding-inline: var(--space-2); }
  #obiFront .obf-btn { padding-inline: var(--space-3); }
}

/* ---- 12. No movement (§19.6): nothing animates; buttons change colour over --motion-fast, which is 0 here ---- */
@media (prefers-reduced-motion: reduce) {
  #obiFront .obf-btn { transition: none; }
}

/* ---- 13. Forced colours (§19.6): frames and buttons keep real borders, the primary button follows obi-web.css §7's filled-button
   rule, the CAPS circles keep their fills (as §8 does for .lvl1 to .lvl7), the progress bar is outlined, the full stop is CanvasText. ---- */
@media (forced-colors: active) {
  #obiFront :focus-visible { outline-color: Highlight; }
  #obiFront .obf-stop { forced-color-adjust: none; background: CanvasText; }
  #obiFront .obf-primary { forced-color-adjust: none; background: ButtonText; color: ButtonFace; border-color: ButtonText; }
  #obiFront :is(.obf-secondary, .obf-ghost) { border-color: ButtonText; }
  #obiFront .obf-lv { forced-color-adjust: none; }
  #obiFront :is(.obf-half, .obf-tag, .obf-window, .obf-strip, .obf-address, .obf-field, .obf-mic, .obf-chip, .obf-avatar, .obf-note-tile,
    .obf-tile, .obf-card, .obf-card-s) { border: 1px solid CanvasText; }
  #obiFront :is(.obf-window, .obf-half) { border-bottom: 0; }
  #obiFront .obf-caps, #obiFront .obf-close { border-block: 1px solid CanvasText; }
  #obiFront .obf-bar-fill { border-bottom-color: CanvasText; }
  #obiFront .obf-pb-track { forced-color-adjust: none; background: Canvas; border: 2px solid CanvasText; }
  #obiFront .obf-pb-fill { forced-color-adjust: none; background: Highlight; }
}

/* ---- 14. Print (§19.6, not gated): the page prints as a normal page, static, with no sticky bar. ---- */
@media print {
  body:has(> #authOverlay.ov-front) { overflow: visible; }
  #authOverlay#authOverlay.ov-front { position: static; overflow: visible; height: auto; }
  #obiFront > .obf-bar { position: static; }
  #obiFront :is(.obf-half, .obf-card, .obf-caps) { break-inside: avoid; }
  #obiFront :is(.obf-lv, .obf-pb-fill, .obf-stop) { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ================================================================
   OPENING NIGHT: D2 "The ovation" as a whole evening (William,
   2026-10-13: R63 to R65; round four at 20:12, "Every learner noticed").
   The light means noticing: a lamp on each learner. It is the rig over
   the hero, the light under your pointer (in the hero, and in every pane
   of glass below it), the follow-spot that climbs the CAPS levels and
   the one that sweeps the closing line. The signature is still Obi's
   apricot full stop: on the tagline, the tick beside each thing Obi does
   in place of the work by hand, the marker in act one's script, the
   applause. The evening: the rig comes on; the difference (the same day
   by hand and with Obi, the chores struck through); act one held while
   its script plays; an intermission; act two sliding from the record to
   the observation book; the climb; act three, where the report prints;
   what's inside; the encore and a standing class; the credits. Behind
   it all one backdrop whose colour follows the section in view (each
   tone a quarter of the way to Obi's Ink, so the variety stays close to
   the design system), with no hard edges.
   Movement (§19.6): CSS here (springs generated with Motion's spring(),
   as CSS linear() curves), plus Motion itself once loaded (.obf-m).
   Everything is drawn in its final state without either; reduced
   motion and forced colours set neither class.
   Values that are not tokens, for the stage (stated here, §19): a stage
   surface #2D2621, muted text on ink #CFC6BA, unlit text #5B514A, and
   the backdrop's tones (listed at "0. The backdrop").
   ================================================================ */
#obiFront {
  --obf-pop: cubic-bezier(.34, 1.56, .64, 1); /*keep: an overshoot, the full stop landing*/
  --st-bg: var(--ink); --st-surface: rgba(255, 253, 248, .045); --st-line: rgba(255, 253, 248, .16);
  /* Obi's elevation, deepened for the dark stage: warm brown-ink shadows, tight under the edge, never a soft black haze */
  --st-elev-1: 0 1px 2px rgba(20, 14, 10, .45), 0 4px 12px rgba(20, 14, 10, .32);
  --st-elev-2: 0 2px 4px rgba(20, 14, 10, .45), 0 18px 40px rgba(20, 14, 10, .42);
  --st-muted: #CFC6BA; --st-dim: #5B514A;
  --obf-bar: 5.25rem; /*keep: the floating bar's own height, up to 32px of air above its 50px pill*/
  background: var(--st-bg); color: var(--cream);
  /* springs from Motion's spring(visualDuration, bounce).toString(), as CSS (the motion-animation skill, §4): curtain (1.1, .18),
     pop (.45, .45), bow (.6, .4), rise (.7, .2), stand (.55, .5) */
  --spring-curtain: linear(0, 0.0099, 0.0364, 0.0755, 0.1238, 0.1785, 0.237, 0.2976, 0.3586, 0.4187, 0.477, 0.5328, 0.5856, 0.635, 0.6808, 0.7228, 0.7612, 0.7959, 0.8271, 0.8549, 0.8796, 0.9012, 0.9202, 0.9366, 0.9507, 0.9627, 0.9729, 0.9814, 0.9885, 0.9943, 0.9989, 1.0026, 1.0054, 1.0076, 1.0091, 1.0101, 1.0108, 1.0111, 1.0111, 1.0109, 1.0105, 1.01, 1.0095, 1.0088, 1.0082, 1.0075, 1.0068, 1.0062, 1.0055, 1.0049, 1.0044, 1.0038, 1.0033, 1.0029, 1.0025, 1.0021, 1.0018, 1);
  --spring-curtain-d: 1750ms;
  --spring-pop: linear(0, 0.0554, 0.1912, 0.3671, 0.5517, 0.7232, 0.8678, 0.9792, 1.0567, 1.1031, 1.1237, 1.1248, 1.1125, 1.0925, 1.0694, 1.0465, 1.0263, 1.0098, 0.9977, 0.9897, 0.9854, 0.9841, 0.9848, 0.9868, 0.9896, 0.9926, 0.9953, 0.9977, 0.9995, 1.0008, 1.0016, 1);
  --spring-pop-d: 950ms;
  --spring-bow: linear(0, 0.0326, 0.1162, 0.2313, 0.3622, 0.4963, 0.6245, 0.7405, 0.8404, 0.9226, 0.9868, 1.034, 1.0661, 1.0852, 1.0937, 1.0941, 1.0885, 1.079, 1.0672, 1.0546, 1.042, 1.0303, 1.02, 1.0113, 1.0043, 0.999, 0.9952, 0.9928, 0.9914, 0.991, 0.9913, 0.992, 0.993, 0.9942, 0.9954, 0.9965, 0.9976, 0.9985, 0.9993, 0.9998, 1.0003, 1, 1);
  --spring-bow-d: 1300ms;
  --spring-rise: linear(0, 0.0234, 0.0827, 0.1642, 0.2574, 0.3547, 0.4505, 0.541, 0.6239, 0.6979, 0.7624, 0.8175, 0.8637, 0.9016, 0.9322, 0.9564, 0.9751, 0.9891, 0.9992, 1.0063, 1.0109, 1.0136, 1.0149, 1.0151, 1.0146, 1.0136, 1.0123, 1.0109, 1.0094, 1.008, 1.0066, 1.0054, 1.0043, 1.0034, 1.0026, 1.0019, 1.0014, 1.0009, 1, 1);
  --spring-rise-d: 1200ms;
  --spring-stand: linear(0, 0.0395, 0.1411, 0.2813, 0.4397, 0.5997, 0.7488, 0.8786, 0.9843, 1.0641, 1.1187, 1.1503, 1.1625, 1.1594, 1.1451, 1.1235, 1.0982, 1.0719, 1.047, 1.0249, 1.0066, 0.9925, 0.9826, 0.9765, 0.9738, 0.9737, 0.9756, 0.9789, 0.9829, 0.9872, 0.9913, 0.9951, 0.9982, 1.0007, 1.0025, 1.0036, 1.0042, 1);
  --spring-stand-d: 1150ms;
}
#obiFront :is(.obf-h1, .obf-h2, .obf-h3) { color: var(--cream); }
#obiFront .obf-secondary { background: transparent; color: var(--cream); border-color: rgba(255, 253, 248, .42); }
#obiFront .obf-secondary:hover { background: rgba(255, 253, 248, .08); }
#obiFront .obf-secondary:active { background: rgba(255, 253, 248, .14); }
#obiFront :is(.obf-screen, .obf-page) { color: var(--ink); } /* the scenes' screens are lit: the app's own colours inside */

@keyframes obf-pop { 0% { transform: scale(0); } 60% { transform: scale(1.35); } 100% { transform: scale(1); } }
@keyframes obf-up { from { opacity: 0; translate: 0 16px; } to { opacity: 1; translate: none; } }
@keyframes obf-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes obf-lights { from { opacity: 0; } to { opacity: 1; } }
@keyframes obf-beam { from { opacity: 0; scale: .5 .7; } to { opacity: 1; scale: 1 1; } }
@keyframes obf-lit { from { color: var(--st-dim); } to { color: var(--cream); } }
@keyframes obf-clap { 0% { opacity: 0; transform: translateX(.08em) scale(.7); } 14% { opacity: 1; } 70% { opacity: 1; }
  100% { opacity: 0; transform: translateX(var(--d)) scale(.15); } }
@keyframes obf-ping { 0% { transform: scale(1); opacity: .5; } 100% { transform: scale(1.9); opacity: 0; } }
@keyframes obf-listen { 0%, 100% { border-color: var(--warm-grey); box-shadow: none; }
  8%, 88% { border-color: var(--apricot); box-shadow: 0 0 0 3px var(--apricot-tint); } }
@keyframes obf-chip { 0% { opacity: 0; transform: scale(.7); } 70% { opacity: 1; transform: scale(1.06); } 100% { opacity: 1; transform: none; } }
@keyframes obf-cue { 0% { transform: scaleY(0); transform-origin: top; } 45% { transform: scaleY(1); transform-origin: top; }
  55% { transform: scaleY(1); transform-origin: bottom; } 100% { transform: scaleY(0); transform-origin: bottom; } }


/* ---- 0. The backdrop: one layer behind the whole page. Its colour is the tone of the section at the middle of the window (set by
   Motion, data-tone) and crossfades over 1.6s, so the evening's light changes as you go, with no hard edge between sections; a soft
   vignette sits on top (no glow from above: it read as a halo that never left). Without Motion it stays at the stage's ink. The tones
   (stated here, §19; each a quarter of the way to Ink #241E1A; cream text on each is above 12:1): the stage #241E1A, the difference
   #201C23, act one a sage night #182019, the intermission #22181C, act two a sky night #161D27, the climb an indigo night #1A1926,
   act three a wine night #24161A, the company #1C1B1E. ---- */
#obiFront { isolation: isolate; }
#obiFront > .obf-backdrop { position: fixed; inset: 0; z-index: -1; pointer-events: none; background-color: #241E1A;
  transition: background-color 1.6s var(--ease-out); }
/* The hero's light under the pointer (--mx, --my in px, set on the frame after each move: no glide, so it never trails the cursor).
   It belongs to the hero: a mask fades it out over the hero's last 6rem and it is gone 1.5rem below the hero's foot (--cut, the
   hero's bottom edge in the window), smoothly, wherever the page has scrolled to. Below the hero the light lives in the glass. */
#obiFront.obf-m > .obf-backdrop::after { content: ""; position: absolute; inset: 0;
  background: radial-gradient(30rem 24rem at var(--mx, -100vw) var(--my, -100vh), rgba(232, 133, 58, .17), rgba(232, 133, 58, .05) 46%, transparent 68%);
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(var(--cut, 100vh) - 6rem), transparent calc(var(--cut, 100vh) + 1.5rem));
  mask-image: linear-gradient(to bottom, #000 calc(var(--cut, 100vh) - 6rem), transparent calc(var(--cut, 100vh) + 1.5rem)); }
#obiFront > .obf-backdrop::before { content: ""; position: absolute; inset: 0;
  background: radial-gradient(120% 90% at 50% 50%, transparent 58%, rgba(0, 0, 0, .28)); }
#obiFront > .obf-backdrop[data-tone="diff"] { background-color: #201C23; }
#obiFront > .obf-backdrop[data-tone="act1"] { background-color: #182019; }
#obiFront > .obf-backdrop[data-tone="interval"] { background-color: #22181C; }
#obiFront > .obf-backdrop[data-tone="act2"] { background-color: #161D27; }
#obiFront > .obf-backdrop[data-tone="climb"] { background-color: #1A1926; }
#obiFront > .obf-backdrop[data-tone="act3"] { background-color: #24161A; }
#obiFront > .obf-backdrop[data-tone="inside"], #obiFront > .obf-backdrop[data-tone="close"] { background-color: #1C1B1E; }
#obiFront.obf-m { background: transparent; }

/* ---- 0b. The glass: panes you only see where the light falls (the bar, the difference rows, act one's script, act two's directions,
   the cast list). With Motion, the pane under the pointer lights from that point (--gx, --gy in px, set on the frame after each
   move) and its edge catches the light near it; the light fades in and out as the pointer arrives and leaves, but never trails it.
   Without Motion the panes are simply invisible. ---- */
#obiFront .obf-glass { position: relative; isolation: isolate; }
#obiFront .obf-glass::before, #obiFront .obf-glass::after { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  border-radius: inherit; opacity: 0; }
#obiFront.obf-m .obf-glass::before, #obiFront.obf-m .obf-glass::after { transition: opacity .3s var(--ease-out); }
#obiFront .obf-glass::before {
  background: radial-gradient(15rem circle at var(--gx, 50%) var(--gy, 50%), rgba(232, 133, 58, .15), rgba(232, 133, 58, .045) 45%, transparent 72%); }
#obiFront .obf-glass::after { border: 1px solid rgba(255, 236, 214, .42);
  -webkit-mask-image: radial-gradient(11rem circle at var(--gx, 50%) var(--gy, 50%), #000, transparent 80%);
  mask-image: radial-gradient(11rem circle at var(--gx, 50%) var(--gy, 50%), #000, transparent 80%); }
#obiFront.obf-m .obf-glass.is-hot::before, #obiFront.obf-m .obf-glass.is-hot::after { opacity: 1; }

/* ---- 1. The bar: a pill floating a little below the top edge, so the logo and Sign in sit down in the window, not against it ---- */
#obiFront > .obf-bar { background: transparent; }
#obiFront .obf-bar-fill { border: 0; padding: clamp(var(--space-4), 2.2vw, var(--space-6)) var(--obf-gutter) 0; } /*keep: the 2.2vw rate, 16px of air above the pill up to about 730 wide, 32px from about 1450*/
#obiFront .obf-bar-in { min-height: 0; padding: var(--space-1) var(--space-1) var(--space-1) var(--space-5);
  max-width: calc(1200px + 2 * var(--space-5)); /*keep: the content's width plus the pill's own inset*/
  border: 1px solid var(--st-line); border-radius: var(--radius-full);
  background: rgba(30, 25, 22, .62); /*keep: Ink's own warm dark as glass at 62%, so the page's light shows through it*/
  -webkit-backdrop-filter: blur(12px) saturate(1.15); backdrop-filter: blur(12px) saturate(1.15); }
#obiFront .obf-btn.obf-btn-bar { border-radius: var(--radius-full); }
#obiFront svg.obf-logo { width: auto; height: 28px; } /* the inline reversed logo, as the img's 28px */
@container scroll-state(stuck: top) { #obiFront .obf-bar-fill { border-bottom-color: transparent; } }
@media (min-height: 480px) { #obiFront > .obf-bar { position: sticky; top: 0; } }
@media (max-width: 359px) { #obiFront .obf-bar-in { padding-left: var(--space-3); } }
/* ---- 2. The stage: the hero fills the first window, the tagline in the middle of the light ---- */
#obiFront .obf-hero { position: relative; overflow: clip; isolation: isolate; display: flex; flex-direction: column; justify-content: center;
  min-height: min(calc(100svh - var(--obf-bar)), 60rem); padding-block: clamp(var(--space-7), 7vw, 7rem) clamp(var(--space-8), 8vw, 8rem);
  text-align: center; margin-top: calc(-1 * var(--obf-bar)); padding-top: calc(var(--obf-bar) + clamp(var(--space-6), 6vw, 6rem)); }
#obiFront .obf-hero > .obf-wrap { position: relative; z-index: 1; }
#obiFront .obf-credit { margin: 0 auto var(--space-5); font-family: Georgia, "Times New Roman", serif; font-style: italic;
  font-size: var(--text-body); color: var(--st-muted); letter-spacing: .01em; }
#obiFront .obf-h1 { font-size: clamp(2.6rem, 1.2rem + 7.2vw, 8.5rem); line-height: .98; letter-spacing: -.04em; }
#obiFront .obf-hero .obf-lede { margin-inline: auto; color: var(--st-muted); }
#obiFront .obf-hero .obf-actions { justify-content: center; }
#obiFront .obf-stage { position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(40rem 28rem at 50% 46%, rgba(232, 133, 58, .16), rgba(232, 133, 58, .04) 52%, transparent 74%),
    radial-gradient(90rem 26rem at 50% 118%, rgba(232, 133, 58, .18), transparent 62%); }
#obiFront .obf-stage::before { content: ""; position: absolute; left: 50%; top: 0; width: min(130vw, 84rem); height: 100%; translate: -50% 0;
  transform-origin: 50% 0;
  background: conic-gradient(from 160deg at 50% 0, transparent 0deg, rgba(255, 240, 222, .035) 6deg, rgba(255, 240, 222, .1) 13deg,
    rgba(255, 240, 222, .12) 20deg, rgba(255, 240, 222, .1) 27deg, rgba(255, 240, 222, .035) 34deg, transparent 40deg);
  -webkit-mask-image: radial-gradient(75% 100% at 50% 0, transparent 6%, #000 22%, rgba(0, 0, 0, .5) 58%, transparent 100%);
  mask-image: radial-gradient(75% 100% at 50% 0, transparent 6%, #000 22%, rgba(0, 0, 0, .5) 58%, transparent 100%); }
#obiFront .obf-h1 .obf-stop { position: relative; }
#obiFront .obf-clap { display: none; }
#obiFront .obf-cue { position: absolute; left: 50%; bottom: var(--space-5); width: 1px; height: var(--space-8); translate: -50% 0;
  background: linear-gradient(to bottom, transparent, rgba(255, 253, 248, .5)); opacity: .7; }

#obiFront.obf-motion .obf-stage { animation: obf-lights 1.6s var(--ease-out) .15s both; }
#obiFront.obf-motion .obf-stage::before { animation: obf-beam 1.1s var(--ease-out) .05s both; }
#obiFront.obf-motion .obf-h1 { animation: obf-lit 1.1s var(--ease-out) .2s both; }
#obiFront.obf-motion .obf-h1 .obf-stop { animation: obf-pop .7s var(--obf-pop) .95s both; }
#obiFront.obf-motion .obf-h1 .obf-clap { display: block; position: absolute; left: 50%; top: 50%; width: 0; height: 0; rotate: var(--a); }
#obiFront.obf-motion .obf-h1 .obf-clap > i { position: absolute; left: -.035em; top: -.035em; width: .07em; height: .07em; border-radius: var(--radius-full);
  background: var(--c); opacity: 0; animation: obf-clap 1.1s cubic-bezier(.15, .75, .25, 1) calc(1.2s + var(--i) * 45ms) both; }
#obiFront.obf-motion .obf-credit { animation: obf-fade 1.2s var(--ease-out) .1s both; }
#obiFront.obf-motion .obf-hero .obf-lede { animation: obf-up .8s var(--ease-out) .55s both; }
#obiFront.obf-motion .obf-hero .obf-actions { animation: obf-up .8s var(--ease-out) .7s both; }
#obiFront.obf-motion .obf-cue { animation: obf-cue 2.4s var(--ease-out) 1.8s 3 both; } /* three times, then still */
/* With Motion: as the hero scrolls away, the light dims and the words drift up (--out, 0 to 1). obi-front.js writes --out on the three
   elements that read it, every scroll frame; registered so it is not inherited and a write restyles that element alone (performance). */
@property --out { syntax: "<number>"; inherits: false; initial-value: 0; }
#obiFront.obf-m .obf-hero > .obf-wrap { translate: 0 calc(var(--out, 0) * -4rem); opacity: calc(1 - var(--out, 0) * .85); }
#obiFront.obf-m .obf-hero .obf-stage { opacity: calc(1 - var(--out, 0)); }

/* The lighting rig: a truss across the top of the stage with five lamps behind coloured gels (sage, sky, apricot, clay, gold), each
   throwing a soft cone in towards the line. On load they come on one after another, like a lighting check; their light mixes over the
   tagline; they dim as the hero scrolls away (--out). */
#obiFront .obf-rig { position: absolute; z-index: 0; left: 0; right: 0; top: calc(var(--obf-bar) - var(--space-3)); height: 100%; pointer-events: none; }
#obiFront .obf-rig::before { content: ""; position: absolute; left: 4%; right: 4%; top: 0; height: 2px; border-radius: var(--radius-full);
  background: linear-gradient(90deg, transparent, rgba(255, 253, 248, .16) 12%, rgba(255, 253, 248, .16) 88%, transparent); } /* the truss */
#obiFront .obf-lamp { position: absolute; top: 0; left: var(--x); width: 1.1rem; height: .8rem; translate: -50% -30%; border-radius: 4px 4px 7px 7px;
  background: #3A3330; box-shadow: inset 0 -3px 0 var(--g); } /*keep: a lamp's dark housing; the gel shows as its lit rim*/
/* the lens: a small bright disc with a bloom that falls off smoothly (radial, not a spread shadow) */
#obiFront .obf-lamp::after { content: ""; position: absolute; left: 50%; bottom: -2px; width: 1.6rem; height: 1.6rem; translate: -50% 50%; border-radius: var(--radius-full);
  background: radial-gradient(closest-side, #FFF6EA 0 22%, color-mix(in srgb, var(--g) 85%, #FFF6EA) 30%, color-mix(in srgb, var(--g) 35%, transparent) 55%, transparent); }
/* the beam: a cone of light from the lens, a conic gradient whose edges are feathered over a few degrees and whose strength falls
   away with distance (a radial mask from the lens), so it leaves the lamp soft-edged and fades out, with no line anywhere */
#obiFront .obf-cone { position: absolute; left: 50%; top: 100%; width: min(66svh, 40rem); height: min(88svh, 52rem); translate: -50% 0; rotate: var(--r);
  transform-origin: 50% 0; mix-blend-mode: screen;
  background: conic-gradient(from 162deg at 50% 0, transparent 0deg, color-mix(in srgb, var(--g) 9%, transparent) 5deg, color-mix(in srgb, var(--g) 26%, transparent) 11deg,
    color-mix(in srgb, var(--g) 32%, transparent) 18deg, color-mix(in srgb, var(--g) 26%, transparent) 25deg, color-mix(in srgb, var(--g) 9%, transparent) 31deg, transparent 36deg);
  -webkit-mask-image: radial-gradient(60% 100% at 50% 0, #000 0, rgba(0, 0, 0, .55) 45%, transparent 95%);
  mask-image: radial-gradient(60% 100% at 50% 0, #000 0, rgba(0, 0, 0, .55) 45%, transparent 95%); }
@media (max-width: 719px) { #obiFront .obf-lamp:nth-child(1), #obiFront .obf-lamp:nth-child(5) { display: none; } #obiFront .obf-cone { width: 90vw; } }
@keyframes obf-lamp-on { 0% { opacity: 0; } 30% { opacity: 1; } 42% { opacity: .35; } 60%, 100% { opacity: 1; } } /* a lamp catching, with one flicker */
@keyframes obf-cone-on { from { opacity: 0; scale: .35 .55; } to { opacity: 1; scale: 1 1; } }
#obiFront.obf-motion .obf-lamp::after { animation: obf-lamp-on .6s linear calc(.15s + var(--i) * 130ms) both; }
#obiFront.obf-motion .obf-cone { animation: obf-cone-on var(--spring-rise-d) var(--spring-rise) calc(.2s + var(--i) * 130ms) both; }
#obiFront.obf-m .obf-hero .obf-rig { opacity: calc(1 - var(--out, 0) * 1.1); }


/* ---- 3. Arrivals: a part rises in as it scrolls into view, a beat apart ---- */
#obiFront.obf-motion [data-in]:not(.obf-close, .obf-scene) { opacity: 0; translate: 0 18px;
  transition: opacity .8s var(--ease-out) calc(var(--i, 0) * 90ms), translate .8s var(--ease-out) calc(var(--i, 0) * 90ms); }
#obiFront.obf-motion [data-in].obf-on { opacity: 1; translate: none; }

/* ---- 4. The lit lines (with Motion): each word goes from unlit to cream as the line rises into the light (--p, 0 to 1, set by
   scroll), and the full stop lands last. Without Motion they are simply cream. ---- */
#obiFront.obf-m .obf-lit .obf-wd {
  color: color-mix(in srgb, var(--cream) calc(clamp(0, (var(--p, 1) - var(--i) / var(--n) * .7) / .3, 1) * 100%), var(--st-dim)); }
#obiFront.obf-m .obf-lit .obf-stop { transform: scale(clamp(0, (var(--p, 1) - .82) / .18, 1)); }

/* ---- 6. The acts. Static (no Motion, a short window, or reduced motion): the text, every stage direction as a list, and the
   scene in its finished state. Held (.obf-pin, with Motion, at least 640px tall): the act is three windows tall, its inner part
   stays put under the bar while the reader's scroll walks the three steps, and only the current direction shows. ---- */
#obiFront .obf-act { position: relative; padding-top: var(--obf-section); }
#obiFront .obf-act-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(var(--space-6), 4vw, var(--space-8)); align-items: center; }
#obiFront .obf-act-no { font-family: Georgia, "Times New Roman", serif; font-style: italic; font-size: var(--text-body-lg); color: var(--apricot); margin: 0 0 var(--space-2); }
#obiFront .obf-act-h { font-size: clamp(var(--text-h2), 1rem + 2.6vw, 3.25rem); line-height: 1.08; } /*keep: an act's title, a step under the h1's scale*/
#obiFront .obf-act-line { max-width: 30em; margin-top: var(--space-4); color: var(--st-muted); }
#obiFront .obf-steps { margin: var(--space-6) 0 0; padding: 0; list-style: none; display: grid; gap: var(--space-3); }
#obiFront .obf-stepc { margin: 0; padding-left: var(--space-4); border-left: 2px solid var(--st-line);
  font-family: Georgia, "Times New Roman", serif; font-style: italic; font-size: var(--text-body-lg); line-height: var(--lh-body); color: var(--cream); }
#obiFront .obf-meter { display: none; }
#obiFront .obf-act-stage { display: grid; gap: var(--space-6); justify-items: center; min-width: 0; }
#obiFront .obf-act-stage > .obf-scene { width: 100%; max-width: 34rem; align-items: flex-start; margin: 0; }
#obiFront .obf-act-stage > .obf-phone { max-width: 17.5rem; }
#obiFront .obf-act1 { --gel: rgba(94, 156, 111, .2); }
#obiFront .obf-act2 { --gel: rgba(78, 134, 180, .2); }
#obiFront .obf-act3 { --gel: rgba(181, 87, 58, .18); padding-bottom: var(--obf-section); }
#obiFront .obf-act > .obf-act-in { position: relative; isolation: isolate; }
#obiFront .obf-act > .obf-act-in::before { content: ""; position: absolute; z-index: -1; pointer-events: none;
  inset: -6% 4% -6% 34%; background: radial-gradient(42% 46% at 60% 45%, var(--gel), transparent 70%); } /* a coloured gel over each act's scene */
@media (min-width: 960px) {
  #obiFront .obf-act-grid { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
}
/* the scenes on a dark stage */
#obiFront .obf-device { box-shadow: 0 0 0 1px rgba(255, 253, 248, .2), var(--st-elev-2); border-bottom: 6px solid var(--ink); border-radius: 32px; }
#obiFront .obf-screen { border-radius: 26px; }
#obiFront .obf-window { border-color: var(--st-line); border-bottom: 1px solid var(--st-line); border-radius: var(--radius-card); box-shadow: 0 0 0 1px rgba(255, 253, 248, .08), var(--st-elev-2); }
#obiFront .obf-scene .obf-tag { background: rgba(255, 253, 248, .1); color: var(--st-muted); border-color: var(--st-line); }

/* Act one's stage directions are a script: every line in view, the one playing marked by the apricot dot that slides beside it
   (--mark-y, a spring) and set in cream, the others muted. */
#obiFront .obf-script { position: relative; margin-inline: calc(-1 * var(--space-4)); padding: var(--space-2) var(--space-4) var(--space-4); border-radius: var(--radius-card); }
#obiFront .obf-script .obf-steps { margin-top: var(--space-4); }
#obiFront .obf-cue-dot { display: none; }
#obiFront.obf-m .obf-script .obf-stepc { color: var(--st-muted); transition: color .4s var(--ease-out), border-color .4s var(--ease-out); }
#obiFront.obf-m .obf-script .obf-stepc.is-now { color: var(--cream); border-left-color: rgba(232, 133, 58, .45); }
#obiFront.obf-m .obf-script .obf-cue-dot { display: block; position: absolute; left: calc(var(--space-4) - 1px); top: 0; width: .7rem; height: .7rem; translate: -50% -50%;
  border-radius: var(--radius-full); background: var(--apricot); box-shadow: 0 0 0 4px rgba(232, 133, 58, .22), 0 0 10px rgba(232, 133, 58, .5);
  transform: translateY(var(--mark-y, 0px)); opacity: 0; transition: transform var(--spring-rise-d) var(--spring-rise), opacity .3s var(--ease-out); }
#obiFront.obf-m .obf-script.is-on .obf-cue-dot { opacity: 1; }

/* Act two: a heading, then a track of two frames (the record; the observation book). Static: the frames one under the other. Held:
   the act is three windows tall, its inner part stays put, and the track slides sideways (--slide, 0 to 1; written on the track and
   its two frames, which read it, every scroll frame, so registered and not inherited). The line that showed how far along the act is
   was retired for the scrub pill (9b). */
@property --slide { syntax: "<number>"; inherits: false; initial-value: 0; }
#obiFront .obf-track-act .obf-act-head { max-width: 40rem; }
#obiFront .obf-track-view { margin-top: clamp(var(--space-6), 4vw, var(--space-7)); }
#obiFront .obf-track { display: grid; gap: var(--space-8); }
#obiFront .obf-frame { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-5); align-items: center; }
#obiFront .obf-frame-text { display: grid; gap: var(--space-3); margin-inline: calc(-1 * var(--space-4)); padding: var(--space-4); border-radius: var(--radius-card); }
#obiFront .obf-dir { padding-left: var(--space-4); border-left: 2px solid rgba(78, 134, 180, .6);
  font-family: Georgia, "Times New Roman", serif; font-style: italic; font-size: var(--text-body-lg); line-height: var(--lh-body); color: var(--cream); }
#obiFront .obf-frame > .obf-scene { width: 100%; max-width: 34rem; margin: 0; justify-self: center; }
#obiFront .obf-progress { display: none; }
@media (min-width: 960px) { #obiFront .obf-frame { grid-template-columns: minmax(0, 4fr) minmax(0, 6fr); gap: var(--space-8); } }

@media (min-height: 640px) {
  #obiFront .obf-act.obf-pin { height: 260vh; /*keep: about half a window of scroll per step, and a little to settle*/ padding-top: 0; }
  #obiFront .obf-pin > .obf-act-in { position: sticky; top: 0; height: 100svh; display: flex; align-items: center;
    padding-top: var(--obf-bar); overflow: clip; }
  #obiFront .obf-pin .obf-act-stage { display: grid; grid-template-areas: "x"; }
  #obiFront .obf-pin .obf-act-stage > .obf-scene { grid-area: x; }
  #obiFront .obf-track-act.obf-pin { height: 250vh; }
  #obiFront .obf-track-act.obf-pin > .obf-act-in > .obf-wrap { width: 100%; }
  #obiFront .obf-track-act.obf-pin .obf-track-view { overflow: visible; }
  #obiFront .obf-track-act.obf-pin .obf-track { display: flex; gap: 0; width: 200%; translate: calc(var(--slide, 0) * -50%) 0; }
  #obiFront .obf-track-act.obf-pin .obf-frame { flex: 0 0 50%; padding-right: var(--obf-gutter); }
  #obiFront .obf-track-act.obf-pin .obf-frame:nth-child(1) { opacity: calc(1 - var(--slide, 0)); }
  #obiFront .obf-track-act.obf-pin .obf-frame:nth-child(2) { opacity: var(--slide, 0); }
  /* the act's own progress line is retired: the scrub pill (9b) carries progress for every pinned act */
  /* a phone-sized window: the act's text above, the scene below, both smaller */
  @media (max-width: 959px) {
    #obiFront .obf-pin .obf-act-grid { gap: var(--space-4); align-content: center; }
    #obiFront .obf-pin .obf-act-line { display: none; }
    #obiFront .obf-pin .obf-act-h { font-size: var(--text-h2); }
    #obiFront .obf-pin .obf-steps { margin-top: var(--space-3); gap: var(--space-2); }
    #obiFront .obf-pin .obf-stepc { font-size: var(--text-body); }
    #obiFront .obf-pin .obf-screen { min-height: 0; gap: var(--space-4); }
    #obiFront .obf-pin .obf-earlier .obf-li:nth-child(n+3) { display: none; } /* one earlier note, so the phone fits the window */
    #obiFront .obf-track-act.obf-pin .obf-track-view { margin-top: var(--space-4); }
    #obiFront .obf-track-act.obf-pin .obf-frame { gap: var(--space-3); }
    #obiFront .obf-track-act.obf-pin .obf-dir { font-size: var(--text-body); }
    #obiFront .obf-track-act.obf-pin .obf-progress { margin-top: var(--space-4); }
  }
}

/* The acts' scenes play their steps (with Motion: .obf-m, the act gets is-s1 to is-s3). Without Motion every part is shown. */
/* act one: the screen comes on and listens (s1), the note arrives word by word and its chips land (s2), the day's notes appear (s3) */
#obiFront.obf-m .obf-act1 .obf-screen { filter: brightness(.25) saturate(.5); transition: filter .8s var(--ease-out); }
#obiFront.obf-m .obf-act1.is-s1 .obf-screen { filter: none; }
#obiFront.obf-m .obf-act1 .obf-w { opacity: 0; }
#obiFront.obf-m .obf-act1.is-s1:not(.is-s2) .obf-field { animation: obf-listen 2.4s linear .3s both; }
#obiFront.obf-m .obf-act1.is-s1:not(.is-s2) .obf-mic::after { animation: obf-ping 1.2s var(--ease-out) .4s 2; }
#obiFront.obf-m .obf-act1.is-s2 .obf-w { animation: obf-fade .2s linear both; animation-delay: calc(.1s + var(--i) * .14s); }
#obiFront.obf-m .obf-act1 .obf-chip { opacity: 0; }
#obiFront.obf-m .obf-act1.is-s2 .obf-chip { animation: obf-chip .45s var(--ease-out) 1.3s both; }
#obiFront.obf-m .obf-act1.is-s2 .obf-chip + .obf-chip { animation-delay: 1.45s; }
#obiFront.obf-m .obf-act1 .obf-earlier { opacity: 0; translate: 0 16px; transition: opacity .6s var(--ease-out), translate .6s var(--ease-out); }
#obiFront.obf-m .obf-act1.is-s3 .obf-earlier { opacity: 1; translate: none; }
#obiFront .obf-mic { position: relative; isolation: isolate; }
#obiFront .obf-mic::after { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: var(--radius-full); background: var(--apricot); opacity: 0; }
/* act two: the record (s1), its levels and observation (s2), then the observation book in front of it (s3) */
#obiFront.obf-m .obf-act2 .obf-browser { transition: opacity .6s var(--ease-out), transform .6s var(--ease-out); }
#obiFront.obf-m .obf-act2:not(.is-s1) .obf-browser { opacity: 0; transform: translateY(24px); }
#obiFront.obf-m .obf-act2 .obf-pb-fill { transform: scaleX(0); transform-origin: left center; transition: transform 1.1s var(--ease-out) .3s; }
#obiFront.obf-m .obf-act2.is-s1 .obf-pb-fill { transform: none; }
#obiFront.obf-m .obf-act2 .obf-rows .obf-lv { transform: scale(0); }
#obiFront.obf-m .obf-act2.is-s2 .obf-rows .obf-lv { animation: obf-pop .55s var(--obf-pop) .1s both; }
#obiFront.obf-m .obf-act2.is-s2 .obf-row + .obf-row .obf-lv { animation-delay: .25s; }
#obiFront.obf-m .obf-act2 .obf-browser .obf-note { opacity: 0; translate: 0 10px; transition: opacity .5s var(--ease-out) .45s, translate .5s var(--ease-out) .45s; }
#obiFront.obf-m .obf-act2.is-s2 .obf-browser .obf-note { opacity: 1; translate: none; }

/* The observation book: learners down the side, skills across, a CAPS circle in every cell (numbers are the levels). */
#obiFront .obf-grid { padding: var(--space-4); gap: var(--space-2); }
#obiFront .obf-grid-title { font-weight: var(--fw-semibold); font-size: var(--text-body); color: var(--ink); margin-bottom: var(--space-1); }
#obiFront .obf-grid-row { display: grid; grid-template-columns: minmax(0, 1.6fr) repeat(4, minmax(0, 1fr)); align-items: center; gap: var(--space-1);
  min-height: 2.25rem; border-top: 1px solid var(--line); }
#obiFront .obf-grid-headrow { border-top: 0; min-height: 0; }
#obiFront .obf-grid-skill { font-size: var(--text-caption); line-height: var(--lh-caption); color: var(--text-muted); text-align: center; }
#obiFront .obf-grid-name { font-weight: var(--fw-medium); color: var(--ink); }
#obiFront .obf-grid-cell { display: flex; justify-content: center; }
#obiFront .obf-grid .obf-lv { width: 1.625rem; height: 1.625rem; font-size: .875rem; }
#obiFront .obf-grid-skill { overflow-wrap: normal; word-break: keep-all; }
#obiFront .obf-grid-name { overflow-wrap: normal; word-break: keep-all; hyphens: none; } /* a name breaks between its words, never inside one */
@media (max-width: 420px) { #obiFront .obf-grid-row { grid-template-columns: minmax(5.25rem, 1.2fr) repeat(4, minmax(0, 1fr)); } #obiFront .obf-grid .obf-lv { width: 1.4rem; height: 1.4rem; font-size: .8125rem; } } /*keep: room for "Mthembu" at 12px beside four 22px circles*/
@media (max-width: 420px) { #obiFront .obf-grid-row { grid-template-columns: minmax(0, 1.1fr) repeat(4, minmax(0, 1fr)); } #obiFront .obf-grid-name { font-size: var(--text-caption); }
  #obiFront .obf-grid-skill { font-size: .6875rem; letter-spacing: -.01em; } } /*keep: 11px, so "Counting" keeps to one line in a phone's column*/


/* ---- 5. The difference: the same day by hand and with Obi, four moments. Each row is a pane of glass. Wide: three columns under a
   head (the moment; by hand, in Georgia italic like a note in pencil; with Obi, in Inter, cream, with the apricot full stop as its
   tick). Narrow: each row stacked, with its own small labels. Static: every chore is already struck through and every tick shown.
   With movement, as a row arrives its chore is struck through from left to right (a pencil line, --sw) and then its tick lands on a
   spring, a beat apart down the list. ---- */
#obiFront .obf-diff { padding-top: var(--obf-section); }
#obiFront .obf-diff .obf-h2 { max-width: 17em; font-size: clamp(var(--text-h2), 1rem + 2.6vw, 3.25rem); line-height: 1.08; }
#obiFront .obf-diff-heads { display: none; }
#obiFront .obf-diff-rows { display: grid; gap: var(--space-2); margin: clamp(var(--space-6), 4vw, var(--space-7)) 0 0; padding: 0; list-style: none; }
#obiFront .obf-diff-row { display: grid; gap: var(--space-3); margin: 0; padding: var(--space-5) var(--space-4); border-radius: var(--radius-card);
  border-top: 1px solid var(--st-line); }
#obiFront .obf-diff-row:first-child { border-top-color: transparent; }
#obiFront .obf-diff-when { margin: 0; font-size: var(--text-label); font-weight: var(--fw-semibold); letter-spacing: .01em; color: var(--st-muted); }
#obiFront .obf-diff-k { display: block; margin-bottom: var(--space-1); font-family: var(--font-sans, Inter, system-ui, sans-serif); font-style: normal;
  font-size: var(--text-caption); font-weight: var(--fw-semibold); letter-spacing: .02em; color: var(--st-muted); }
#obiFront .obf-diff-row p { margin: 0; }
#obiFront .obf-diff-hand { margin: 0; font-family: Georgia, "Times New Roman", serif; font-style: italic; font-size: var(--text-body-lg);
  line-height: var(--lh-body); color: var(--st-muted); }
#obiFront .obf-strike { --sw: 100%; padding-inline: .1em; margin-inline: -.1em; text-decoration: none;
  background: linear-gradient(rgba(240, 230, 216, .5), rgba(240, 230, 216, .5)) no-repeat 0 58% / var(--sw) 1px; } /* a light pencil line: the words stay readable */
#obiFront .obf-diff-obi { margin: 0; font-size: var(--text-body-lg); line-height: var(--lh-body); font-weight: var(--fw-medium); color: var(--cream); }
#obiFront .obf-diff-says { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: var(--space-3); align-items: baseline; }
#obiFront .obf-diff-obi .obf-diff-k { color: var(--apricot); }
#obiFront .obf-diff-tick { width: .62rem; height: .62rem; border-radius: var(--radius-full); background: var(--apricot); translate: 0 -.08em;
  box-shadow: 0 0 0 4px rgba(232, 133, 58, .2); }
@media (min-width: 900px) {
  #obiFront .obf-diff-heads { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 5fr) minmax(0, 5fr); column-gap: var(--space-7);
    margin-top: clamp(var(--space-6), 4vw, var(--space-7)); padding: 0 var(--space-5) var(--space-3);
    font-family: Georgia, "Times New Roman", serif; font-style: italic; font-size: var(--text-body-lg); }
  #obiFront .obf-diff-k-hand { color: var(--st-muted); }
  #obiFront .obf-diff-k-obi { color: var(--apricot); padding-left: calc(.62rem + var(--space-3)); }
  #obiFront .obf-diff-rows { margin-top: 0; gap: 0; }
  #obiFront .obf-diff-row { grid-template-columns: minmax(0, 2fr) minmax(0, 5fr) minmax(0, 5fr); column-gap: var(--space-7); align-items: baseline;
    padding: var(--space-6) var(--space-5); }
  #obiFront .obf-diff-row:first-child { border-top-color: var(--st-line); }
  #obiFront .obf-diff-k { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } /* read, not shown */
  #obiFront .obf-diff-when { font-size: var(--text-body); color: var(--cream); }
}
#obiFront.obf-motion .obf-diff-row .obf-strike { --sw: 0%; transition: background-size .9s cubic-bezier(.6, .05, .3, 1) calc(.35s + var(--i) * 140ms); }
#obiFront.obf-motion .obf-diff-row.obf-on .obf-strike { --sw: 100%; }
#obiFront.obf-motion .obf-diff-row .obf-diff-tick { transform: scale(0); }
#obiFront.obf-motion .obf-diff-row.obf-on .obf-diff-tick { transform: none; transition: transform var(--spring-pop-d) var(--spring-pop) calc(1.1s + var(--i) * 140ms); }
#obiFront.obf-motion .obf-diff-row .obf-diff-hand { transition: color .6s var(--ease-out) calc(1s + var(--i) * 140ms); }
#obiFront.obf-motion .obf-diff-row:not(.obf-on) .obf-diff-hand { color: var(--cream); }

/* ---- 6a. Act three's term comment: the window, the comment's lines, Save and Print ---- */
#obiFront .obf-doc { padding: var(--space-5); gap: var(--space-4); }
#obiFront .obf-doc-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-2) var(--space-4); }
#obiFront .obf-doc-title { font-size: var(--text-h3); font-weight: var(--fw-semibold); color: var(--ink); }
#obiFront .obf-doc .obf-who { flex: 0 1 auto; flex-direction: row; gap: var(--space-2); align-items: baseline; }
#obiFront .obf-doc .obf-name { font-size: var(--text-body); }
#obiFront .obf-doc-lines { display: flex; flex-direction: column; gap: var(--space-3); padding-block: var(--space-2); }
#obiFront .obf-doc-line { display: block; width: var(--w); height: .5rem; border-radius: var(--radius-full); background: var(--sand); transform-origin: left center; }
#obiFront .obf-doc-actions { display: flex; justify-content: flex-end; gap: var(--space-2); }
#obiFront .obf-fakebtn { display: inline-flex; align-items: center; min-height: var(--row-dense); padding: 0 var(--space-4); border-radius: var(--radius-control);
  border: 1px solid var(--warm-grey); background: var(--cream); color: var(--ink); font-weight: var(--fw-semibold); }
#obiFront .obf-fakebtn-primary { background: var(--apricot); border-color: transparent; color: var(--apricot-ink-strong); }
#obiFront .obf-doc { min-height: 19rem; }

/* ---- 6b. The scenes turn to face you as a held act begins (--tilt, 1 to 0 over its first third, set by scroll on the stage itself;
   registered so it is not inherited and a write restyles the stage alone, not the scene inside it) ---- */
@property --tilt { syntax: "<number>"; inherits: false; initial-value: 0; }
@media (min-height: 640px) {
  #obiFront.obf-m .obf-pin .obf-act-stage { transform: perspective(1400px) rotateY(calc(var(--tilt, 0) * -16deg)) rotateX(calc(var(--tilt, 0) * 7deg))
    translateY(calc(var(--tilt, 0) * 2.5rem)); transform-origin: 30% 60%; }
}
/* act three: the comment writes itself (s1), Save and Print land (s2), and the printed sheet slides out under the window (s3) */
#obiFront .obf-report { position: relative; }
#obiFront .obf-sheet { display: none; }
#obiFront.obf-m .obf-act3 .obf-doc .obf-doc-line { transform: scaleX(0); transition: transform .8s var(--ease-out) calc(var(--i) * 110ms); }
#obiFront.obf-m .obf-act3.is-s1 .obf-doc .obf-doc-line { transform: none; }
#obiFront.obf-m .obf-act3 .obf-fakebtn { opacity: 0; transform: scale(.7); transition: opacity .3s var(--ease-out), transform var(--spring-pop-d) var(--spring-pop); }
#obiFront.obf-m .obf-act3.is-s2 .obf-fakebtn { opacity: 1; transform: none; }
#obiFront.obf-m .obf-act3.is-s2 .obf-fakebtn + .obf-fakebtn { transition-delay: .12s; }
#obiFront.obf-m .obf-act3.is-s3 .obf-fakebtn-primary { box-shadow: 0 0 0 6px rgba(232, 133, 58, .28); transform: scale(.96); }
#obiFront.obf-m .obf-act3 .obf-sheet { display: flex; flex-direction: column; gap: var(--space-3); position: absolute; z-index: -1; left: 9%; right: 9%; bottom: 6%;
  padding: var(--space-6) var(--space-5) var(--space-5); background: var(--cream); border-radius: 6px; box-shadow: 0 30px 60px rgba(0, 0, 0, .5);
  transform: translateY(0) rotate(0deg); opacity: 0; transition: transform var(--spring-rise-d) var(--spring-rise), opacity .3s var(--ease-out); }
#obiFront.obf-m .obf-act3.is-s3 .obf-sheet { opacity: 1; transform: translateY(30%) rotate(-3deg); } /* out from under the window, short of the next section */
#obiFront .obf-sheet-head { display: block; width: 40%; height: .7rem; border-radius: var(--radius-full); background: var(--ink-70); opacity: .5; margin-bottom: var(--space-2); }
#obiFront .obf-sheet .obf-doc-line { width: var(--w); }

/* ---- 6c. The intermission: the closing promise, large and still, the whole line on the screen at once. A follow-spot sweeps across
   it, left to right, as it passes through the window (--sx, set by Motion): the words are lit where the light is and readable but
   dim elsewhere; once the light has crossed, the line stays lit. Without Motion it is simply lit. Decoration: aria-hidden, the words
   are the closing h2's. ---- */
@property --sx { syntax: "<number>"; inherits: true; initial-value: 1.2; }
#obiFront .obf-interval { position: relative; display: grid; place-items: center; min-height: 80svh; margin-top: var(--obf-section);
  padding-block: clamp(var(--space-8), 8vw, 8rem); text-align: center; }
#obiFront .obf-sweep { margin: 0 auto; max-width: 16em; font-size: clamp(2.25rem, 1rem + 4.6vw, 5.5rem); font-weight: var(--fw-bold);
  letter-spacing: -.04em; line-height: 1.02; text-wrap: balance; color: var(--cream); }
#obiFront .obf-sweep-line { display: block; }
#obiFront .obf-sweep-line + .obf-sweep-line { margin-top: .12em; }
#obiFront .obf-mq-dot { display: inline-block; width: .17em; height: .17em; margin-left: .04em; border-radius: var(--radius-full); background: var(--apricot); }
#obiFront.obf-m .obf-interval:not(.is-lit) .obf-sweep-line {
  background-image: radial-gradient(closest-side, var(--cream) 50%, rgba(255, 253, 248, .42) 100%), linear-gradient(rgba(255, 253, 248, .42), rgba(255, 253, 248, .42));
  background-repeat: no-repeat; background-size: 55% 260%, 100% 100%; background-position: calc(var(--sx) * 100%) 50%, 0 0;
  -webkit-background-clip: text; background-clip: text; color: transparent; }
#obiFront.obf-m .obf-interval:not(.is-lit) .obf-sweep-line + .obf-sweep-line { background-position: calc((var(--sx) - .12) * 100%) 50%, 0 0; }
#obiFront .obf-interval::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(40% 50% at calc(var(--sx) * 100%) 50%, rgba(255, 240, 222, .07), transparent 70%); }

/* ---- 7. The climb: every child's growth as a staircase of the seven CAPS levels. Held (with Motion, a tall window), a spotlight
   climbs it one level per stretch of scroll, each level lighting as it is reached, and at the top they all take a bow. Static:
   every level lit. In a narrow window the steps are rows, each with a bar as long as its level. ---- */
#obiFront .obf-caps { position: relative; isolation: isolate; margin-top: 0; background: transparent; text-align: center; padding-block: var(--obf-section); }
#obiFront .obf-climb .obf-wrap { container: obf-caps / inline-size; }
#obiFront .obf-caps-line { margin-inline: auto; max-width: 19em; font-size: clamp(1.5rem, 1rem + 2.2vw, 2.75rem); font-weight: var(--fw-bold);
  line-height: 1.15; letter-spacing: -.02em; color: var(--cream); }
#obiFront .obf-stairs { position: relative; margin-top: clamp(var(--space-6), 4vw, var(--space-8)); }
#obiFront .obf-stairs::after { content: ""; position: absolute; left: -5%; right: -5%; bottom: -1px; height: 40%; z-index: -1; pointer-events: none;
  background: radial-gradient(50% 60% at 50% 100%, rgba(232, 133, 58, .2), transparent 75%); } /* footlights */
#obiFront .obf-levels { margin: 0 auto; padding: 0; text-align: left; }
#obiFront .obf-levels > li { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-2); }
#obiFront .obf-levels .obf-rc { color: var(--cream); }
#obiFront .obf-riser { display: block; height: .5rem; width: calc(var(--lv) / 7 * 100%); border-radius: var(--radius-full); background: var(--c); }
#obiFront .obf-follow { display: none; }
@container obf-caps (min-width: 0) { #obiFront .obf-levels { grid-template-columns: minmax(0, 1fr); max-width: 30rem; } }
@container obf-caps (min-width: calc(51.1rem + 198px)) {
  #obiFront .obf-levels { grid-template-columns: repeat(7, minmax(0, 1fr)); max-width: none; align-items: end; gap: var(--space-3); text-align: center; }
  #obiFront .obf-levels > li { justify-items: center; gap: var(--space-4); }
  #obiFront .obf-levels .obf-rc { flex-direction: column; gap: var(--space-2); }
  #obiFront .obf-levels .obf-lv { width: 3.25rem; height: 3.25rem; font-size: 1.3rem; }
  #obiFront .obf-riser { width: 100%; height: calc(var(--lv) * 1.6rem + 1.25rem); border-radius: var(--radius-control) var(--radius-control) 0 0;
    background: linear-gradient(to bottom, color-mix(in srgb, var(--c) 34%, var(--st-surface)), var(--st-surface) 85%); border-top: 3px solid var(--c); }
  /* The follow-spot, as light rather than a shape: a lamp above the stairs throws a beam (a conic, feathered at its edges and
     strongest near the floor) down onto the step reached; where it lands, an oval pool lights the step's top, and the step's face
     catches the light. It moves from step to step on a spring (--lit, the level reached). --st is the lit step's top above the floor. */
  #obiFront .obf-follow { --st: calc(var(--lit, 0) * 1.6rem + 1.25rem); display: block; position: absolute; z-index: 1; pointer-events: none;
    bottom: 0; top: -38%; left: calc((var(--lit, 0) - .5) / 7 * 100%); width: calc(100% / 7 * 2.4); translate: -50% 0; opacity: 0;
  }
  #obiFront .obf-follow::before { content: ""; position: absolute; left: 0; right: 0; top: 0; bottom: calc(var(--st) - .35rem); mix-blend-mode: screen;
    background: linear-gradient(to bottom, rgba(255, 240, 222, .015), rgba(255, 240, 222, .07) 55%, rgba(255, 240, 222, .16));
    -webkit-mask-image: conic-gradient(from 164deg at 50% 0, transparent 0deg, rgba(0, 0, 0, .45) 5deg, #000 12deg, #000 20deg, rgba(0, 0, 0, .45) 27deg, transparent 32deg);
    mask-image: conic-gradient(from 164deg at 50% 0, transparent 0deg, rgba(0, 0, 0, .45) 5deg, #000 12deg, #000 20deg, rgba(0, 0, 0, .45) 27deg, transparent 32deg); }
  #obiFront .obf-follow::after { content: ""; position: absolute; left: 50%; bottom: calc(var(--st) - .9rem); width: 46%; height: 1.8rem; translate: -50% 0;
    border-radius: var(--radius-full); mix-blend-mode: screen;
    background: radial-gradient(closest-side, rgba(255, 244, 228, .5), rgba(255, 240, 222, .18) 55%, transparent); }
  /* it moves only with Motion (never under reduced motion): along the stairs, and down onto each step, on a spring */
  #obiFront.obf-m .obf-follow { transition: left var(--spring-rise-d) var(--spring-rise), opacity .5s var(--ease-out); }
  #obiFront.obf-m .obf-follow::before, #obiFront.obf-m .obf-follow::after { transition: bottom var(--spring-rise-d) var(--spring-rise); }
}
/* with Motion: unlit levels wait in the dark; a lit one comes up in its colour */
#obiFront.obf-m .obf-climb .obf-levels > li { transition: opacity .5s var(--ease-out); }
#obiFront.obf-m .obf-climb .obf-levels > li:not(.is-lit) { opacity: .28; }
#obiFront.obf-m .obf-climb .obf-levels > li:not(.is-lit) .obf-lv { filter: grayscale(1); }
#obiFront.obf-m .obf-climb .obf-riser { transform-origin: left bottom; transition: transform var(--spring-rise-d) var(--spring-rise); }
#obiFront.obf-m .obf-climb .obf-levels > li:not(.is-lit) .obf-riser { transform: scaleX(.15); }
#obiFront.obf-m .obf-climb .obf-levels > li.is-lit .obf-lv { box-shadow: 0 0 0 5px color-mix(in srgb, var(--c) 24%, transparent), 0 0 22px color-mix(in srgb, var(--c) 45%, transparent);
  transition: box-shadow .6s var(--ease-out); }
@container obf-caps (min-width: calc(51.1rem + 198px)) {
  #obiFront.obf-m .obf-climb .obf-levels > li:not(.is-lit) .obf-riser { transform: scaleY(.2); }
  #obiFront.obf-m .obf-climb .obf-riser { transform-origin: center bottom; }
  #obiFront.obf-m .obf-climb .obf-follow { opacity: calc(min(var(--lit, 0), 1)); }
  /* the step the light is on: its face lit from the top edge down */
  #obiFront.obf-m .obf-climb .obf-levels > li.is-now .obf-riser { background: linear-gradient(to bottom, color-mix(in srgb, var(--c) 62%, var(--st-surface)),
    color-mix(in srgb, var(--c) 18%, var(--st-surface)) 55%, var(--st-surface) 95%); }
}
@media (min-height: 640px) {
  #obiFront .obf-climb.obf-pin { height: 230vh; padding-block: 0; }
  #obiFront .obf-climb.obf-pin > .obf-climb-in { position: sticky; top: 0; height: 100svh; display: flex; align-items: center; padding-top: var(--obf-bar); overflow: clip; }
  #obiFront .obf-climb.obf-pin > .obf-climb-in > .obf-wrap { width: 100%; }
}

/* ---- 8. What's inside: the company, set like a programme's cast list (icon, name, dotted leader, a line in italic) ---- */
#obiFront .obf-inside { padding-top: var(--obf-section); }
#obiFront .obf-cast { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: clamp(var(--space-6), 5vw, var(--space-9));
  margin: clamp(var(--space-6), 4vw, var(--space-7)) 0 0; padding: 0; list-style: none; }
@media (min-width: 900px) { #obiFront .obf-cast { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
#obiFront .obf-castrow { position: relative; isolation: isolate; display: flex; align-items: flex-start; gap: var(--space-4); margin: 0;
  padding: var(--space-5) var(--space-2); border-bottom: 1px solid var(--st-line); }
#obiFront .obf-castrow { border-radius: var(--radius-card); } /* a pane of glass (0b): lit where the pointer is */
#obiFront .obf-castrow .obf-tile { margin: 0; }
#obiFront .obf-cast-body { display: flex; flex-direction: column; gap: var(--space-1); flex: 1 1 auto; min-width: 0; }
#obiFront .obf-cast-top { display: flex; align-items: baseline; gap: var(--space-3); }
#obiFront .obf-cast-top .obf-h3 { flex: 0 1 auto; font-size: clamp(var(--text-h3), 1rem + .7vw, 1.5rem); }
#obiFront .obf-cast-lead { flex: 1 1 1rem; min-width: 1rem; border-bottom: 2px dotted rgba(255, 253, 248, .22); translate: 0 -.25em; transform-origin: left center; }
#obiFront .obf-cast-body p { font-family: Georgia, "Times New Roman", serif; font-style: italic; font-size: var(--text-body-lg); line-height: var(--lh-body); color: var(--st-muted); }
#obiFront.obf-motion .obf-castrow .obf-tile { transform: scale(0); }
#obiFront.obf-motion .obf-castrow.obf-on .obf-tile { transform: none; transition: transform var(--spring-pop-d) var(--spring-pop) calc(.2s + var(--i) * 120ms); }
#obiFront.obf-motion .obf-castrow .obf-cast-lead { transform: scaleX(0); }
#obiFront.obf-motion .obf-castrow.obf-on .obf-cast-lead { transform: none; transition: transform .9s var(--ease-out) calc(.35s + var(--i) * 120ms); }

/* ---- 9. The encore: house lights (with Motion the band comes up from ink to sand as it arrives, its words turning to ink half way;
   without, it is sand), then the audience stands, from the middle out, and the closing full stop is applauded. ---- */
#obiFront .obf-close { position: relative; isolation: isolate; overflow: clip; background: transparent;
  padding-block: clamp(var(--space-8), 10vw, 10rem) calc(clamp(var(--space-8), 10vw, 10rem) + clamp(3.5rem, 8vw, 7rem)); }
#obiFront .obf-close .obf-h2 { color: var(--ink); font-size: clamp(var(--text-h2), 1rem + 3.4vw, 4.25rem); line-height: 1.05; letter-spacing: -.035em; }
#obiFront .obf-close .obf-h2 { max-width: 16em; }
/* the band's sand comes up from nothing at its top edge (a mask), so the dark page fades into it rather than stopping at a line. The
   sand is a leaf span, the band's first child (.obf-house, where a ::before was), so the scroll's --p restyles it alone, not the band. */
#obiFront .obf-close > .obf-house { position: absolute; inset: 0; z-index: -1; pointer-events: none; background: var(--sand);
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 2.5rem); mask-image: linear-gradient(to bottom, transparent, #000 2.5rem); }
/* with Motion the house lights come up from the floor: the sand rises through the band as it arrives (--p), behind a soft 2.5rem edge,
   so the band is never a half-lit grey */
#obiFront.obf-m .obf-close > .obf-house {
  -webkit-mask-image: linear-gradient(to bottom, transparent calc((1 - var(--p, 1)) * 100%), #000 calc((1 - var(--p, 1)) * 100% + 2.5rem));
  mask-image: linear-gradient(to bottom, transparent calc((1 - var(--p, 1)) * 100%), #000 calc((1 - var(--p, 1)) * 100% + 2.5rem)); }
#obiFront.obf-m .obf-close:not(.is-lit) .obf-h2 { color: var(--cream); }
#obiFront.obf-m .obf-close .obf-h2 { transition: color .35s var(--ease-out); }
#obiFront .obf-crowd { position: absolute; left: 0; right: 0; bottom: 0; height: clamp(3.5rem, 8vw, 7rem); display: flex; justify-content: center; align-items: flex-end;
  gap: clamp(2px, .5vw, 8px); pointer-events: none; overflow: hidden; }
#obiFront .obf-head { position: relative; flex: 0 0 auto; width: clamp(1.5rem, 3.6vw, 3.4rem); height: calc(var(--h) * 100%); }
#obiFront .obf-head::before { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 52%; background: var(--c); border-radius: 50% 50% 0 0 / 80% 80% 0 0; }
#obiFront .obf-head::after { content: ""; position: absolute; left: 24%; right: 24%; bottom: 50%; aspect-ratio: 1; background: var(--c); border-radius: var(--radius-full); }
#obiFront .obf-close .obf-stop { position: relative; }
#obiFront.obf-motion .obf-close.is-standing .obf-clap { display: block; position: absolute; left: 50%; top: 50%; width: 0; height: 0; rotate: var(--a); }
#obiFront.obf-motion .obf-close.is-standing .obf-clap > i { position: absolute; left: -.035em; top: -.035em; width: .07em; height: .07em; border-radius: var(--radius-full);
  background: var(--c); opacity: 0; animation: obf-clap 1.1s cubic-bezier(.15, .75, .25, 1) calc(.35s + var(--i) * 45ms) both; }
/* The credits: the brand and its line with Sign in on one row; under a hairline, the companies and the legal links. */
#obiFront > .obf-foot { padding: var(--space-7) 0 var(--space-6); color: var(--text-muted); }
#obiFront .obf-foot-in { display: block; }
#obiFront .obf-foot-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-4) var(--space-6); }
#obiFront .obf-foot-brand { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); }
#obiFront .obf-foot-line { color: var(--ink-70); }
#obiFront .obf-foot-base { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2) var(--space-6);
  margin-top: var(--space-5); padding-top: var(--space-4); border-top: 1px solid var(--line); font-size: var(--text-caption); }
#obiFront .obf-foot-credit { color: var(--ink-70); font-weight: var(--fw-medium); }
#obiFront .obf-foot-base .obf-legal a { min-height: var(--control-dense); }


/* ---- 9b. While a held scene plays: the scrub pill at the foot of the window (the act's name, a bar that fills with the scroll, a
   mark per step, lit as it is reached, the climb's in the CAPS colours, and a chevron that nods three times), so the reader can see
   the page is moving with them. ---- */
@keyframes obf-nudge { 0%, 100% { translate: 0 0; } 50% { translate: 0 4px; } }
#obiFront .obf-scrub { position: fixed; z-index: 4; left: 50%; bottom: max(var(--space-5), env(safe-area-inset-bottom)); display: flex; align-items: center;
  gap: var(--space-4); padding: var(--space-3) var(--space-5); border: 1px solid var(--st-line); border-radius: var(--radius-full);
  background: rgba(30, 25, 22, .8); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); box-shadow: var(--st-elev-2);
  pointer-events: none; opacity: 0; translate: -50% 160%; transition: translate var(--spring-rise-d) var(--spring-rise), opacity .3s var(--ease-out); }
#obiFront .obf-scrub.is-on { opacity: 1; translate: -50% 0; }
#obiFront .obf-scrub-label { font-family: Georgia, "Times New Roman", serif; font-style: italic; font-size: var(--text-body); color: var(--apricot); white-space: nowrap; }
#obiFront .obf-scrub-label:empty { display: none; }
#obiFront .obf-scrub-track { position: relative; width: clamp(8rem, 20vw, 15rem); height: 6px; border-radius: var(--radius-full); background: rgba(255, 253, 248, .14); }
#obiFront .obf-scrub-fill { position: absolute; inset: 0; border-radius: inherit; transform-origin: left center; transform: scaleX(var(--sp, 0));
  background: linear-gradient(90deg, var(--apricot), #F4B27A); } /*keep: apricot lightened at the bar's leading end*/
#obiFront .obf-scrub-marks { position: absolute; inset: 0; display: flex; justify-content: space-between; align-items: center; }
#obiFront .obf-scrub-marks > span { width: .875rem; height: .875rem; margin: 0 -.4375rem; border-radius: var(--radius-full); background: #2A2830;
  border: 2px solid rgba(255, 253, 248, .35); transition: background-color .3s var(--ease-out), border-color .3s var(--ease-out), transform var(--spring-pop-d) var(--spring-pop); }
#obiFront .obf-scrub-marks > span.is-done { background: var(--c, var(--apricot)); border-color: var(--c, var(--apricot)); transform: scale(1.15); }
#obiFront .obf-scrub-chev { width: .7rem; height: .7rem; margin: -.25rem .1rem 0; border-right: 2px solid var(--cream); border-bottom: 2px solid var(--cream); rotate: 45deg; opacity: .8; }
#obiFront .obf-scrub.is-on .obf-scrub-chev { animation: obf-nudge 1s var(--ease-out) .3s 3; }
@media (max-width: 420px) { #obiFront .obf-scrub { gap: var(--space-3); padding: var(--space-2) var(--space-4); } #obiFront .obf-scrub-track { width: 7.5rem; } }

@media (forced-colors: active) {
  #obiFront :is(.obf-stage, .obf-clap, .obf-cue, .obf-rig, .obf-crowd, .obf-follow, .obf-sheet, .obf-backdrop, .obf-cue-dot, .obf-progress, .obf-scrub) { display: none; }
  #obiFront .obf-caps::before, #obiFront .obf-stairs::after, #obiFront .obf-glass::before, #obiFront .obf-glass::after, #obiFront .obf-act > .obf-act-in::before { display: none; }
  #obiFront .obf-strike { background: none; text-decoration: line-through; } #obiFront .obf-diff-tick { background: CanvasText; box-shadow: none; }
  #obiFront .obf-fakebtn, #obiFront .obf-doc-line { border: 1px solid CanvasText; }
  #obiFront .obf-bar-in { border: 0; background: Canvas; } /* no pill edge: it would sit right beside Sign in's own (a transparent border is still drawn here) */
}
@media print {
  #obiFront { background: var(--bone); color: var(--ink); }
  #obiFront :is(.obf-stage, .obf-clap, .obf-cue, .obf-rig, .obf-crowd, .obf-follow, .obf-sheet, .obf-interval, .obf-backdrop, .obf-cue-dot, .obf-progress, .obf-scrub) { display: none; }
  #obiFront :is(.obf-act, .obf-climb).obf-pin { height: auto; }
  #obiFront .obf-track-act.obf-pin .obf-track { display: grid; width: auto; translate: none; }
  #obiFront .obf-pin > :is(.obf-act-in, .obf-climb-in) { position: static; height: auto; }
  #obiFront.obf-motion *, #obiFront.obf-motion *::before, #obiFront.obf-motion *::after { animation: none !important; transition: none !important; opacity: 1 !important; translate: none !important; filter: none !important; }
  #obiFront.obf-motion :is(.obf-stop, .obf-pb-fill, .obf-lv, .obf-tile, .obf-doc-line, .obf-browser, .obf-book, .obf-riser, .obf-act-stage, .obf-head, .obf-diff-tick) { transform: none !important; }
  #obiFront .obf-strike { --sw: 100% !important; }
}

