/* Coverground — coverground.eu one-pager.
   Brand tokens mirror the app's @theme block (resources/css/app.css). Plain CSS,
   no build step. Azure #0c4688 is the primary; it hits 9.34:1 on white (AAA).

   The page is laid out as a route: each section is a "stop" on a vertical route
   line (the spine) with waypoint pins — S(tart), 2, 3, 4, F(inish). The pins and
   spine are decorative (aria-hidden); the sequence is carried by the visible
   .eyebrow text ("Start", "Stop 2", …), which must stay present at every
   breakpoint and must move together with the pin labels when sections change. */

/* Instrument Sans, self-hosted (no third-party font CDN). Variable woff2 covers
   weights 400–700; OFL-1.1 licensed (see fonts/OFL.txt). */
@font-face {
    font-family: 'Instrument Sans';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('/fonts/instrument-sans-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Instrument Sans';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('/fonts/instrument-sans-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
:root {
    --azure: #0c4688;
    --azure-bright: #8fb6ef;
    --azure-tint: #dbe6f5;
    --crimson: #fb5012;
    --fuchsia: #dc0073;
    --ink: #18181b;
    --muted: #525c5e;
    --silver-tint: #eef1f1;
    --surface: #ffffff;
    --border: #767680; /* 3.07:1 on white so the embed frame reads under forced-colors/dark */

    --maxw: 64rem;
    --font: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif,
            'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
}

@media (prefers-color-scheme: dark) {
    :root {
        --azure: #8fb6ef;
        --ink: #f4f4f5;
        --muted: #a1a1aa;
        --silver-tint: #2f2f34;
        --surface: #27272a;
        --border: #757582; /* 3.28:1 on the dark surface */
    }
}

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

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    font-family: var(--font);
    font-size: 1.125rem;
    line-height: 1.6;
    color: var(--ink);
    background: var(--surface);
    -webkit-font-smoothing: antialiased;
}

.wrap {
    width: 100%;
    max-width: var(--maxw);
    margin-inline: auto;
    padding-inline: 1.5rem;
}

/* --- Skip link --- */
.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    background: var(--surface);
    color: var(--azure);
    padding: 0.5rem 0.875rem;
    border-radius: 0.5rem;
    z-index: 10; /* above the route spine and everything else */
}
.skip-link:focus { left: 1rem; top: 1rem; outline: 3px solid var(--azure); }

/* --- Header / brand --- */
.site-header { padding-block: 1.5rem; }

/* Brand on the left, language switcher on the right. Wraps on very narrow
   screens so neither is clipped. */
.site-header .wrap {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.75rem 1.5rem;
}

/* Language switcher: the switch-target is the only link; the current language is a
   non-link <span> status label (you can't switch to the language you're already in).
   Affordance lives on the link (azure + a persistent underline, not colour alone —
   1.4.1); the current item is bold neutral-muted text with no underline/azure so it
   reads as "selected", not as a (disabled) link. Items are a mix of <a> and <span>,
   so the separator is element-agnostic. Mirrors the app's .locale-switcher. */
.lang-switch {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.9375rem;
}
/* Switch-target link: persistent underline so the affordance never relies on colour. */
.lang-switch a {
    color: var(--azure);
    text-decoration: underline;
    border-radius: 0.25rem;
}
.lang-switch a:hover { text-decoration-thickness: 2px; }
.lang-switch a:focus-visible { outline: 2px solid var(--azure); outline-offset: 2px; }
/* Current language: status, not a control. */
.lang-current { color: var(--muted); font-weight: 700; }
/* Decorative separator (not read out). Element-agnostic (a/span mix); inline-block +
   text-decoration:none keep the link's underline from running through the dot. */
.lang-switch > * + *::before {
    content: "·";
    display: inline-block;
    color: var(--muted);
    margin-inline-end: 0.5rem;
    text-decoration: none;
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
    text-decoration: none;
    color: inherit;
}
.brand svg { width: 2.25rem; height: 2.25rem; flex: none; }
.brand .wordmark {
    font-size: 1.375rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--azure);
}

