/*
 * Self-hosted, latin subset only, 96 KB for both.
 *
 * These are the same files Google Fonts serves, fetched once and committed
 * rather than requested at runtime: a third-party font request blocks first
 * paint, leaks the visitor's IP to another host, and is the single thing that
 * made the old site slow. font-display:swap means text is readable in the
 * fallback immediately and reflows once - the right trade when the fallback
 * (Iowan/Palatino/Georgia) is already a serif of similar colour.
 *
 * Fraunces is variable on the weight axis, so one file covers 400-700.
 */
@font-face {
  font-family: 'Fraunces';
  src: url('/assets/fonts/fraunces-latin.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+2000-206F, U+2074, U+20AC, U+2122, U+2191,
                 U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono';
  src: url('/assets/fonts/jetbrains-mono-latin.woff2') format('woff2');
  font-weight: 400 500;
  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+2000-206F, U+2074, U+20AC, U+2122, U+2191,
                 U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/*
 * Metric-matched fallbacks, so font-display:swap costs no layout shift.
 *
 * Measured in Chrome against the real file: rendering the h1 string at the
 * heading weight, Georgia Bold sets 31% wider than Fraunces 600, Iowan Old
 * Style Bold 21% wider, Palatino Bold 16%. That is a whole line of an h1
 * appearing or disappearing when the swap lands, with the rest of the page
 * moving under it — on a slow connection, long after first paint.
 *
 * These faces download nothing: src is local() only, so a browser that has the
 * font renders it at a corrected size and a browser that doesn't skips the
 * rule and falls through. A browser without size-adjust support renders
 * exactly what it renders today.
 *
 * Two faces per family, not one. A local() @font-face binds a single static
 * face, so one rule can only be right at one weight — and the site sets serif
 * at 600 (h1/h2/h3, .brand) and at 400 (.prose blockquote). Declaring 400 and
 * 700 lets the matching algorithm pick the real Bold for the 600 headings
 * instead of synthesising one, and each face carries the size-adjust measured
 * at the weight it will actually serve.
 *
 * Every percentage below was measured, not estimated, except Palatino Linotype
 * — absent from this machine, and carried on Apple Palatino's numbers because
 * they are the same Zapf design with the same widths.
 *
 * The local() names are full font names, not family names: local('Iowan Old
 * Style') silently matches nothing, local('Iowan Old Style Roman') matches.
 * That is exactly the failure mode this whole block exists to avoid, so the
 * names here were each confirmed to resolve before being written down.
 *
 * Only size-adjust is needed. Every rule that uses the serif sets a unitless
 * line-height, so line boxes are already independent of a face's own ascent
 * and descent, and there is no vertical shift left to override.
 *
 * Android has none of these fonts and falls through to generic serif (Noto
 * Serif), which is deliberately left uncorrected: it cannot be measured from
 * here, and a guessed size-adjust is worse than none.
 */
@font-face {                                    /* macOS */
  font-family: 'Fraunces Fallback'; font-weight: 400;
  src: local('Iowan Old Style Roman'); size-adjust: 85.0%;
}
@font-face {
  font-family: 'Fraunces Fallback'; font-weight: 700;
  src: local('Iowan Old Style Bold'); size-adjust: 82.8%;
}
@font-face {                                    /* macOS, and Windows' Palatino Linotype */
  font-family: 'Fraunces Fallback 2'; font-weight: 400;
  src: local('Palatino-Roman'), local('Palatino Linotype'); size-adjust: 85.7%;
}
@font-face {
  font-family: 'Fraunces Fallback 2'; font-weight: 700;
  src: local('Palatino-Bold'), local('Palatino Linotype Bold'); size-adjust: 86.4%;
}
@font-face {                                    /* everywhere else that has it */
  font-family: 'Fraunces Fallback 3'; font-weight: 400;
  src: local('Georgia'); size-adjust: 85.2%;
}
@font-face {
  font-family: 'Fraunces Fallback 3'; font-weight: 700;
  src: local('Georgia Bold'); size-adjust: 76.6%;
}

/*
 * SparkKing site — shared stylesheet.
 *
 * Palette reasoning: the brand already owns a warm mark (orange → amber → gold)
 * and the redesign already chose a deep navy ground. Those two want each other,
 * so the accent system is the flame's own gradient and the violet from the
 * earlier draft is gone — violet fought the orange, and a navy-to-violet
 * gradient is also the single most over-used look in generated web design.
 *
 * One bold colour, everything else quiet.
 *
 * Theming covers all three viewer states: bare :root carries the complete light
 * palette, the media query handles the default "system" setting where nothing is
 * stamped on the root element, and the [data-theme] blocks let an explicit
 * choice win in either direction. No colour is ever defined only inside a media
 * block, or the un-stamped state renders one theme's text on the other's ground.
 */

:root {
  /* Tells the browser this page is light, so form controls, scrollbars and
     Chrome's auto-dark heuristics do not invert it behind our backs. */
  color-scheme: light;

  /* ground */
  --paper:      #FBF7EF;   /* warm cream, biased toward the flame not away */
  --paper-2:    #F3ECDF;   /* recessed panels */
  --navy:       #0E1633;   /* the deep ground - hero, footer, dark panels */
  --navy-2:     #16203F;

  /* ink */
  --ink:        #111827;   /* 16.6:1 on --paper */
  --ink-soft:   #4A5164;   /* 7.4:1 on --paper, 6.7:1 on --paper-2 */
  --ink-faint:  #5F6675;   /* 5.4:1 on --paper, 4.9:1 on --paper-2 */
  --on-navy:    #EEF1F8;
  --on-navy-soft:#A8B2CC;  /* 8.4:1 on --navy */

  /* the one accent, taken straight from the logo gradient */
  --flame:      #B34310;   /* darkened from #FF6B35 for text contrast on cream:
                              5.3:1 on --paper, 4.8:1 on --paper-2 */
  --flame-pure: #FF6B35;   /* the true brand orange - fills and gradients only */
  --amber:      #F7931E;
  --gold:       #FFD700;   /* only ever on a navy ground - 1.3:1 on cream */

  /* semantic - deliberately separate from the accent */
  --good:       #0F6E4F;
  --warn:       #8A5B00;

  --line:       #E0D7C6;   /* hairlines between rows and cards: decorative */
  --line-navy:  #2A3559;
  /* boundaries that are the only thing outlining a control, so they owe 3:1
     under 1.4.11 - a hairline that only has to separate two blocks does not */
  --edge:       #8E8574;   /* 3.4:1 on --paper, 3.1:1 on --paper-2 */
  --edge-navy:  #626D91;   /* 3.5:1 on --navy, 3.1:1 on --navy-2 */

  /* type */
  /* the three Fallback families are the same Iowan / Palatino / Georgia the
     stack always named, wrapped in size-adjust - see the @font-face block */
  --serif: 'Fraunces', 'Fraunces Fallback', 'Fraunces Fallback 2',
           'Fraunces Fallback 3', serif;
  --sans:  system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --mono:  'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;

  /*
   * Indic text cannot use Fraunces - it has no coverage for any of these
   * scripts. So it gets its own stack of locally-installed faces, named and
   * never downloaded. This is the whole reason the old site's 11-family
   * Google Fonts request existed, and dropping it is the single biggest
   * performance win available here.
   */
  --indic: 'Noto Sans Devanagari', 'Noto Sans Tamil', 'Noto Sans Telugu',
           'Noto Sans Kannada', 'Noto Sans Malayalam', 'Noto Sans Bengali',
           'Noto Sans Gujarati', 'Noto Sans Gurmukhi', 'Noto Sans Oriya',
           'Kohinoor Devanagari', 'Tamil Sangam MN', 'Telugu Sangam MN',
           'Kannada Sangam MN', 'Malayalam Sangam MN', 'Bangla Sangam MN',
           'Gujarati Sangam MN', 'Gurmukhi MN', 'Oriya Sangam MN',
           'Nirmala UI', system-ui, sans-serif;

  --measure: 62ch;
  --gutter: clamp(20px, 5vw, 64px);
}

/*
 * No prefers-color-scheme block, deliberately.
 *
 * Following the OS meant anyone with dark mode on - which is most phones -
 * got the dark palette whether they wanted it or not, and the dark palette is
 * not what this brand should lead with: the flame reads warm on cream and goes
 * muddy on near-black. Light is the design; dark is available to anyone who
 * asks for it with the toggle, and the choice is remembered.
 */
:root[data-theme="dark"] {
  color-scheme: dark;
  --paper:      #0B1122;
  --paper-2:    #131C36;
  --navy:       #070C1A;
  --navy-2:     #101830;
  --ink:        #E8ECF6;
  --ink-soft:   #B3BCD4;
  --ink-faint:  #8E98B2;
  --on-navy:    #EEF1F8;
  --on-navy-soft:#A8B2CC;
  --flame:      #FF8A5B;
  --flame-pure: #FF6B35;
  --amber:      #FFA940;
  --gold:       #FFD700;
  --good:       #4ECFA4;
  --warn:       #E7B24A;
  --line:       #232E4C;
  --line-navy:  #232E4C;
  --edge:       #5F6A88;
  --edge-navy:  #5C6785;
}

/*
 * Navy panels on the light theme.
 *
 * In the light theme the page is cream but several panels are navy — the hero,
 * the picker, the pronunciation card, the footer, the dock. The accents above
 * are tuned to be readable on cream, which makes them too dark to read on navy:
 * --flame is 4.2:1 there, --good 2.9:1, --warn 3.0:1. Re-point them for any
 * navy ground rather than hand-patching each rule, so a new navy panel inherits
 * the right values automatically.
 *
 * These are the same values the dark theme already uses, so in the dark theme
 * this block resolves to a no-op.
 */
.on-navy, .picker, .score-card, .foot, .dock {
  --flame: #FF8A5B;   /* 7.7:1 on --navy, 6.9:1 on --navy-2 */
  --good:  #4ECFA4;   /* 9.1:1 on --navy */
  --warn:  #E7B24A;   /* 9.2:1 on --navy */
  --edge:  var(--edge-navy);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
body, h1, h2, h3, h4, p, figure, blockquote, dl, dd, ul, ol { margin: 0; }
ul[role="list"] { list-style: none; padding: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/*
 * The masthead is sticky at 66px, so an in-page link scrolled its target to
 * y=0 and the header sat on top of it - "/#get" from another page landed the
 * visitor on content hidden behind the bar, which reads as the link being
 * broken.
 */
[id] { scroll-margin-top: 84px; }

body {
  /* explicit, from a token: the artifact/browser paints its own ground behind
     the page, and a transparent body borrows the host's theme */
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.65;
  margin: 0;
  -webkit-font-smoothing: antialiased;
}

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

a { color: var(--flame); text-decoration-thickness: 1px; text-underline-offset: 3px; }

/*
 * Two-tone focus ring.
 *
 * A single orange ring was invisible in two of the places it matters most: on
 * the cream ground it is 2.7:1 (needs 3:1), and around .btn-primary — which is
 * itself #FF6B35 — it was orange on orange. This page has cream grounds, navy
 * grounds and an orange button, and no one colour clears 3:1 against all of
 * them, so the indicator is two: an orange band with a navy halo either side.
 * Whichever ground the control sits on, at least one band contrasts:
 *
 *   orange band  6.3:1 on --navy   5.6:1 on --navy-2   6.6:1 on dark --paper
 *   navy halo   16.6:1 on --paper 15.1:1 on --paper-2  6.3:1 on --flame-pure
 *
 * Each band is >= 2px so it is a perceivable indicator, not a hairline.
 */
:focus-visible {
  outline: 2px solid var(--flame-pure);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px var(--navy);
  border-radius: 2px;
}
/* the skip link paints its own navy ground, so the halo would disappear into
   it - give that one the plain ring, which is already 6.3:1 there */
.skip:focus-visible { box-shadow: none; outline-offset: 3px; }

.skip {
  position: absolute; left: -9999px;
  background: var(--navy); color: var(--on-navy);
  padding: 12px 18px; z-index: 100;
}
.skip:focus { left: var(--gutter); top: 12px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- type ---------- */
h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.015em;
  text-wrap: balance;
}
h1 { font-size: clamp(2.4rem, 6vw, 4.2rem); }
h2 { font-size: clamp(1.8rem, 3.6vw, 2.9rem); }
h3 { font-size: clamp(1.15rem, 1.8vw, 1.4rem); }

p { max-width: var(--measure); }

.eyebrow {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 14px;
  /* the 62ch measure on <p> is for prose; on a one-line mono eyebrow it forces
     a wrap mid-phrase */
  max-width: none;
}
.on-navy .eyebrow { color: var(--on-navy-soft); }

.lede { font-size: clamp(1.05rem, 1.6vw, 1.25rem); color: var(--ink-soft); }
.on-navy .lede { color: var(--on-navy-soft); }

/* Indic runs anywhere on the page */
[lang]:not([lang^="en"]) { font-family: var(--indic); }
.indic { font-family: var(--indic); }

/* tabular figures wherever numbers line up */
.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* ---------- layout ---------- */
.wrap { max-width: 1200px; margin: 0 auto; padding-inline: var(--gutter); }
.section { padding-block: clamp(56px, 9vw, 120px); }
.on-navy { background: var(--navy); color: var(--on-navy); }
.on-navy h1, .on-navy h2, .on-navy h3 { color: var(--on-navy); }

.stack { display: flex; flex-direction: column; gap: var(--gap, 20px); }
.grid { display: grid; gap: clamp(20px, 3vw, 40px); }

/* wide content never scrolls the page sideways */
.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* ---------- header ---------- */
/*
 * Solid by default, translucent only on wide screens.
 *
 * A blurred backdrop on a *sticky* bar is repainted every scroll frame, and on
 * the mid-range Android this site is mostly read on that is the single most
 * expensive thing on the page. It also means the masthead's text contrast
 * depends on whatever has scrolled under it, which is not something we can
 * measure. Phones get an opaque bar: cheaper to paint and contrast that holds.
 */
.masthead {
  position: sticky; top: 0; z-index: 50;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
}
@media (min-width: 900px) {
  @supports (backdrop-filter: blur(1px)) {
    .masthead {
      background: color-mix(in srgb, var(--paper) 88%, transparent);
      backdrop-filter: saturate(150%) blur(10px);
    }
  }
}
.masthead .wrap {
  display: flex; align-items: center; gap: 24px;
  min-height: 66px;
}
.brand {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--serif); font-size: 1.3rem; font-weight: 600;
  color: var(--ink); text-decoration: none; letter-spacing: -0.01em;
}
.brand svg { width: 26px; height: 27px; flex: none; }
/*
 * The wordmark has to be one flex item. .brand is inline-flex with a gap, so a
 * bare "Spark" text node and <b>King</b> were two separate items and the gap
 * opened a 10px hole in the middle of the name - it read as two words.
 */
.brand .wordmark { display: inline; }
.brand b { font-weight: 600; color: var(--flame); }
.nav { margin-left: auto; display: flex; gap: 22px; align-items: center; }
/* :not(.btn) matters. `.nav a` outranks `.btn-primary` on specificity, so
   without it the masthead's "Get the app" rendered --ink-soft on --flame-pure
   - 2.8:1, on all eight pages - instead of the button's own near-black. */
.nav a:not(.btn) { color: var(--ink-soft); text-decoration: none; font-size: 0.94rem; }
.nav a:not(.btn):hover { color: var(--ink); }
@media (max-width: 820px) { .nav .hide-sm { display: none; } }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 14px 26px;
  font: 700 0.95rem/1 var(--sans);
  letter-spacing: 0.01em;
  border-radius: 999px;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.14s ease, box-shadow 0.14s ease, filter 0.14s ease;
}

/*
 * The primary button carries the logo's own gradient rather than a flat fill.
 * Flat orange read as a default framework button; the gradient ties the control
 * to the mark, and the pill shape plus a warm shadow makes it look pressable
 * instead of merely coloured.
 */
.btn-primary {
  background: linear-gradient(135deg, #FF6B35 0%, #F7931E 55%, #FFC02E 100%);
  color: #2A1405;
  box-shadow: 0 2px 10px -2px rgba(210, 82, 26, 0.55);
}
.btn-primary:hover { transform: translateY(-1px); filter: saturate(112%); box-shadow: 0 6px 18px -4px rgba(210, 82, 26, 0.6); }
.btn-primary:active { transform: translateY(1px); box-shadow: 0 1px 5px -1px rgba(210, 82, 26, 0.5); }
.btn:active { transform: translateY(1px); }
/* --edge, not --line: this border is the entire visual boundary of a control,
   which owes 3:1 - the old --line was 1.3:1 and the button had no edge at all */
.btn-ghost {
  background: transparent; color: var(--ink); border-color: var(--edge);
}
.on-navy .btn-ghost { color: var(--on-navy); }
.btn-ghost:hover { border-color: var(--flame); }

/* ---------- footer ---------- */
.foot { background: var(--navy); color: var(--on-navy-soft); padding-block: 52px; }
.foot a { color: var(--on-navy); text-decoration: none; }
.foot a:hover { text-decoration: underline; }
.foot .cols { display: flex; flex-wrap: wrap; gap: 40px 64px; }
/* class, not a tag selector: these were <h4> under pages whose deepest heading
   is <h2>, which is a skipped level on every page in the site. They are <h2>
   now and keep the small mono look through .foot-h. */
.foot .foot-h {
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--on-navy-soft);
  margin-bottom: 12px; font-weight: 500; line-height: 1.4;
}
.foot ul { list-style: none; padding: 0; display: grid; gap: 8px; font-size: 0.94rem; }
.foot .fine {
  margin-top: 40px; padding-top: 20px; border-top: 1px solid var(--line-navy);
  font-size: 0.85rem;
}

/* ---------- utilities ---------- */
.vh {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.alt { background: var(--paper-2); }
.cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }
.fineprint { font-size: 0.85rem; color: var(--ink-faint); margin-top: 14px; max-width: 52ch; }
.on-navy .fineprint { color: var(--on-navy-soft); }

/* ---------- hero ---------- */
.hero h1 { max-width: 15ch; }
.hero .lede { max-width: 56ch; }

/* ---------- the any-to-any picker ---------- */
.picker {
  margin-top: 40px;
  border: 1px solid var(--line-navy);
  border-radius: 10px;
  padding: clamp(18px, 3vw, 28px);
  background: var(--navy-2);
}
.picker-row { display: grid; gap: 10px; margin-bottom: 18px; }
.picker-lab {
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--on-navy-soft);
}
.chips { display: flex; flex-wrap: wrap; gap: 7px; }
.chip {
  display: inline-flex; align-items: baseline; gap: 7px;
  padding: 8px 13px;
  font: 500 0.88rem/1.2 var(--sans);
  color: var(--on-navy);
  background: transparent;
  /* --edge-navy (3.5:1) not --line-navy (1.3:1): the border is the only thing
     that says "this is a control you can pick" */
  border: 1px solid var(--edge);
  border-radius: 5px;
  cursor: pointer;
}
.chip i { font-style: normal; color: var(--on-navy-soft); font-size: 0.95em; }
.chip:hover { border-color: var(--flame-pure); }
.chip[aria-checked="true"] {
  background: var(--flame-pure);
  border-color: var(--flame-pure);
  color: #1A0E06;              /* 6.7:1 on --flame-pure */
}
.chip[aria-checked="true"] i { color: #3E2109; }   /* 5.2:1 on --flame-pure */

.result {
  display: block; margin-top: 22px; padding-top: 18px;
  border-top: 1px solid var(--line-navy);
  font-size: clamp(1.05rem, 2vw, 1.3rem); line-height: 1.5;
}
.result b { color: var(--gold); font-weight: 600; }
.result i { font-style: normal; }
.result-sub {
  display: block; margin-top: 6px;
  font-family: var(--mono); font-size: 0.78rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--on-navy-soft);
}
.result-note { color: var(--on-navy-soft); }

/* ---------- specimen table ---------- */
.specimen { border-collapse: collapse; margin-top: 34px; min-width: 460px; width: 100%; }
.specimen th, .specimen td { text-align: left; padding: 14px 20px 14px 0; border-bottom: 1px solid var(--line); }
.specimen thead th {
  font: 500 0.7rem/1 var(--mono); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-faint); padding-bottom: 10px;
}
.specimen tbody th { font-weight: 500; color: var(--ink-soft); font-size: 0.95rem; width: 1%; white-space: nowrap; }
.sp-word { font-size: clamp(1.5rem, 3.4vw, 2.1rem); line-height: 1.4; color: var(--ink); }
.specimen .num { color: var(--ink-faint); font-size: 0.9rem; }

