/* ══════════════════════════════════════════════════════════════════════════
   BARRE — reset, typography ground, font faces
   ══════════════════════════════════════════════════════════════════════ */

/* ── Web fonts ──────────────────────────────────────────────────────────
   Self-hosted per spec 05 §9. Both are Google Fonts under the SIL OFL 1.1;
   fonts/OFL-Marcellus.txt and fonts/OFL-DMSans.txt must ship with them.
   The .woff2 are Google's own pre-built subsets from fonts.gstatic.com — no
   local subsetter needed (there is no Node/Python here). To refresh: open the
   css2 URL with a desktop UA and save the .woff2 each @font-face points at.

   unicode-range keeps only the two `latin` files on the first-paint path
   (51,484 B); `latin-ext` is declared but never fetched, because the French
   ballet vocabulary (relevé, chaîné, développé, penchée) is all Latin-1.

   Use format('woff2'), NOT format('woff2-variations') — the latter is
   deprecated and some engines drop the whole face. Google serves variable
   DM Sans as plain woff2; match it.                                        */

/* Marcellus — latin */
@font-face {
  font-family: 'Marcellus';
  src: url('../fonts/marcellus-latin.woff2') format('woff2');
  font-weight: 400; 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+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Marcellus — latin-ext (lazy: nothing in the app needs it today) */
@font-face {
  font-family: 'Marcellus';
  src: url('../fonts/marcellus-latin-ext.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* DM Sans — latin, variable 400–700 */
@font-face {
  font-family: 'DM Sans';
  src: url('../fonts/dmsans-latin-var.woff2') format('woff2');
  font-weight: 400 700; 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+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* DM Sans — arrows. ← and → are genuine DM Sans glyphs, but Google's `latin`
   subset cuts everything in U+2190–2194 except ↑ and ↓, so the back button
   (2.9) and the quiz teaser's trailing → would otherwise drop to a system
   font mid-sentence. 2,352 B custom subset from the css2 `text=` endpoint. */
@font-face {
  font-family: 'DM Sans';
  src: url('../fonts/dmsans-arrows-var.woff2') format('woff2');
  font-weight: 400 700; font-style: normal; font-display: swap;
  unicode-range: U+2190-2194;
}
/* DM Sans — latin-ext (lazy, as above) */
@font-face {
  font-family: 'DM Sans';
  src: url('../fonts/dmsans-latin-ext-var.woff2') format('woff2');
  font-weight: 400 700; font-style: normal; font-display: swap;
  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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ── Metric-matched fallbacks ───────────────────────────────────────────
   So that font-display:swap swaps without moving anything. MEASURED, not
   guessed (spec 05 §9). ascent/descent from the TTF hhea/OS_2 tables;
   size-adjust from laying a 34,366-char corpus of content/*.json out at 100px
   in each face via canvas measureText (that, not hmtx, is what decides where
   text wraps — the two disagreed by ~0.4%).

     size-adjust      = targetAdvance / fallbackAdvance
     ascent-override  = targetAscent  / upem / size-adjust   (size-adjust
     descent-override = targetDescent / upem / size-adjust    rescales these)

     Marcellus asc .9741 desc .2798 gap 0 | DM Sans asc .9920 desc .3100 gap 0
     Marcellus/Georgia 1.01769 <-used   Marcellus/Times 1.12007
     DM Sans/Arial     1.05021 <-used   DM Sans/Segoe UI 1.05352

   Tuned for Georgia (ships on Windows, macOS, iOS). Times would want 112%, so
   it is a last resort. Arial and Segoe UI are within 0.3%, so they share one
   number. Verified: swapping the real faces in moves nothing vertically —
   0.00px on every one of 475 elements across TODAY/MOVES/SKILLS at 375px. */
@font-face {
  font-family: 'Marcellus Fallback';
  src: local('Georgia'), local('Noto Serif'), local('Times New Roman');
  size-adjust: 101.77%; ascent-override: 95.72%; descent-override: 27.49%; line-gap-override: 0%;
}
@font-face {
  font-family: 'DM Sans Fallback';
  src: local('Helvetica Neue'), local('Arial'), local('Roboto'), local('Segoe UI');
  size-adjust: 105.02%; ascent-override: 94.46%; descent-override: 29.52%; line-gap-override: 0%;
}

/* ── Reset ─────────────────────────────────────────────────────────────── */
* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  background: var(--surface-app);
  color: var(--text-ink);
  font: var(--font-body-lg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow: hidden;                 /* the app frame owns scrolling */
  overscroll-behavior: none;        /* kill rubber-band in standalone */
  -webkit-text-size-adjust: 100%;
}

h1, h2, h3, h4, p, figure, blockquote, ul, ol, dl, dd {
  margin: 0;
  padding: 0;
}
ul, ol { list-style: none; }

img, svg, video { display: block; max-width: 100%; }

a {
  color: var(--accent-link);
  text-decoration: none;
}
a:hover { color: var(--accent-link-hover); }

::selection { background: var(--accent-blush); }

/* Interactive elements: no browser chrome, native tap feel. */
button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  margin: 0;
  padding: 0;
  text-align: inherit;
  cursor: pointer;
}
button, [data-action], .b-tap {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
}
input, select, textarea { font: inherit; color: inherit; }

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

[hidden] { display: none !important; }

/* ── Scroll containers ─────────────────────────────────────────────────── */
.scroll {
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}

/* ── Typography helpers (used by screens instead of inline `font:`) ────── */
.t-kicker {
  font: var(--font-kicker);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--text-kicker);
}
.t-title      { font: var(--font-display-screen); margin-top: var(--space-5); }
.t-title-move { font: var(--font-display-move);   margin-top: var(--space-6); }
.t-section    { font: var(--font-display-section); }
.t-body       { font: var(--font-body); color: var(--text-muted); }
.t-body-sm    { font: var(--font-body-sm); color: var(--text-muted); }
.t-meta       { font: var(--font-meta); color: var(--text-faint); }
.t-eyebrow {
  font: var(--font-eyebrow);
  letter-spacing: var(--ls-mid);
  text-transform: uppercase;
  color: var(--text-kicker);
}
.t-micro {
  font: var(--font-microlabel);
  letter-spacing: var(--ls-mid);
  text-transform: uppercase;
}

/* Landscape on a phone: the design is one portrait column. Ask politely. */
@media (orientation: landscape) and (max-height: 500px) {
  .b-rotate-note { display: flex; }
  #main, #tabbar { display: none; }
}
.b-rotate-note {
  display: none;
  position: fixed;
  inset: 0;
  z-index: var(--z-studio);
  background: var(--surface-app);
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--gutter);
  font: var(--font-body-lg);
  color: var(--text-muted);
}
