/* Spec 034 T008 + T029/T030 + site redesign: shell styles for the product site —
   structural skeleton, Developer Dark marketing layer (gradient mesh hero, glow, monospace
   touches), CSS-only mobile nav, media sections, and the responsive pass.
   Consumes --akml-* custom properties from css/themes/{dark,light,high-contrast}.css
   (generated from docs/theme-tokens.json by scripts/generate-theme-css.ps1 — never hand-edit
   those). ALL colors here come from those tokens; effects use color-mix() on tokens so the
   light and high-contrast palettes stay intentional. */

*,
*::before,
*::after {
    box-sizing: border-box;
}

/* --- Site design layer (UI-001) --------------------------------------------------
   The generated themes come from docs/theme-tokens.json, which exists to style WPF chrome
   in the desktop IDE. Its COLOURS are exactly what this site wants — one product, one
   palette — but its scalars are not: the spacing scale stops at 16px, there is no type
   scale, and the font families are Windows-only face names.

   So: keep consuming --akml-* for colour, and define the site's own spacing, type and
   font stacks here. Never edit the generated theme files to add these; the palette stays
   shared, the layout scale belongs to the web.

   Everything is rem-based (A11Y-002): --akml-type-*-size are device-independent units
   meant for WPF, and as CSS px they ignore the reader's browser font-size setting. */
:root {
    --site-header-h: 60px;
    --site-content-max: 1200px;

    /* Spacing scale. The --akml-scalar-spacing-* tokens stop at 16px, so section rhythm
       had to be hand-rolled with ad-hoc clamp() at every call site. */
    --s-1: 0.25rem;
    --s-2: 0.5rem;
    --s-3: 0.75rem;
    --s-4: 1rem;
    --s-5: 1.5rem;
    --s-6: 2rem;
    --s-7: 3rem;
    --s-8: 4rem;
    /* Fluid steps for section rhythm — the page breathes with the viewport.

       These were `--s-section: var(--s-section)` and `--s-block: var(--s-block)` — SELF-REFERENTIAL,
       which CSS resolves to the guaranteed-invalid value. Every rule using them silently computed to
       NO margin at all, including `.page-body > section + section`, which is the rhythm between
       every section on every page of this site. That is why the whole site read as cramped and why
       panels sat flush against each other; it looked like a dozen unrelated spacing bugs.

       A self-referential custom property is legal syntax and fails silently, so nothing flagged it.
       If either of these is ever edited, give it a real length. */
    --s-section: clamp(3rem, 6vw, 5rem);
    --s-block: clamp(2rem, 4vw, 3rem);

    /* Type scale (1.2 minor third at the small end, opening up for display sizes). */
    --t-xs: 0.75rem;
    --t-sm: 0.875rem;
    --t-base: 1rem;
    --t-md: 1.125rem;
    --t-lg: clamp(1.25rem, 1.6vw, 1.4rem);
    --t-xl: clamp(1.4rem, 2.4vw, 1.8rem);
    --t-2xl: clamp(1.75rem, 3vw, 2.25rem);
    --t-3xl: clamp(2rem, 4.5vw, 2.75rem);
    --t-display: clamp(2.75rem, 6vw, 3.5rem);

    /* Font stacks. The theme tokens name "Segoe UI" and Consolas — Windows-only, so every
       Mac, iOS, Android and Linux visitor silently fell through to a generic default.
       These stacks name a real face on each platform. */
    --f-sans:
        var(--akml-type-chrome-family), -apple-system, BlinkMacSystemFont, "Segoe UI",
        Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif;
    --f-mono:
        var(--akml-type-editor-family), ui-monospace, SFMono-Regular, "SF Mono", Menlo,
        "Cascadia Mono", "Roboto Mono", "Liberation Mono", monospace;

    /* Code sizing: --akml-type-editor-size is 13px absolute. Relative, so it scales. */
    --t-code: 0.875em;
    --t-code-block: 0.9375rem;
}

body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background-color: var(--akml-surface-canvas);
    color: var(--akml-text-primary);
    font-family: var(--f-sans);
    /* U6: 16 px base for prose/docs; chrome elements (nav, footer, sidebar) pin
       themselves back to 0.875rem below. */
    font-size: 1rem;
    line-height: 1.5;
}

code,
pre {
    font-family: var(--f-mono);
}

/* Images never overflow their box and never distort (explicit width/height attrs on
   marketing screenshots keep their aspect ratio via height:auto — zero CLS). */
img {
    max-width: 100%;
    height: auto;
}

a {
    color: var(--akml-text-link);
    transition: color 0.16s ease;
}

a:hover {
    color: color-mix(in srgb, var(--akml-text-link) 82%, var(--akml-text-primary));
}

:focus-visible {
    outline: 2px solid var(--akml-border-focus);
    outline-offset: 2px;
}

/* U4: FocusOnNavigate programmatically focuses the page <h1> (tabindex="-1") on every
   navigation — don't paint the focus ring on it. Real keyboard focus on interactive
   elements keeps the ring above. */
[tabindex="-1"]:focus,
[tabindex="-1"]:focus-visible {
    outline: none;
}

.container {
    width: 100%;
    max-width: var(--site-content-max);
    margin-inline: auto;
    padding-inline: var(--akml-scalar-spacing-l);
}

/* Skip-to-content link: hidden until focused (SC-006). */
.skip-link {
    position: absolute;
    left: var(--akml-scalar-spacing-s);
    top: -100%;
    z-index: 1000;
    padding: var(--akml-scalar-spacing-xs) var(--akml-scalar-spacing-m);
    background-color: var(--akml-accent-primary);
    color: var(--akml-text-onaccent);
    border-radius: var(--akml-scalar-radius-xs);
    transition: top 0.18s ease;
}

.skip-link:focus-visible {
    top: var(--akml-scalar-spacing-s);
}

/* --- Typography helpers ---------------------------------------------------- */

/* Section eyebrow: small uppercase token-colored label above headings. */
.eyebrow {
    margin: 0 0 var(--akml-scalar-spacing-s);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--akml-text-link);
}

/* Gradient-text accent (hero headline). Token-only stops, so both themes stay on-palette. */
.text-gradient {
    background: linear-gradient(92deg, var(--akml-text-link) 0%, var(--akml-syntax-function) 55%, var(--akml-syntax-tablecolumn) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
}

/* --- Page scaffolding --------------------------------------------------------
   <main> carries no .container: pages opt into .page-body (or full-bleed sections like
   the Home hero). .docs-layout containers itself below. */

.site-main {
    flex: 1;
}

.page-body {
    padding-block: clamp(2.25rem, 5vw, 3.5rem) clamp(3rem, 6vw, 4.5rem);
}

/* U5: vertical rhythm between marketing sections inside a page body. */
.page-body > section + section,
.page-body > .cta-row {
    margin-top: var(--s-section);
}

.page-header {
    max-width: 65ch;
    margin-bottom: clamp(2rem, 5vw, 3rem);
}

/* Display scale for page H1s (>=2rem everywhere). */
.page-header h1 {
    margin: 0 0 var(--akml-scalar-spacing-s);
    font-size: var(--t-3xl);
    line-height: 1.12;
    letter-spacing: -0.02em;
    font-weight: 600;
}

.page-intro {
    margin: 0;
    max-width: 65ch;
    color: var(--akml-text-secondary);
    font-size: var(--t-md);
    line-height: 1.6;
}

/* Section headings inside a page body share the display treatment.

   NOTE the specificity: this is (0,1,2) -- one class, two elements -- so a panel rule written as
   `.some-panel h2` at (0,1,1) LOSES to it. That is exactly how every panel heading on this site
   ended up flush against its own content. Panel rules that need their own spacing must name the
   panel class in the chain (see the .admin-panel heading rule below), not assume they win by being
   later in the file. */
.page-body > section > h2 {
    margin: 0;
    font-size: var(--t-xl);
    letter-spacing: -0.01em;
}

/* (0,2,1) beats the (0,1,2) above on class count, so panelled headings get their spacing back
   while keeping the shared type treatment. The download page's headings sit inside a wrapper
   rather than directly under .page-body, so the rule above never reaches them and they set their
   own type in the download section. */
.page-body > .admin-panel > h2 {
    margin-bottom: var(--s-4);
}

/* --- Buttons --------------------------------------------------------------- */

.cta-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--akml-scalar-spacing-m);
}

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--akml-scalar-spacing-s);
    padding: 10px 18px;
    border: 1px solid var(--akml-border-strong);
    border-radius: var(--akml-scalar-radius-s);
    font-size: 0.95rem;
    font-weight: 600;
    line-height: 1.25;
    text-decoration: none;
    transition: background-color 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
}

.btn-primary {
    background-color: var(--akml-accent-primary);
    color: var(--akml-text-onaccent);
    border-color: var(--akml-accent-primary);
    box-shadow: 0 0 18px color-mix(in srgb, var(--akml-accent-primary) 42%, transparent);
}

.btn-primary:hover {
    background-color: var(--akml-accent-primaryhover);
    border-color: var(--akml-accent-primaryhover);
    color: var(--akml-text-onaccent);
    transform: translateY(-1px);
    box-shadow: 0 4px 26px color-mix(in srgb, var(--akml-accent-primary) 55%, transparent);
}

.btn-secondary {
    background-color: color-mix(in srgb, var(--akml-surface-elevated) 60%, transparent);
    color: var(--akml-text-primary);
}

.btn-secondary:hover {
    background-color: var(--akml-surface-hover);
    border-color: color-mix(in srgb, var(--akml-accent-primary) 45%, var(--akml-border-strong));
    color: var(--akml-text-primary);
    transform: translateY(-1px);
}

/* Press state: after the hover rules so it wins the transform while hovered. */
.btn:active {
    transform: translateY(1px);
    box-shadow: none;
}

/* --- Header + primary nav ----------------------------------------------------
   Sticky, token-translucent, backdrop-blurred. The nav children use explicit flex order
   so the mobile row reads: brand | … | theme toggle | hamburger. */

/* A #fragment target — an F1 help link from the product, an "On this page" entry, a shared
   link — scrolls to just below the sticky header instead of underneath it. */
html {
    scroll-padding-top: calc(var(--site-header-h) + var(--akml-scalar-spacing-m));
}

.site-header {
    position: sticky;
    top: 0;
    z-index: 60;
    background-color: color-mix(in srgb, var(--akml-surface-canvas) 80%, transparent);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--akml-border-subtle);
}

.site-nav {
    display: flex;
    align-items: center;
    gap: var(--akml-scalar-spacing-s) var(--akml-scalar-spacing-m);
    min-height: var(--site-header-h);
    padding-block: var(--akml-scalar-spacing-s);
}

.site-brand {
    order: 1;
    display: inline-flex;
    align-items: center;
    gap: var(--akml-scalar-spacing-s);
    color: var(--akml-text-primary);
    font-family: var(--f-mono);
    font-weight: var(--akml-type-chrometitle-weight);
    letter-spacing: 0.02em;
    text-decoration: none;
}

.site-brand-mark {
    flex: none;
    color: var(--akml-text-link);
}

.site-nav-links {
    order: 2;
    display: flex;
    align-items: center;
    gap: 2px;
    margin: 0;
    padding: 0;
    list-style: none;
    /* U6: chrome stays compact against the 16 px body base. */
    font-size: var(--t-sm);
}

.site-nav-links a {
    display: block;
    padding: 6px 12px;
    color: var(--akml-text-secondary);
    text-decoration: none;
    border-radius: var(--akml-scalar-radius-xs);
    transition: color 0.16s ease, background-color 0.16s ease;
}

.site-nav-links a svg {
    margin-inline-start: 2px;
}

.site-nav-links a:hover {
    color: var(--akml-text-primary);
    background-color: var(--akml-surface-hover);
}

.site-nav-links a.active {
    color: var(--akml-text-primary);
    background-color: color-mix(in srgb, var(--akml-accent-primary) 14%, transparent);
}

/* T028: theme toggle button. U24: inert without JS, so it is hidden by default and
   revealed by theme-toggle.js via the .js-theme-toggle class on <html>. */
.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* U14: >=40x40 px touch target (44 ideal, 40 keeps header density). */
    min-width: 40px;
    min-height: 40px;
    padding: var(--akml-scalar-spacing-xs) var(--akml-scalar-spacing-s);
    background: none;
    color: var(--akml-text-secondary);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-xs);
    cursor: pointer;
    transition: color 0.16s ease, background-color 0.16s ease, border-color 0.16s ease;
}

