/* ============================================================================
   type-scale.css -- the IBIX house fluid type scale.
   Written 2026-08-01.

   WHAT THIS IS
   One ladder of nine steps, each a clamp() that interpolates between a 360px
   and a 1440px viewport. No font-size media queries anywhere on the site, ever
   again. Plus the line-height, measure and RTL overrides that make the ladder
   safe in both languages.

   SATISFIES (design/CHECKLISTS.md section B -- foundations)
   - Every fluid value contains a rem term; no bare vw sizing anywhere, so the
     scale still tracks a user's default-font-size setting (R 02 section 2.1).
   - Both ends of every step are arithmetically verified and written into the
     comment beside it.
   - /ar/ routes clear the 18.7px Arabic body floor at every viewport width (D-5).
   - Arabic body line-height is 1.7 and Arabic is never letter-spaced (D-4, D-12).
   - Nothing here sets a fixed height on a text container, so the layout survives
     the WCAG 1.4.12 user-override tolerances (F-29).
   Assertion IDs back-fill when section B is numbered; the assertions are the contract.

   LOAD ORDER (matters)
       ibix-base.css -> tokens-template.css -> fonts.css -> type-scale.css
       -> layout-primitives.css -> the site's own stylesheet
   type-scale.css must come after ibix-base.css: it re-states the RTL heading
   font-family rule at equal specificity, so the later file has to be this one.

   HOW THE NUMBERS WERE MADE (R 02 section 1 -- reproduce, don't guess)
       slope        = (maxPx - minPx) / (maxViewportPx - minViewportPx)
       interceptPx  = minPx - slope * minViewportPx
       vwCoefficient= slope * 100
       font-size: clamp(min/16 rem, calc(intercept/16 rem + vwCoefficient vw), max/16 rem)
   Anchors: 360px and 1440px viewports. Every step below was evaluated at BOTH
   anchors and the result written into its comment. If you add a step, do the
   same or do not add it.

   Corpus: R 02 sections 1/2/3/11, R 01 sections 3/7, R 11 sections 6/8,
   D-4, D-5, D-12, D-23, F-14, F-28, F-29, F-73, B-13, B-48.
   ========================================================================= */

