/*
 * Design tokens, base type and the shared component classes: the Broadsheet design system
 * (_docs/design/_ds/broadsheet-…/styles.css + readme.md), translated into this app's cascade
 * layers. Newsprint: near-black Source Serif 4 on paper white, cyan and magenta used small like
 * spot colour, hierarchy from the serif scale and white space alone — no boxes, no dividers
 * between sections (the masthead's thick-thin rule is the one exception).
 *
 * Light only. Broadsheet has no dark surfaces, so there is no `prefers-color-scheme` branch: a
 * night palette would be a design nobody drew.
 *
 * The token names the components already used (taken over from sedem-rokov: --space-s,
 * --color-border, --radius-full, …) are kept as aliases of the Broadsheet values, so the
 * components did not have to be renamed. New code uses the Broadsheet names first.
 *
 * The layer order is also pinned by an inline <style> in base.html.twig, above every stylesheet —
 * see the comment there for why repeating it here is not enough.
 */
@layer tokens, base, components, utilities;

/*
 * Self-hosted, and that is the point rather than a preference: this site loads nothing from a
 * third party, so it needs no cookie banner — Broadsheet's `@import` of fonts.googleapis.com
 * would send every visitor's IP to Google before they had read a word. bin/fetch-fonts wrote
 * these files.
 *
 * Two subsets per style. `latin-ext` is not optional: without it Slovak loses č, š, ž, ľ, ĺ, ŕ to
 * a fallback face letter by letter. The upright face is variable (wght 200–900), so 400 and 600
 * are one file; the italic is the true italic at the body weight (Broadsheet: never a synthesised
 * oblique).
 *
 * `font-display: swap` — the text is the content, so it has to be readable before the face
 * arrives, not after.
 */