#theme-toggle {
    display: none;
}

html.js-theme-toggle #theme-toggle {
    display: inline-flex;
}

.theme-toggle:hover {
    color: var(--akml-text-primary);
    background-color: var(--akml-surface-hover);
}

/* Icon reflects the ACTIVE theme (the control is now a three-option menu, not a flip, so
   "the theme you will switch to" no longer has a single answer): moon while dark, sun while
   light, half-circle while high contrast. */
.theme-toggle-icon {
    display: none;
}

.theme-toggle-moon,
html[data-akml-theme="light"] .theme-toggle-sun,
html[data-akml-theme="high-contrast"] .theme-toggle-contrast {
    display: inline;
}

html[data-akml-theme="light"] .theme-toggle-moon,
html[data-akml-theme="high-contrast"] .theme-toggle-moon {
    display: none;
}

/* UI-004: theme menu anchored under the header button. */
.theme-picker {
    order: 3;
    position: relative;
    margin-inline-start: auto;
}

.theme-menu {
    position: absolute;
    inset-inline-end: 0;
    top: calc(100% + 6px);
    z-index: 70;
    display: grid;
    min-width: 11rem;
    padding: var(--s-1);
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-strong);
    border-radius: var(--akml-scalar-radius-s);
    box-shadow: 0 12px 32px color-mix(in srgb, var(--akml-text-primary) 18%, transparent);
}

.theme-menu[hidden] {
    display: none;
}

.theme-menu button {
    display: flex;
    align-items: center;
    gap: var(--s-2);
    padding: var(--s-2) var(--s-3);
    background: none;
    color: var(--akml-text-secondary);
    border: 0;
    border-radius: var(--akml-scalar-radius-xs);
    font: inherit;
    font-size: var(--t-sm);
    text-align: start;
    cursor: pointer;
}

.theme-menu button:hover {
    color: var(--akml-text-primary);
    background-color: var(--akml-surface-hover);
}

/* Check mark for the active option — the visual partner to aria-checked. */
.theme-menu button::before {
    content: "";
    flex: none;
    width: 1em;
    height: 1em;
    border-radius: 50%;
    border: 1px solid var(--akml-border-strong);
}

.theme-menu button[aria-checked="true"] {
    color: var(--akml-text-primary);
}

.theme-menu button[aria-checked="true"]::before {
    background-color: var(--akml-accent-primary);
    border-color: var(--akml-accent-primary);
    box-shadow: inset 0 0 0 2px var(--akml-surface-panel);
}

/* CSS-only mobile menu button. Desktop: fully hidden (the inline nav shows instead). */
.nav-toggle-btn {
    order: 4;
    display: none;
}

/* --- Hero (Home) --------------------------------------------------------------
   Full-bleed section: layered radial gradient mesh + masked grid backdrop (pure CSS,
   token-tinted), centered display copy, theme-matched SSMS product screenshot. */

.hero {
    position: relative;
    isolation: isolate;
    overflow: clip;
    text-align: center;
    padding-block: clamp(4rem, 9vw, 6.5rem) clamp(3.5rem, 7vw, 5.5rem);
    border-bottom: 1px solid var(--akml-border-subtle);
}

.hero-backdrop {
    position: absolute;
    inset: 0;
    z-index: -1;
    background:
        radial-gradient(55rem 26rem at 72% -12%, color-mix(in srgb, var(--akml-accent-primary) 24%, transparent), transparent 62%),
        radial-gradient(45rem 24rem at 12% -8%, color-mix(in srgb, var(--akml-syntax-function) 15%, transparent), transparent 60%),
        radial-gradient(50rem 22rem at 50% 118%, color-mix(in srgb, var(--akml-syntax-tablecolumn) 10%, transparent), transparent 65%),
        var(--akml-surface-canvas);
}

/* Grid pattern, faded out with a radial mask so it reads as depth, not wallpaper. */
.hero-backdrop::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(color-mix(in srgb, var(--akml-text-primary) 5%, transparent) 1px, transparent 1px),
        linear-gradient(90deg, color-mix(in srgb, var(--akml-text-primary) 5%, transparent) 1px, transparent 1px);
    background-size: 40px 40px;
    -webkit-mask-image: radial-gradient(ellipse 85% 75% at 50% 0%, black 25%, transparent 78%);
    mask-image: radial-gradient(ellipse 85% 75% at 50% 0%, black 25%, transparent 78%);
}

/* Hero eyebrow is a pill badge (centered above the headline). */
.hero-eyebrow {
    display: inline-flex;
    padding: 5px 14px;
    background: color-mix(in srgb, var(--akml-accent-primary) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--akml-accent-primary) 30%, transparent);
    border-radius: var(--akml-scalar-radius-pill);
}

.hero h1 {
    margin: var(--akml-scalar-spacing-m) auto;
    max-width: 20ch;
    font-size: var(--t-display);
    line-height: 1.05;
    letter-spacing: -0.03em;
    font-weight: 600;
}

.hero-tagline {
    margin: 0 auto;
    max-width: 58ch;
    color: var(--akml-text-secondary);
    font-size: clamp(1.05rem, 1.6vw, 1.25rem);
    line-height: 1.6;
    /* Even out the lines instead of filling one and orphaning two words onto the next. Unsupported
       browsers just get the normal greedy wrap, which is what they render today. */
    text-wrap: balance;
}

.hero-cta {
    justify-content: center;
    margin-block: 1.75rem 0;
}

/* Product visual: accent glow bloom behind the framed screenshot. */
.hero-visual {
    position: relative;
    margin-top: var(--s-block);
}

.hero-visual::before {
    content: "";
    position: absolute;
    inset: 6% -6% -8%;
    z-index: -1;
    background: radial-gradient(52% 58% at 50% 42%, color-mix(in srgb, var(--akml-accent-primary) 32%, transparent), transparent 72%);
    filter: blur(56px);
}

/* Slight perspective tilt + gentle float (motion gated below). */
.hero-screenshot {
    max-width: 1060px;
    transform: perspective(1600px) rotateX(3deg);
    transform-origin: 50% 0;
}

@keyframes hero-float {
    0%, 100% {
        transform: perspective(1600px) rotateX(3deg) translateY(0);
    }

    50% {
        transform: perspective(1600px) rotateX(3deg) translateY(-8px);
    }
}

/* --- Screenshot frames (hero + media sections) --------------------------------
   Native SSMS crops keep their own window chrome and explicit image dimensions. */

.screenshot-frame {
    margin: 0;
    overflow: hidden;
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-strong);
    border-radius: var(--akml-scalar-radius-m);
    box-shadow:
        0 24px 64px color-mix(in srgb, var(--akml-accent-primary) 16%, transparent),
        0 6px 24px color-mix(in srgb, var(--akml-text-primary) 10%, transparent);
}

.screenshot-frame.hero-screenshot {
    margin-inline: auto;
}

.screenshot-caption {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.4rem 1rem;
    padding: 0.8rem 1rem;
    background-color: var(--akml-surface-elevated);
    border-top: 1px solid var(--akml-border-subtle);
    color: var(--akml-text-secondary);
    font-size: 0.8rem;
    line-height: 1.5;
    text-align: left;
}

/* Primary text, not the link colour: link blue on the elevated caption bar is ~4.1:1 at this
   size in both themes, under the 4.5:1 AA floor. The icon keeps the accent. */
.screenshot-hint {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--akml-text-primary);
    white-space: nowrap;
}

.screenshot-hint-icon {
    flex: none;
    color: var(--akml-text-link);
}

.screenshot-variant {
    display: block;
    cursor: zoom-in;
}

.screenshot-variant:focus-visible {
    outline: 3px solid var(--akml-border-focus);
    outline-offset: -3px;
}

/* The boot script sets this attribute before first paint; the theme picker updates it.
   Dark is also the fallback for no JavaScript and the site's high-contrast theme. */
.screenshot-light,
html[data-akml-theme="light"] .screenshot-dark {
    display: none;
}

html[data-akml-theme="light"] .screenshot-light {
    display: block;
}

.screenshot-frame img {
    display: block;
    width: 100%;
    height: auto;
}

/* --- Screenshot viewer (js/screenshot-viewer.js) -----------------------------
   Clicking a screenshot opens it in a modal <dialog> instead of a new tab; on a page with
   several screenshots it is a gallery: arrows, thumbnails, and the section's heading and text
   beside the picture. The picture keeps the page's screenshot frame, so it reads as the same
   object, larger. Sizes are set by the script through the CSSOM (CSP forbids style=""). */

/* Locking the scroll removes the scrollbar; keeping its gutter stops the page behind the
   viewer jumping sideways. */
html.screenshot-viewer-open {
    overflow: hidden;
    scrollbar-gutter: stable;
}

.viewer {
    width: 100vw;
    max-width: none;
    height: 100vh;
    height: 100dvh;
    max-height: none;
    margin: 0;
    padding: 0;
    border: 0;
    color: var(--akml-text-primary);
    background:
        radial-gradient(60rem 30rem at 50% -10%, color-mix(in srgb, var(--akml-accent-primary) 14%, transparent), transparent 70%),
        color-mix(in srgb, var(--akml-surface-canvas) 94%, transparent);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    overscroll-behavior: contain;
}

.viewer::backdrop {
    background: transparent;
}

.viewer-stage {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas:
        "top"
        "fig";
    width: 100%;
    height: 100%;
    padding: 0.75rem clamp(0.75rem, 3vw, 2rem) clamp(1rem, 3vw, 2rem);
}

.viewer-top {
    grid-area: top;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 1rem;
    min-height: 44px;
}

.viewer-count {
    margin: 0 auto 0 0;
    color: var(--akml-text-secondary);
    font-size: 0.875rem;
    font-variant-numeric: tabular-nums;
}

.viewer-btn {
    display: inline-grid;
    place-items: center;
    width: 44px;
    height: 44px;
    padding: 0;
    color: var(--akml-text-primary);
    background: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-strong);
    border-radius: 50%;
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

.viewer-btn:hover {
    border-color: var(--akml-accent-primary);
    background: var(--akml-surface-hover);
}

/* aria-disabled (not disabled) keeps a focused arrow focusable at either end of the gallery. */
.viewer-btn[aria-disabled="true"] {
    opacity: 0.35;
    cursor: default;
}

.viewer-figure {
    grid-area: fig;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 0;
    margin: 0;
}

.viewer-figure > * {
    width: 100%;
}

.viewer-frame {
    overflow: hidden;
    background: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-strong);
    border-radius: var(--akml-scalar-radius-m) var(--akml-scalar-radius-m) 0 0;
    box-shadow:
        0 30px 80px color-mix(in srgb, var(--akml-accent-primary) 18%, transparent),
        0 8px 30px color-mix(in srgb, var(--akml-text-primary) 14%, transparent);
    /* One-finger swipes belong to the viewer; pinch still zooms the page. */
    touch-action: pinch-zoom;
}

.viewer-img {
    display: block;
    height: auto;
    max-width: 100%;
}

.viewer-caption {
    margin: 0 auto;
    padding: 0.7rem 1rem;
    color: var(--akml-text-primary);
    font-size: 0.875rem;
    background: var(--akml-surface-elevated);
    border: 1px solid var(--akml-border-strong);
    border-top: 0;
    border-radius: 0 0 var(--akml-scalar-radius-m) var(--akml-scalar-radius-m);
}

.viewer-nav,
.viewer-notes,
.viewer-strip {
    display: none;
}

/* Gallery: arrows either side, the section's text beside the picture, thumbnails below. */
.viewer.is-gallery .viewer-stage {
    grid-template-columns: 56px minmax(0, 1fr) minmax(220px, 300px) 56px;
    grid-template-rows: auto minmax(0, 1fr) auto;
    grid-template-areas:
        "top   top   top   top"
        "prev  fig   notes next"
        "strip strip strip strip";
    column-gap: clamp(0.75rem, 2vw, 1.5rem);
}

.viewer.is-gallery .viewer-nav {
    display: inline-grid;
    align-self: center;
    width: 52px;
    height: 52px;
}