.note {
  margin-top: 30px; padding: 18px 22px;
  border-left: 3px solid var(--flame);
  background: var(--paper-2);
  max-width: 62ch; font-size: 0.95rem; color: var(--ink-soft);
}
.note strong { color: var(--flame); }
.alt .note { background: var(--paper); }

/* ---------- two column ---------- */
.two-col { display: grid; gap: clamp(30px, 5vw, 64px); align-items: start; }
@media (min-width: 900px) { .two-col { grid-template-columns: 1fr 380px; } }

/* ---------- pronunciation card ---------- */
.score-card {
  margin: 0; padding: 22px;
  background: var(--navy); color: var(--on-navy);
  border-radius: 10px;
}
.score-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px; }
.mono-lab {
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--on-navy-soft);
}
.badge {
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--gold);
  border: 1px solid var(--line-navy); border-radius: 3px; padding: 3px 7px;
}
.score-word { font-size: 2.3rem; line-height: 1.4; margin: 0; }
.score-rom { color: var(--on-navy-soft); font-size: 0.85rem; margin-top: 4px; }
.score-gloss { color: var(--on-navy-soft); font-size: 0.9rem; margin-top: 2px; }
.syls { list-style: none; padding: 0; display: flex; gap: 8px; margin: 18px 0 0; flex-wrap: wrap; }
.syls li {
  display: flex; align-items: baseline; gap: 7px;
  padding: 7px 11px; border: 1px solid var(--line-navy); border-radius: 4px;
  font-size: 0.9rem;
}
.syls b { font-size: 0.8rem; }
.syls .ok { color: var(--good); }
.syls .low { color: var(--warn); }
.score-tip { font-size: 0.88rem; color: var(--on-navy-soft); margin-top: 18px; max-width: none; }
.score-tip strong { color: var(--flame); }
.score-card figcaption {
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line-navy);
  font-size: 0.76rem; color: var(--on-navy-soft);
}