@font-face {
    font-family: 'Source Serif 4';
    font-style: normal;
    font-weight: 200 900;
    font-display: swap;
    src: url("../fonts/source-serif-4-normal-latin-jg6Byvd.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: 'Source Serif 4';
    font-style: normal;
    font-weight: 200 900;
    font-display: swap;
    src: url("../fonts/source-serif-4-normal-latin-ext-djyBhpt.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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Source Serif 4';
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/source-serif-4-italic-latin-SYLRdsm.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: 'Source Serif 4';
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/source-serif-4-italic-latin-ext-fT3gex_.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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@layer tokens {
    :root {
        color-scheme: light;

        /* — Broadsheet colour roles — */
        --color-bg: #f3f2f2;
        --color-surface: #eae9e9;
        --color-text: #201e1d;
        --color-accent: #0088b0;
        --color-accent-2: #d6006c;
        --color-divider: color-mix(in srgb, #201e1d 16%, transparent);

        /* Tonal ramps, generated in OKLCH on one shared lightness scale: the same step of any
           role has the same visual weight. 100–300 tinted fills, 500 base, 700–900 text on
           tints and pressed states. */
        --color-neutral-100: #f8f4f4;
        --color-neutral-200: #eae7e7;
        --color-neutral-300: #d7d3d3;
        --color-neutral-400: #bab6b6;
        --color-neutral-500: #9b9797;
        --color-neutral-600: #7d7979;
        --color-neutral-700: #605d5d;
        --color-neutral-800: #444141;
        --color-neutral-900: #2d2b2b;

        --color-accent-100: #e9f8ff;
        --color-accent-200: #cbeeff;
        --color-accent-300: #99e0ff;
        --color-accent-400: #62c5ee;
        --color-accent-500: #38a6cf;
        --color-accent-600: #1186ac;
        --color-accent-700: #006786;
        --color-accent-800: #004961;
        --color-accent-900: #0a303e;

        --color-accent-2-100: #fff1f4;
        --color-accent-2-200: #ffdee6;
        --color-accent-2-300: #ffc0d0;
        --color-accent-2-400: #ff90b1;
        --color-accent-2-500: #ff458e;
        --color-accent-2-600: #d82071;
        --color-accent-2-700: #aa0b56;
        --color-accent-2-800: #790e3d;
        --color-accent-2-900: #4b1528;

        /* The third process ink, for print treatments only — and for the lanterns, the one
           "light" on the page (design mock). Body copy and chrome never take it. */
        --color-process-yellow: #edbb00;

        /* — Type — all serif; the serif is the chrome. The fallback is a serif too, unlike
           Broadsheet's `system-ui, sans-serif`, so a slow font never flashes a sans page. */
        --font-heading: 'Source Serif 4', Georgia, 'Times New Roman', serif;
        --font-heading-weight: 600;
        --font-body: 'Source Serif 4', Georgia, 'Times New Roman', serif;
        --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

        /* Broadsheet's px scale in rem, so the visitor's own text size still applies. */
        --text-xs: 0.6875rem;   /* 11px — rails, captions */
        --text-s: 0.8125rem;    /* 13px */
        --text-m: 0.9375rem;    /* 15px — body */
        --text-l: 1.0625rem;    /* 17px — lede */
        --text-h1: clamp(2.5rem, 2.2rem + 1.2vw, 2.625rem);
        --text-h2: clamp(1.875rem, 1.75rem + 0.6vw, 2rem);
        --text-h3: 1.5625rem;
        --text-h4: 1.25rem;
        --text-h5: 1rem;
        --text-h6: 0.8125rem;

        /* Density 1.25× is baked in — never tighten it (Broadsheet "Don't"). */
        --space-1: 5px;
        --space-2: 10px;
        --space-3: 15px;
        --space-4: 20px;
        --space-6: 30px;
        --space-8: 40px;

        --radius-sm: 1px;
        --radius-md: 2px;
        --radius-lg: 4px;

        --shadow-sm: 0 1px 2px color-mix(in srgb, #2d2b2b 14%, transparent);
        --shadow-md: 0 3px 10px color-mix(in srgb, #2d2b2b 16%, transparent);
        --shadow-lg: 0 12px 32px color-mix(in srgb, #2d2b2b 22%, transparent);

        /* Left-aligned, content hugging the left edge: a column wide enough for the phone,
           capped so a laptop does not get 120-character lines. */
        --measure: 34rem;
        --page-max: 46rem;
        --gutter: var(--space-4);

        /* — Aliases kept from the sedem-rokov tokens (used by UI/SwUpdate and the sign-in
           screen). Mapped onto Broadsheet; do not add new names here. — */
        --space-2xs: var(--space-1);
        --space-xs: var(--space-2);
        --space-s: var(--space-3);
        --space-m: var(--space-4);
        --space-l: var(--space-6);
        --space-xl: var(--space-8);
        --space-2xl: clamp(3.5rem, 9vw, 7rem);

        --text-display: var(--text-h1);
        --text-title: var(--text-h2);
        --text-section: var(--text-h3);
        --text-lead: var(--text-l);

        --font-display: var(--font-heading);
        --font-book: var(--font-body);

        --radius-s: var(--radius-sm);
        --radius-m: var(--radius-md);
        --radius-l: var(--radius-lg);
        --radius-full: 999px;

        --paper: var(--color-bg);
        --paper-raised: var(--color-surface);
        --paper-sunken: var(--color-neutral-200);
        --ink: var(--color-text);
        --ink-muted: var(--color-neutral-700);
        --ink-line: var(--color-divider);
        --mark: var(--color-accent);
        --mark-contrast: var(--color-bg);
        --mark-wash: color-mix(in srgb, var(--color-process-yellow) 25%, var(--color-bg));

        /* Something failed and somebody has to act (CLAUDE.md: no invisible failures).
           Broadsheet has no red; the deep magenta steps are its loudest ink. */
        --danger: var(--color-accent-2-700);
        --danger-wash: var(--color-accent-2-100);

        --color-canvas: var(--color-bg);
        --color-sunken: var(--paper-sunken);
        --color-border: var(--color-divider);
        --color-text-muted: var(--color-neutral-700);
        --color-accent-contrast: var(--color-bg);
        --color-highlight: var(--mark-wash);
        --color-focus: var(--color-accent);
    }
}

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

    /* `hidden` always hides. The user-agent `[hidden] { display: none }` loses to any author
       `display` rule, so a component styling its element `display: flex` silently cancelled every
       `element.hidden = true` (UI/SwUpdate's bar, then "Kedy to bolo?" in UI/PhotoStart — QA
       2026-11-03). An important declaration in the first layer outranks every later layer, so no
       component rule can undo it; components never need their own `[hidden]` rule.
       `until-found` keeps its own browser behaviour. */
    [hidden]:not([hidden='until-found']) {
        display: none !important;
    }

    body {
        margin: 0;
        min-height: 100dvh;
        background-color: var(--color-bg);
        color: var(--color-text);
        font-family: var(--font-body);
        font-size: var(--text-m);
        font-weight: 400;
        line-height: 1.55;
        -webkit-font-smoothing: antialiased;
        /* Visitors' text (summit-book names and sentences, range names, lantern names) may be one
           long unbroken word; on a 360 px phone it must wrap, never scroll the page sideways. */
        overflow-wrap: break-word;
        /* The page sets viewport-fit=cover; the installed app must not put the brand under the
           status bar or a button under a notch. */
        padding-block-start: env(safe-area-inset-top, 0px);
        padding-inline: env(safe-area-inset-left, 0px) env(safe-area-inset-right, 0px);
    }

    h1,
    h2,
    h3,
    h4,
    h5,
    h6 {
        margin: 0 0 var(--space-2);
        font-family: var(--font-heading);
        font-weight: var(--font-heading-weight);
        line-height: 1.12;
        letter-spacing: -0.015em;
        text-wrap: balance;
    }

    h1 { font-size: var(--text-h1); line-height: 1.02; }
    h2 { font-size: var(--text-h2); }
    h3 { font-size: var(--text-h3); }
    h4 { font-size: var(--text-h4); }
    h5 { font-size: var(--text-h5); }

    /* The kicker: small capitals-by-spacing above a heading. */
    h6 {
        font-size: var(--text-h6);
        letter-spacing: 0.08em;
        text-transform: uppercase;
    }

    /* The same look on any element: a kicker above a heading is a label, not a heading of its own
       (an <h6> before the <h2> broke the page's outline) — `<p class="kicker">`, or a real heading
       of the right level that only looks like one. */
    .kicker {
        margin: 0 0 var(--space-2);
        font-family: var(--font-heading);
        font-size: var(--text-h6);
        font-weight: var(--font-heading-weight);
        line-height: 1.12;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        text-wrap: balance;
    }

    /* Prose, never a layout: a paragraph that breaks one word onto the last line is the most
       common thing wrong with a page that is otherwise fine. */
    p {
        margin: 0 0 var(--space-3);
        text-wrap: pretty;
    }

    /* Accent-to-ground is tuned to 3:1 — enough for chrome, not for running text — so links in
       prose take the deep step (Broadsheet "Components"). */
    a {
        color: var(--color-accent-700);
        text-underline-offset: 3px;

        &:hover {
            color: var(--color-accent-600);
        }
    }

    img {
        display: block;
        max-width: 100%;
    }

    figure {
        margin: 0;
    }

    figcaption {
        margin-top: var(--space-1);
        color: var(--color-neutral-700);
        font-size: var(--text-xs);
    }

    :focus {
        outline: none;
    }

    :focus-visible {
        outline: 2px solid var(--color-accent);
        outline-offset: 2px;
    }

    ::selection {
        background: color-mix(in srgb, var(--color-accent) 30%, transparent);
    }

    button,
    input,
    textarea,
    select {
        font: inherit;
        color: inherit;
    }
}

@layer components {
    /* — buttons — 44px is the floor for a thumb; Broadsheet's desktop 36px is not. */
    .btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 6px;
        min-block-size: 44px;
        padding: var(--space-2) calc(var(--space-3) * 1.2);
        border: 1px solid transparent;
        border-radius: var(--radius-md);
        background: transparent;
        color: var(--color-text);
        font-family: var(--font-heading);
        font-size: 0.875rem;
        font-weight: var(--font-heading-weight);
        line-height: 1.2;
        text-decoration: none;
        cursor: pointer;

        /* Zero specificity: a component hiding one of its icons inside a .btn (a single-class rule
           in the same layer) must always win — `.btn svg` beat three of them (both icons showed). */
        :where(& svg) {
            display: block;
            flex: none;
        }

        &:disabled {
            opacity: 0.45;
            cursor: not-allowed;
        }
    }

    /* Paper on the 700 step, not on the brand cyan (Broadsheet's own choice): paper-coloured text
       on the cyan is 3.6:1, on the 700 step 5.7:1 — WCAG AA for a 14px label. Every surface that
       carries text on the accent (the checked `.seg-opt`, SwUpdate, SignInCard) does the same. */
    .btn-primary {
        background: var(--color-accent-700);
        color: var(--color-bg);

        &:hover {
            background: var(--color-accent-800);
            color: var(--color-bg);
        }

        &:active {
            background: var(--color-accent-900);
        }
    }

    .btn-secondary {
        border-color: var(--color-divider);

        &:hover {
            background: color-mix(in srgb, var(--color-text) 7%, transparent);
            color: var(--color-text);
        }

        &:active {
            background: color-mix(in srgb, var(--color-text) 14%, transparent);
        }
    }

    .btn-ghost {
        padding-inline: var(--space-1);
        color: var(--color-accent-700);

        &:hover {
            background: color-mix(in srgb, var(--color-accent) 10%, transparent);
        }

        &:active {
            background: color-mix(in srgb, var(--color-accent) 18%, transparent);
        }
    }

    .btn-icon {
        inline-size: 44px;
        block-size: 44px;
        padding: 0;
    }

    .btn-block {
        inline-size: 100%;
        margin-top: var(--space-2);
    }

    /* The page's main call to action (Donio, the generator): a size up. */
    .btn-lg {
        min-block-size: 48px;
        padding-inline: 22px;
        font-size: 1rem;
    }

    /* — tags — */
    .tag {
        display: inline-flex;
        align-items: center;
        padding: 3px 10px;
        border-radius: calc(var(--radius-md) * 0.75);
        font-size: var(--text-xs);
        letter-spacing: 0.02em;
    }

    .tag-accent { background: var(--color-accent-100); color: var(--color-accent-800); }
    .tag-accent-2 { background: var(--color-accent-2-100); color: var(--color-accent-2-800); }
    .tag-neutral { background: var(--color-neutral-100); color: var(--color-neutral-800); }
    .tag-outline { border: 1px solid var(--color-accent); color: var(--color-accent-700); }

    /* — forms — */
    .field > label {
        display: block;
        margin-bottom: 5px;
        color: color-mix(in srgb, var(--color-text) 70%, transparent);
        font-size: 0.75rem;
    }

    /* 16px, not Broadsheet's 14px: iOS Safari zooms the page into any input under 16px, and
       most visitors are on an iPhone from Instagram. */
    .input {
        inline-size: 100%;
        min-block-size: 44px;
        padding: 6px 10px;
        border: 1px solid var(--color-divider);
        border-radius: var(--radius-md);
        background: var(--color-surface);
        color: var(--color-text);
        font: inherit;
        font-size: 1rem;
        caret-color: var(--color-accent);

        &::placeholder {
            color: color-mix(in srgb, var(--color-text) 65%, transparent);
            opacity: 1;
        }

        &:hover {
            border-color: color-mix(in srgb, var(--color-text) 45%, transparent);
        }

        &:focus-visible {
            border-color: var(--color-accent);
            outline-offset: 0;
        }
    }

    textarea.input {
        min-block-size: 90px;
        resize: vertical;
    }

    .seg {
        display: inline-flex;
        overflow: hidden;
        border: 1px solid var(--color-divider);
        border-radius: var(--radius-md);
    }

    .seg-opt {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        min-block-size: 44px;
        padding: 7px 12px;
        font-size: var(--text-s);
        cursor: pointer;

        & + & {
            border-left: 1px solid var(--color-divider);
        }

        & input {
            position: absolute;
            inline-size: 0;
            block-size: 0;
            opacity: 0;
            pointer-events: none;
        }

        &:has(input:checked) {
            background: var(--color-accent-700);
            color: var(--color-bg);
        }

        &:not(:has(input:checked)):hover {
            background: color-mix(in srgb, var(--color-text) 7%, transparent);
        }

        &:has(input:focus-visible) {
            outline: 2px solid var(--color-accent);
            outline-offset: -2px;
        }
    }

    /* — card — the one boxed component, for genuinely discrete items, never for layout. */
    .card {
        display: flex;
        flex-direction: column;
        gap: var(--space-2);
        padding: var(--space-3);
        border-radius: var(--radius-md);
        background: var(--color-surface);
    }

    .card-kicker {
        color: var(--color-accent-700);
        font-size: 0.625rem;
        letter-spacing: 0.1em;
        text-transform: uppercase;
    }

    .card-title {
        font-family: var(--font-heading);
        font-size: 1.0625rem;
        font-weight: var(--font-heading-weight);
        line-height: 1.2;
    }

    .card-body {
        flex: 1;
        margin: 0;
        font-size: var(--text-s);
        opacity: 0.8;
    }

    .card-meta {
        display: flex;
        align-items: center;
        gap: 6px;
        color: var(--color-neutral-700);
        font-size: var(--text-xs);
    }

    /* — dialog — */
    .dialog-backdrop {
        position: fixed;
        inset: 0;
        display: grid;
        place-items: center;
        padding: var(--space-4);
        background: color-mix(in srgb, var(--color-neutral-900) 50%, transparent);
    }

    .dialog {
        display: flex;
        flex-direction: column;
        gap: var(--space-3);
        inline-size: min(440px, 100%);
        padding: var(--space-4);
        border-radius: var(--radius-lg);
        background: var(--color-surface);
        box-shadow: var(--shadow-lg);
    }

    .dialog-title {
        font-family: var(--font-heading);
        font-size: 1.25rem;
        font-weight: var(--font-heading-weight);
    }

    .dialog-body {
        font-size: 0.875rem;
        opacity: 0.85;
    }

    .dialog-actions {
        display: flex;
        justify-content: flex-end;
        gap: var(--space-2);
        margin-top: var(--space-2);
    }

    /* — image treatments — */

    /* The newsprint dot screen, for interface imagery. */
    .halftone {
        position: relative;
        overflow: hidden;
        filter: grayscale(0.35) contrast(1.15);

        &::after {
            content: '';
            position: absolute;
            inset: 0;
            background-image: radial-gradient(circle, rgb(0 0 0 / 22%) 30%, transparent 32%);
            background-size: 3px 3px;
            mix-blend-mode: multiply;
            pointer-events: none;
        }
    }

    /*
     * A photograph printed as its four misregistered process plates. Markup: figure.cmyk holding
     * five copies of the image — the first sizes the layout and carries the alt (transparent, not
     * hidden, so it stays in the accessibility tree), then one per plate with .sep-c/-m/-y/-k
     * (and alt=""). The filters are the inline defs from templates/_print_plates.html.twig,
     * which base.html.twig includes once per page. Offsets sized for a phone photo.
     */
    .cmyk {
        position: relative;
        overflow: hidden;
        background: var(--color-bg);

        & img:first-child {
            opacity: 0;
        }

        & img + img {
            position: absolute;
            inset: 0;
            inline-size: 100%;
            block-size: 100%;
            object-fit: cover;
            mix-blend-mode: multiply;
        }

        & .sep-c { filter: url('#sep-c'); }
        & .sep-m { filter: url('#sep-m'); translate: 2px 1px; }
        & .sep-y { filter: url('#sep-y'); translate: -2px -1px; }
        & .sep-k { filter: url('#sep-k'); translate: 1px 2px; }

        &::after {
            content: '';
            position: absolute;
            inset: 0;
            background-image: radial-gradient(circle, rgb(0 0 0 / 22%) 30%, transparent 32%);
            background-size: 3px 3px;
            mix-blend-mode: multiply;
            pointer-events: none;
        }
    }

    /*
     * — the page layout (templates/base.html.twig) —
     * Mobile first: one left-aligned column with a 20px gutter (the mock's 390px phone). On a
     * wide screen the column stays narrow and hugs the left with an indent, whitespace to the
     * right (Broadsheet: asymmetric, flush left), rather than centring.
     */
    .page {
        max-inline-size: var(--page-max);
        padding-inline: var(--gutter);
        /* Centred on wide screens (user decision, 2026-10-26) — not the left-offset column of the
           Broadsheet export. */
        margin-inline: auto;
    }

    .masthead__bar {
        display: flex;
        align-items: center;
        /* Tighter on the narrowest phones, so brand, account corner and "Kniha" keep one line. */
        gap: clamp(var(--space-2), 4vw, var(--space-4));
        padding-block: var(--space-3) var(--space-1);
    }

    .masthead__brand {
        margin-inline-end: auto;
        color: inherit;
        font-family: var(--font-heading);
        font-size: 1.125rem;
        font-weight: var(--font-heading-weight);
        text-decoration: none;
    }

    /* The narrowest phones (≈320 px) cannot fit brand, account corner and "Kniha" on one line even
       without wrapping words: the brand takes its own row and the links line up under it. */
    @media (max-width: 22.5rem) {
        .masthead__bar {
            flex-wrap: wrap;
            justify-content: flex-end;
            row-gap: 0;
        }

        .masthead__brand {
            flex-basis: 100%;
        }
    }

    .masthead__link {
        display: inline-flex;
        align-items: center;
        gap: 4px;
        min-block-size: 44px;
        color: inherit;
        font-size: 0.875rem;
        white-space: nowrap;
        text-decoration: none;

        &:hover {
            color: var(--color-accent-700);
        }
    }

    /* The thick-thin pair: 3px, a 2px gap of paper, then the 1px line the rail sits on. */
    .masthead__rule {
        margin-block-start: 4px;
        border-block-start: 3px solid var(--color-text);
    }

    .masthead__dateline {
        display: flex;
        justify-content: space-between;
        gap: var(--space-2);
        margin: 2px 0 0;
        padding-block: 6px;
        border-block-start: 1px solid var(--color-text);
        font-size: var(--text-xs);
        letter-spacing: 0.08em;
        text-transform: uppercase;
    }

    .masthead__status {
        color: var(--color-accent-700);
        text-align: end;
    }

    .page__main {
        display: block;
    }

    /* The footer's single rule follows the mock; everything else in it is white space. */
    .colophon {
        display: flex;
        flex-direction: column;
        gap: var(--space-4);
        padding-block: calc(var(--space-8) + var(--space-1)) calc(var(--space-6) + env(safe-area-inset-bottom, 0px));
    }

    .colophon__book {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        justify-content: space-between;
        gap: var(--space-2);
        padding-block-start: var(--space-2);
        border-block-start: 1px solid var(--color-text);
    }

    .colophon__title {
        display: flex;
        flex-direction: column;
        margin: 0;
        font-size: var(--text-m);
    }

    .colophon__status {
        color: var(--color-neutral-700);
        font-size: 0.75rem;
    }

    /* The newsletter sign-up in the footer (UI/NewsletterSignup, compact). */
    .colophon__newsletter {
        display: flex;
        flex-direction: column;
        gap: var(--space-2);
    }

    .colophon__newsletter-title {
        margin: 0;
        font-size: var(--text-m);
        font-weight: 600;
    }

    /* The challenge's way in, above the small print (templates/base.html.twig). */
    .colophon__challenge {
        margin: 0;
        font-size: var(--text-s);

        & a {
            display: inline-flex;
            align-items: center;
            min-block-size: 44px;
        }
    }

    /* The legal links: small print in a row that wraps, each link tall enough for a thumb. */
    .colophon__legal {
        display: flex;
        flex-wrap: wrap;
        column-gap: var(--space-4);
        font-size: var(--text-xs);

        & a {
            display: inline-flex;
            align-items: center;
            min-block-size: 44px;
            color: var(--color-neutral-700);
        }
    }

    /*
     * Phase-3 sign-in screen, taken over from sedem-rokov with the old tokens; it restyles
     * itself in Broadsheet through the aliases above.
     */
    .login {
        display: grid;
        gap: var(--space-l);
        align-content: center;
        max-width: 24rem;
        min-height: 80dvh;
        margin-inline: auto;
        padding: var(--space-l);
    }

    .login__title {
        margin: 0;
        text-align: center;
        font-size: var(--text-section);
    }

    .login__form {
        display: grid;
        gap: var(--space-xs);
        padding: var(--space-l);
        border-radius: var(--radius-m);
        background-color: var(--color-surface);
    }

    .login__hint {
        margin: 0 0 var(--space-m);
        color: var(--color-text-muted);
        font-size: var(--text-s);
    }

    .login__error {
        margin: 0;
        padding: var(--space-s) var(--space-m);
        border-radius: var(--radius-m);
        background-color: var(--danger-wash);
        color: var(--danger);
        font-size: var(--text-s);
    }

    .login__submit {
        min-block-size: 3rem;
        padding-inline: var(--space-m);
        border: none;
        border-radius: var(--radius-m);
        background-color: var(--color-accent);
        color: var(--color-accent-contrast);
        font-weight: 600;
        cursor: pointer;
    }
}

@layer utilities {
    .text-muted {
        color: var(--color-neutral-700);
    }

    /* A required configuration value that is not set (templates/legal/_macros.html.twig, dev only —
       `app:config:check` stops a deploy without it): loud on purpose wherever it is printed, so nobody
       mistakes it for the text. */
    .legal-missing {
        padding-inline: 0.25em;
        background: var(--color-accent-2-100);
        color: var(--color-accent-2-800);
        font-family: monospace;
    }

    /*
     * One line, shortened with "…" — for names (contributors, ridges, summit entries). Slovak
     * diacritics reach outside the glyph box: the caron of a final ľ/ď/ť overhangs the advance by
     * ~0.075em (Source Serif 4 Semibold), a leading j by ~0.09em, accented capitals (Ľ Ď Ť Á Ô) rise
     * above a tight line box. `overflow` clips at the padding edge while the ellipsis is placed at
     * the content edge, so the padding gives the overhang room in every browser (Safari has no
     * `overflow-clip-margin`) and the negative margin keeps the text where it was. Needs a block or
     * inline-block box (a grid or flex item is one).
     */
    .text-truncate {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        padding: 0.15em 0.1em;
        margin: -0.15em -0.1em;
    }

    /*
     * Off-screen but still announced, and still part of the accessible name of its parent.
     * `clip-path` rather than `display: none`, which would remove it from the accessible name.
     */
    .visually-hidden {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }
}