:root {
  /* -- THE LADDER ---------------------------------------------------------
     Two-value fluid scale (min and max set independently per step), not one
     ratio stretched by a multiplier: headings and body do not need to grow at
     the same rate, and a single ratio forces them to (R 02 section 1).
     Mobile ratio runs tighter than desktop, which is the whole point.

     step        min      max      measured @360 / @1440      typical use     */
  --step--2: clamp(0.75rem, calc(0.729rem + 0.093vw), 0.812rem);   /* 12.00 / 13.00  legal, fine print */
  --step--1: clamp(0.875rem, calc(0.854rem + 0.093vw), 0.938rem);  /* 14.00 / 15.00  UI, captions, labels */
  --step-0:  clamp(1rem, calc(0.958rem + 0.185vw), 1.125rem);      /* 16.00 / 18.00  BODY */
  --step-1:  clamp(1.188rem, calc(1.125rem + 0.278vw), 1.375rem);  /* 19.00 / 22.00  lead paragraph, h4 */
  --step-2:  clamp(1.375rem, calc(1.25rem + 0.556vw), 1.75rem);    /* 22.00 / 28.00  h3 */
  --step-3:  clamp(1.625rem, calc(1.438rem + 0.833vw), 2.188rem);  /* 26.01 / 35.00  h2 */
  --step-4:  clamp(1.938rem, calc(1.667rem + 1.204vw), 2.75rem);   /* 31.01 / 44.00  h1 on inner pages */
  --step-5:  clamp(2.25rem, calc(1.854rem + 1.759vw), 3.438rem);   /* 36.00 / 54.99  section statement */
  --step-6:  clamp(2.5rem, calc(1.5rem + 4.444vw), 5.5rem);        /* 40.00 / 87.99  hero display */

  /* Why step-6 jumps: R 02 section 2.3 wants roughly 2:1 or more between a
     fluid step's min and max so the value is not already pinned at its ceiling
     the moment someone zooms. Text steps cannot honour that (body is 1.12:1 by
     nature and that is correct); the DISPLAY step can and does -- 2.20:1.
     Practitioner rule of thumb, MEDIUM confidence, costs nothing.

     For a full-viewport hero headline use ibix-base.css's .hero-display
     instead: it sizes by min(vw, vh) so a wide-but-short laptop does not push
     the CTA below the fold. That bug has shipped twice. */

  /* -- SEMANTIC ALIASES ---------------------------------------------------
     Components reference these, not the raw steps, so a rebrand can move the
     whole page one step without touching a single component. */
  --text-fine: var(--step--2);
  --text-ui: var(--step--1);
  --text-body: var(--step-0);
  --text-lead: var(--step-1);
  --text-h4: var(--step-1);
  --text-h3: var(--step-2);
  --text-h2: var(--step-3);
  --text-h1: var(--step-4);
  --text-statement: var(--step-5);
  --text-display: var(--step-6);

  /* -- LINE HEIGHT --------------------------------------------------------
     1.5 for Latin body is good practice, NOT a WCAG floor. SC 1.4.12 sets no
     authored minimum -- it requires the layout to survive a user forcing 1.5x
     (F-29, B-13). Never call it a "WCAG hard floor" to a client. */
  --lh-latin: 1.5;
  --lh-arabic: 1.7;    /* D-4: the single canonical Arabic body value, ~+13%
                          over Latin. [convention -- single practitioner source,
                          freezil.com; no foundry or standard publishes a
                          number. W3C ALReq confirms the mechanism only.] D-23. */
  --lh-long: 1.65;     /* long-form editorial, or any measure past ~75 chars */
  --lh-ui: 1.3;        /* buttons, nav, short strings that rarely wrap */
  --lh-display: 1.08;  /* 36px+ display. Tight leading is standard at display
                          sizes; loose leading reads as broken rhythm, not
                          breathing room (R 02 section 3, practitioner consensus). */

  /* -- MEASURE ------------------------------------------------------------
     50-75 characters is the converged practitioner range; 80 is WCAG 1.4.8,
     which is Level AAA, best practice we follow rather than an AA requirement
     (F-28). There is NO Baymard percentage for line length -- that statistic is
     folklore and is banned (B-1).
     The page shell max-width is a SEPARATE decision, set in
     layout-primitives.css -- do not cap a whole page at the prose measure. */
  --measure: 65ch;
  --measure-narrow: 50ch;
  --measure-wide: 75ch;

  /* -- TRACKING -----------------------------------------------------------
     Slight negative tracking on large grotesk display type only. Never applied
     to body copy, and never to Arabic at any size (see the RTL block). */
  --tracking-display: -0.02em;
  --tracking-eyebrow: 0.08em;

  /* -- FAMILIES -----------------------------------------------------------
     Declared in fonts.css; re-stated here as the names this file expects.
     Keep the fallback stacks in fonts.css, not duplicated here. */
  --font-body: var(--font-body-latin, system-ui, sans-serif);
  --font-display: var(--font-display-latin, var(--font-body));
}

/* Do not set a px font-size on :root. The root rem is the user's accessibility
   setting; overriding it is how a "16px base" quietly becomes an unzoomable
   page. This rule exists to say so -- it is deliberately a no-op. */
html { font-size: 100%; }

body {
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: var(--lh-latin);
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  line-height: var(--lh-display);
  text-wrap: balance;      /* progressive enhancement: ignored where unsupported */
}
h1 { font-size: var(--text-h1); letter-spacing: var(--tracking-display); }
h2 { font-size: var(--text-h2); letter-spacing: var(--tracking-display); }
h3 { font-size: var(--text-h3); }
h4 { font-size: var(--text-h4); line-height: var(--lh-ui); }

.text-display {
  font-family: var(--font-display);
  font-size: var(--text-display);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-display);
}
.text-lead { font-size: var(--text-lead); line-height: var(--lh-long); }
.text-ui { font-size: var(--text-ui); line-height: var(--lh-ui); }
.text-fine { font-size: var(--text-fine); line-height: 1.45; }

/* Prose container. max-width, never a fixed width or height -- a fixed-height
   text box is precisely what breaks under the 1.4.12 user overrides (F-29). */
.prose { max-width: var(--measure); }
.prose > * + * { margin-block-start: 1em; }
.prose p { text-wrap: pretty; }