/* --- Route spine (decorative) ---------------------------------------------- */
/* Each .stop section carries one vertical line segment in the left gutter;
   contiguous sections (padding, no vertical margins) make the segments read as
   one continuous route from the hero's S pin to the finish's F pin. SVG (not a
   CSS background) so the stroke survives forced-colors; currentColor picks up
   the forced ink there. Decorative: aria-hidden, focusable=false, and inert to
   the pointer. Hidden below 56rem — the visible eyebrow text carries the
   sequence at every breakpoint. */
.stop-line {
    display: none;
    position: absolute;
    top: 0;
    /* height must be explicit: the viewBox gives the svg an intrinsic 4:100
       ratio, so height:auto would resolve to 100px, not the section height. */
    height: 100%;
    /* Center of the trail gutter: wrap's centered left edge + 2.625rem. */
    left: calc((100% - min(100%, var(--maxw))) / 2 + 2.625rem - 2px);
    width: 4px;
    color: var(--azure);
    pointer-events: none;
    z-index: 0;
}
.stop-line line {
    fill: none;
    stroke: currentColor;
    /* The svg is only stretched vertically (preserveAspectRatio=none) and the
       line is vertical, so stroke width is undistorted without
       vector-effect:non-scaling-stroke — which must stay off: it breaks the
       pathLength=1 normalisation that the dash-draw animation relies on. */
    stroke-width: 3;
}

/* Waypoint pin: white disc + dark label, a self-contained always-legible unit
   in both themes (deliberately NOT tokenized — tokens would invert it in dark
   mode). Ring colour marks the stop type, matching the logo: crimson start,
   azure waypoints, fuchsia finish. Decorative — the eyebrow text beside it is
   the real content, and the two must always agree. */
.pin { width: 1.75rem; height: 1.75rem; flex: none; pointer-events: none; }
.pin circle { fill: #fff; stroke-width: 3; }
.pin text {
    fill: #18181b;
    font-family: var(--font);
    font-size: 12px;
    font-weight: 700;
    text-anchor: middle;
}
.pin--start  circle { stroke: var(--crimson); }
.pin--stop   circle { stroke: var(--azure); }
.pin--finish circle { stroke: var(--fuchsia); }

/* In forced-colors mode the hardcoded white discs would glow on a dark canvas;
   let the system palette take over. The line inherits the forced ink via
   currentColor automatically. */
@media (forced-colors: active) {
    .pin circle { fill: Canvas; }
    .pin text { fill: CanvasText; }
}

/* Stop label ("Start", "Stop 2", …): visible real text — the accessible
   counterpart of the decorative pin/spine. Uppercase and tracking via CSS only
   (never typed capitals or inserted spaces). Sits before the heading, outside
   it, so heading names stay clean for rotor navigation. */
.eyebrow {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.625rem;
    margin: 0 0 1rem;
    font-size: 0.875rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted); /* 7.0:1 light / 7.6:1 dark — small text needs 4.5:1 */
}

/* Wide screens: the spine appears and pins move off the text column into the
   gutter, centered on the line. Content shifts right to make room. */
@media (min-width: 56rem) {
    .stop { position: relative; }
    /* position:relative also lifts the content above the absolutely-positioned
       spine in paint order. */
    .stop > .wrap { position: relative; padding-left: 5.75rem; }
    .stop-line { display: block; }
    .stop .eyebrow .pin {
        position: absolute;
        left: -4rem; /* gutter center (2.625rem from wrap edge) minus half a pin */
        top: 50%;
        translate: 0 -50%;
    }
}

/* The route draws itself as you scroll — the single animated moment on the
   page. Both gates matter: the undrawn state (dashoffset 1) exists ONLY here,
   so reduced-motion users and non-supporting browsers always get the complete,
   static line. Scroll-driven = user-initiated and self-pausing (2.2.2 n/a;
   2.3.3 handled by the reduced-motion gate). */
