/* =====================================================================
   OSE design system · TIER 1 · PRIMITIVES
   ---------------------------------------------------------------------
   The raw palette and scales. This is the ONLY file in the repo that may
   contain hex / rgb / px / rem / em / vw / ms / deg / unitless magic
   numbers. Everything else references tokens.

   Rules
   - Nothing outside styles/tokens/semantic.css may reference a --p-* token.
   - Colour values come from brand/tokens.css + the brand spec PDF
     (reference/OSE_Brand_Spec_Navy_Aurora.pdf). Derived tints are marked
     "derived" and were contrast-checked against cream / navy.
   - Annotations: "@group <name>" comments group tokens for the styleguide
     (/styleguide/), which parses this file. Keep one declaration per line.
   ===================================================================== */

/* ---- Brand type, self-hosted from /brand/fonts (the Vietnamese subset is required).
   TikTok Sans is ONE variable font (weights 500–700) used for headings at 700,
   H3 / titles at 600 and UI (buttons, labels, nav) at 500. Questrial 400 is the
   body (its only weight); Geist Mono 500 the data labels. Nothing uses 800 or 900;
   font-synthesis-weight is off (base.css), so a weight without a face renders the
   nearest hosted one instead of a faux bold. Each family has the vietnamese,
   latin-ext and latin subsets; unicode-range is copied from Google Fonts (css2,
   2026-10-09). Lexend stays in /brand/fonts for the logo and print only: the site
   no longer loads it. Licences: /brand/fonts/LICENSE-*.txt (SIL OFL 1.1).
   Chosen by John on 2026-10-09 (headings 700, buttons 500). ---- */