/* No notes to show (docs images): the picture takes the notes column too. */
.viewer.is-gallery:not(.has-notes) .viewer-stage {
    grid-template-columns: 56px minmax(0, 1fr) 56px;
    grid-template-areas:
        "top   top   top"
        "prev  fig   next"
        "strip strip strip";
}

.viewer.is-gallery:not(.has-notes) .viewer-notes {
    display: none;
}

.viewer.is-gallery .viewer-prev {
    grid-area: prev;
}

.viewer.is-gallery .viewer-next {
    grid-area: next;
}

.viewer.is-gallery .viewer-notes {
    grid-area: notes;
    display: block;
    align-self: center;
    max-height: 100%;
    overflow-y: auto;
}

.viewer-notes h2 {
    margin: 0 0 0.6rem;
    font-size: var(--t-xl);
    line-height: 1.2;
    letter-spacing: -0.01em;
}

.viewer-notes .viewer-text {
    margin: 0;
    color: var(--akml-text-secondary);
    line-height: 1.6;
}

/* position: relative so a thumbnail's offsetLeft is measured from the strip (the script scrolls
   the strip itself); the side/bottom padding keeps focus rings from being clipped. */
.viewer.is-gallery .viewer-strip {
    grid-area: strip;
    position: relative;
    display: flex;
    justify-content: center;
    gap: 0.5rem;
    padding: 1rem 4px 4px;
    overflow-x: auto;
    scrollbar-width: thin;
}

.viewer-thumb {
    flex: none;
    width: 76px;
    height: 50px;
    padding: 0;
    overflow: hidden;
    background: var(--akml-surface-panel);
    border: 2px solid var(--akml-border-default);
    border-radius: var(--akml-scalar-radius-xs);
    opacity: 0.6;
    cursor: pointer;
    transition: opacity 0.15s ease, border-color 0.15s ease;
}

.viewer-thumb img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top left;
}

.viewer-thumb:hover,
.viewer-thumb:focus-visible {
    opacity: 1;
}

.viewer-thumb[aria-current="true"] {
    opacity: 1;
    border-color: var(--akml-accent-primary);
}

/* Narrow screens: the text under the picture, arrows side by side above the strip. Rows are
   max-content and the stage scrolls, so a short (landscape) phone never squeezes the picture
   over the controls — with `auto` rows the frame (overflow: hidden) and the notes (a scroll
   box) have a zero automatic minimum height and were crushed to fit the screen. */
@media (max-width: 900px) {
    .viewer.is-gallery .viewer-stage {
        grid-template-columns: 1fr 1fr;
        grid-template-rows: repeat(5, max-content);
        grid-template-areas:
            "top   top"
            "fig   fig"
            "notes notes"
            "prev  next"
            "strip strip";
        row-gap: 0.75rem;
        overflow-y: auto;
    }

    .viewer.is-gallery:not(.has-notes) .viewer-stage {
        grid-template-columns: 1fr 1fr;
        grid-template-rows: repeat(4, max-content);
        grid-template-areas:
            "top   top"
            "fig   fig"
            "prev  next"
            "strip strip";
    }

    /* The stage scrolls here, so vertical drags on the picture must scroll it too. */
    .viewer.is-gallery .viewer-frame {
        touch-action: pan-y pinch-zoom;
    }

    .viewer.is-gallery .viewer-notes {
        align-self: start;
        max-height: none;
        overflow: visible;
    }

    .viewer.is-gallery .viewer-frame,
    .viewer.is-gallery .viewer-caption {
        flex-shrink: 0;
    }

    .viewer-notes h2 {
        font-size: var(--t-lg);
    }

    .viewer.is-gallery .viewer-prev {
        justify-self: end;
    }

    .viewer.is-gallery .viewer-next {
        justify-self: start;
    }

    .viewer.is-gallery .viewer-strip {
        justify-content: flex-start;
        padding-top: 0;
    }
}

/* High contrast: solid system colours, no glow or blur. */
html[data-akml-theme="high-contrast"] .viewer {
    background: Canvas;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

html[data-akml-theme="high-contrast"] .viewer-frame {
    box-shadow: none;
}

/* The theme's hover surface is CanvasText — the same as the icon colour, which would vanish. */
html[data-akml-theme="high-contrast"] .viewer-btn:hover {
    color: HighlightText;
    background: Highlight;
    border-color: Highlight;
}

/* Opacity alone does not mark the current thumbnail in high contrast. */
html[data-akml-theme="high-contrast"] .viewer-thumb {
    opacity: 1;
    border-color: GrayText;
}

html[data-akml-theme="high-contrast"] .viewer-thumb[aria-current="true"] {
    border-color: Highlight;
    outline: 2px solid Highlight;
}

/* --- Feature cards (Home + /features) ------------------------------------------
   3-col desktop grid (2 at tablet) collapsing to 1 col on phones; hover lift + accent
   border glow; hand-drawn stroke icons in a tinted chip. */

.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
    gap: var(--akml-scalar-spacing-l);
    margin: clamp(1.5rem, 3vw, 2rem) 0 0;
    padding: 0;
    list-style: none;
}

.card {
    padding: 1.5rem;
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-m);
    transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

.card:hover {
    transform: translateY(-3px);
    border-color: color-mix(in srgb, var(--akml-accent-primary) 45%, var(--akml-border-strong));
    box-shadow: 0 12px 32px color-mix(in srgb, var(--akml-accent-primary) 16%, transparent);
}

.card h2,
.card h3 {
    margin: 0 0 var(--akml-scalar-spacing-xs);
    font-size: 1.05rem;
}

.card p {
    margin: 0;
    color: var(--akml-text-secondary);
    font-size: 0.925rem;
    line-height: 1.55;
}

.feature-card-icon {
    display: inline-flex;
    margin-bottom: 0.9rem;
    padding: 9px;
    color: var(--akml-text-link);
    background: color-mix(in srgb, var(--akml-accent-primary) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--akml-accent-primary) 22%, transparent);
    border-radius: 10px;
}

.feature-card-icon svg {
    display: block;
}

/* --- Media sections (/features): alternating text + screenshot rows. */

.media-row {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: clamp(2rem, 5vw, 4rem);
    align-items: center;
}

.media-row-flip .media-text {
    order: 2;
}

.media-row-flip .media-frame {
    order: 1;
}

.media-text h2 {
    margin: 0 0 var(--akml-scalar-spacing-s);
    font-size: clamp(1.5rem, 2.6vw, 2rem);
    line-height: 1.15;
    letter-spacing: -0.02em;
}

.media-text p {
    margin: 0;
    max-width: 52ch;
    color: var(--akml-text-secondary);
    line-height: 1.6;
}

/* --- CTA banner (Home) -------------------------------------------------------- */

.cta-banner {
    position: relative;
    overflow: hidden;
    padding: clamp(2rem, 5vw, 3rem);
    background:
        radial-gradient(42rem 18rem at 15% -20%, color-mix(in srgb, var(--akml-accent-primary) 16%, transparent), transparent 70%),
        var(--akml-surface-panel);
    border: 1px solid color-mix(in srgb, var(--akml-accent-primary) 28%, var(--akml-border-subtle));
    border-radius: var(--akml-scalar-radius-m);
}

.cta-banner h2 {
    margin-top: 0;
    font-size: var(--t-xl);
    letter-spacing: -0.01em;
}

.cta-banner p {
    max-width: 60ch;
    color: var(--akml-text-secondary);
}

/* --- Download page: release blocks. */

.release-card {
    margin-bottom: var(--akml-scalar-spacing-l);
    padding: clamp(1.25rem, 3vw, 1.75rem);
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-m);
}

.release-card-latest {
    border-color: var(--akml-accent-primary);
    box-shadow: 0 0 20px color-mix(in srgb, var(--akml-accent-primary) 30%, transparent);
}

/* Spacing is owned by the download page's own rhythm rule, so every top-level block there shares
   one gap. Left at 0 here rather than deleted: the class carries its own borders and type below. */
.release-history {
    margin-top: 0;
}

.release-facts {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: var(--akml-scalar-spacing-xs) var(--akml-scalar-spacing-l);
    margin-block: var(--akml-scalar-spacing-m);
}

.release-facts dt {
    color: var(--akml-text-secondary);
    font-weight: var(--akml-type-chrometitle-weight);
}

.release-facts dd {
    margin: 0;
}

.host-badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--akml-scalar-spacing-s);
    margin: 0;
    padding: 0;
    list-style: none;
}

.host-badges li {
    padding: var(--akml-scalar-spacing-xs) var(--akml-scalar-spacing-s);
    background-color: var(--akml-surface-elevated);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-pill);
    font-family: var(--f-mono);
    font-size: var(--t-xs);
}

/* Code-first touches: version strings in the editor face (hash/digest blocks already
   render monospace via the base code rule). */
.release-card h2,
.release-card h3 {
    font-family: var(--f-mono);
}

/* Copyable monospace digest block (FR-003). */
.hash-block code {
    display: block;
    overflow-wrap: anywhere;
    user-select: all;
    padding: var(--akml-scalar-spacing-s);
    background-color: var(--akml-surface-elevated);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-xs);
    font-size: var(--t-code-block);
}

.hash-hint {
    margin-block: var(--akml-scalar-spacing-xs);
    color: var(--akml-text-secondary);
}

/* SmartScreen guidance under the download CTA: why the first download may be held. */
.download-note {
    max-width: 56ch;
    margin-block: var(--akml-scalar-spacing-s) 0;
    color: var(--akml-text-secondary);
    font-size: 0.95em;
    line-height: 1.5;
}

/* U22: copy-to-clipboard affordance for the SHA-256 digest. Hidden by default so no-JS
   users never see a dead button; copy-hash.js reveals it via .js-copy-hash on <html>. */
.copy-hash-btn {
    display: none;
    margin-inline-start: var(--akml-scalar-spacing-s);
    padding: var(--akml-scalar-spacing-xs) var(--akml-scalar-spacing-s);
    background-color: var(--akml-surface-elevated);
    color: var(--akml-text-primary);
    border: 1px solid var(--akml-border-strong);
    border-radius: var(--akml-scalar-radius-xs);
    font-size: var(--t-sm);
    cursor: pointer;
}

.copy-hash-btn:hover {
    background-color: var(--akml-surface-hover);
}

.copy-hash-btn.copied {
    color: var(--akml-status-success);
    border-color: var(--akml-status-success);
}

html.js-copy-hash .copy-hash-btn {
    display: inline-block;
}

.release-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Friendly fallback panel (contracts/releases-json.md failure behavior) — same polish
   level as the marketing cards: soft info tint, generous padding. */
.notice {
    padding: clamp(1.5rem, 4vw, 2.25rem);
    background: color-mix(in srgb, var(--akml-status-info) 7%, var(--akml-surface-panel));
    border: 1px solid color-mix(in srgb, var(--akml-status-info) 35%, transparent);
    border-radius: var(--akml-scalar-radius-m);
}

.notice h2 {
    margin-top: 0;
}

.notice p {
    max-width: 65ch;
    color: var(--akml-text-secondary);
}

/* "Now for SSMS 22 only" (HostSupportNotice): sits under the home hero and between the download
   hero and .download-columns, whose own margin-top keeps the gap below it. */
.host-notice {
    margin-top: var(--s-6);
}

.host-notice h2 {
    font-size: 1.25rem;
}

.host-notice p {
    margin-bottom: 0;
}

/* --- Footer -------------------------------------------------------------------- */

.site-footer {
    background-color: var(--akml-surface-panel);
    border-top: 1px solid var(--akml-border-subtle);
    color: var(--akml-text-secondary);
    /* U6: chrome stays compact against the 16 px body base. */
    font-size: var(--t-sm);
}

.site-footer-inner {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) repeat(3, minmax(0, 1fr));
    gap: clamp(1.75rem, 4vw, 3rem);
    padding-block: clamp(2.5rem, 5vw, 3.5rem) clamp(1.75rem, 4vw, 2.5rem);
}

.site-footer-tagline {
    margin: 0.9rem 0 0;
    max-width: 34ch;
    line-height: 1.6;
}

