/* Foundation base (UI_SPEC §1). Everything visual references tokens.css — no literals here. The
   loading splash and Blazor error UI hooks (required by index.html) are kept, restyled to tokens. */

*, *::before, *::after { box-sizing: border-box; }

/* rem basis = 16px. The mockups render at a 16px html root, so their rem values — and our px tokens,
   which ARE those rem values computed at 16px (--text-sm 13px = 0.8125rem, the brand wordmark
   0.9375rem = 15px) — assume it. The mockups then set the .syn wrapper's base TEXT to 0.875rem = 14px
   (= --text-base), which `body` mirrors below. Putting 14px on `html` itself silently shrank every
   rem-based value in the ported CSS to 87.5% — the pervasive-undersizing bug. */
html { font-size: 16px; }
/* The R10 TEXT-SIZE-LAW root switch (Q208; RATIFIED Ken 2026-08-17): Settings › Appearance › Text
   size scales the app by THIS mechanism and no other. S/M/L/XL = 0.9/1.0/1.1/1.2 of the 16px root —
   READING-class text (declared in rem at port) reflows within unchanged geometry; CHROME-class text
   (micro-labels, badges, riders, tags, count-dots, rail text, tab/button labels, stamps, mono
   tokens — literal px at port) never scales. M carries no attribute: the comps' exact rendering. */
html[data-text-scale="s"] { font-size: 14.4px; }
html[data-text-scale="l"] { font-size: 17.6px; }
html[data-text-scale="xl"] { font-size: 19.2px; }

body {
    margin: 0;
    font-family: var(--kit-body-font-family, var(--type-family));
    font-size: var(--text-base);
    line-height: var(--kit-body-line-height, var(--leading-normal));
    letter-spacing: var(--kit-body-letter-spacing, var(--tracking-normal));
    background: var(--kit-body-background, var(--surface-canvas));
    color: var(--kit-body-color, var(--text-ink));
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* [AF-36] — THE PAGE CONTAINER. Every page shell (Form or Live, APP-FACTORY.md §6) renders inside .af-page, the one
   inline-size container the responsive rules key off: `@container af-page (width < 640px)` is compact, `(width < 1024px)`
   medium, else wide. The names and numbers are tokens.css's --bp-* / --cq-page. A page never writes a media query; the
   shell declares the container and the package's blocks and controls answer it. */
.af-page { container: af-page / inline-size; min-width: 0; }   /* d-my-fixes (row 217, [AF-435]): ONE declaration, ONE name — blocks.css
   named it `page` too and, linked later, won: every `af-page` rule under the shell, this sheet's compact padding among them, never applied */
.af-page-body { display: flex; flex-direction: column; gap: var(--af-page-body-gap, var(--space-4)); padding: var(--af-page-body-padding, var(--space-5) var(--space-6)); max-width: var(--af-page-body-max-width, var(--page-max-width)); margin: 0 auto; }
@container af-page (width < 640px) { .af-page-body { padding: var(--af-page-body-at-to640-padding, var(--space-3) var(--space-4)); gap: var(--af-page-body-at-to640-gap, var(--space-3)); } }
/* the page head never wraps its actions beneath the title (AF-DESIGN-SYSTEM.md §3.6 #1; [AF-121]): the title shrinks and wraps
   its words, the actions keep the head's end edge — so the primary's position is the same on every page whatever the title's
   length or the face the machine has (the runner's fallback face is wider than Geist) */
.af-page-title { font: var(--af-page-title-font, var(--type-title)); letter-spacing: var(--af-page-title-letter-spacing, var(--type-title-tracking)); color: var(--af-page-title-color, var(--text-ink)); flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.af-page-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--af-page-head-gap, var(--space-3)); }
.af-page-head > .af-actions { flex: none; margin-inline-start: auto; }

h1, h2, h3, h4 { font-weight: var(--kit-h1-font-weight, var(--font-semibold)); letter-spacing: var(--kit-h1-letter-spacing, var(--tracking-tight)); margin: 0; }
h1:focus { outline: none; }

/* Q294(e) — KF-4, THE LINK CANON (root cause: this base rule painted every unpinned anchor
   accent-blue — indistinguishable from the bootstrap/vendor default Ken flagged, and wrong
   against the comps, which draw in-app chrome links as QUIET INK with a hover underline (the
   entity-reference law). The canon now: a bare anchor reads its surface's ink and underlines
   on hover; the DELIBERATE link registers keep their own pins (.syn-link = the accent-active
   act link; prose scopes pin their hyperlink color: .syn-md a, .syn-res-prose a); drawn
   accent doors (.syn-mc-docopen …) carry their own classes. Bootstrap + the DX theme load
   BEFORE this sheet, so this rule also beats their `a` defaults at equal specificity. */