/* Headings (700), H3 / titles (600), UI (500): TikTok Sans, one variable file per subset. To swap the heading family, change --p-font-family-heading and this block. */
@font-face{font-family:"TikTok Sans";font-style:normal;font-weight:500 700;font-display:swap;src:url("../../brand/fonts/tiktok-sans-vietnamese-500-700-normal.woff2") format("woff2");unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}
@font-face{font-family:"TikTok Sans";font-style:normal;font-weight:500 700;font-display:swap;src:url("../../brand/fonts/tiktok-sans-latin-ext-500-700-normal.woff2") format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"TikTok Sans";font-style:normal;font-weight:500 700;font-display:swap;src:url("../../brand/fonts/tiktok-sans-latin-500-700-normal.woff2") format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
/* Body, lead and small text: Questrial 400 */
@font-face{font-family:"Questrial";font-style:normal;font-weight:400;font-display:swap;src:url("../../brand/fonts/questrial-vietnamese-400-normal.woff2") format("woff2");unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}
@font-face{font-family:"Questrial";font-style:normal;font-weight:400;font-display:swap;src:url("../../brand/fonts/questrial-latin-ext-400-normal.woff2") format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"Questrial";font-style:normal;font-weight:400;font-display:swap;src:url("../../brand/fonts/questrial-latin-400-normal.woff2") format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
/* Data labels (dates, class sizes, step numbers): Geist Mono 500 */
@font-face{font-family:"Geist Mono";font-style:normal;font-weight:500;font-display:swap;src:url("../../brand/fonts/geist-mono-vietnamese-500-normal.woff2") format("woff2");unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}
@font-face{font-family:"Geist Mono";font-style:normal;font-weight:500;font-display:swap;src:url("../../brand/fonts/geist-mono-latin-ext-500-normal.woff2") format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"Geist Mono";font-style:normal;font-weight:500;font-display:swap;src:url("../../brand/fonts/geist-mono-latin-500-normal.woff2") format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}

/* ---- Breakpoints (mobile-first, min-width). Custom media is not yet supported
   by browsers, so media queries elsewhere may use ONLY these literal values;
   scripts/check-tokens.sh enforces that. JS reads --p-bp-* via semantic --bp-*.
   @custom-media --bp-sm (width >= 30em);   480px  large phones
   @custom-media --bp-md (width >= 48em);   768px  tablets: lighter motion below this
   @custom-media --bp-lg (width >= 64em);  1024px  laptops
   @custom-media --bp-xl (width >= 80em);  1280px  desktops: type scale reaches 1.25
   ---- */

:root {
  /* @group Colour · Brand core */
  --p-color-navy: #1E3A5F; /* Space Navy: primary ink + dark surfaces (10.6:1 on cream) */
  --p-color-cream: #F7F5F0; /* Cloud Cream: page background. Never pure white */
  --p-color-night: #16294A; /* Night Navy: footer and deep bands. Darkest brand colour */
  --p-color-navy-70: #5F728A; /* Navy 70 %: secondary text on cream (4.5:1) */
  --p-color-cream-70: #B6BDC4; /* Cream 70 %: secondary text on navy (6.1:1) */

  /* @group Colour · Aurora accents */
  --p-color-mint: #9FEBD8; /* Aurora Mint: small details only, never text on cream */
  --p-color-lilac: #B7A4FF; /* Aurora Lilac: focus ring, hover underline */
  --p-color-peach: #FFC2A6; /* Aurora Peach: warm highlight; error ink on navy */
  --p-color-ring-a: #7FE0C8; /* O-ring gradient start */
  --p-color-ring-b: #A994FF; /* O-ring gradient end */
  --p-gradient-ring: linear-gradient(90deg, var(--p-color-ring-a), var(--p-color-ring-b)); /* O-ring: horizontal, left to right */

  /* @group Colour · Planets (true order, flat fill only) */
  --p-color-mercury: #9E9A94; /* Sao Thuỷ */
  --p-color-venus: #E6D7A8; /* Sao Kim (pale: outline on cream) */
  --p-color-earth: #3F7FCC; /* Trái Đất */
  --p-color-mars: #C4572E; /* Sao Hoả */
  --p-color-jupiter: #D0A77A; /* Sao Mộc */
  --p-color-saturn: #E2C98F; /* Sao Thổ (pale: outline on cream) */
  --p-color-uranus: #A7D8DE; /* Sao Thiên Vương (pale: outline on cream) */
  --p-color-neptune: #8EC3DE; /* Sao Hải Vương */

  /* @group Colour · Derived solids */
  --p-color-cream-50: #FCFBF8; /* derived: paper. Raised surfaces on cream; navy-70 text 4.8:1 */
  --p-color-brick: #A63A1F; /* derived: Mars hue deepened. Error ink on cream 5.9:1 */
  --p-color-pine: #1F6B58; /* derived: mint hue deepened. Success ink on cream 5.8:1 */

  /* @group Colour · Navy alpha (for use on cream) */
  --p-color-navy-a06: rgb(30 58 95 / 0.06); /* hover wash */
  --p-color-navy-a10: rgb(30 58 95 / 0.1); /* pressed wash */
  --p-color-navy-a14: rgb(30 58 95 / 0.14); /* hairline (brand --line) */
  --p-color-navy-a20: rgb(30 58 95 / 0.2); /* outline for pale planet dots on cream (brand spec) */
  --p-color-navy-a40: rgb(30 58 95 / 0.4); /* disabled ink */
  --p-color-navy-a85: rgb(30 58 95 / 0.85); /* glass bar on navy */

  /* @group Colour · Cream alpha (for use on navy) */
  --p-color-cream-a06: rgb(247 245 240 / 0.06); /* raised surface on navy */
  --p-color-cream-a10: rgb(247 245 240 / 0.1); /* hover wash on navy */
  --p-color-cream-a14: rgb(247 245 240 / 0.14); /* hairline on navy */
  --p-color-cream-a20: rgb(247 245 240 / 0.2); /* pressed wash on navy */
  --p-color-cream-a40: rgb(247 245 240 / 0.4); /* disabled ink on navy */
  --p-color-cream-a85: rgb(247 245 240 / 0.85); /* glass bar on cream */

  /* @group Colour · Night & accent alpha */
  --p-color-night-a64: rgb(22 41 74 / 0.64); /* modal scrim */
  --p-color-night-a90: rgb(22 41 74 / 0.9); /* glass bar on night */
  --p-color-mint-a14: rgb(159 235 216 / 0.14); /* success / selected wash on navy */
  --p-color-mint-a32: rgb(159 235 216 / 0.32); /* success / selected wash on cream (navy text 9.8:1) */
  --p-color-peach-a14: rgb(255 194 166 / 0.14); /* error wash on navy */
  --p-color-peach-a32: rgb(255 194 166 / 0.32); /* error wash on cream (navy text 9.5:1) */
  --p-color-transparent: transparent;

  /* @group Typography · Family & weight */
  --p-font-family-heading: "TikTok Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; /* John may swap this family: only this line + its @font-face block change */
  --p-font-family-ui: "TikTok Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; /* buttons, labels, nav links, form labels, chips, tabs: 500 */
  --p-font-family-body: "Questrial", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; /* body, lead, small: 400 only (its one weight) */
  --p-font-family-mono: "Geist Mono", ui-monospace, "SF Mono", "Cascadia Mono", "Segoe UI Mono", Menlo, Consolas, monospace; /* data labels: dates, class sizes, step numbers. 500 only */
  --p-font-weight-400: 400; /* Regular: Questrial body text */
  --p-font-weight-500: 500; /* Medium: TikTok Sans UI (buttons, labels, nav) and Geist Mono data labels */
  --p-font-weight-600: 600; /* SemiBold: TikTok Sans H3 and titles; b / strong in body text */
  --p-font-weight-700: 700; /* Bold: TikTok Sans headings (display, H1, H2). Nothing uses 800 or 900 */

  /* @group Typography · Size (modular 1.25, base 17px, fluid) */
  --p-font-size-minus-2: clamp(0.68rem, 0.8517rem - 0.2146vw, 0.8034rem); /* 12.9px @360 → 10.9px @1280. Completes the -2…6 scale; deliberately NOT mapped to any text role: below the legibility floor for stacked Vietnamese diacritics */
  --p-font-size-minus-1: clamp(0.85rem, 0.9528rem - 0.1285vw, 0.9239rem); /* 14.8px @360 → 13.6px @1280 */
  --p-font-size-0: 1.0625rem; /* 17px: base at every width */
  --p-font-size-1: clamp(1.2219rem, 1.1803rem + 0.1848vw, 1.3281rem); /* 19.6px → 21.3px */
  --p-font-size-2: clamp(1.4052rem, 1.3054rem + 0.4435vw, 1.6602rem); /* 22.5px → 26.6px */
  --p-font-size-3: clamp(1.6159rem, 1.4362rem + 0.7987vw, 2.0752rem); /* 25.9px → 33.2px */
  --p-font-size-4: clamp(1.8583rem, 1.5704rem + 1.2794vw, 2.594rem); /* 29.7px → 41.5px */
  --p-font-size-5: clamp(2.1371rem, 1.7045rem + 1.9225vw, 3.2425rem); /* 34.2px → 51.9px */
  --p-font-size-6: clamp(2.4576rem, 1.8333rem + 2.7748vw, 4.0531rem); /* 39.3px → 64.9px. Ratio compresses to 1.15 at 360px so phones stay readable */

  /* @group Typography · Line height & tracking */
  --p-leading-tight: 1.2; /* headings: minimum for Vietnamese stacked diacritics (Ữ Ể Ậ) */
  --p-leading-snug: 1.3; /* H3, uppercase labels (brand spec minimum for caps) */
  --p-leading-normal: 1.5; /* small text, UI */
  --p-leading-relaxed: 1.65; /* body copy */
  --p-tracking-tightest: -0.025em; /* display: 800 at the largest sizes */
  --p-tracking-tighter: -0.02em; /* H1 */
  --p-tracking-snug: -0.015em; /* H2 */
  --p-tracking-tight: -0.01em; /* big stat figures (brand spec -1 %) */
  --p-tracking-normal: 0;
  --p-tracking-wide: 0.02em; /* mono data labels: a little air between monospaced figures */
  --p-tracking-caps: 0.12em; /* uppercase labels (brand spec +12 %) */
  --p-tracking-mono-caps: 0.06em; /* uppercase mono labels (eyebrows): monospaced capitals already sit apart, so half the UI caps tracking */
  --p-underline-offset: 0.22em;

  /* @group Space (4px base) */
  --p-space-0: 0;
  --p-space-1: 0.25rem; /* 4px */
  --p-space-2: 0.5rem; /* 8px */
  --p-space-3: 0.75rem; /* 12px */
  --p-space-4: 1rem; /* 16px */
  --p-space-6: 1.5rem; /* 24px */
  --p-space-8: 2rem; /* 32px */
  --p-space-10: 2.5rem; /* 40px */
  --p-space-12: 3rem; /* 48px */
  --p-space-16: 4rem; /* 64px */
  --p-space-20: 5rem; /* 80px */
  --p-space-24: 6rem; /* 96px */
  --p-space-32: 8rem; /* 128px */

  /* @group Space · Fluid */
  --p-space-fluid-gutter: clamp(1rem, 4vw, 2.5rem); /* 16px phone → 40px (brand gutter) */
  --p-space-fluid-inset: clamp(1.5rem, 1.1087rem + 1.7391vw, 2.5rem); /* 24px → 40px */
  --p-space-fluid-section-tight: clamp(3rem, 2.2174rem + 3.4783vw, 5rem); /* 48px → 80px */
  --p-space-fluid-section: clamp(4rem, 2.4348rem + 6.9565vw, 8rem); /* 64px → 128px */

  /* @group Radius */
  --p-radius-none: 0;
  --p-radius-xs: 4px; /* flat labels: badges, tags */
  --p-radius-sm: 8px;
  --p-radius-md: 14px; /* brand card radius */
  --p-radius-lg: 24px;
  --p-radius-pill: 999px;
  --p-radius-round: 50%;

  /* @group Border width */
  --p-border-1: 1px;
  --p-border-2: 2px;

  /* @group Shadow (navy-tinted, never black) */
  --p-shadow-none: none;
  --p-shadow-1: 0 1px 2px rgb(22 41 74 / 0.06), 0 2px 6px rgb(22 41 74 / 0.06); /* raised */
  --p-shadow-2: 0 2px 4px rgb(22 41 74 / 0.06), 0 10px 24px rgb(22 41 74 / 0.1); /* overlay */
  --p-shadow-3: 0 4px 10px rgb(22 41 74 / 0.08), 0 24px 56px rgb(22 41 74 / 0.18); /* floating */
  --p-shadow-1-deep: 0 1px 2px rgb(22 41 74 / 0.4), 0 2px 8px rgb(22 41 74 / 0.4); /* raised, on navy */
  --p-shadow-2-deep: 0 2px 6px rgb(22 41 74 / 0.5), 0 12px 28px rgb(22 41 74 / 0.6); /* overlay, on navy */
  --p-shadow-3-deep: 0 6px 14px rgb(22 41 74 / 0.6), 0 28px 64px rgb(22 41 74 / 0.8); /* floating, on navy */

  /* @group Z-index */
  --p-z-0: 0;
  --p-z-1: 1;
  --p-z-2: 2; /* one step above 1: a scene's foreground over its own backdrop (home hero: planet over the night layer) */
  --p-z-100: 100;
  --p-z-200: 200;
  --p-z-300: 300;
  --p-z-400: 400;
  --p-z-500: 500;
  --p-z-600: 600;
  --p-z-900: 900;

  /* @group Breakpoints (min-width; see @custom-media notes above) */
  --p-bp-sm: 30em; /* 480px */
  --p-bp-md: 48em; /* 768px */
  --p-bp-lg: 64em; /* 1024px */
  --p-bp-xl: 80em; /* 1280px */

  /* @group Containers */
  --p-container-xs: 22rem; /* 352px: popovers, toasts */
  --p-container-sm: 32rem; /* 512px: dialogs, forms */
  --p-container-measure: 40rem; /* 640px: headline + lead measure (section headers) */
  --p-container-md: 45rem; /* 720px: hero copy, narrow columns */
  --p-container-prose: 68ch; /* blog reading width */
  --p-container-lg: 72.5rem; /* 1160px: page max (brand maxw) */
  --p-container-xl: 82.5rem; /* 1320px: full-bleed bands */
  --p-container-card-min: 17rem; /* 272px: min card width in auto-fit grids */

  /* @group Size · Controls & icons */
  --p-size-tap: 2.75rem; /* 44px: minimum tap target */
  --p-size-control-xs: 2.25rem; /* 36px visual (hit area padded to 44) */
  --p-size-control-sm: 2.75rem; /* 44px */
  --p-size-control-md: 3rem; /* 48px */
  --p-size-control-field: 3.25rem; /* 52px: inputs, selects */
  --p-size-control-lg: 3.5rem; /* 56px */
  --p-size-icon-sm: 1rem; /* 16px */
  --p-size-icon-md: 1.25rem; /* 20px */
  --p-size-icon-lg: 1.5rem; /* 24px */
  --p-size-dot: 0.625rem; /* 10px: radio dot */
  --p-size-badge: 1.5rem; /* 24px */

  /* @group Size · Brand & layout */
  --p-size-logo-mark: 2.5rem; /* 40px header mark (brand: 36–44px) */
  --p-size-logo-lockup: 11.25rem; /* 180px footer lockup (brand min 120px) */
  --p-size-nav: clamp(4rem, 3.8043rem + 0.8696vw, 4.5rem); /* 64px → 72px */
  --p-size-contact-bar: 4rem; /* 64px + safe area */
  --p-size-avatar: 6rem; /* 96px */
  --p-size-planet-d-sm: 0.5rem; /* 8px Earth dot */
  --p-size-planet-d: 0.75rem; /* 12px Earth dot */
  --p-size-planet-d-lg: 1.25rem; /* 20px Earth dot */
  --p-size-planet-sm: clamp(3.5rem, 3rem + 2.5vw, 5rem); /* planet disc D, small: 57px @360 → 80px @1280 (orbit-diagram centre) */
  --p-size-planet-md: 6rem; /* planet disc D, default: 96px */
  --p-size-planet-hero: clamp(12rem, max(min(6rem + 30vw, 18rem), -6.25rem + 39.0625vw), 26rem); /* planet disc D, hero: 204px @360 → 288px @640–1010 (stacked hero) → 300px @1024 → 400px @1280 → 416px max */
  --p-size-planet-hero-compact: clamp(7.5rem, 4rem + 15vw, 12rem); /* planet disc D, home hero below 64em, above the headline: 120px @360 → 179px @768 → 192px max, so the planet and the headline share the first screen of a phone */
  --p-size-screen: 100svh; /* small viewport height: no jump when a phone's URL bar hides */
  --p-size-screen-step: 70svh; /* one scroll step of a sticky chapter (home learning path, ≥ 64em): 70 % of the small viewport height */
  --p-size-seat: clamp(1.5rem, 1rem + 2vw, 2.25rem); /* classroom seat disc: 24px @400 → 36px @1000+ */
  --p-size-textarea-min: 8rem; /* 128px */
  --p-size-dropdown-max: 18rem; /* 288px */
  --p-size-accent-bar: 0.25rem; /* 4px */
  --p-size-accent-dash: 1.5rem; /* 24px */
  --p-size-star-sm: 0.5px; /* starfield: far-layer star radius (CSS px, not rem: stars never grow with the text size) */
  --p-size-star-md: 0.75px; /* starfield: mid-layer star radius */
  --p-size-star-lg: 1.1px; /* starfield: near-layer star radius */
  --p-safe-area-bottom: env(safe-area-inset-bottom, 0px);

  /* @group Ratio */
  --p-ratio-wide: 16 / 9;
  --p-ratio-photo: 4 / 3;
  --p-ratio-square: 1 / 1;
  --p-ratio-portrait: 4 / 5;
  --p-ratio-ring-gap: 1.55; /* logo spec: the cut where the ring crosses the O / planet = 1.55 × ring stroke */
  --p-ratio-twinkle: 0.75; /* starfield: a layer breathes down to 75 % of its opacity, never lower */

  /* @group Planet scale (dot = Earth d × ∛(diameter ÷ Earth's); gap = d; row = 18.0 d) */
  --p-planet-scale-mercury: 0.726;
  --p-planet-scale-venus: 0.983;
  --p-planet-scale-earth: 1;
  --p-planet-scale-mars: 0.811;
  --p-planet-scale-jupiter: 2.238;
  --p-planet-scale-saturn: 2.114;
  --p-planet-scale-uranus: 1.588;
  --p-planet-scale-neptune: 1.572;
  --p-planet-row-length: 18; /* whole row = 18.0 Earth dots (8 dots + 7 gaps), brand spec */

  /* @group Brand geometry (logo ring and O as unitless ratios; the planet radius R = D ÷ 2) */
  --p-geo-ring-rx: 1.36; /* ring x radius ÷ R (logo: 199.2 ÷ 146.45) */
  --p-geo-ring-ry: 0.28; /* ring y radius ÷ R (logo: 41.0 ÷ 146.45) */
  --p-geo-ring-stroke: 0.2; /* ring stroke ÷ R (logo: 29.2 ÷ 146.45) */
  --p-geo-logo-o-cx: 0.2668; /* O centre x ÷ logo image width (OSE_mark_*.svg: 265.2 ÷ 994) */
  --p-geo-logo-o-cy: 0.5084; /* O centre y ÷ logo image height (218.1 ÷ 429) */
  --p-geo-logo-o-d: 0.2947; /* O outer diameter ÷ logo image width (292.9 ÷ 994) */
  --p-geo-orbit-1: 0.46; /* orbit diagram: inner orbit diameter ÷ diagram width */
  --p-geo-orbit-2: 0.68; /* middle orbit */
  --p-geo-orbit-3: 0.9; /* outer orbit: leaves room for its label above */

  /* @group Opacity, scale, angle, offset, count */
  --p-opacity-0: 0;
  --p-opacity-35: 0.35; /* faint: far starfield layer */
  --p-opacity-45: 0.45;
  --p-opacity-65: 0.65; /* soft: mid starfield layer */
  --p-opacity-75: 0.75; /* dim but readable: Cream 70 % text on night stays 4.9:1 (AA) */
  --p-opacity-100: 1;
  --p-scale-none: 1;
  --p-scale-pressed: 0.97;
  --p-scale-enter: 0.96;
  --p-scale-appear: 0.6; /* classroom scene: a seat or an adult's ring grows from 60 % as it appears */
  --p-scale-ring-open: 1.6; /* through-ring: the hero ring's scaleY once it has opened (a 3D-looking tilt); keep ≤ 1.6 (planet.css back-half mask note) */
  --p-scale-approach: 1.5; /* through-ring below 48em: the hero planet grows to 150 % as it scrolls out (the camera nears it) */
  --p-angle-none: 0deg; /* also through-ring: the hero ring levels out to this */
  --p-angle-half: 180deg;
  --p-angle-ring-tilt: -14deg; /* logo ring tilt (brand spec) */
  --p-offset-lift: -2px;
  --p-lines-2: 2;
  --p-lines-3: 3;
  --p-count-stars: 150; /* starfield: stars per navy band, all 3 layers together (motion spec: ≤ 150) */
  --p-count-stars-small: 72; /* starfield below --bp-md: about half, for mid-range phones */

  /* @group Blur */
  --p-blur-sm: 8px;
  --p-blur-md: 16px;

  /* @group Motion · Duration */
  --p-duration-0: 0ms;
  --p-duration-instant: 80ms;
  --p-duration-fast: 160ms;
  --p-duration-base: 240ms;
  --p-duration-slow: 480ms;
  --p-duration-scene: 1200ms;
  --p-duration-ambient: 4800ms; /* one slow breath of an ambient loop (starfield twinkle); runs only while on screen */

  /* @group Motion · Delay (reading and typing time: never shortened by reduced motion) */
  --p-delay-typeahead: 500ms; /* type-ahead buffer in listboxes (WAI-ARIA APG) */
  --p-delay-toast: 8000ms; /* success toast auto-dismiss; paused while hovered or focused */

  /* @group Motion · Easing */
  --p-ease-linear: linear; /* scroll scrub */
  --p-ease-standard: cubic-bezier(0.2, 0, 0, 1); /* most UI state changes */
  --p-ease-emphasized: cubic-bezier(0.05, 0.7, 0.1, 1); /* entrances: fast start, long settle */
  --p-ease-exit: cubic-bezier(0.3, 0, 0.8, 0.15); /* exits: accelerate away */
  --p-ease-orbit: cubic-bezier(0.45, 0.05, 0.25, 1); /* floaty: slow lift-off, long weightless glide */

  /* @group Motion · Countdown scene (unitless: viewport-height multipliers, read by js/motion/scenes/countdown.js) */
  --p-scene-countdown-fill: 0.6; /* the line under the countdown fills over 0.6 × the viewport height of scroll, from the moment it enters at the bottom of the screen (no pin) */

  /* @group Motion · Learning path scene (unitless shares and viewport fractions, plus one angle; read by js/motion/scenes/learning-path.js) */
  --p-scene-path-transfer: 0.4; /* ≥ 64em: the marker moves out to the next orbit over 0.4 of one stage's scroll, centred where one stage hands over to the next (no pin; each stage's scroll = its height) */
  --p-scene-path-snap: 0.75; /* < 64em: a stage's small diagram moves its marker once, when the diagram's centre reaches 75 % of the viewport height */
  --p-angle-path-sweep: 75deg; /* the marker's whole journey, clockwise: from 6 o'clock on orbit 1 to about half past 8 on orbit 3 (its label stays inside the diagram) */

  /* @group Motion · Classroom scene (unitless: viewport-height fractions, read by js/motion/scenes/classroom.js) */
  --p-scene-classroom-start: 0.85; /* the scene begins when the seating plan's top edge reaches 85 % of the viewport height (phones: the plan, then the class facts, each play once at this line) */
  --p-scene-classroom-end: 0.45; /* ≥ 48em: the seats are all in when the plan's top edge reaches 45 % of the viewport height (0.4 × the viewport height of scrubbed scroll, no pin); the figures count up once the facts' top edge has passed this line too */

  /* @group Motion · Through-ring scene (unitless: viewport-height multipliers and shares of the pinned scroll, read by js/motion/scenes/through-ring.js) */
  --p-scene-flight-length: 1; /* ≥ 48em: the hero stays pinned for 1 × the viewport height of scroll while the camera flies through the planet's ring */
  --p-scene-flight-hold: 0.4; /* the hero copy stays put and fully readable for the first 40 % of the pin (the planet only grows in place) */
  --p-scene-flight-copy-out: 0.6; /* … and has faded out, drifting up, by 60 % */
  --p-scene-flight-aim: 0.7; /* by 70 % the ring has levelled and opened, and the camera points at the gap between the disc and the ring */
  --p-scene-flight-night-from: 0.66; /* the night layer starts fading in at 66 % of the pin, once the planet fills most of the screen (a short blend: no muddy cream-navy mix) … */
  --p-scene-flight-night-to: 0.82; /* … and is opaque at 82 %, as the ring sweeps past the screen edges */
  --p-size-cover-circle: calc(100vw + 100svh); /* a circle this wide, centred on the screen, covers it (≥ the diagonal): the hero's night reveal */
  --p-scene-flight-fade: 0.86; /* the planet dissolves into the starry night over the last 14 % */
  --p-scene-flight-night-lead-small: 0.1; /* below 48em (no pin): the night starts fading in when the copy's last line is 10 % of the viewport height below the nav */

  /* @group Icons (SVG masks: colour comes from background-color: currentColor) */
  --p-icon-chevron-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  --p-icon-chevron-right: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 6l6 6-6 6'/%3E%3C/svg%3E");
  --p-icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E");
  --p-icon-plus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M12 5v14M5 12h14'/%3E%3C/svg%3E");
  --p-icon-minus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M5 12h14'/%3E%3C/svg%3E");
  --p-icon-close: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E");
  --p-icon-arrow-right: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6'/%3E%3C/svg%3E");
  --p-icon-phone: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.6 3.5h2.9l1.4 4.1-2 1.5a12 12 0 0 0 6 6l1.5-2 4.1 1.4v2.9a2 2 0 0 1-2.2 2A17 17 0 0 1 4.6 5.7a2 2 0 0 1 2-2.2z'/%3E%3C/svg%3E");
  --p-icon-chat: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.5 11.5a8.5 8 0 0 1-12.2 7.2L3.5 20l1.3-4.2a8.5 8 0 1 1 15.7-4.3z'/%3E%3C/svg%3E");
  --p-icon-edit: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h4L19 9l-4-4L4 16v4zM13.5 6.5l4 4'/%3E%3C/svg%3E");
  --p-icon-menu: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M4 7h16M4 12h16M4 17h16'/%3E%3C/svg%3E");
  --p-icon-check-circle: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M8 12.5l2.7 2.7L16 9.8'/%3E%3C/svg%3E"); /* success: toasts */
  --p-icon-alert-circle: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7.5v5.5M12 16.5h.01'/%3E%3C/svg%3E"); /* error: field messages, toasts */
  --p-icon-messenger: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5c-4.8 0-8.5 3.5-8.5 8 0 2.4 1.1 4.6 2.9 6.1v3l2.8-1.6c.9.3 1.8.4 2.8.4 4.8 0 8.5-3.5 8.5-7.9S16.8 3.5 12 3.5z'/%3E%3Cpath d='M7.5 13.5l3-3.2 2.6 2.4 3.4-3.2'/%3E%3C/svg%3E"); /* round bubble + zigzag: Messenger, distinct from the Zalo bubble (--p-icon-chat) */
}