.site-footer-heading {
    margin: 0 0 0.9rem;
    color: var(--akml-text-primary);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.site-footer-list {
    display: grid;
    gap: 0.55rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.site-footer-list a {
    color: var(--akml-text-secondary);
    text-decoration: none;
    transition: color 0.16s ease;
}

.site-footer-list a:hover,
.site-footer-list a:focus-visible {
    color: var(--akml-text-primary);
}

.site-footer-base {
    padding-block: 1.1rem;
    border-top: 1px solid var(--akml-border-subtle);
    font-size: 0.82rem;
}

.site-footer-base p {
    margin: 0;
}

/* --- Docs section skeleton (DocsLayout): collapsible sidebar + content grid.
   <main> no longer carries .container, so the layout containers itself. */

.docs-layout {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    gap: var(--akml-scalar-spacing-l);
    align-items: start;
    width: 100%;
    max-width: var(--site-content-max);
    margin-inline: auto;
    margin-block: clamp(1.5rem, 3vw, 2.25rem) clamp(2.5rem, 5vw, 4rem);
    padding-inline: var(--akml-scalar-spacing-l);
}

.docs-sidebar {
    position: sticky;
    /* Sticks below the sticky site header. */
    top: calc(var(--site-header-h) + var(--akml-scalar-spacing-l));
    max-height: calc(100vh - var(--site-header-h) - 2 * var(--akml-scalar-spacing-l));
    overflow-y: auto;
    padding: var(--akml-scalar-spacing-m);
    background-color: var(--akml-surface-sidebar);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-s);
    font-size: var(--t-sm);
}

.docs-content {
    min-width: 0;
}

/* Always-on title filter (plain GET form — works with JS disabled, FR-007). */
.docs-filter {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--akml-scalar-spacing-xs);
    margin-bottom: var(--akml-scalar-spacing-m);
}

/* U16: once docs-search.js has the full-text index ready it marks <html> with .js —
   JS users then see only the full-text box, not two stacked search affordances.
   No-JS users keep this GET filter. */
html.js .docs-filter {
    display: none;
}

.docs-filter input[type="search"],
.docs-search input[type="search"] {
    flex: 1;
    min-width: 0;
    padding: var(--akml-scalar-spacing-xs) var(--akml-scalar-spacing-s);
    background-color: var(--akml-surface-input);
    color: var(--akml-text-primary);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-xs);
}

.docs-filter button {
    padding: var(--akml-scalar-spacing-xs) var(--akml-scalar-spacing-s);
    background-color: var(--akml-accent-primary);
    color: var(--akml-text-onaccent);
    border: 1px solid var(--akml-accent-primary);
    border-radius: var(--akml-scalar-radius-xs);
    cursor: pointer;
}

.docs-filter button:hover {
    background-color: var(--akml-accent-primaryhover);
    border-color: var(--akml-accent-primaryhover);
}

.docs-filter-clear {
    color: var(--akml-text-secondary);
}

/* Full-text search: progressive enhancement — hidden until js/docs-search.js marks
   documentElement with .js (T027). Without JS only the title filter above shows. */
.docs-search {
    display: none;
    margin-bottom: var(--akml-scalar-spacing-m);
}

html.js .docs-search {
    display: block;
}

.docs-search input[type="search"] {
    width: 100%;
}

.docs-search-results {
    margin: var(--akml-scalar-spacing-xs) 0 0;
    padding: 0;
    list-style: none;
    max-height: 40vh;
    overflow-y: auto;
    background-color: var(--akml-surface-elevated);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-xs);
}

.docs-search-results a {
    display: block;
    padding: var(--akml-scalar-spacing-xs) var(--akml-scalar-spacing-s);
    color: var(--akml-text-primary);
    text-decoration: none;
}

.docs-search-results a:hover,
.docs-search-results a:focus-visible {
    background-color: var(--akml-surface-hover);
}

/* U21: no-matches row emitted by docs-search.js. */
.docs-search-empty {
    padding: var(--akml-scalar-spacing-xs) var(--akml-scalar-spacing-s);
    color: var(--akml-text-secondary);
}

/* Collapsible section tree (native details — deep trees stay usable). */
.docs-section {
    margin-bottom: var(--akml-scalar-spacing-xs);
}

.docs-section summary {
    cursor: pointer;
    /* U14: roomier touch target (~37 px tall row). */
    padding-block: var(--akml-scalar-spacing-s);
    color: var(--akml-text-primary);
    font-weight: var(--akml-type-chrometitle-weight);
}

.docs-tree ul {
    margin: 0;
    padding: 0 0 0 var(--akml-scalar-spacing-s);
    list-style: none;
}

.docs-tree li a {
    display: block;
    /* U14: ~37 px touch target (>=32 px floor; 44 would wreck tree density). */
    padding: var(--akml-scalar-spacing-s);
    color: var(--akml-text-secondary);
    text-decoration: none;
    border-left: 2px solid transparent;
    border-radius: var(--akml-scalar-radius-xs);
    transition: color 0.16s ease, background-color 0.16s ease;
}

.docs-tree li a:hover {
    color: var(--akml-text-primary);
    background-color: var(--akml-surface-hover);
}

.docs-tree li a.docs-current {
    color: var(--akml-text-primary);
    background-color: var(--akml-surface-hover);
    border-left-color: var(--akml-accent-primary);
}

.docs-no-matches,
.docs-filter-status {
    color: var(--akml-text-secondary);
}

.docs-index-list {
    margin-block: var(--akml-scalar-spacing-s);
    padding-left: var(--akml-scalar-spacing-l);
}

.docs-index-list li {
    margin-block: var(--akml-scalar-spacing-xs);
}

.docs-index-summary {
    margin: 2px 0 0;
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
}

.doc-updated {
    color: var(--akml-text-secondary);
    font-size: 0.9em;
}

/* Freshness badges (wwwroot/docs-metadata.json + Docs:BadgeWindowDays): green "New" pill
   for recently added docs, red "Updated" pill for recently changed ones. Outline style on
   the status token colors keeps both legible across light/dark themes. */
.doc-badge {
    display: inline-block;
    margin-left: var(--akml-scalar-spacing-s);
    padding: 0.1em 0.55em;
    font-size: 0.65rem;
    font-weight: var(--akml-type-chrometitle-weight);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    vertical-align: middle;
    border: 1px solid currentColor;
    border-radius: 999px;
}

/* A11Y-001: the raw status tokens are tuned as ICON colours, and at this pill.s 0.65rem
   the light-theme green measured 3.30:1 on a white card -- below the 4.5:1 AA floor for
   small text. Darkening toward the theme.s primary text keeps the semantic hue (green =
   new, red = changed) while clearing the floor in both themes. */
.doc-badge-new {
    color: color-mix(in srgb, var(--akml-status-success) var(--badge-mix), var(--akml-text-primary));
}

.doc-badge-updated {
    color: color-mix(in srgb, var(--akml-status-danger) var(--badge-mix), var(--akml-text-primary));
}

/* Legend at the bottom of the docs index explaining the badges. */
.docs-legend {
    margin-top: var(--akml-scalar-spacing-l);
    color: var(--akml-text-secondary);
    font-size: 0.8rem;
}

/* Rendered Markdown content (cached HTML from the T022 pipeline). Redesign polish:
   ~80ch measure, airier line-height, styled blockquotes. */
.doc-header h1 {
    font-size: var(--t-2xl);
    line-height: 1.15;
    letter-spacing: -0.02em;
}

.doc-body {
    max-width: 80ch;
    line-height: 1.7;
}

.doc-body img {
    max-width: 100%;
    height: auto;
}

/* Content images open in the screenshot viewer (js/screenshot-viewer.js); MarkdownRenderer
   wraps each one in a link to itself. */
.doc-body .doc-image-link {
    display: inline-block;
    max-width: 100%;
    vertical-align: top;
    border-radius: var(--akml-scalar-radius-s);
    cursor: zoom-in;
}

.doc-body .doc-image-link img {
    display: block;
    border-radius: inherit;
}

.doc-body blockquote {
    margin: 1.25rem 0;
    padding: 0.75rem 1rem;
    color: var(--akml-text-secondary);
    background-color: var(--akml-surface-panel);
    border-left: 3px solid var(--akml-accent-primary);
    border-radius: 0 var(--akml-scalar-radius-xs) var(--akml-scalar-radius-xs) 0;
}

.doc-body pre {
    overflow-x: auto;
    padding: var(--akml-scalar-spacing-m);
    background-color: var(--akml-surface-elevated);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-s);
    font-size: var(--t-code-block);
    line-height: 1.55;
}

.doc-body :not(pre) > code {
    padding: 0 var(--akml-scalar-spacing-xs);
    background-color: var(--akml-surface-elevated);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-xs);
    font-size: 0.875em;
}

.table-scroll {
    /* Wide tables scroll inside their own container instead of clipping (mobile). */
    max-width: 100%;
    overflow-x: auto;
    margin-block: var(--akml-scalar-spacing-m);
}

.doc-body table {
    border-collapse: collapse;
    margin-block: 0;
}

.doc-body th,
.doc-body td {
    padding: var(--akml-scalar-spacing-xs) var(--akml-scalar-spacing-m);
    /* U10: 5%-white subtle borders are nearly invisible in dark; default border reads. */
    border: 1px solid var(--akml-border-default);
}

.doc-body th {
    background-color: var(--akml-surface-panel);
}

/* ColorCode server-side highlighting (HtmlFormatterType.Css classes) on syntax tokens.

   A11Y-001: the shared syntax palette is tuned for the EDITOR's background, not for a code
   block on this site's --akml-surface-elevated. Measured against that surface, six of twelve
   token/theme combinations failed WCAG AA (worst: light `string` at 2.67:1, dark `comment` at
   2.18:1). Only the comment token had ever been corrected (the original U9 note).

   Rather than fork the palette, each token is blended toward the theme's primary text by a
   per-theme ratio: the hue still comes from --akml-syntax-*, so a palette change carries
   through, and only the blend is tuned here. Ratios are the smallest that clear 4.5:1 with
   headroom; every combination now measures 4.58-5.94:1. */
:root {
    --syn-mix-keyword: 80%;
    --syn-mix-string: 100%;
    --syn-mix-number: 100%;
    --syn-mix-comment: 45%;
    --syn-mix-function: 75%;
    --syn-mix-tablecolumn: 100%;

    /* A11Y-001: freshness-pill blend (see .doc-badge-new). Dark needs none. */
    --badge-mix: 100%;
}

html[data-akml-theme="light"] {
    /* A light code surface needs the opposite push -- darker, and harder, because the
       saturated greens and oranges sit close to that background's luminance. */
    --syn-mix-keyword: 85%;
    --syn-mix-string: 60%;
    --syn-mix-number: 65%;
    --syn-mix-comment: 80%;
    --syn-mix-function: 88%;
    --syn-mix-tablecolumn: 65%;
    --badge-mix: 72%;
}

.doc-body pre .keyword {
    color: color-mix(in srgb, var(--akml-syntax-keyword) var(--syn-mix-keyword), var(--akml-text-primary));
}

.doc-body pre .string {
    color: color-mix(in srgb, var(--akml-syntax-string) var(--syn-mix-string), var(--akml-text-primary));
}

.doc-body pre .number {
    color: color-mix(in srgb, var(--akml-syntax-number) var(--syn-mix-number), var(--akml-text-primary));
}

.doc-body pre .comment {
    color: color-mix(in srgb, var(--akml-syntax-comment) var(--syn-mix-comment), var(--akml-text-primary));
    font-style: italic;
}

.doc-body pre .function,
.doc-body pre .typeName,
.doc-body pre .className {
    color: color-mix(in srgb, var(--akml-syntax-function) var(--syn-mix-function), var(--akml-text-primary));
}

.doc-body pre .preprocessor {
    color: color-mix(in srgb, var(--akml-syntax-tablecolumn) var(--syn-mix-tablecolumn), var(--akml-text-primary));
}

/* U15: "On this page" H2 anchor nav emitted by DocPage for long documents — compact
   card treatment; hidden on narrow viewports where it would push the article down
   (the sidebar tree already provides navigation there). */
.on-this-page {
    margin-block: var(--akml-scalar-spacing-m);
    padding: var(--akml-scalar-spacing-m);
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-s);
    font-size: var(--t-sm);
}

.on-this-page-heading {
    margin: 0 0 var(--akml-scalar-spacing-xs);
    color: var(--akml-text-primary);
    font-weight: var(--akml-type-chrometitle-weight);
}

.on-this-page ul {
    margin: 0;
    padding-left: var(--akml-scalar-spacing-l);
}

.on-this-page li {
    margin-block: 2px;
}

