/* ─────────────────────────────────────────────────────────────────────────────
   Bench foundation — the shared type scale, measure, and accessibility floor.

   Served at: _content/TechBenchEco.Blazor.Common/bench-foundation.css

   WHY THIS EXISTS
   Two independent UX audits (WebGuard desktop 2026-09-06, Spark.Web 2026-09-05)
   found the same defect from opposite directions:

     · WebGuard ships 32 distinct ad-hoc font sizes against 16 uses of its token
       scale — and 20 of the 32 sit between 0.6rem and 0.9rem. Twenty sizes in a
       five-pixel band means nothing CAN look more important than anything else,
       so no restructure of that app has ever made it feel lighter.
     · Spark.Web renders two visual eras and four different "this one is
       selected" languages, one click apart.

   Both are the same missing thing: a scale nobody can bypass by accident. This
   file is that scale, plus the two accessibility rules both apps were short of
   (Spark.Web had 4 :focus-visible rules and 3 prefers-reduced-motion blocks
   across 121 components).

   WHAT THIS FILE MUST NEVER DO — THE THEMING CONTRACT
   It imposes NO palette. guided.css documents the rule and
   GuidedThemingContractTests pins it: the hosts have different token systems
   (Spark.Web --sk-*, WebGuard --color-*, QaToolKit --shell-*, plus signature
   skins that restyle everything), so a colour declared here would either break
   a host or kill its skins.

   Every colour below therefore resolves through the SAME four-rung chain
   guided.css established, in the same order:

       var(--guided-X, var(--shell-X, var(--color-X, <literal>)))

   Sizes and spacing are host-neutral and ARE declared here — that is the whole
   point. A host that wants different numbers overrides the token, not the rule.

   LOAD ORDER: after the host's own token/app CSS (so its --color- and --sk-
   variables exist for the chain to find) and before any signature-skin layer
   (so a skin still wins).

   ⚠ DO NOT write a glob like `--color-<star>/` in a comment in this file. The
   `<star>/` sequence CLOSES the comment early, after which the remaining prose
   is parsed as a selector and the :root block below is swallowed as its body.
   That exact typo shipped here once: the file loaded, 22 rules parsed, nothing
   errored in the console, and the ENTIRE token layer was silently missing.
   ───────────────────────────────────────────────────────────────────────────── */