@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .stop-line line {
            stroke-dasharray: 1;
            stroke-dashoffset: 1;
            animation: cg-draw linear both;
            animation-timeline: view();
            /* Draw while the segment scrolls through the lower half of the
               viewport; long segments finish by the time their midpoint is
               reached, so the trail always leads the reader. */
            animation-range: entry 0% cover 50%;
        }
        @keyframes cg-draw {
            to { stroke-dashoffset: 0; }
        }
    }
}

/* --- Hero --- */
.hero { padding-block: 2.5rem 1.5rem; }
/* The S pin sits beside the hero eyebrow (~2.5rem padding + half an eyebrow
   line); the segment starts just below it. Small drift under text zoom hides
   behind the opaque pin disc. */
.stop--start .stop-line { top: 3.1rem; height: calc(100% - 3.1rem); }
.hero h1 {
    font-size: clamp(2rem, 6vw, 3.25rem);
    line-height: 1.1;
    letter-spacing: -0.02em;
    font-weight: 700;
    margin: 0 0 1rem;
    max-width: 18ch;
}
.hero .lead {
    font-size: 1.25rem;
    color: var(--muted);
    margin: 0;
    max-width: 60ch;
}
.hero .lead-sub {
    font-size: 1rem;
    color: var(--muted);
    margin: 0.75rem 0 0;
    max-width: 60ch;
}

/* Beta notice — bordered (not filled), so --ink/--surface keep contrast in both
   themes; --azure-tint isn't dark-mode-adjusted, so a fill would fail there.
   Sits inside the finish stop, after the payoff statement: the page's one call
   to action, at the end of the route. */
.beta-note {
    display: block;
    width: fit-content;
    max-width: 100%;
    margin: 1.75rem auto 0;
    padding: 0.625rem 1rem;
    border: 1px solid var(--azure);
    border-radius: 0.5rem;
    font-size: 1rem;
    color: var(--ink);
    text-align: center;
}
.beta-note a { color: var(--azure); font-weight: 600; text-decoration: underline; }

/* --- Principles --- */
.principles { padding-block: 1.5rem; }
.principles h2 {
    font-size: 1.5rem;
    font-weight: 700;
    margin: 0 0 1.25rem;
}
.principle-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 1.25rem 2rem;
    grid-template-columns: 1fr;
}
@media (min-width: 40rem) {
    .principle-list { grid-template-columns: 1fr 1fr; }
}
.principle-list li { margin: 0; max-width: 60ch; }
.principle-list strong { display: block; margin-bottom: 0.25rem; }
.principles-note {
    margin: 1.75rem 0 0;
    color: var(--muted);
    max-width: 60ch;
}

/* --- Building a route (who does what) --- */
.build { padding-block: 1.5rem; }
.build h2 {
    font-size: 1.5rem;
    font-weight: 700;
    margin: 0 0 0.5rem;
}
.build-intro { color: var(--muted); margin: 0 0 1.5rem; max-width: 60ch; }
.build-split {
    display: grid;
    gap: 1.5rem 2rem;
    grid-template-columns: 1fr;
}
@media (min-width: 40rem) {
    .build-split { grid-template-columns: 1fr 1fr; }
}
.build-col h3 {
    font-size: 1.125rem;
    font-weight: 700;
    margin: 0 0 0.75rem;
}
.build-list {
    margin: 0;
    padding-left: 1.25rem;
    display: grid;
    gap: 0.5rem;
}
.build-list li { margin: 0; max-width: 60ch; }
.build-list li::marker { color: var(--azure); }

/* --- Demo / embed --- */
.demo { padding-block: 2.5rem; }
.demo h2 {
    font-size: 1.5rem;
    font-weight: 700;
    margin: 0 0 0.5rem;
}
.demo p { color: var(--muted); margin: 0 0 1.5rem; max-width: 60ch; }

.embed-frame {
    display: block;
    width: 480px;
    max-width: 100%;
    height: 380px;
    margin-inline: 0;   /* left-aligned with the heading/intro; the .wrap supplies the gutter */
    /* border:0 (not just omitted) — otherwise the browser's default <iframe>
       border shows. No frame/shadow: the card defines itself and the brand tab
       reads as an external label hanging off its edge. */
    border: 0;
}