.on-this-page a {
    color: var(--akml-text-secondary);
    text-decoration: none;
}

.on-this-page a:hover,
.on-this-page a:focus-visible {
    color: var(--akml-text-link);
}

/* U11: wrap long words/URLs in prose only — applying `anywhere` to the whole article
   mangled code identifiers at 360 px ("SqlcmdPrepro cessor"). Inline code stays
   unbroken; a too-long span scrolls with its own block (p/li) instead of pushing the
   whole page sideways. */
.doc-body p,
.doc-body li {
    overflow-wrap: break-word;
    overflow-x: auto;
}

/* A scroll-container li clips its outside marker — move markers inside the box. */
.doc-body li {
    list-style-position: inside;
}

.doc-body :not(pre) > code {
    overflow-wrap: normal;
}

/* --- Light-theme balancing ------------------------------------------------------
   On a light canvas the glow alphas composite into heavy solid outlines — dial the
   meshes, halos, and shadows down so the light theme reads as intentional, not faded. */

html[data-akml-theme="light"] .hero-backdrop {
    background:
        radial-gradient(55rem 26rem at 72% -12%, color-mix(in srgb, var(--akml-accent-primary) 13%, transparent), transparent 62%),
        radial-gradient(45rem 24rem at 12% -8%, color-mix(in srgb, var(--akml-syntax-function) 8%, transparent), transparent 60%),
        radial-gradient(50rem 22rem at 50% 118%, color-mix(in srgb, var(--akml-syntax-tablecolumn) 7%, transparent), transparent 65%),
        var(--akml-surface-canvas);
}

html[data-akml-theme="light"] .hero-visual::before {
    opacity: 0.45;
}

html[data-akml-theme="light"] .screenshot-frame {
    box-shadow:
        0 20px 48px color-mix(in srgb, var(--akml-accent-primary) 10%, transparent),
        0 4px 16px color-mix(in srgb, var(--akml-text-primary) 12%, transparent);
}

html[data-akml-theme="light"] .btn-primary {
    box-shadow: 0 0 10px color-mix(in srgb, var(--akml-accent-primary) 18%, transparent);
}

html[data-akml-theme="light"] .btn-primary:hover {
    box-shadow: 0 4px 14px color-mix(in srgb, var(--akml-accent-primary) 26%, transparent);
}

html[data-akml-theme="light"] .release-card-latest {
    box-shadow: none;
}

html[data-akml-theme="light"] .card:hover {
    box-shadow: 0 10px 24px color-mix(in srgb, var(--akml-accent-primary) 10%, transparent);
}

/* --- Responsive pass, 360–1920 px (FR-008 / SC-003). */

@media (max-width: 900px) {
    .docs-layout {
        grid-template-columns: 1fr;
    }

    .docs-sidebar {
        position: static;
        max-height: none;
        /* U13: stacked layout leads with the article; the nav tree follows it. */
        order: 2;
    }

    .on-this-page {
        display: none;
    }

    /* Media sections stack, text always first. */
    .media-row {
        grid-template-columns: 1fr;
        gap: 1.5rem;
    }

    .media-row-flip .media-text,
    .media-row-flip .media-frame {
        order: 0;
    }

    .site-footer-inner {
        grid-template-columns: 1fr 1fr;
    }

    .site-footer-brand {
        grid-column: 1 / -1;
    }
}

/* Mobile nav: collapse the inline links into the CSS-only hamburger panel. */
@media (max-width: 768px) {
    .nav-toggle-btn {
        display: inline-flex;
        position: relative;
        align-items: center;
        justify-content: center;
        flex: none;
        width: 40px;
        height: 40px;
        color: var(--akml-text-secondary);
        border: 1px solid var(--akml-border-subtle);
        border-radius: var(--akml-scalar-radius-xs);
        cursor: pointer;
        transition: color 0.16s ease, background-color 0.16s ease;
    }

    .nav-toggle-btn:hover {
        color: var(--akml-text-primary);
        background-color: var(--akml-surface-hover);
    }

    /* The real control: an invisible checkbox filling the button, so mouse, touch, and
       keyboard (Space/Enter on the focused input) all work without JS. */
    .nav-toggle {
        position: absolute;
        inset: 0;
        margin: 0;
        opacity: 0;
        cursor: pointer;
    }

    .nav-toggle-btn:has(.nav-toggle:focus-visible) {
        outline: 2px solid var(--akml-border-focus);
        outline-offset: 2px;
    }

    .nav-icon-close {
        display: none;
    }

    .nav-toggle:checked ~ .nav-icon-open {
        display: none;
    }

    .nav-toggle:checked ~ .nav-icon-close {
        display: block;
    }

    /* Dropdown panel under the header; hidden until the checkbox is checked. */
    .site-nav-links {
        position: absolute;
        inset-inline: 0;
        top: 100%;
        flex-direction: column;
        align-items: stretch;
        gap: 2px;
        padding: var(--akml-scalar-spacing-s);
        background-color: var(--akml-surface-panel);
        border-bottom: 1px solid var(--akml-border-default);
        box-shadow: 0 24px 48px color-mix(in srgb, var(--akml-text-primary) 16%, transparent);
        visibility: hidden;
        opacity: 0;
        transform: translateY(-6px);
        transition: opacity 0.18s ease, transform 0.18s ease, visibility 0s linear 0.18s;
    }

    .site-nav:has(.nav-toggle:checked) .site-nav-links {
        visibility: visible;
        opacity: 1;
        transform: none;
        transition: opacity 0.18s ease, transform 0.18s ease;
    }

    /* U14: big vertical touch targets in the open panel. */
    .site-nav-links a {
        padding: 12px 14px;
        font-size: 0.95rem;
        border-radius: var(--akml-scalar-radius-s);
    }
}

@media (max-width: 640px) {
    .container,
    .docs-layout {
        padding-inline: var(--akml-scalar-spacing-m);
    }

    /* Supplied screenshots are already cropped. Keep the complete screen visible on phones;
       a tap opens the screenshot viewer for reading smaller option labels. */
    .hero-visual {
        margin-top: var(--s-6);
    }

    .hero-screenshot {
        transform: none;
        animation: none;
    }

    /* Release facts stack at phone width so long labels never squeeze the values. */
    .release-facts {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 560px) {
    .site-footer-inner {
        grid-template-columns: 1fr;
    }
}

/* --- Motion --------------------------------------------------------------------
   Float animation only where motion is welcome; the blanket reduce rule flattens every
   transition/animation above (cards, buttons, nav panel, hero). */

@media (prefers-reduced-motion: no-preference) {
    html {
        scroll-behavior: smooth;
    }

    .hero-screenshot {
        animation: hero-float 8s ease-in-out infinite;
    }
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        scroll-behavior: auto !important;
        transition-duration: 0.01ms !important;
    }
}

/* --- Forced colors (Windows High Contrast) --------------------------------------
   Decorative depth (mesh, glows, blurs, gradient text) would render as muddy system-color
   composites — strip it and let the high-contrast token theme carry the look. */

@media (forced-colors: active) {
    .text-gradient {
        background: none;
        color: CanvasText;
        -webkit-text-fill-color: CanvasText;
    }

    .site-header {
        background: Canvas;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }

    .hero-backdrop::after,
    .hero-visual::before {
        display: none;
    }

    .screenshot-frame,
    .viewer-frame,
    .card,
    .cta-banner,
    .btn-primary,
    .release-card-latest,
    .site-nav-links {
        box-shadow: none;
    }

    .viewer {
        background: Canvas;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
}

/* --- Admin portal (/admin) -----------------------------------------------------
   Static SSR metrics dashboard + login card. Token-only colors; the bar chart is pure CSS —
   strict CSP forbids inline styles, so bar heights come from the precomputed .bar-h-* bucket
   classes below (0..100 step 5), chosen server-side in AdminDashboard.razor. */

.admin-login {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 55vh;
}

.admin-login-card {
    width: min(380px, 100%);
    padding: clamp(1.5rem, 4vw, 2.25rem);
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-m);
}

.admin-login-card h1 {
    margin-top: 0;
}

.admin-login-submit {
    width: 100%;
}

.admin-field {
    display: flex;
    flex-direction: column;
    gap: var(--akml-scalar-spacing-xs);
    margin-bottom: var(--akml-scalar-spacing-l);
}

.admin-field label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--akml-text-secondary);
}

.admin-input {
    padding: 10px 12px;
    background-color: var(--akml-surface-input);
    color: var(--akml-text-primary);
    border: 1px solid var(--akml-border-strong);
    border-radius: var(--akml-scalar-radius-s);
    font-size: 0.95rem;
}

.admin-input:focus {
    outline: none;
    border-color: var(--akml-border-focus);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--akml-border-focus) 30%, transparent);
}

.admin-error {
    padding: var(--akml-scalar-spacing-s) var(--akml-scalar-spacing-m);
    color: var(--akml-status-danger);
    background-color: color-mix(in srgb, var(--akml-status-danger) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--akml-status-danger) 40%, transparent);
    border-radius: var(--akml-scalar-radius-s);
    font-size: 0.9rem;
}

.admin-header-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--akml-scalar-spacing-m);
}

.admin-signout {
    margin: 0;
}

.admin-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--akml-scalar-spacing-m);
    margin-bottom: clamp(1.75rem, 4vw, 2.5rem);
}

.admin-stat {
    padding: var(--akml-scalar-spacing-l);
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-m);
}

.admin-stat-value {
    margin: 0;
    font-size: 1.75rem;
    font-weight: 700;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.admin-stat-label {
    margin: var(--akml-scalar-spacing-xs) 0 0;
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--akml-text-secondary);
}

.admin-panel {
    padding: var(--akml-scalar-spacing-l);
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-m);
    margin-bottom: clamp(1.75rem, 4vw, 2.5rem);
}

.admin-panel h2 {
    margin-top: 0;
    margin-bottom: var(--s-4);
    font-size: 1.05rem;
    line-height: 1.3;
}

.admin-tables {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: var(--akml-scalar-spacing-l);
}

.admin-tables .admin-panel {
    margin-bottom: 0;
}

.admin-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

.admin-table th {
    padding: var(--akml-scalar-spacing-s);
    text-align: left;
    font-size: var(--t-xs);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--akml-text-secondary);
    border-bottom: 1px solid var(--akml-border-strong);
}

.admin-table td {
    padding: var(--akml-scalar-spacing-s);
    border-bottom: 1px solid var(--akml-border-subtle);
}

.admin-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.admin-empty {
    color: var(--akml-text-secondary);
    font-size: 0.9rem;
}

.admin-path {
    margin: 0 0 var(--akml-scalar-spacing-s);
    font-size: 0.85rem;
    color: var(--akml-text-secondary);
    word-break: break-all;
}

/* Daily-visits bar chart: fixed-height flex row; each bar's height comes from its bucket class. */
.admin-chart-bars {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 160px;
    padding-top: var(--akml-scalar-spacing-s);
}

.admin-chart-bar {
    flex: 1 1 0;
    min-width: 2px;
    background-color: var(--akml-accent-primary);
    border-radius: 2px 2px 0 0;
    transition: background-color 0.16s ease;
}

.admin-chart-bar:hover {
    background-color: var(--akml-accent-primaryhover);
}

.admin-chart-bar.bar-h-0 {
    height: 2px;
    background-color: var(--akml-surface-elevated);
}

.admin-chart-labels {
    display: flex;
    gap: 2px;
    margin-top: var(--akml-scalar-spacing-xs);
    border-top: 1px solid var(--akml-border-subtle);
    padding-top: var(--akml-scalar-spacing-xs);
}

/* A11Y-001: --akml-text-disabled measured 3.07:1 on the dark panel at this size.
   text-secondary is the correct token for small-but-readable chrome (5.71:1). */
.admin-chart-label {
    flex: 1 1 0;
    min-width: 2px;
    overflow: hidden;
    text-align: center;
    font-size: 0.65rem;
    color: var(--akml-text-secondary);
    white-space: nowrap;
}

/* Bar height buckets (percentages of the 160px chart track), step 5 — referenced from
   AdminDashboard.razor as bar-h-{bucket}. */