/* ---------- facts ---------- */
.facts { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.facts div { display: grid; gap: 6px; align-content: start; }
.facts b { font-size: clamp(2rem, 4vw, 2.8rem); font-weight: 500; color: var(--flame); line-height: 1; }
.facts span { font-size: 0.92rem; color: var(--ink-soft); }

/* ---------- install dock ---------- */
.dock {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 11px var(--gutter);
  padding-bottom: calc(11px + env(safe-area-inset-bottom, 0px));
  background: var(--navy); color: var(--on-navy);
  border-top: 1px solid var(--line-navy);
  font-size: 0.88rem;
}
.dock[hidden] { display: none; }
@media (min-width: 900px) { .dock { display: none; } }

/*
 * The dock is 66px tall and fixed to the bottom, and the footer's own 52px of
 * bottom padding was not enough to clear it - the copyright line sat under it
 * at the end of every scroll. The class is set by initDock() only on the page
 * that actually has a #get anchor, so pages where the dock can never appear
 * don't grow a strip of dead space.
 */
@media (max-width: 899px) {
  .has-dock .foot { padding-bottom: calc(52px + 70px + env(safe-area-inset-bottom, 0px)); }
}

/* ---------- languages page ---------- */
.lang-grid { grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); }
.lang-card {
  border: 1px solid var(--line); border-radius: 8px;
  padding: 20px; display: grid; gap: 4px; align-content: start;
  background: var(--paper);
}
.lang-card .native { font-size: 1.9rem; line-height: 1.5; color: var(--ink); }
.lang-card .en { font-weight: 600; font-size: 1rem; }
.lang-card .script {
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-faint); margin-top: 6px;
}
.lang-card .sample { font-size: 1.05rem; color: var(--ink-soft); margin-top: 10px; }
.lang-card .sample .num { font-size: 0.82rem; color: var(--ink-faint); }