.embed-fallback { margin-top: 1rem; font-size: 1rem; text-align: center; }
.embed-fallback a { color: var(--azure); }

/* Visually hidden but available to assistive tech. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* Reveal when a descendant (the fallback link) gets keyboard focus, so the
   focused control is actually visible — WCAG 2.4.7. Mirrors the skip-link. */
.sr-only:focus-within {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip: auto;
    clip-path: none;
    white-space: normal;
}

/* --- Finish stop (payoff + beta CTA) --- */
/* The route's last segment runs from the section top down to the F pin beside
   the "Finish" eyebrow, then stops. */
.payoff-stop { padding-block: 2rem 3rem; }
.stop--finish .stop-line { height: 2.6rem; }
.payoff {
    margin-top: 0.25rem;
    padding: 2.5rem;
    background: var(--silver-tint);
    border-radius: 1rem;
    text-align: center;
}
.payoff-statement {
    font-size: clamp(1.5rem, 4vw, 2rem);
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.01em;
    margin: 0 auto;
    max-width: 22ch;
}
.payoff-sub {
    margin: 0.75rem auto 0;
    color: var(--muted);
    font-size: 1rem;
}

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 2.75rem;
    padding: 0 1.25rem;
    border-radius: 0.5rem;
    font-weight: 600;
    font-size: 1rem;
    text-decoration: none;
    background: var(--azure);
    color: #fff;
    border: 1px solid var(--azure);
}
.btn:hover { filter: brightness(0.95); }
/* Two-colour ring so it contrasts both the button and the page, both themes. */
.btn:focus-visible {
    outline: 2px solid var(--surface);
    outline-offset: 2px;
    box-shadow: 0 0 0 4px var(--azure);
}

@media (prefers-color-scheme: dark) {
    /* Fixed dark ink — the theme --ink is near-white, which is illegible on
       azure-bright (#8fb6ef). #18181b on #8fb6ef = 8.53:1. */
    .btn { color: #18181b; }
}

/* Shared focus ring for text links (the .btn rule above is more specific). */
a:focus-visible {
    outline: 2px solid var(--azure);
    outline-offset: 2px;
    border-radius: 0.25rem;
}

/* --- Changelog --- */
/* The changelog is deliberately not a route (no spine, no stops): it's an
   archive, not a walk. */
.changelog { padding-block: 1rem 0.5rem; }
.changelog-entry {
    padding-block: 1.75rem;
    border-top: 1px solid var(--border);
    max-width: 60ch;
}
.changelog-entry:first-of-type { border-top: 0; padding-top: 0.5rem; }
.changelog-entry .date {
    display: block;
    margin: 0 0 0.25rem;
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--azure);
}
.changelog-entry h2 {
    font-size: 1.5rem;
    font-weight: 700;
    margin: 0 0 0.5rem;
}
.changelog-entry p { color: var(--muted); margin: 0 0 0.75rem; }
.changelog-entry ul {
    margin: 0;
    padding-left: 1.25rem;
    display: grid;
    gap: 0.5rem;
    color: var(--muted);
}
.changelog-entry li { margin: 0; }
.changelog-entry li::marker { color: var(--azure); }
/* Arriving from a feed item's anchor: mark which of the entries the link meant.
   A border is a shape cue — never colour alone. (Class + :target, so no CSS
   escaping of the digit-first ids is ever needed.) */
.changelog-entry:target { border-inline-start: 3px solid var(--azure); padding-inline-start: 1rem; }

/* Feed link (changelog hero): icon + text. text-decoration is drawn per flex
   item and can drop off the text child, so the span carries its own underline —
   the link's affordance must not rely on colour alone. */
.feed-link { display: inline-flex; align-items: center; gap: 0.4em; color: var(--azure); }
.feed-link span { text-decoration: underline; }
.feed-link:hover span { text-decoration-thickness: 2px; }

/* --- Footer --- */
.site-footer {
    padding-block: 2rem;
    border-top: 1px solid var(--border);
    color: var(--muted);
    font-size: 0.9375rem;
}
.site-footer a { color: var(--azure); display: inline-block; padding-block: 0.25rem; }