/* Eyebrow / kicker. Tracked out on purpose -- and switched off for Arabic below. */
.eyebrow {
  font-size: var(--text-ui);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

/* ===========================================================================
   RTL / ARABIC OVERRIDES
   Everything below is a real bug that shipped on day one of a bilingual build,
   not a stylistic preference.
   ======================================================================== */

[dir="rtl"] {
  /* D-5, THE ONE THAT MATTERS. The Latin body step is 16px at 360px, which is
     BELOW the ~14pt (18.67px) Arabic body floor at every viewport width, so
     /ar/ routes must not inherit it. Machine-verified at both anchors with the
     formula above: 18.70px at 360px, 20.00px at 1440px -- at or above the floor
     everywhere. Headings and UI text keep the shared ladder.
     The floor itself is a HOUSE RULE [convention -- single practitioner source
     (freezil.com); no foundry or standards body publishes one] (D-23, B-48).
     qa.py assertion: on /ar/ routes, body computes >=18.7px at 360px width. */
  --step-0: clamp(1.169rem, calc(1.142rem + 0.12vw), 1.25rem);

  /* Arabic needs the vertical room: ALReq confirms Arabic ascenders and
     descenders extend much further than Latin's (qualitative, HIGH). */
  line-height: var(--lh-arabic);

  /* `ch` is derived from the "0" glyph of the LATIN font, so 65ch does not
     transfer to an Arabic column -- and Arabic runs ~20% longer per the
     planning heuristic. Set this by eye against the real face; the value below
     is [judgement], and R 11 section 6 leaves it explicitly open. */
  --measure: 58ch;

  /* Latin display faces (Bebas, Archivo, Saira) carry NO Arabic glyphs, so an
     Arabic heading silently falls back to an ugly system default. Pair a Kufi
     display face with a Naskh/geometric body face -- they are different design
     categories and are not interchangeable (F-73). */
  --font-display: var(--font-display-ar, var(--font-body-ar, var(--font-body)));
  --font-body: var(--font-body-ar, system-ui, sans-serif);

  /* Compatibility bridge: ibix-base.css's own RTL heading rule reads var(--body).
     Aliasing it here means that rule resolves correctly whichever file loads
     last, so the two guardrails cannot fight each other. */
  --body: var(--font-body-ar, system-ui, sans-serif);
}

[dir="ltr"] body { line-height: var(--lh-latin); }
[dir="rtl"] body { line-height: var(--lh-arabic); }

/* Arabic letters join cursively; tracking visually breaks the joins, and Blink
   and Gecko additionally implemented letter-spacing incorrectly for RTL runs.
   Script-level reason alone makes this a "never", not a "be careful" (D-12,
   R 11 section 8). ibix-base.css enforces it globally with !important; this
   rule keeps the intent visible at the point where tracking is applied. */
[dir="rtl"] .eyebrow,
[dir="rtl"] h1,
[dir="rtl"] h2,
[dir="rtl"] .text-display { letter-spacing: normal; }

/* Do NOT uppercase Arabic -- the script has no case, so text-transform is a
   no-op at best and a signal that the CSS was never reviewed for /ar/. */
[dir="rtl"] .eyebrow { text-transform: none; }

/* ---------------------------------------------------------------------------
   FORBIDDEN IN THIS LAYER
   1. A clamp() preferred value with no rem term (e.g. font-size: 5vw). It is
      blind to the user's default-font-size setting (R 02 section 2.1).
   2. font-size inside a media query. That is what the ladder replaced. Media
      queries are for ARRANGEMENT (column counts, nav collapsing), clamp() is
      for MAGNITUDE (R 01 section 3).
   3. Overriding :root font-size in px.
   4. Any fixed height on an element containing text -- it breaks under the
      1.4.12 user overrides the site is required to survive (F-29).
   5. Telling a client that 1.5 line-height is a WCAG requirement. It is not
      (B-13). Nor is any px font-size minimum (F-28).
   6. Letter-spacing or text-transform on Arabic (D-12).
   7. A number for "Arabic runs N% larger" presented as consensus. All three
      Arabic figures in circulation trace to ONE practitioner blog (B-48);
      the house position is the two tokens above, labelled as convention.

   QA THIS LAYER
   - Ctrl/Cmd + "+" to 200% zoom on a real browser, then 400%. Resizing the
     window is NOT the same test as zooming and does not satisfy SC 1.4.4
     (R 02 section 2.2).
   - Force the 1.4.12 overrides (0.12em letter, 0.16em word, 1.5 line, 2x
     paragraph) and confirm nothing clips or overlaps -- on /ar/ too (D-12).
   - qa.py at 360px on an /ar/ route: computed body font-size >= 18.7px.
   ------------------------------------------------------------------------ */