/* ---------- pricing ---------- */
/* align-items:start made every card hug its own content, so five cards with
   different numbers of bullets gave five different heights and neither the top
   nor the bottom edges lined up. Stretch, and let the card distribute its own
   contents instead. */
.tiers { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); align-items: stretch; }
.tier {
  border: 1px solid var(--line); border-radius: 8px; padding: 24px;
  display: flex; flex-direction: column; gap: 6px;
}
/* the bullet list takes the slack, so every card's border ends on the same
   line no matter how many bullets it carries */
.tier ul { flex: 1; align-content: start; }
.tier-free { border-color: var(--flame); border-width: 2px; }
/*
 * Fraunces is variable on an optical-size axis, and the browser applies it
 * automatically: at 1.35rem it was picking a text cut with thick strokes and
 * low contrast, which is why the tier names read as a different typeface from
 * the heading above them even though the family is identical.
 *
 * Pinning opsz to the display end gives them the same high-contrast character
 * as "Start free", and a step up in weight and size keeps them from looking
 * thin at card scale.
 */
.tier h2 {
  font-size: 1.5rem;
  font-weight: 700;
  font-variation-settings: 'opsz' 144;
  letter-spacing: -0.01em;
}
.tier-price { display: flex; align-items: baseline; gap: 5px; margin-top: 8px; }
.tier-price b { font-size: 2.1rem; font-weight: 500; color: var(--ink); }
.tier-price span { color: var(--ink-faint); font-size: 0.9rem; }
.tier-note { font-size: 0.84rem; color: var(--ink-faint); }
.tier ul { list-style: none; padding: 0; margin-top: 14px; display: grid; gap: 9px; font-size: 0.93rem; color: var(--ink-soft); }
.tier li { padding-left: 20px; position: relative; }
.tier li::before { content: "→"; position: absolute; left: 0; color: var(--flame); }

