/* Semantic tokens — spacing and radius, salamcendekia-blog
 *
 * Components reference THESE, never `--space-N` or `--radius-*`. Same rule as
 * the colour and typography tiers, and the same reason: `checks/literals.py`
 * catches a raw `16px` but not a primitive used where a semantic token
 * belongs, because a primitive is still a token.
 *
 * THE NAMES ARE ROLES, and the roles come from what a reading page is made of
 * rather than from a guess at what components might want. A blog page has four
 * spacing questions and no more:
 *
 *   between paragraphs        the rhythm of the body copy
 *   before a heading          the gap that makes structure visible
 *   inside a card or callout  padding on a contained thing
 *   between page sections     the rhythm of the page itself
 *
 * `base` derives its names from measured template usage, which this system
 * cannot do yet — it has no templates. So these are derived from the SURFACE
 * instead: the landing page's own section rhythm (88px, 14 uses at source) and
 * card padding (24px, the most-used value at 33 uses) are carried over, and
 * the article-body values follow from the type scale rather than from that
 * page, which has no article on it.
 *
 * REVISIT THESE WHEN #89 LANDS. If a component reaches for a primitive because
 * no role fits, the missing role is a bug in this file, not a reason to skip
 * the tier.
 */

:root {
  /* Article body rhythm.
     Paragraph spacing is 0.75 of the body leading (31px) rather than a grid
     step: paragraph gaps are read against the line spacing around them, and a
     gap equal to a full line makes the text look double-spaced. */
  --space-paragraph: var(--space-6);      /* 24px — between paragraphs */
  --space-before-heading: var(--space-12); /* 48px — above an h2, twice the
                                              paragraph gap so structure reads
                                              before the words do */
  --space-after-heading: var(--space-4);   /* 16px — a heading belongs to what
                                              follows it, so this is tighter */
  --space-list-item: var(--space-3);       /* 12px — between list items */

  /* Contained things — cards, callouts, pull quotes. 24px is the landing
     page's most-used value (33 of 261 uses). */
  --space-card: var(--space-6);
  --space-card-gap: var(--space-4);        /* between items inside a card */

  /* Page rhythm. 88px is the landing page's section padding (90px at source,
     14 uses), which is the one large value there used often enough to be a
     decision rather than a one-off. */
  --space-section: var(--space-22);
  --space-section-tight: var(--space-14);  /* 56px — between related sections */

  /* Site chrome */
  --space-chrome-x: var(--space-6);        /* header/footer horizontal padding */
  --space-chrome-y: var(--space-5);        /* header/footer vertical padding */
  --space-inline: var(--space-2);          /* gap inside one control or link row */

  /* Radius by role. Four steps because the source's eight were surface-by-
     surface styling rather than a scale — see the primitives file. */
  --radius-rule: var(--radius-sm);         /* dividers, a pull-quote's rule */
  /* NO COMPONENT USES THIS TODAY -- #116, and the honest note is more useful
     than quietly deleting it.

     It was `.site-menu`'s radius. #116 made that control a `pill-quiet` and
     moved it to `--radius-pill`, on the argument that two adjacent controls at
     one height with different corner radii read as an inconsistency rather
     than a hierarchy. So every control in this system is now a pill and this
     role has no occupant.

     KEPT RATHER THAN DELETED, because the role is real and unrendered rather
     than wrong: an input or a tag is a plausible near-term component here and
     neither should be a 9999px pill. It is recorded as unused so a reader does
     not infer from its presence that something renders it -- the inference
     `--radius-pill` itself invited between #86 and #114. */
  --radius-control: var(--radius-md);      /* inputs, tags -- UNUSED, see above */
  --radius-card: var(--radius-lg);         /* cards, callouts, images */
  /* Declared in #86 for "avatars, category pills", unused until #114, and since
     #116 the radius of EVERY control in this system.

     The note here used to distinguish it from `--radius-control` by saying "the
     header CTA is a pill and its in-article sibling is a rounded rectangle."
     That was already wrong when written: #114 gave the in-article CTA
     `--radius-pill` in the same change, so the two were never the pair this
     comment described. Corrected in #116 rather than left, because a semantic
     file explaining a distinction the components do not draw is the kind of
     stale record this repository keeps finding. */
  --radius-pill: var(--radius-full);

  /* Focus ring geometry.
     ADDED IN #89, which is the case this file's header describes: a component
     reached for a value and no role fit. `--color-focus` existed from #86, so
     the ring had a colour and no width or offset -- and a focus ring cannot be
     written without both. The alternatives were a raw `2px` in the component
     (the literal `checks/literals.py` exists to reject) or a primitive
     (`checks/literals.py` cannot see, which is the omission review of #49
     found 50 times in `base`). So the roles are added here, as the README
     instructs.

     THE OFFSET IS NOT DECORATION. `base` records why: flush against an
     element's own border the ring merges into it and stops reading as focus.
     A blog page's focusable things are links in running text, where the ring
     must clear descenders on the line below. */
  --focus-ring-width: var(--space-1);      /* 4px -- see below */
  --focus-ring-offset: var(--space-1);     /* 4px */

  /* The hairline.
     ALSO ADDED IN #89, and found the same way but later: `post-card` needed a
     1px border and there was no role, so the component named a `--space-px`
     that did not exist. Every check stayed green -- `literals.py` sees a
     `var()` and asks no more, which its own docstring says plainly ("THE WRONG
     TOKEN ... passes here and always will"), and `tokens.py` does not read
     this system. The border simply rendered as nothing.

     It is a BORDER WIDTH, not a spacing step. `base` keeps
     `primitives/border-width.css` separate for that reason: 1px is not on the
     4px grid and never will be, and putting it there would be the second grid
     that `literals.py`'s docstring records accumulating in `base` -- three
     values on a 2px grid among 47 on a 4px one, chosen by nobody.

     Declared as a literal rather than through a primitive because this system
     has no border-width primitive file to hold one value, and inventing a
     scale from a single member would imply steps that were never designed --
     the same argument `primitives/color.css` makes for not remapping the
     `--sc-*` names onto a ramp. */
  --border-hairline: 1px;

  /* The pull-quote's rule. Thick enough to read as a mark rather than a
     divider, which is what separates a quotation from a section break.
     A THIRD border role rather than a reuse: `--focus-ring-width` happens to
     be the same 4px today, and borrowing it would mean a change to the focus
     ring silently restyled every blockquote in the system. */
  --border-quote: var(--space-1);

  /* The minimum hit target.
     ADDED IN #90 -- the first component in this system with a control. A
     reading surface had none until the site header needed a menu button, so
     there was no role and `site-header` reached for a `--control-target` that
     did not exist. Caught by the undefined-var() probe from #98, not by any
     check: `literals.py` sees a var() and asks no more.

     44px is WCAG 2.5.5 Level AAA and the floor `checks/targets.mjs` measures.
     2.5.8 (AA) asks only 24px, and the higher bar is taken because a blog is
     read on a phone with a thumb, which is the case AAA exists for.

     NOT ON THE SPACING GRID, deliberately. 44 is not a multiple of 4 by
     accident of arithmetic -- it is a number from the spec, and rounding it to
     48 to fit the grid would be choosing tidiness over the reason the value
     exists. `base` keeps its control sizes in a separate primitive file for the
     same reason. */
  --control-target: 2.75rem;

  /* THE BRAND MARK'S SIZE IN THE NARROW HEADER.
     ADDED IN REVIEW OF #132, which caught the mark being sized by
     `--control-target`. The value wanted was 44px and that token happened to
     hold it -- but it names a HIT TARGET, the minimum a finger needs, and a
     brand mark is not a control. Borrowing a token for its value rather than
     its meaning is how a rebrand stops being a token swap: change the
     hit-target floor and the brand would resize with it, for a reason nobody
     could reconstruct.

     It is the same 44px today, deliberately: the mark sits in a row with the
     menu button and matching their heights is what keeps that row level. They
     are equal by intent rather than by accident, and now they can diverge. */
  --size-brand-mark: 2.75rem;
}

/* WHY 4px AND NOT 2px, which is the usual web default.
   The ring is drawn in `--color-focus`, which measures 3.31:1 against the
   background -- above WCAG 1.4.11's 3.0 for a non-text indicator, but not far
   above. A 2px ring at that ratio is legible; a 4px one is unmissable, and
   `--space-1` is the grid step that already exists rather than a new value
   invented for this. The alternative -- a darker ring -- was rejected in #86:
   `--color-focus` is `--sc-blue-light` precisely so the ring stays visible ON
   `--color-primary`, which the primary blue itself would not be. */