.bar-h-0 { height: 0%; }
.bar-h-5 { height: 5%; }
.bar-h-10 { height: 10%; }
.bar-h-15 { height: 15%; }
.bar-h-20 { height: 20%; }
.bar-h-25 { height: 25%; }
.bar-h-30 { height: 30%; }
.bar-h-35 { height: 35%; }
.bar-h-40 { height: 40%; }
.bar-h-45 { height: 45%; }
.bar-h-50 { height: 50%; }
.bar-h-55 { height: 55%; }
.bar-h-60 { height: 60%; }
.bar-h-65 { height: 65%; }
.bar-h-70 { height: 70%; }
.bar-h-75 { height: 75%; }
.bar-h-80 { height: 80%; }
.bar-h-85 { height: 85%; }
.bar-h-90 { height: 90%; }
.bar-h-95 { height: 95%; }
.bar-h-100 { height: 100%; }

/* DOC-003: "Last updated" line under a document title — quiet, sits between the H1 and the
   article body without competing with either. */
.doc-meta {
    margin: calc(-1 * var(--akml-scalar-spacing-xs)) 0 var(--akml-scalar-spacing-m);
    color: var(--akml-text-secondary);
    font-size: 0.85rem;
}

/* MISC-001: request-id block on the error page reuses the .hash-block monospace treatment. */
.error-request-id {
    max-width: 65ch;
    margin-top: clamp(2rem, 5vw, 3rem);
}

.error-request-id h2 {
    margin-top: 0;
    font-size: 1.05rem;
}

/* --- Docs reading experience (DOC-004 / DOC-005 / DOC-006) ---------------------- */

/* DOC-004: heading permalinks. The anchor is emitted by MarkdownRenderer for every H2-H4
   that AutoIdentifiers gave an id; it stays invisible until the heading is hovered or the
   link itself is focused, so the prose is not littered with hashes. */
.doc-heading {
    position: relative;
}

.doc-anchor {
    position: absolute;
    inset-inline-start: -1em;
    width: 1em;
    color: var(--akml-text-link);
    text-decoration: none;
    opacity: 0;
    transition: opacity 0.12s ease;
}

.doc-heading:hover .doc-anchor,
.doc-anchor:focus-visible {
    opacity: 1;
}

/* At narrow widths there is no gutter to hang the anchor in — inline it instead. */
@media (max-width: 720px) {
    .doc-anchor {
        position: static;
        margin-inline-end: 0.25em;
    }
}

/* DOC-005: copy button on documentation code blocks. The wrapper is injected by
   js/copy-hash.js, so no-JS readers get the plain <pre> they always did. */
.code-block {
    position: relative;
}

.copy-code-btn {
    position: absolute;
    top: var(--s-2);
    inset-inline-end: var(--s-2);
    margin: 0;
    opacity: 0;
    transition: opacity 0.14s ease;
}

.code-block:hover .copy-code-btn,
.copy-code-btn:focus-visible {
    opacity: 1;
}

/* Touch has no hover — keep the button visible there rather than unreachable. */
@media (hover: none) {
    .copy-code-btn {
        opacity: 1;
    }
}

/* DOC-004: article footer — source link and prev/next pager. */
.doc-footer {
    margin-top: var(--s-block);
    padding-top: var(--s-5);
    border-top: 1px solid var(--akml-border-default);
}

.doc-source {
    margin: 0 0 var(--s-5);
    font-size: var(--t-sm);
}

.doc-pager {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
    gap: var(--s-4);
}

.doc-pager-link {
    display: grid;
    gap: var(--s-1);
    padding: var(--s-4);
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-s);
    text-decoration: none;
    transition: border-color 0.16s ease, transform 0.16s ease;
}

.doc-pager-link:hover {
    border-color: color-mix(in srgb, var(--akml-accent-primary) 45%, var(--akml-border-strong));
    transform: translateY(-2px);
}

/* "Next" sits on the right and reads right-aligned, so the pair mirrors the page flow. */
.doc-pager-next {
    text-align: end;
    grid-column: -2;
}

.doc-pager-dir {
    color: var(--akml-text-secondary);
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
}

.doc-pager-title {
    color: var(--akml-text-primary);
    font-weight: 600;
}

/* DOC-006 / A11Y-003: result count live region, and richer result rows. */
.docs-search-status {
    margin: var(--s-1) 0 0;
    color: var(--akml-text-secondary);
    font-size: var(--t-xs);
}

.docs-search-status:empty {
    display: none;
}

.docs-search-results a {
    display: grid;
    gap: 2px;
}

.docs-search-title {
    font-weight: 600;
}

.docs-search-excerpt {
    color: var(--akml-text-secondary);
    font-size: var(--t-xs);
    line-height: 1.45;
    /* Two lines of context is enough to judge a hit; more turns the list into a wall. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* A11Y-007: arrow-key selection needs the same visual weight as hover. */
.docs-search-results li.is-active a,
.docs-search-results li[aria-selected="true"] a {
    background-color: var(--akml-surface-hover);
}

/* DOC-004: on wide viewports the "On this page" list becomes a sticky right rail instead of a
   card wedged between the title and the first paragraph — the convention readers expect, and it
   stays visible while they scroll. Below this width it keeps its original inline treatment, and
   below 900px it stays hidden (U15: the sidebar tree already provides navigation there).

   The rail needs room, so the docs layout widens past the marketing pages' 1200px measure. The
   article column keeps its 80ch cap, so prose length is unchanged. */
@media (min-width: 1180px) {
    .docs-layout {
        max-width: 1440px;
    }

    .doc-article {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 15rem;
        column-gap: var(--s-7);
        align-items: start;
    }

    .doc-header {
        grid-column: 1;
        grid-row: 1;
    }

    .doc-body {
        grid-column: 1;
        grid-row: 2;
    }

    .doc-footer {
        grid-column: 1;
        grid-row: 3;
    }

    .on-this-page {
        grid-column: 2;
        /* span 3, not "1 / -1": with no explicit grid-template-rows, -1 resolves against the
           EXPLICIT grid (which has no rows), so the rail landed in its own implicit row and
           pushed the body down, leaving an empty band under the title. */
        grid-row: 1 / span 3;
        position: sticky;
        top: calc(var(--site-header-h) + var(--s-4));
        max-height: calc(100vh - var(--site-header-h) - var(--s-6));
        overflow-y: auto;
        margin: 0;
    }
}

/* --- Admin portal, Phase 4 additions --------------------------------------------- */

/* Screen-reader-only helper (chart captions). */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* ADM-003/007: window selector + export, above the metrics. */
.admin-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-3);
    margin-bottom: var(--s-5);
}

.admin-toolbar-label {
    color: var(--akml-text-secondary);
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.admin-ranges {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    margin: 0;
    padding: var(--s-1);
    list-style: none;
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-s);
}

.admin-ranges a {
    display: block;
    padding: var(--s-1) var(--s-3);
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
    text-decoration: none;
    border-radius: var(--akml-scalar-radius-xs);
    transition: color 0.16s ease, background-color 0.16s ease;
}

.admin-ranges a:hover {
    color: var(--akml-text-primary);
    background-color: var(--akml-surface-hover);
}

.admin-ranges a.is-current {
    color: var(--akml-text-onaccent);
    background-color: var(--akml-accent-primary);
}

.admin-export {
    margin-inline-start: auto;
    font-size: var(--t-sm);
}

/* The bot-hits tile is context, not a headline number — keep it visually secondary. */
.admin-stat-muted .admin-stat-value {
    color: var(--akml-text-secondary);
    font-weight: 600;
}

/* --- Charts ---------------------------------------------------------------------- */

.admin-chart-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s-3);
}

.admin-chart-head h2 {
    margin: 0;
}

.admin-chart-total {
    margin: 0;
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
    font-variant-numeric: tabular-nums;
}

/* Axis column + plot area. */
.admin-chart {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--s-2);
    margin-top: var(--s-4);
}

.admin-chart-scale {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    height: 160px;
    padding-top: var(--s-2);
    color: var(--akml-text-secondary);
    font-size: var(--t-xs);
    font-variant-numeric: tabular-nums;
    text-align: end;
}

.admin-chart-plot {
    min-width: 0;
}

/* One column per day; two bars inside when a secondary series is present. */
.admin-chart-col {
    display: flex;
    align-items: flex-end;
    gap: 1px;
    flex: 1 1 0;
    min-width: 2px;
    height: 100%;
}

.admin-chart-bar-secondary {
    background-color: color-mix(in srgb, var(--akml-accent-primary) 45%, var(--akml-surface-panel));
}

.admin-chart-legend {
    display: flex;
    align-items: center;
    gap: var(--s-2);
    margin: var(--s-3) 0 0;
    color: var(--akml-text-secondary);
    font-size: var(--t-xs);
}

.admin-legend-key {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 2px;
}

.admin-legend-primary {
    background-color: var(--akml-accent-primary);
}

.admin-legend-secondary {
    background-color: color-mix(in srgb, var(--akml-accent-primary) 45%, var(--akml-surface-panel));
}

/* A11Y-005: the table behind each chart. Collapsed by default so the panel still reads as a
   chart, but present in the DOM for assistive tech and for anyone wanting exact numbers. */
.admin-chart-data {
    margin-top: var(--s-4);
    border-top: 1px solid var(--akml-border-subtle);
    padding-top: var(--s-3);
}

.admin-chart-data summary {
    cursor: pointer;
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
}

.admin-chart-data summary:hover {
    color: var(--akml-text-primary);
}

.admin-chart-data .table-scroll {
    max-height: 22rem;
    overflow-y: auto;
}

/* Engagement tile row sits under the charts — slightly quieter than the headline metrics. */
.admin-stats-secondary {
    margin-top: calc(-1 * var(--s-4));
}

.admin-stats-secondary .admin-stat-value {
    font-size: 1.4rem;
}

/* Privacy note under the dashboard intro: it states what is actually stored, so it should be
   readable rather than fine print. */
.admin-privacy {
    max-width: 70ch;
    margin: var(--s-3) 0 0;
    padding: var(--s-3);
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
    line-height: 1.55;
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-s);
}

.admin-privacy strong {
    color: var(--akml-text-primary);
}

/* Long keys (referrer URLs, campaign names) must wrap rather than stretch the table. */
.admin-key {
    max-width: 32ch;
    overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------------------
   Spec 038 (US4): admin portal shell -- persistent section navigation plus the
   shared reporting window, rendered by Components/Layout/AdminLayout.razor on
   every portal page. Design tokens only; nothing here belongs in the generated
   themes/*.css files, which are produced from docs/theme-tokens.json.
   --------------------------------------------------------------------------- */
.admin-shell-bar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-3);
    align-items: center;
    justify-content: space-between;
    padding-block: var(--s-3) var(--s-2);
    margin-bottom: var(--s-4);
    border-bottom: 1px solid var(--akml-border-subtle);
}

