/* OrbitLab shared design tokens + global primitives.
   Single source of truth for colours, loaded by the Explore page and every
   learning-portal page. Dark is the default; [data-theme="light"] flips tokens. */

/* ── Browser baseline (normative; mirrors design.md "Browser_Baseline") ──────
   Baseline: iOS Safari 15+ / evergreen Chrome, Firefox, Edge. Below-baseline
   browsers must still render a complete, usable interface via the fallbacks
   noted below. Keep this table in sync with the design document.

   | Capability                     | Baseline support                 | Below-baseline behaviour                                  |
   | ------------------------------ | -------------------------------- | --------------------------------------------------------- |
   | Portal core (layout, JS, JSON) | iOS Safari 15+ / evergreen       | Supported                                                 |
   | 100dvh                         | iOS Safari 15.4+                 | Falls back to the preceding `100vh` declaration           |
   | backdrop-filter blur           | iOS Safari 15+ (`-webkit-` pfx)  | Solid/semi-opaque background, AA contrast preserved       |
   | color-mix(in srgb, ...)          | iOS Safari 16.2+ / Chrome 111+   | Preceding opaque solid-colour fallback on same property   |

   IMPORTANT: color-mix() is unsupported below iOS Safari 16.2 / Chrome 111.
   Every color-mix() declaration (e.g. --ring focus ring, themed tints) MUST be
   immediately preceded by an opaque solid-colour fallback for the same property
   so focus rings and tints remain visible below baseline (see C7 fallbacks). */

/* ── Typefaces (self-hosted; the CSP sets font-src 'self') ───────────────────
   Three roles, plus Arabic counterparts that the browser reaches only when it
   actually has Arabic glyphs to draw (the unicode-range keeps those files off
   the wire for English and French readers):

     display  Fraunces        an almanac/atlas serif. Variable: the optical-size
                              axis is what makes it work at both 68px in a hero
                              and 17px on a card, so the full-axis file is worth
                              its bytes. WONK is used sparingly on the hero.
     body     Atkinson Hyperlegible   drawn by the Braille Institute to keep
                              similar letterforms (I l 1, O 0) distinguishable.
                              An education portal with a dyslexia toggle should
                              read well before it reads stylishly.
     data     IBM Plex Mono    every measured quantity on the site - distances,
                              magnitudes, rise times, scores - is set in it, so
                              numbers align in columns and never look like prose.

     Arabic   Reem Kufi (display) + IBM Plex Sans Arabic (body/data). Reem Kufi's
                              geometry comes out of the same Kufic inscription
                              tradition as the instruments in the history module. */