:root {
    /* ── Type scale ───────────────────────────────────────────────────────────
       The fix is NOT a bigger ratio. It is that there are THREE sizes at or
       below body instead of twenty. Steps of 2px are perfectly discernible in
       UI type; twenty steps averaging 0.25px apart are not discernible by
       anyone, which is the actual defect being repaired.

       Ratios widen toward the display end (1.18, 1.15, 1.13, 1.18, 1.4) because
       that is where a jump has to carry rank across whitespace, while the small
       end only has to separate three tiers sitting adjacent.

       EXACTLY ONE MULTIPLIER. rem, so the host's text-size preference (WebGuard
       sets html[data-text-size] to 14/16/18px; it is an accessibility control
       and must keep working) scales the whole ramp coherently. What must NOT
       happen is a SECOND multiplier on top — a density modifier that also
       re-declares font sizes is how 0.72rem and 0.73rem came to exist in the
       same file. Density owns spacing here, and nothing else.

       Comments give the px at a 16px root. */
    --bench-t-display:   1.75rem;    /* 28px — the one verdict on a screen, and nothing else */
    --bench-t-title:     1.25rem;    /* 20px — section heads */
    --bench-t-lead:      1.0625rem;  /* 17px — a card's own heading, inside a section */
    --bench-t-body:      0.9375rem;  /* 15px — prose, finding text, table cells */
    --bench-t-secondary: 0.8125rem;  /* 13px — supporting lines, metadata, captions */
    --bench-t-label:     0.6875rem;  /* 11px — eyebrows and column heads ONLY, always caps + tracking */
    --bench-t-mono:      0.78125rem; /* 12.5px — URLs, selectors, command lines, raw output */

    --bench-lh-tight: 1.25;
    --bench-lh-body:  1.6;
    --bench-label-tracking: 0.08em;

    /* ── Measure ──────────────────────────────────────────────────────────────
       WebGuard's .app-shell-center has no max-width, so on a 1400px window its
       report prose runs to ~150 characters per line against a comfortable range
       of 45-75. Applied via .bench-measure rather than globally, because tables,
       command output and diagrams legitimately want the full width. */
    --bench-measure: 68ch;

    /* ── Focus ring ───────────────────────────────────────────────────────────
       Resolved through the chain, so each host's own accent draws it. */
    --bench-focus-ring: var(--guided-accent, var(--shell-accent, var(--color-primary, #6366f1)));
    --bench-focus-width: 2px;
    --bench-focus-offset: 2px;
}

/* ── Type utilities ───────────────────────────────────────────────────────────
   Named for ROLE, not size, so a later change to the scale doesn't require
   renaming call sites. */
.bench-display   { font-size: var(--bench-t-display);   line-height: var(--bench-lh-tight); letter-spacing: -0.015em; }
.bench-title     { font-size: var(--bench-t-title);     line-height: var(--bench-lh-tight); letter-spacing: -0.008em; }
.bench-lead      { font-size: var(--bench-t-lead);      line-height: var(--bench-lh-tight); }
.bench-body      { font-size: var(--bench-t-body);      line-height: var(--bench-lh-body); }
.bench-secondary { font-size: var(--bench-t-secondary); line-height: var(--bench-lh-body); }
.bench-label {
    font-size: var(--bench-t-label);
    line-height: var(--bench-lh-tight);
    letter-spacing: var(--bench-label-tracking);
    text-transform: uppercase;
    font-weight: 600;
}
.bench-mono {
    font-size: var(--bench-t-mono);
    font-family: var(--font-mono, ui-monospace, "Cascadia Code", Consolas, monospace);
}

/* Headings inside a bench-scoped region take the scale rather than the browser's
   own h1..h6 ramp, which is what let two visual eras coexist page-to-page. */
.bench-measure { max-width: var(--bench-measure); }

/* Digits that line up in columns must not jitter between rows. Cheap, and it is
   the difference between a table you can scan and one you have to read. */
.bench-num { font-variant-numeric: tabular-nums; }

/* ── State ramp ───────────────────────────────────────────────────────────────
   FOUR states, not three. "didn't run" is a first-class member and must never
   read as a pass — a skipped check rendering green is the false-green class the
   whole WebGuard product exists to prevent, and it is the one state both apps
   were collapsing into either grey-as-good or grey-as-nothing. The dashed
   border carries it non-chromatically, so it survives every theme and reads for
   colour-blind users. */
.bench-state {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--bench-t-label);
    letter-spacing: var(--bench-label-tracking);
    text-transform: uppercase;
    font-weight: 600;
    padding: 3px 8px;
    border-radius: 3px;
    border: 1px solid transparent;
}
.bench-state-pass {
    color: var(--guided-ok, var(--shell-success, var(--color-success, #16a34a)));
    background: var(--color-success-soft, rgba(34, 197, 94, 0.12));
}
.bench-state-warn {
    color: var(--guided-warn, var(--shell-warning, var(--color-warning, #d97706)));
    background: var(--color-warning-soft, rgba(245, 158, 11, 0.12));
}
.bench-state-fail {
    color: var(--guided-bad, var(--shell-danger, var(--color-danger, #dc2626)));
    background: var(--color-danger-soft, rgba(239, 68, 68, 0.12));
}
.bench-state-didnotrun {
    color: var(--guided-muted, var(--shell-text-muted, var(--color-text-muted, #8b8d97)));
    background: transparent;
    border-style: dashed;
    border-color: var(--guided-border-hi, var(--shell-border-strong, var(--color-border-strong, #475569)));
}

/* ── Severity ramp ────────────────────────────────────────────────────────────
   Instruction words, not adjectives. "Blocks" tells the reader what to do;
   "Critical" asks them to interpret a scale they were never given. Deliberately
   parallel to the state ramp above but a SEPARATE vocabulary — conflating "this
   check failed" with "this finding blocks the release" is how a report ends up
   with six competing answers to one question. */
.bench-sev {
    display: inline-flex;
    align-items: center;
    font-size: var(--bench-t-label);
    letter-spacing: var(--bench-label-tracking);
    text-transform: uppercase;
    font-weight: 600;
    padding: 3px 8px;
    border-radius: 3px;
}
.bench-sev-blocks     { color: var(--guided-bad,  var(--shell-danger,  var(--color-severity-critical, #dc2626))); background: var(--color-danger-soft,  rgba(239, 68, 68, 0.12)); }
.bench-sev-shouldfix  { color: var(--guided-warn, var(--shell-warning, var(--color-severity-high,     #d97706))); background: var(--color-warning-soft, rgba(245, 158, 11, 0.12)); }
.bench-sev-worthknowing { color: var(--guided-muted, var(--shell-text-muted, var(--color-text-muted, #8b8d97))); background: var(--color-surface-2, rgba(127, 127, 127, 0.1)); }
.bench-sev-info       { color: var(--guided-accent, var(--shell-accent, var(--color-info, #0ea5e9))); background: var(--color-info-soft, rgba(14, 165, 233, 0.12)); }

/* ── Accessibility floor ──────────────────────────────────────────────────────
   Global, and deliberately so. Spark.Web had 4 :focus-visible rules across 121
   components; WebGuard set focus per-control in components.css and missed every
   inline-styled control (of which there are 1,527). A single global rule is the
   only version of this that cannot be forgotten by the next component.

   :focus-visible, not :focus — a mouse click on a button should not draw a ring. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: var(--bench-focus-width) solid var(--bench-focus-ring);
    outline-offset: var(--bench-focus-offset);
    border-radius: 2px;
}

/* Keyboard users must be able to see where they are even inside a scroll pane
   whose overflow would otherwise clip the ring. */
:where(a, button, [tabindex]):focus-visible {
    scroll-margin: 16px;
}

@media (prefers-reduced-motion: reduce) {
    /* Not `*` with !important on transition alone — a zeroed transition-duration
       on an element mid-animation can leave it stuck at a keyframe. Both
       properties, both reset, so anything animating lands at its end state. */
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}