.admin-nav-list {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.admin-nav-list a {
    display: block;
    padding: var(--s-1) var(--s-3);
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
    font-weight: 500;
    text-decoration: none;
    border-radius: var(--akml-scalar-radius-xs);
    transition: color 0.16s ease, background-color 0.16s ease;
}

.admin-nav-list a:hover {
    color: var(--akml-text-primary);
    background-color: var(--akml-surface-hover);
}

.admin-nav-list a.is-current {
    color: var(--akml-text-onaccent);
    background-color: var(--akml-accent-primary);
    font-weight: 600;
}

/* FR-032, second clause: the active window is stated in words on every section,
   so a screenshot is never ambiguous about the range it describes. */
.admin-range-active {
    margin-inline-start: auto;
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
}

@media (max-width: 640px) {
    .admin-shell-bar {
        align-items: flex-start;
    }

    .admin-range-active {
        margin-inline-start: 0;
        width: 100%;
    }
}

/* Spec 038 (US2): settings-page controls — radio choices with an explanatory hint,
   and the "what the public sees" preview list. Tokens only. */
.admin-choice {
    padding-block: var(--s-2);
}

.admin-choice label {
    display: flex;
    gap: var(--s-2);
    align-items: baseline;
    cursor: pointer;
}

.admin-choice-hint {
    margin: var(--s-1) 0 0;
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
}

.release-preview {
    margin: 0;
    padding-inline-start: var(--s-4);
}

.release-preview li {
    padding-block: var(--s-1);
}

/* Reserved for the admin Releases section (T088): advertised-but-missing and
   present-but-unadvertised both need to read as a warning, not as body text. */
.admin-flag {
    color: var(--akml-status-warning, #b45309);
    font-weight: 600;
}

/* ---------------------------------------------------------------------------
   Spec 038 (US5): consent bar. NON-BLOCKING by contract (FR-043b) — a bar, not
   a modal. No overlay, no backdrop, no scroll lock. It sits at the bottom of the
   viewport and must never cover the download button; on narrow screens it stacks
   and scrolls with the page rather than pinning.
   --------------------------------------------------------------------------- */
.consent-bar {
    position: sticky;
    bottom: 0;
    z-index: 20;
    background-color: var(--akml-surface-panel);
    border-top: 1px solid var(--akml-border-subtle);
}

.consent-bar-inner {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-3);
    align-items: center;
    justify-content: space-between;
    padding-block: var(--s-3);
}

.consent-bar-text {
    margin: 0;
    flex: 1 1 28rem;
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
}

.consent-bar-actions {
    display: flex;
    gap: var(--s-2);
    flex-wrap: wrap;
}

/* Accept and Decline must read as equally available choices (FR-043b). */
.consent-btn {
    min-width: 7rem;
}

@media (max-width: 640px) {
    .consent-bar {
        position: static;
    }

    .consent-bar-actions {
        width: 100%;
    }

    .consent-btn {
        flex: 1 1 auto;
    }
}

/* ---------------------------------------------------------------------------
   Spec 038: download page.

   The first rebuild stacked five full-width panels, each holding a sentence or
   two. It turned about six facts into a 2,000px page and repeated the filename
   and size three times over, which read as unfinished rather than spare.

   This is the layout vendor download pages converge on, and for a reason: the
   facts sit BESIDE the button (they are the questions asked before clicking,
   not after), and everything below splits into a main column and a narrow one.
   Two columns is what makes the page dense without being cramped -- a single
   column of short sections can only ever be sparse or long.

   Design tokens only.
   --------------------------------------------------------------------------- */
.download-hero {
    display: grid;
    grid-template-columns: minmax(0, 1.55fr) minmax(17rem, 1fr);
    gap: var(--s-7);
    align-items: start;
    padding: var(--s-6) var(--s-5);
    /* .release-card sets a bottom margin for the old stacked-card layout. The gap below the hero
       is owned by .download-columns' margin-top; two owners for one gap is how gaps compound. */
    margin-bottom: 0;
}

.download-hero h1 {
    margin: var(--s-2) 0 var(--s-3);
}

.download-hero-lead {
    max-width: 52ch;
    margin: 0 0 var(--s-5);
    color: var(--akml-text-secondary);
    font-size: var(--t-lg);
}

/* The primary action carries the platform and size on a second line, so the
   visitor knows what they are about to get without hunting for it.

   Generous padding is deliberate: this is the one control the whole page exists
   for, and at 12px it read as cramped against its own two lines of text. */
.btn-lg {
    padding: var(--s-4) var(--s-6);
    font-size: var(--t-md);
    line-height: 1.3;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: var(--s-1);
    min-width: 15rem;
}

.btn-lg .btn-sub {
    font-size: var(--t-xs);
    font-weight: 400;
    line-height: 1.2;
    opacity: 0.85;
}

/* The secondary action sits beside a two-line button, so it stretches to match
   rather than floating against its top edge. */
.cta-row .btn-lg + .btn {
    align-self: stretch;
}

/* Breathing room around the primary action specifically. The generic .cta-row
   rhythm is fine in a paragraph flow; the hero's CTA is the focal point and
   earns more space above it. */
.download-hero .cta-row {
    margin-block: var(--s-6) 0;
}

.download-hero-note {
    max-width: 46ch;
    margin: var(--s-5) 0 0;
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
    line-height: 1.6;
}

/* ---- The facts panel beside the hero ---- */

/* Elevated, not the plain panel ground: this sits INSIDE the hero card, which is already
   --akml-surface-panel, and a panel on a panel is an invisible panel. */
.release-facts-panel {
    padding: var(--s-5);
    background-color: var(--akml-surface-elevated);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-m);
}

.release-facts-title {
    margin: 0 0 var(--s-4);
    /* `.release-card h2` sets the mono face, for the release cards that used a version number as
       their heading. This is a label, not a version, so it takes the body face back. */
    font-family: var(--f-sans);
    color: var(--akml-text-secondary);
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* Each fact is one row with the label opposite the value, so the panel scans as
   a table rather than as a list of sentences. Label-above-value would double
   its height for no gain. */
.release-facts-list {
    margin: 0;
    display: grid;
    gap: var(--s-3);
    font-size: var(--t-sm);
}

.release-facts-list > div {
    display: grid;
    grid-template-columns: minmax(0, auto) minmax(0, 1fr);
    gap: var(--s-3);
    align-items: baseline;
    padding-bottom: var(--s-3);
    border-bottom: 1px solid var(--akml-border-subtle);
}

.release-facts-list > div:last-child {
    padding-bottom: 0;
    border-bottom: none;
}

.release-facts-list dt {
    color: var(--akml-text-secondary);
}

.release-facts-list dd {
    margin: 0;
    justify-self: end;
    text-align: right;
    overflow-wrap: anywhere;
}

/* The filename is the one value long enough to fight the panel for width. */
.release-facts-file {
    font-size: var(--t-xs);
}

.release-facts-list .host-badges {
    justify-content: flex-end;
}

/* ---- The two columns below the hero ---- */

.download-columns {
    display: grid;
    grid-template-columns: minmax(0, 1.55fr) minmax(17rem, 1fr);
    gap: var(--s-7);
    align-items: start;
}

/* Rhythm between the page's top-level blocks. `.page-body > section + section` (80px) matches only
   between literal <section> elements and carries marketing-section spacing, both wrong here: the
   hero, the two-column body and the version history are one continuous document about a single
   download, not three separate pitches. At (0,2,1) this outranks that (0,1,2) rule on class count,
   and it is tag-agnostic, so the <div> wrapper cannot silently break the chain the way a <details>
   element did in the previous layout. */
.page-body > .download-columns,
.page-body > .release-history {
    margin-top: var(--s-block);
}

.download-main > .download-block + .download-block {
    margin-top: var(--s-6);
}

.download-aside > .download-card + .download-card {
    margin-top: var(--s-5);
}

/* The main column is plain sections on the page ground; only the aside is
   carded. Boxing everything was what made the previous version monotonous --
   with no contrast between a card and its surroundings, a card means nothing. */
.download-block > p {
    margin: 0 0 var(--s-3);
    max-width: 70ch;
}

.download-block > p:last-child {
    margin-bottom: 0;
}

.download-card {
    padding: var(--s-5);
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-m);
}

/* Specificity note, and the cause of a "no margin" bug fixed earlier in this
   spec: `.page-body > section > h2 { margin: 0 }` is (0,1,2) -- one class, two
   elements -- so a plain `.download-card > h2` at (0,1,1) LOSES to it and every
   heading renders flush against its own content. These chains are (0,2,1),
   which wins on class count. Any new panel class needs the same treatment. */
.download-columns .download-block > h2 {
    margin: 0 0 var(--s-4);
    font-size: var(--t-lg);
    line-height: 1.3;
}

.download-columns .download-card > h2 {
    margin: 0 0 var(--s-4);
    font-size: var(--t-base);
    line-height: 1.3;
}

/* ---- Install steps ---- */

.download-steps {
    margin: 0;
    padding-left: var(--s-5);
    display: grid;
    gap: var(--s-4);
    max-width: 70ch;
}

.download-steps li {
    padding-left: var(--s-1);
    line-height: 1.6;
}

.download-steps strong {
    display: block;
}

.download-note {
    margin: var(--s-5) 0 var(--s-2);
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
}

/* A command line is read left to right and must never be silently clipped, so
   it scrolls inside its own box rather than wrapping mid-switch. */
.download-cmd {
    display: block;
    padding: var(--s-3) var(--s-4);
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-s);
    font-size: var(--t-sm);
    overflow-x: auto;
    white-space: nowrap;
}

/* ---- Link lists ---- */

.download-links {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: var(--s-3);
    font-size: var(--t-sm);
    max-width: 70ch;
}

.download-links li {
    line-height: 1.5;
}

.spec-table {
    width: 100%;
    margin: 0;
    border-collapse: collapse;
}

/* .table-scroll sets its own margin-block; inside a section the heading already
   provides the space above, so collapse the duplicate. */
.release-history .table-scroll {
    margin-block: 0;
}

.spec-table th,
.spec-table td {
    padding: var(--s-2) 0;
    text-align: left;
    vertical-align: top;
    border-bottom: 1px solid var(--akml-border-subtle);
}

.spec-table tbody tr:last-child th,
.spec-table tbody tr:last-child td {
    border-bottom: none;
}

.spec-table th[scope="row"] {
    width: 34%;
    padding-inline-end: var(--s-4);
    color: var(--akml-text-secondary);
    font-weight: 500;
}

.release-table th[scope="col"] {
    color: var(--akml-text-secondary);
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.release-table td {
    padding-block: var(--s-3);
}

/* .spec-table sets `padding: var(--s-2) 0` -- no horizontal padding at all. On a wide viewport the
   columns are far enough apart that it never shows, but once the table hits its 30rem min-width and
   starts scrolling inside its container, adjacent cells touch: "1.26.0911.2219September 12, 2026".
   Only the version/date table needs this; the spec table's two columns are explicitly sized. */
.release-table th,
.release-table td {
    padding-inline-end: var(--s-5);
}

.release-table th:last-child,
.release-table td:last-child {
    padding-inline-end: 0;
}

.release-table-action {
    white-space: nowrap;
}

.hash-block-inline {
    display: inline-block;
    margin-inline-start: var(--s-3);
    font-size: var(--t-xs);
}

.hash-block-inline code {
    display: block;
    margin-top: var(--s-1);
    overflow-wrap: anywhere;
}

.hash-cmd {
    display: block;
    margin-top: var(--s-1);
    overflow-wrap: anywhere;
}

/* One breakpoint collapses both grids. Below roughly 62rem the narrow column is
   too tight for a checksum, and its 17rem minimum would start forcing the page
   itself to scroll sideways. */
@media (max-width: 62rem) {
    .download-hero,
    .download-columns {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--s-5);
    }

    /* Stacked, the facts panel reads better left-aligned -- right-aligned values
       only make sense when a label sits opposite them across a narrow gutter. */
    .release-facts-list dd {
        justify-self: start;
        text-align: left;
    }

    .release-facts-list .host-badges {
        justify-content: flex-start;
    }
}

@media (max-width: 640px) {
    .download-hero {
        padding: var(--s-5) var(--s-4);
    }

    .spec-table th[scope="row"] {
        width: 42%;
    }

    /* The version table is the one place the page may scroll sideways, inside
       its own container -- the page body never does. */
    .release-table {
        min-width: 30rem;
    }
}

/* ---------------------------------------------------------------------------
   Home page: the credibility strip and the comparison section. Design tokens
   only; the hero, card grid and CTA banner keep their existing styles.
   --------------------------------------------------------------------------- */

/* The hero's second line carries the free/open-source fact, which is the single
   strongest thing this project can say against a paid alternative. Quieter than
   the tagline above it, louder than fine print. */
.hero-tagline-sub {
    margin-top: var(--s-3);
    font-size: var(--t-base);
    color: var(--akml-text-secondary);
    text-wrap: balance;
}

.proof-strip {
    margin-block: var(--s-7) var(--s-8);
    padding-block: var(--s-5);
    border-block: 1px solid var(--akml-border-subtle);
}

.proof-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: var(--s-5);
    margin: 0;
}

.proof-item dt {
    font-size: var(--t-2xl);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--akml-accent-primary);
}

.proof-item dd {
    margin: var(--s-2) 0 0;
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
    line-height: 1.5;
}

.comparison {
    margin-block: var(--s-8);
}

.comparison-lead {
    max-width: 68ch;
    margin: 0 0 var(--s-4);
    font-size: var(--t-md);
    line-height: 1.7;
    color: var(--akml-text-secondary);
}

.comparison-lead:last-child {
    margin-bottom: 0;
}

/* The comparison heading is a classed section, so it needs its own spacing --
   `.page-body > section > h2 { margin: 0 }` is (0,1,2) and outranks a bare
   `.comparison h2`. Same trap the panel headings fell into. */
.page-body > .comparison > h2 {
    margin: var(--s-2) 0 var(--s-4);
}