@font-face {
  font-family: "Fraunces";
  src: url("/assets/fonts/fraunces-latin-full-normal.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  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+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Atkinson Hyperlegible";
  src: url("/assets/fonts/atkinson-hyperlegible-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Atkinson Hyperlegible";
  src: url("/assets/fonts/atkinson-hyperlegible-latin-700-normal.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/assets/fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/assets/fonts/ibm-plex-mono-latin-500-normal.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
/* Arabic faces: the unicode-range means these are fetched only by pages that
   actually render Arabic text, so en/fr readers never pay for them. */
@font-face {
  font-family: "Reem Kufi";
  src: url("/assets/fonts/reem-kufi-arabic-wght-normal.woff2") format("woff2-variations");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0898-08E1,
                 U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF,
                 U+FE70-FE74, U+FE76-FEFC;
}
@font-face {
  font-family: "IBM Plex Sans Arabic";
  src: url("/assets/fonts/ibm-plex-sans-arabic-arabic-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0898-08E1,
                 U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF,
                 U+FE70-FE74, U+FE76-FEFC;
}
@font-face {
  font-family: "IBM Plex Sans Arabic";
  src: url("/assets/fonts/ibm-plex-sans-arabic-arabic-600-normal.woff2") format("woff2");
  font-weight: 600 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0898-08E1,
                 U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF,
                 U+FE70-FE74, U+FE76-FEFC;
}

:root {
  /* ── Colour: "narrowband" ──────────────────────────────────────────────────
     The two accents are not a taste call. Nearly every nebula photograph you
     have ever seen is built from two emission lines - hydrogen-alpha at 656.3nm
     and doubly-ionised oxygen at 500.7nm - and those two lines are the accent
     pair. Rose carries attention (actions, current position, emphasis); teal
     carries information (links, data, progress). The base is a violet-black
     rather than a neutral one so both accents sit on a surface that shares
     their hue family, the way they do in the sky. */
  --bg: #0a0817;
  --app-bg: #07060f;
  --panel: #12102a;
  --panel-2: #1b1840;
  --border: #2f2b5e;
  --text: #eceaff;
  --text-soft: #c9c6ee;
  --muted: #8f8ac0;
  --accent: #ff5c86;          /* H-alpha 656.3nm - vs --panel 6.3:1 (AA) */
  --accent-2: #46e0d5;        /* [O III] 500.7nm - vs --panel 12.9:1 (AAA) */
  --rule: #241f4a;
  --shadow: rgba(2, 1, 12, 0.55);
  --danger: #ff6b6b;
  --good: #5cf2a0;
  /* Ink laid on top of a filled accent (buttons, badges, the active nav dot). */
  --accent-ink: #0b0518;

  /* Islamic-astronomy learning path - brass/gold accent (design B.4). Extends the
     theme; does NOT fork it. `--history-accent` is a FILLED brand gold that always
     carries dark `--history-accent-ink` text, and is also used for decorative tints
     (hotspot dots, panorama glow, certificate seal). Contrast (dark theme):
       • ink #1b1200 on gold #c9a227 ....... 7.7:1  (AAA normal text)
       • gold #c9a227 vs --panel #121829 ... 7.3:1  (>=3:1 non-text / 1.4.11)
     Use `--history-accent-line` for gold shown as foreground text/hairlines on the
     page surface - it is brightened on dark and darkened on light so it clears AA
     against each theme's panels (see the light overrides below). */
  --history-accent: #c9a227;
  --history-accent-ink: #1b1200;
  --history-accent-line: #e6c25a; /* vs --panel #12102a = 10.8:1 (AAA) */

  /* Dedicated keyboard focus-ring colour (Req 12.7). Deliberately a third hue,
     owned by nothing else in the system: the indicator must never blend into a
     gold surface, a rose button or a teal link. */
  --focus: #9db4ff;

  /* Elevation: layered shadows give cards real depth instead of a flat border. */
  --elev-1: 0 1px 2px rgba(0,0,0,0.25), 0 1px 3px rgba(0,0,0,0.2);
  --elev-2: 0 4px 12px -2px rgba(0,0,0,0.4), 0 2px 6px -2px rgba(0,0,0,0.3);
  --elev-3: 0 14px 38px -10px rgba(0,0,0,0.55), 0 6px 14px -6px rgba(0,0,0,0.4);
  /* Opaque fallback first: below-baseline browsers ignore the color-mix() line
     below and keep this solid accent ring so focus stays visible (C7). */
  --ring: 0 0 0 3px var(--accent);
  --ring: 0 0 0 3px color-mix(in srgb, var(--accent) 38%, transparent);

  /* Accent gradient used by primary actions, progress and hero flourishes.
     Weighted so most of the surface is one colour and only the tail shifts to
     the second line: a button should read as rose with a spectral edge, not as
     a rainbow sweep. */
  --grad-accent: linear-gradient(100deg, var(--accent) 62%, var(--accent-2));
  /* The spectral rule: the signature hairline of the design, running H-alpha to
     [O III]. It marks the current position and nothing else - under the active
     nav item, beneath a section title, along the spine of a lesson, across a
     progress bar. If it is on screen, it is telling you where you are. */
  --spectral: linear-gradient(90deg, var(--accent), var(--accent-2));

  /* ── Type ─────────────────────────────────────────────────────────────────
     Latin first, Arabic next in the same stack: the browser falls through per
     character, so an Arabic heading picks up Reem Kufi without a second rule. */
  --font-display: "Fraunces", "Reem Kufi", "Iowan Old Style", Georgia, serif;
  --font-body: "Atkinson Hyperlegible", "IBM Plex Sans Arabic", "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-mono: "IBM Plex Mono", "IBM Plex Sans Arabic", "Cascadia Code", Consolas, monospace;

  /* Fluid scale. Body never drops below 16px (iOS zooms smaller inputs). */
  --fs-hero: clamp(38px, 6vw, 66px);
  --fs-h1: clamp(29px, 4.2vw, 43px);
  --fs-h2: clamp(21px, 2.3vw, 27px);
  --fs-h3: 17.5px;
  --fs-body: 16.5px;
  --fs-sm: 14px;
  --fs-label: 11.5px;   /* mono, uppercase, tracked - the instrument-label size */

  /* Radius scale */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 22px;

  /* Motion tokens (one place to tune the feel; honoured app-wide). */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --t-fast: 0.14s;
  --t-med: 0.26s;
  --t-slow: 0.5s;
}

/* Light is the daylight reading mode, not a second design: the same two
   emission lines, darkened until they clear AA on paper, over a warm off-white
   that keeps the rose from turning pink. */
[data-theme="light"] {
  --bg: #ece7f0;
  --app-bg: #f6f3f7;
  --panel: #ffffff;
  --panel-2: #f3eff6;
  --border: #dcd4e6;
  --text: #191430;
  --text-soft: #3a3358;
  --muted: #5b5480;          /* vs --panel 6.9:1 (AA) */
  --accent: #b81b52;         /* vs --panel 6.3:1 (AA) */
  --accent-2: #0f6b70;       /* vs --panel 6.3:1 (AA) */
  --rule: #e6e0ec;
  --shadow: rgba(60, 40, 100, 0.16);
  --danger: #c0392b;
  --good: #1a8f5a;
  --accent-ink: #ffffff;
  --focus: #3b4fd0;

  /* Brass/gold, darkened for the light theme so it clears WCAG on white panels.
     Contrast (light theme):
       • ink #1b1200 on gold #a17b12 ......... 4.7:1  (AA normal text)
       • gold #a17b12 vs --panel #ffffff ..... 3.9:1  (>=3:1 non-text / 1.4.11)
       • line #7a5c10 vs --panel #ffffff ..... 5.6:1  (AA normal text) */
  --history-accent: #a17b12;
  --history-accent-ink: #1b1200;
  --history-accent-line: #7a5c10;

  --elev-1: 0 1px 2px rgba(60,40,100,0.08), 0 1px 3px rgba(60,40,100,0.06);
  --elev-2: 0 6px 16px -4px rgba(60,40,100,0.14), 0 2px 6px -2px rgba(60,40,100,0.1);
  --elev-3: 0 18px 40px -12px rgba(60,40,100,0.2), 0 6px 14px -6px rgba(60,40,100,0.13);
}

/* ---------------- type primitives ---------------- */
/* Headings are the display face; everything else inherits the body face set on
   <body> (explore.css / styles.css) so a single stack change reaches the whole
   product. The dyslexia toggle overrides both from a higher-specificity rule
   further down this file. */
h1, h2, h3, .display {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.012em;
  line-height: 1.14;
  font-variation-settings: "opsz" 40, "SOFT" 0, "WONK" 0;
}
h1 { font-size: var(--fs-h1); font-variation-settings: "opsz" 96, "SOFT" 0, "WONK" 1; }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); letter-spacing: -0.004em; line-height: 1.3; }
h4, h5, h6 { font-family: var(--font-display); font-weight: 600; }

/* ── Reading comfort ────────────────────────────────────────────────────────
   A small, deliberate loosening of the text for long reading sessions. Word
   spacing does most of the work: it separates without disturbing the shape of
   the words themselves, which is what letter spacing does when overused.

   Arabic is handled separately and NOT given letter-spacing. It is a cursive
   script - its letters are drawn joined - and spacing them apart pulls the
   joins open and makes the word look broken rather than airy. The same lever
   that helps Latin readers (a little space between letters) actively harms an
   Arabic reader, so there the extra room goes into word spacing and line
   height instead. This mirrors what the dyslexia toggle already does. */
body {
  letter-spacing: 0.006em;
  word-spacing: 0.03em;
}
html[lang="ar"] body {
  letter-spacing: 0;
  word-spacing: 0.08em;
}
/* Long-form text carries the taller line; headings and controls keep their own
   tighter leading so buttons and chips do not grow. */
p, li, dd, blockquote, figcaption {
  line-height: 1.65;
}
html[lang="ar"] p,
html[lang="ar"] li,
html[lang="ar"] dd,
html[lang="ar"] blockquote,
html[lang="ar"] figcaption {
  line-height: 1.9;
}

/* Instrument label: the small mono, uppercase, wide-tracked caption used for
   eyebrows, group headings, units and any "this is a reading" text. */
.label-mono {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
/* Measured quantities: mono, tabular, so digits line up between rows. */
.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }

/* Arabic sets no uppercase and needs no tracking - both only hurt legibility in
   a cursive script - so the instrument label relaxes into a weight change. */
html[lang="ar"] .label-mono { text-transform: none; letter-spacing: 0; font-weight: 600; }
html[lang="ar"] h1, html[lang="ar"] h2, html[lang="ar"] h3 { letter-spacing: 0; line-height: 1.35; }

/* ---------------- global primitives ---------------- */
.skip-link {
  position: absolute; left: 12px; top: -48px; z-index: 100;
  background: var(--accent); color: var(--accent-ink, #0b0518); padding: 8px 14px; border-radius: 8px;
  font-weight: 700; text-decoration: none; transition: top 0.15s ease;
}
.skip-link:focus { top: 12px; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }

/* High-contrast rendering (Req 12.4). When the learner (or their OS) asks for more
   contrast, widen the focus indicator and lift the gold accent / borders toward the
   theme's brightest ink so state stays legible. In Windows forced-colors mode we hand
   colour control to the system palette and pin the focus ring to `Highlight` so the
   keyboard indicator survives the override (WCAG 2.4.7 / 1.4.11). */
@media (prefers-contrast: more) {
  :root {
    --border: #46557f;               /* firmer panel/card edges on dark */
    --muted: #aab6da;                /* lift secondary text toward AA */
    --history-accent-line: #f2d27a;  /* brighter gold text on dark */
  }
  [data-theme="light"] {
    --border: #9fb0d2;
    --muted: #3c476a;
    --history-accent: #7a5c10;       /* darker gold fill/detail on light */
    --history-accent-line: #5e470a;
  }
  /* A thicker, higher-contrast keyboard focus ring in both themes. */
  :focus-visible { outline-width: 3px; outline-offset: 3px; }
}

@media (forced-colors: active) {
  /* Let the system palette drive colour; keep the focus ring on a system colour so
     the keyboard indicator is never removed by the forced-colors override. */
  :focus-visible { outline: 3px solid Highlight; outline-offset: 2px; }
  .skip-link:focus { outline: 3px solid Highlight; }
}

/* Smooth in-page scrolling and tidy text selection (premium polish). */
html { scroll-behavior: smooth; }
::selection { background: color-mix(in srgb, var(--accent) 35%, transparent); color: var(--text); }

.btn {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: inherit; font-size: 15px; font-weight: 700; cursor: pointer;
  border-radius: var(--r-md); padding: 12px 20px; border: 1px solid transparent;
  text-decoration: none;
  transition: transform var(--t-fast) var(--ease-out), box-shadow var(--t-med) var(--ease-out),
              background var(--t-med) ease, border-color var(--t-med) ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(1px) scale(0.99); }
.btn-primary { background: var(--grad-accent); color: var(--accent-ink, #0b0518); box-shadow: var(--elev-1); }
.btn-primary:hover { box-shadow: 0 8px 22px -6px color-mix(in srgb, var(--accent) 60%, transparent); }
.btn-ghost { background: transparent; color: var(--text); border-color: var(--border); }
.btn-ghost:hover { border-color: var(--accent-2); background: color-mix(in srgb, var(--accent-2) 10%, transparent); }

.badge {
  display: inline-block; font-family: var(--font-mono);
  font-size: 11px; font-weight: 500; letter-spacing: 0.12em;
  text-transform: uppercase; padding: 3px 9px; border-radius: 999px;
  background: var(--panel-2); color: var(--accent-2); border: 1px solid var(--border);
}

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; font-size: 15px; cursor: pointer;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px; color: var(--text);
  transition: border-color var(--t-med) ease, transform var(--t-fast) var(--ease-out), background var(--t-med) ease;
}
.icon-btn:hover { border-color: var(--accent); transform: translateY(-1px); }
.icon-btn:active { transform: translateY(0) scale(0.94); }

/* Comfortable 44px targets on touch devices (WCAG 2.5.5 / pointer: coarse). */
@media (pointer: coarse) {
  .icon-btn { width: 44px; height: 44px; }
  .lang-select { padding: 9px 10px; }

  /* Grow shared quiz/related controls to a >=44px box via padding + min-height
     (box-sizing: border-box is in effect), centring the label vertically inside
     the enlarged target. Padding - not font growth - does the sizing so labels
     stay within the box. .quiz-choice keeps its left-aligned label; chips centre. */
  .quiz-choice {
    display: flex; align-items: center; justify-content: flex-start;
    min-height: 44px; padding-top: 11px; padding-bottom: 11px;
  }
  .related-chips a {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 44px; padding-top: 11px; padding-bottom: 11px; line-height: 1.2;
  }
}

/* ---------------- inline SVG icons (icons.js) ---------------- */
/* Icons inherit text colour and scale with font-size by default; specific
   contexts (buttons, step dots) set an explicit size below. */
.svg-icon { width: 1em; height: 1em; display: inline-block; vertical-align: -0.14em; flex-shrink: 0; }
.icon-btn .svg-icon { width: 18px; height: 18px; }
.btn .svg-icon { width: 1.05em; height: 1.05em; vertical-align: -0.18em; }

/* Language switcher (built by i18n.js). Themed so it matches the chrome on every
   page, with explicit option colours so the open dropdown is readable in both themes. */
.lang-switcher { display: inline-flex; }
.lang-select {
  background: var(--panel-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  padding: 6px 8px; font-size: 13px; cursor: pointer;
  /* Deliberately NOT var(--font-body): this control lists every language in its
     own script, so inheriting the Arabic face would make every English and
     French reader download 43 KB of Arabic glyphs to render one dropdown
     option. The system Arabic font renders it perfectly well. */
  font-family: "Atkinson Hyperlegible", "Segoe UI", system-ui, -apple-system, sans-serif;
}
.lang-select:hover { border-color: var(--accent); }
.lang-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.lang-select option { background: var(--panel); color: var(--text); }

.loading { color: var(--muted); font-size: 14px; }

/* =====================================================================
   Motion & feedback utilities (driven by motion.js, used across pages).
   Everything here degrades to "instantly visible, no animation" when the
   user prefers reduced motion (see the media query at the foot of the file).
   ===================================================================== */

/* Scroll-reveal: motion.js adds .reveal to off-screen elements, then .in. */
.reveal { opacity: 0; transform: translateY(16px); will-change: opacity, transform; }
.reveal.in { opacity: 1; transform: none; transition: opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-out); }

/* Page entrance: the main content fades up once on load. */
.page-enter { animation: pageEnter var(--t-slow) var(--ease-out) both; }
@keyframes pageEnter { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* Skeleton loaders: a shimmering placeholder while content hydrates. */
.skeleton {
  position: relative; overflow: hidden;
  background: var(--panel-2); border-radius: var(--r-sm);
}
.skeleton::after {
  content: ""; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--text) 9%, transparent), transparent);
  animation: shimmer 1.3s infinite;
}
@keyframes shimmer { 100% { transform: translateX(100%); } }
.skeleton-card { height: 132px; border-radius: var(--r-md); }
.skeleton-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }

/* Animated circular progress ring (student progress visualisation). */
.ring { display: inline-grid; place-items: center; position: relative; }
.ring svg { transform: rotate(-90deg); display: block; }
.ring .ring-track { stroke: var(--panel-2); }
.ring .ring-fill {
  stroke: var(--accent); stroke-linecap: round;
  transition: stroke-dashoffset 0.9s var(--ease-out);
}
.ring .ring-label { position: absolute; font-size: 13px; font-weight: 700; color: var(--text); }

/* Confetti / celebration canvas (motion.js mounts this full-screen, transient). */
.fx-confetti { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 9999; }

/* A soft pop used for success states and achievement unlocks. */
.pop { animation: pop var(--t-med) var(--ease-spring) both; }
@keyframes pop { 0% { transform: scale(0.8); opacity: 0; } 60% { transform: scale(1.04); } 100% { transform: scale(1); opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { scroll-behavior: auto !important; }
  .btn, .icon-btn { transition: none; }
  .btn:hover, .icon-btn:hover { transform: none; }
  .reveal { opacity: 1; transform: none; }
  .reveal.in { transition: none; }
  .page-enter { animation: none; }
  .skeleton::after { animation: none; }
  .ring .ring-fill { transition: none; }
  .pop { animation: none; }
}

/* ── Accessibility helper: visually hidden but read by assistive tech ──────── */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* ── Dyslexia-friendly reading typography (Req 12.5) ─────────────────────────
   Toggled by portal.js via <html data-font="dyslexic">, persisted and applied
   pre-paint by the inline head script. A self-hosted OFL Latin face is loaded
   (font-display: swap → the readable fallback stack shows immediately and if the
   binary is absent nothing breaks), and letter/word/line spacing are widened - 
   the spacing changes are what most help dyslexic readers. Arabic is a cursive
   script with no dyslexia face, so there we keep the system Arabic font and only
   widen spacing (the button's help text explains this). */
@font-face {
  font-family: "OpenDyslexic";
  src: url("/assets/fonts/OpenDyslexic-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
.font-toggle-glyph { font-weight: 700; font-size: 13px; letter-spacing: 0.02em; }
html[data-font="dyslexic"] body {
  font-family: "OpenDyslexic", "Comic Sans MS", "Trebuchet MS", "Segoe UI", system-ui, sans-serif;
  letter-spacing: 0.03em;
  word-spacing: 0.08em;
  line-height: 1.8;
}
/* Arabic: preserve the cursive system font; widen spacing and line-height only.
   Higher specificity ([lang="ar"]) so it wins over the Latin rule above. */
html[lang="ar"][data-font="dyslexic"] body {
  font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
  letter-spacing: normal;
  word-spacing: 0.14em;
  line-height: 2.05;
}

/* ── Themed scrollbars ──────────────────────────────────────────────
   Slim, rounded, token-driven scrollbars so long lists (sky star names, code
   blocks, the page itself) match the theme in both dark and light modes.
   Firefox/new Chromium take the two standard properties; older WebKit falls
   back to the ::-webkit-scrollbar rules (ignored wherever scrollbar-width is
   supported, so the two never fight). */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 999px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover { background: var(--muted); background-clip: padding-box; }