a {
    color: inherit;
    text-decoration: var(--kit-a-text-decoration, none);
    transition: var(--kit-a-transition, color var(--motion-duration-fast) var(--motion-easing));
}
a:hover { text-decoration: var(--kit-a-hover-text-decoration, underline); }

code, .mono { font-family: var(--kit-code-font-family, var(--type-family-mono)); }

/* The Icon wrapper's fixed SVG attributes live HERE, not per instance (Q22 markup diet): the
   --ic/--if/--iw custom properties carry the rare per-instance Color/Fill/StrokeWidth overrides,
   so each rendered icon is just <svg width height class><use/></svg>. These are inherited
   properties, so they flow into the <use> shadow tree exactly as the old attributes did. */
.syn-icon {
    display: inline-block; vertical-align: middle; flex-shrink: 0;
    fill: var(--if, none); stroke: var(--ic, currentColor); stroke-width: var(--iw, 2);
    stroke-linecap: round; stroke-linejoin: round;
}

/* AF-2071 ([AF-1042] (4), Ken 13:46: "The scrollbar's size and position gives the user clues about the length of the page and where they
   are within it, free"): EVERY SCROLLER SHOWS ITS BAR — the standard width, a Harbor-toned thumb on a toned track, so the OS's overlay
   scrollbar (Windows 11 Chrome: on hover only) never hides it; the `*` rule reaches html and every internal scroller. A scroller the kit
   declares (overflow auto) keeps its gutter stable, so a bar arriving never reflows the content (blocks.css, the scrollers' list). Q236's
   loud light strip on a dark ground stays answered: the track is the theme's inset in either scheme. */
* { scrollbar-width: auto; scrollbar-color: var(--kit-scrollbar-color, var(--scrollbar-thumb) var(--scrollbar-track)); }

/* Blazor error UI: styled in Layout/MainLayout.razor.css (Q405 — the one home). */

.blazor-error-boundary { background: var(--kit-blazor-error-boundary-background, var(--state-attention)); padding: var(--kit-blazor-error-boundary-padding, var(--space-4)); color: var(--kit-blazor-error-boundary-color, var(--text-on-accent)); }
.blazor-error-boundary::after { content: "An error has occurred."; }

/* WASM load splash. */
.loading-progress {
    position: absolute;
    display: block;
    width: var(--kit-loading-progress-width, var(--splash-size));
    height: var(--kit-loading-progress-height, var(--splash-size));
    inset: var(--kit-loading-progress-inset, var(--splash-top) 0 auto 0);
    margin: 0 auto;
}
.loading-progress circle {
    fill: none;
    stroke: var(--kit-loading-progress-circle-stroke, var(--border-default));
    stroke-width: var(--kit-loading-progress-circle-stroke-width, 0.6rem);
    transform-origin: 50% 50%;
    transform: rotate(-90deg);
}
.loading-progress circle:last-child {
    stroke: var(--kit-loading-progress-circle-last-child-stroke, var(--accent-action));
    stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
    transition: var(--kit-loading-progress-circle-last-child-transition, stroke-dasharray var(--motion-duration-fast) var(--motion-easing));
}
.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: var(--kit-loading-progress-text-font-weight, var(--font-semibold));
    color: var(--kit-loading-progress-text-color, var(--text-muted));
    inset: var(--kit-loading-progress-text-inset, calc(var(--splash-top) + var(--splash-text-drop)) 0 auto var(--splash-text-nudge));
}
.loading-progress-text:after { content: var(--blazor-load-percentage-text, "Loading"); }

/* Q164 (Q-EDIT ruling 5): keyboard-reachable + focus-visible throughout — one app-wide ring
   for keyboard focus (mouse clicks stay ringless via :focus-visible). DL §2.5: no accent focus
   rings — the ring is quiet ink. */
:focus-visible { outline: var(--focus-ring-width) solid var(--focus-ring); outline-offset: var(--focus-ring-offset-width); }
/* d-a11y (AF-DESIGN-SYSTEM.md §3.3 (2)): text for assistive technology only — a label the eye does not need */
.aptive-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
/* DIALOG-1 (Relay 49a CANON-DELTA 10): a dialog CONTAINER is the ringless focus seat — focus lands on it (tabindex -1) and it
   never paints the ring; only a tabbable act inside shows the ring on keyboard focus. */
[role="dialog"]:focus-visible { outline: none; }