/* ---------- faq ---------- */
.qa h2 { font-size: clamp(1.2rem, 2vw, 1.5rem); margin-top: 44px; }
.qa h2:first-child { margin-top: 0; }
.qa p { margin-top: 10px; color: var(--ink-soft); }

/* ---------- about ---------- */
.prose p { margin-bottom: 18px; }
.prose blockquote {
  margin: 24px 0; padding-left: 20px;
  border-left: 3px solid var(--flame);
  font-family: var(--serif); font-size: 1.2rem; line-height: 1.45;
  color: var(--ink);
}
.principles { grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.principles div { border-top: 2px solid var(--flame); padding-top: 16px; }
.principles p { margin-top: 8px; font-size: 0.94rem; color: var(--ink-soft); }
.stat-band {
  border-block: 1px solid var(--line);
  padding-block: 36px;
}
/* Gold is a navy-ground colour: 12.7:1 there and 1.3:1 on cream. Every h1 em on
   the site is currently inside .on-navy, but the unscoped rule meant the first
   emphasised heading written on a cream section would be invisible. */
h1 em { font-style: italic; color: var(--flame); }
.on-navy h1 em { color: var(--gold); }

/* ---------- legal / support ---------- */
.legal .wrap { max-width: 780px; }
.legal h1 { font-size: clamp(2rem, 4.5vw, 3rem); margin-bottom: 10px; }
.legal h2 { font-size: clamp(1.15rem, 2vw, 1.4rem); margin-top: 38px; margin-bottom: 10px; }
.legal h3 { font-size: 1.02rem; margin-top: 24px; margin-bottom: 6px; }
.legal p, .legal li { color: var(--ink-soft); font-size: 0.97rem; }
.legal p { margin-bottom: 10px; }
.legal ul { margin: 0 0 16px 22px; display: grid; gap: 6px; }
.legal .updated { color: var(--ink-faint); font-size: 0.86rem; margin-bottom: 26px; }
.legal .contact {
  background: var(--paper-2); border-left: 3px solid var(--flame);
  padding: 20px 24px; margin: 24px 0 32px; border-radius: 0 6px 6px 0;
}
.legal .contact .email { font-size: 1.05rem; font-weight: 700; }

/* ---------- certificate verification ---------- */
.verify-wrap {
  max-width: 720px;
  /* .wrap centres its own box; without this the form block floats to the
     middle while the hero above it stays left-aligned */
  margin-inline: 0;
}
.verify-wrap label { display: block; font-weight: 600; margin-bottom: 4px; }
.field-hint { font-size: 0.88rem; color: var(--ink-faint); margin-bottom: 12px; }
.field-row { display: flex; flex-wrap: wrap; gap: 10px; }
.field-row input {
  flex: 1 1 260px;
  font: 500 1rem/1 var(--mono);
  letter-spacing: 0.04em;
  padding: 13px 14px;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--edge, var(--line));
  border-radius: 6px;
}
.field-row input::placeholder { color: var(--ink-faint); letter-spacing: 0.04em; }