@media (max-width: 640px) {
    .proof-strip {
        margin-block: var(--s-6);
    }

    .proof-list {
        gap: var(--s-4);
    }
}

/* ===========================================================================
   Admin: headline figures, change indicators, badge.
   =========================================================================== */

/* The four compared figures lead the overview, so they carry more weight than the running totals
   below them. */
.admin-headline .admin-stat-value {
    font-size: clamp(1.75rem, 3vw, 2.25rem);
}

/* Change against the comparison period. Colour is never the only signal: the arrow and the
   visually-hidden sentence carry the same meaning. */
.admin-delta {
    margin: var(--s-2) 0 0;
    font-size: var(--t-sm);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.admin-delta-up,
.admin-delta-new {
    color: var(--akml-status-success);
}

.admin-delta-down {
    color: var(--akml-status-danger);
}

.admin-delta-flat {
    color: var(--akml-text-secondary);
}

.admin-footnote {
    max-width: 75ch;
    margin: calc(-1 * var(--s-3)) 0 var(--s-6);
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
    line-height: 1.6;
}

.admin-footnote a {
    white-space: nowrap;
}

/* Open-feedback count beside "Feedback" in the portal navigation. */
.admin-badge {
    display: inline-block;
    min-width: 1.35rem;
    margin-left: var(--s-2);
    padding: 0 0.35rem;
    border-radius: 999px;
    background-color: var(--akml-status-danger);
    color: var(--akml-text-ondanger);
    font-size: var(--t-xs);
    font-weight: 700;
    line-height: 1.35rem;
    text-align: center;
    vertical-align: 0.1em;
}

/* ===========================================================================
   Admin: Insights.
   =========================================================================== */

.insights-kpi {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--s-2) var(--s-4);
    margin-bottom: var(--s-3);
}

.insights-kpi-value {
    margin: 0;
    font-size: clamp(2.25rem, 5vw, 3rem);
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--akml-accent-primary);
}

.insights-kpi-text {
    margin: 0;
    max-width: 50ch;
}

/* Two tables per row at most: at three, a 1200px page leaves each ~360px, less than a label, three
   figures and a meter need, and the labels were being broken mid-word. */
.insights-tables {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr));
    gap: var(--s-5);
    margin-top: var(--s-5);
}

.insights-table-block h3 {
    margin: 0 0 var(--s-3);
    font-size: var(--t-base);
}

/* .admin-key wraps anywhere, which lets a squeezed label column shrink to one character per
   line ("/do|wnlo|ad"). A floor keeps labels readable; a table that no longer fits scrolls
   inside its .table-scroll instead. */
.insights-table-block .admin-key {
    min-width: 7.5rem;
}

@media (max-width: 40rem) {
    /* The rate is the value; the meter only decorates it, and on a phone it costs the label
       column the room it needs. Scoped to the table so it outranks the base .insights-meter rule,
       which comes later in this file. */
    .insights-table-block .insights-meter {
        display: none;
    }

    /* Tighter cells so label, both counts AND the rate fit a phone without scrolling: the rate
       is the column the table exists for, and it is the one a sideways scroll would hide. */
    .insights-table-block .admin-table th,
    .insights-table-block .admin-table td {
        padding-inline: 0.35rem;
    }

    .insights-table-block .admin-table th {
        letter-spacing: 0.02em;
    }

    .insights-table-block .admin-key {
        min-width: 5.5rem;
    }
}

/* The rate as a figure and a short meter. The meter is decoration (aria-hidden); the figure is
   the value. */
.insights-rate {
    white-space: nowrap;
}

.insights-meter {
    display: inline-block;
    width: 3.5rem;
    height: 0.4rem;
    margin-left: var(--s-2);
    vertical-align: middle;
    border-radius: 999px;
    background-color: var(--akml-border-subtle);
    overflow: hidden;
}

.insights-meter-fill {
    display: block;
    height: 100%;
    background-color: var(--akml-accent-primary);
}

/* Meter widths in 5% steps -- the strict CSP forbids inline styles, so widths come from a fixed
   class set, the same way chart bar heights do. */
.bar-w-0 { width: 0%; }
.bar-w-5 { width: 5%; }
.bar-w-10 { width: 10%; }
.bar-w-15 { width: 15%; }
.bar-w-20 { width: 20%; }
.bar-w-25 { width: 25%; }
.bar-w-30 { width: 30%; }
.bar-w-35 { width: 35%; }
.bar-w-40 { width: 40%; }
.bar-w-45 { width: 45%; }
.bar-w-50 { width: 50%; }
.bar-w-55 { width: 55%; }
.bar-w-60 { width: 60%; }
.bar-w-65 { width: 65%; }
.bar-w-70 { width: 70%; }
.bar-w-75 { width: 75%; }
.bar-w-80 { width: 80%; }
.bar-w-85 { width: 85%; }
.bar-w-90 { width: 90%; }
.bar-w-95 { width: 95%; }
.bar-w-100 { width: 100%; }

.insights-summary {
    margin: 0 0 var(--s-4);
}

/* Weekday x hour. A grid of 25 columns (label + 24 hours) that fits a phone -- small cells, like
   a contribution graph, read better than a grid you have to scroll to see the evening. Only below
   its floor (narrower than any phone) does it scroll inside its wrapper. */
.insights-heatmap-wrap {
    margin: 0 0 var(--s-3);
}

.insights-heatmap {
    display: grid;
    grid-template-columns: 2.25rem repeat(24, minmax(0, 1fr));
    gap: 2px;
    min-width: 17rem;
    font-size: var(--t-xs);
    color: var(--akml-text-secondary);
}

@media (min-width: 40rem) {
    .insights-heatmap {
        grid-template-columns: 2.75rem repeat(24, minmax(0, 1fr));
        gap: 3px;
    }
}

.insights-heatmap-hour {
    text-align: left;
    font-variant-numeric: tabular-nums;
}

.insights-heatmap-day {
    align-self: center;
    font-weight: 600;
}

.insights-heat {
    display: inline-block;
    min-height: 1.1rem;
    border-radius: 2px;
}

@media (min-width: 40rem) {
    .insights-heat {
        min-height: 1.35rem;
        border-radius: 3px;
    }
}

.insights-legend {
    margin: 0 0 var(--s-4);
    color: var(--akml-text-secondary);
    font-size: var(--t-xs);
}

.insights-legend .insights-heat {
    width: 1rem;
    min-height: 0.8rem;
    margin: 0 1px;
    vertical-align: middle;
}

.heat-0 { background-color: var(--akml-surface-hover); }
.heat-1 { background-color: color-mix(in srgb, var(--akml-accent-primary) 18%, transparent); }
.heat-2 { background-color: color-mix(in srgb, var(--akml-accent-primary) 36%, transparent); }
.heat-3 { background-color: color-mix(in srgb, var(--akml-accent-primary) 55%, transparent); }
.heat-4 { background-color: color-mix(in srgb, var(--akml-accent-primary) 75%, transparent); }
.heat-5 { background-color: var(--akml-accent-primary); }

.insights-heat-table th,
.insights-heat-table td {
    padding-inline: 0.35rem;
}

.insights-loyalty {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
    gap: var(--s-4);
    margin-bottom: var(--s-4);
}

.insights-loyalty-card {
    padding: var(--s-4) var(--s-5);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-m);
}

.insights-loyalty-label {
    margin: 0;
    color: var(--akml-text-secondary);
    font-size: var(--t-xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.insights-loyalty-value {
    margin: var(--s-1) 0;
    font-size: 1.75rem;
    font-weight: 700;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.insights-loyalty-detail {
    margin: 0;
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
}

.insights-coverage {
    max-width: 75ch;
}

/* ===========================================================================
   Feedback: the public form.
   =========================================================================== */

.feedback-layout {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) minmax(15rem, 1fr);
    gap: var(--s-7);
    align-items: start;
}

.feedback-form {
    padding: var(--s-6) var(--s-5);
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-m);
}

.feedback-field {
    margin: 0 0 var(--s-5);
    padding: 0;
    border: 0;
}

.feedback-field > label,
.feedback-field > legend {
    display: block;
    margin-bottom: var(--s-2);
    padding: 0;
    font-weight: 600;
}

.feedback-optional {
    color: var(--akml-text-secondary);
    font-weight: 400;
}

.feedback-hint {
    margin: 0 0 var(--s-2);
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
}

.feedback-input {
    display: block;
    width: 100%;
    max-width: 100%;
    padding: var(--s-3);
    border: 1px solid var(--akml-border-strong);
    border-radius: var(--akml-scalar-radius-s);
    background-color: var(--akml-surface-input);
    color: var(--akml-text-primary);
    font: inherit;
    line-height: 1.5;
}

textarea.feedback-input {
    min-height: 9rem;
    resize: vertical;
}

.feedback-input:focus-visible {
    outline: 2px solid var(--akml-border-focus);
    outline-offset: 1px;
    border-color: var(--akml-border-focus);
}

/* The categories as large, tappable choices rather than a dropdown: five options fit, and a
   visitor sees all of them at once. */
.feedback-choices {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
    gap: var(--s-2);
}

.feedback-choice {
    display: flex;
    align-items: center;
    gap: var(--s-2);
    min-height: 2.75rem;
    padding: var(--s-2) var(--s-3);
    border: 1px solid var(--akml-border-subtle);
    border-radius: var(--akml-scalar-radius-s);
    cursor: pointer;
}

.feedback-choice:has(input:checked) {
    border-color: var(--akml-accent-primary);
    background-color: color-mix(in srgb, var(--akml-accent-primary) 8%, transparent);
}

.feedback-choice input {
    flex: none;
    margin: 0;
}

/* The spam trap: out of sight and out of the accessibility tree, but still in the form for a bot
   to fill. Not display:none -- some bots skip fields that are. */
.feedback-trap {
    position: absolute;
    left: -10000px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.feedback-privacy {
    margin: var(--s-4) 0 0;
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
}

.feedback-errors {
    margin-bottom: var(--s-5);
}

.feedback-errors ul {
    margin: var(--s-2) 0 0;
    padding-left: var(--s-5);
}

.feedback-sent {
    max-width: 60ch;
    padding: var(--s-6) var(--s-5);
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-status-success);
    border-radius: var(--akml-scalar-radius-m);
}

.feedback-sent h2 {
    margin-top: 0;
}

.feedback-aside h2 {
    margin: 0 0 var(--s-3);
    font-size: var(--t-base);
}

.download-help p:last-child {
    margin-bottom: 0;
}

@media (max-width: 62rem) {
    .feedback-layout {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--s-5);
    }
}

@media (max-width: 640px) {
    .feedback-form {
        padding: var(--s-5) var(--s-4);
    }
}

/* ===========================================================================
   Feedback: the admin inbox.
   =========================================================================== */

.feedback-inbox {
    display: grid;
    gap: var(--s-4);
    margin: 0 0 var(--s-6);
    padding: 0;
    list-style: none;
}

.feedback-item {
    padding: var(--s-5);
    background-color: var(--akml-surface-panel);
    border: 1px solid var(--akml-border-subtle);
    border-left: 3px solid var(--akml-accent-primary);
    border-radius: var(--akml-scalar-radius-m);
}

.feedback-item.is-handled {
    border-left-color: var(--akml-border-subtle);
    opacity: 0.8;
}

.feedback-item-head {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--s-1) var(--s-4);
    margin-bottom: var(--s-3);
}

.feedback-item-category {
    margin: 0;
    font-weight: 700;
}

.feedback-item-id {
    color: var(--akml-text-secondary);
    font-weight: 400;
}

.feedback-item-meta {
    margin: 0;
    color: var(--akml-text-secondary);
    font-size: var(--t-sm);
}

/* The visitor's own line breaks are kept; long unbroken strings (a pasted URL, a stack trace
   token) wrap instead of widening the page. */
.feedback-item-message {
    margin: 0 0 var(--s-4);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    line-height: 1.6;
}

.feedback-item-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-3);
}

.feedback-item-actions form {
    margin: 0;
}

/* Header cells are uppercased for labels; a setting or variable name inside one must keep its
   real case, or it reads as the wrong name. */
.admin-table th code {
    text-transform: none;
    letter-spacing: normal;
}

.btn-danger-quiet:hover,
.btn-danger-quiet:focus-visible {
    border-color: var(--akml-status-danger);
    color: var(--akml-status-danger);
}