.verify-result { display: block; margin-top: 30px; }
.verify-result:empty { display: none; }
.verify-result h2 { font-size: clamp(1.4rem, 2.6vw, 1.9rem); }
.verify-result p { margin-top: 10px; color: var(--ink-soft); }
.verify-result.is-good { border-left: 3px solid var(--good); padding-left: 20px; }
.verify-result.is-good h2 { color: var(--good); }
.verify-result.is-bad { border-left: 3px solid var(--flame); padding-left: 20px; }
.verify-result.is-busy { color: var(--ink-faint); }

.cert { display: grid; grid-template-columns: auto 1fr; gap: 8px 22px; margin-top: 18px; }
.cert dt {
  font: 500 0.7rem/1.6 var(--mono); letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-faint);
}
.cert dd { margin: 0; color: var(--ink); }

/* ---------- pricing controls ---------- */
.price-controls { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 34px; }
.seg {
  display: inline-flex; gap: 2px; padding: 3px;
  border: 1px solid var(--edge, var(--line)); border-radius: 8px;
  background: var(--paper-2);
}
.seg button {
  font: 600 0.88rem/1 var(--sans);
  padding: 10px 15px; border: 0; border-radius: 6px;
  background: transparent; color: var(--ink-soft); cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
}
.seg button[aria-checked="true"] { background: var(--navy); color: var(--on-navy); }
.seg .save {
  font: 500 0.68rem/1 var(--mono); letter-spacing: 0.06em;
  padding: 4px 7px; border-radius: 4px;
  background: var(--good); color: var(--paper);
}
.seg button[aria-checked="true"] .save { background: var(--flame-pure); color: #1A0E06; }
.sr-price-status {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
.tiers {
  /* five tiers must sit on one row at desktop width, or Free and Pro+ end up on
     different rows and the ladder stops reading as a ladder */
  grid-template-columns: repeat(auto-fit, minmax(178px, 1fr));
  gap: clamp(14px, 1.6vw, 22px);
}

/* ---------- theme toggle ---------- */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0;
  color: var(--ink-soft);
  background: transparent;
  border: 1px solid var(--edge, var(--line));
  border-radius: 999px;
  cursor: pointer;
  transition: color 0.14s ease, border-color 0.14s ease;
}
.theme-toggle:hover { color: var(--flame); border-color: var(--flame); }

/* ---------- inner-page heads ---------- */
/*
 * The home hero earns its height - it carries the picker and both store
 * buttons. An inner page's navy band carries a heading and one paragraph, and
 * at the same padding it pushed the actual content (prices, language cards)
 * below the fold on a laptop. Tighter band, and the section under it starts
 * sooner.
 */
.section.on-navy:not(.hero) {
  padding-block: clamp(36px, 4.5vw, 62px);
}
.section.on-navy:not(.hero) + .section {
  padding-top: clamp(30px, 3.5vw, 52px);
}
.section.on-navy:not(.hero) h1 {
  font-size: clamp(2.1rem, 4.6vw, 3.3rem);
}

/* ---------- phone masthead ---------- */
/*
 * At 375-390 the header carries brand + theme toggle + CTA, and the CTA was
 * wrapping onto two lines inside its own pill. Tightening the gaps and the
 * button padding buys enough room to keep it on one line; nowrap makes sure it
 * stays there rather than wrapping again at some in-between width.
 */
.btn { white-space: nowrap; }

@media (max-width: 460px) {
  .masthead .wrap { gap: 10px; }
  .masthead .nav { gap: 10px; }
  .brand { font-size: 1.12rem; gap: 7px; }
  .brand svg { width: 22px; height: 23px; }
  .masthead .btn { padding: 11px 15px; font-size: 0.86rem; }
  .theme-toggle { width: 32px; height: 32px; }
}
