/*! Sappar Studio — Copyright (c) 2026 Carrier Nation LLC. All rights reserved. */
/* ═══════════════════════════════════════════════════════════════════════════
   /news/ — the marketing news section.

   Design: docs/decisions/2026-08-12-news-section-architecture.md

   ── WHY THE TOKENS LIVE HERE AND NOT IN A PER-PAGE <style> ──────────────────

   Every other marketing page carries its own inline copy of the brand-token
   block. That is the existing convention and it is the reason `roadmap.html`
   could carry the right token NAMES with the wrong token VALUES for months —
   three of them under a comment asserting they were UNCHANGED, which is why
   nobody re-checked. News pages are generated from a template, so a per-page
   copy would be N copies of one block, minted automatically, all drifting
   together the moment the kit moves. One stylesheet, one definition.

   ── WHAT THIS FILE OWES THE INJECTED COMPONENTS (MEASURED, NOT ASSUMED) ─────

   🚨 css/footer.css DEFINES NOTHING AND CONSUMES NINE TOKENS:
        --bone --fog-1 --fog-2 --fog-3
        --font-display --font-italic --font-mono
        --hair --hair-strong
   css/nav.css is self-sufficient EXCEPT for --font-ui, which it consumes at
   two rules without defining. Both were established by diffing definitions
   against consumptions in those files, not by copying another page's block.

   A page carrying the injected footer without these renders it unstyled — no
   error, no build failure, nothing to see until someone loads the page.

   🚨 --font-display MEANS TWO DIFFERENT THINGS ON THIS SITE, and picking the
   wrong one is silent. On index.html and roadmap.html — the two pages that
   carry the injected site footer — it is INTER. On mission/refund/terms/
   privacy it is CORMORANT GARAMOND. footer.css:68 renders the footer wordmark
   at 40px/300 through var(--font-display), so adopting the legal-page meaning
   would restyle the footer here and nowhere else, and it would look plausible.
   This file therefore uses INTER for --font-display, matching the pages whose
   footer it shares, and carries its own --news-display for editorial type.

   ⚠ --text-secondary / --text-tertiary are deliberately NOT defined here.
   The legal pages need them because css/fonts.css hovers a footer X-link
   through them — but that rule selects a[aria-label="Follow us on X"] and the
   injected partial emits aria-label="Follow Sappar Studio on X", so it does
   not match this footer at all. Defining them would be cargo cult: two tokens
   nothing reads, indistinguishable from two tokens something reads.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
    /* Ground and surfaces — Sappar Studio brand kit, near-monochrome, no accent. */
    --ink-0: #000000;
    --ink-1: #060607;
    --ink-2: #0c0c0e;
    --ink-3: #121214;
    --ink-4: #17171a;
    --ink-5: #1e1e21;
    --ink-6: #27272b;
    --ink-7: #3a3a3f;

    --fog-1: #8c8c92;
    --fog-2: #a0a0a6;
    --fog-3: #c8c8cc;
    --fog-4: #e6e6e8;
    --bone: #ffffff;

    --hair: rgba(255, 255, 255, 0.07);
    --hair-strong: rgba(255, 255, 255, 0.14);

    /* Shared with the injected nav + footer. Values must match index.html. */
    --font-display: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
    --font-italic: "Source Serif 4", Georgia, "Times New Roman", serif;
    --font-ui: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
    --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
    --font-nav: "IBM Plex Sans", sans-serif;

    /* Editorial type, this section only. Cormorant Garamond is the kit's
       display face and its true display italic is what headlines use — NOT
       Source Serif 4, whose italic deforms above ~60px. */
    --news-display: "Cormorant Garamond", Georgia, serif;
    --news-body: "Source Serif 4", Georgia, serif;

    --maxw: 1280px;
    --news-measure: 68ch;      /* article body line length */
    --news-content: 760px;     /* article column          */
    --news-list-max: 940px;    /* listing column          */
}

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

html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }

body.news-page {
    background: var(--ink-1);
    color: var(--fog-2);
    font-family: var(--news-body);
    font-size: 17px;
    line-height: 1.75;
    /* ⚠ var(--nav-h), never the literal. nav.css publishes it precisely because
       it had been emergent: /help/* reserved no space and the fixed bar covered
       Help's own sidebar logo on all 14 pages. */
    padding-top: var(--nav-h);

    /* ── The footer must sit at the BOTTOM on a short page ──────────────────
       This section ships with no articles, so the listing is a heading and one
       line of empty state — far shorter than a viewport. Without this the
       footer ends mid-screen with dead ground beneath it, which reads as a
       broken page rather than a quiet one.

       ⚠ It is a real constraint here and not a hypothetical: an empty state is
       the SHIPPED state of /news/ until DT8/DT13 publish, and a long article is
       the case that hides the problem. The layout has to be correct for the
       shortest page, not the typical one.

       min-height and not height: the page must still grow past the viewport
       once articles exist. box-sizing is border-box globally, so the 100dvh
       includes the nav padding above rather than adding to it. dvh over vh so
       mobile browser chrome does not produce a scrollbar on a page that fits. */
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
}

/* Takes the slack, so the footer is pushed down rather than centred. `0%` for
   the basis, not `auto`: with `auto` the box would be sized from its content
   first and short content would not expand. */
body.news-page > .news-main { flex: 1 0 0%; }

/* ── Skip link ───────────────────────────────────────────────────────────────
   Defined with BOTH states here.

   🚨 mission.html was the only page on the site with no .skip-link:focus rule,
   and because the anchor carries an inline top:-9999px the link existed in the
   markup and was UNREACHABLE BY KEYBOARD. There is no inline style on the news
   anchor, so this rule is the only thing positioning it — but position:fixed +
   !important is kept anyway, matching creators.html, so that a copied anchor
   carrying the legacy inline style still focuses correctly.
   ────────────────────────────────────────────────────────────────────────── */
.skip-link {
    position: fixed !important;
    top: -9999px;
    left: 16px;
    z-index: 10000;
    padding: 10px 18px;
    background: var(--ink-3);
    color: var(--bone);
    font-family: var(--font-ui);
    font-size: 13px;
    font-weight: 500;
    border: 1px solid var(--hair-strong);
    border-radius: 0 0 10px 10px;
    text-decoration: none;
}
.skip-link:focus { top: 0 !important; }

/* Visible focus for keyboard users on every interactive element in the section. */
.news-page a:focus-visible,
.news-page button:focus-visible {
    outline: 2px solid var(--fog-3);
    outline-offset: 3px;
    border-radius: 2px;
}

/* ── Shared layout ─────────────────────────────────────────────────────────── */

.news-main {
    max-width: var(--maxw);
    margin: 0 auto;
    padding: 72px 24px 96px;
}

/* ── Listing ───────────────────────────────────────────────────────────────── */

.news-index-head {
    max-width: var(--news-list-max);
    margin: 0 auto 56px;
    padding-bottom: 32px;
    border-bottom: 1px solid var(--hair);
}

.news-kicker {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--fog-1);
    margin-bottom: 18px;
}

.news-index-title {
    font-family: var(--news-display);
    font-weight: 300;
    font-size: clamp(44px, 7vw, 76px);
    line-height: 1.04;
    letter-spacing: -0.015em;
    color: var(--bone);
}

.news-index-lede {
    margin-top: 18px;
    max-width: 56ch;
    font-size: 18px;
    color: var(--fog-2);
}

.news-list {
    list-style: none;
    max-width: var(--news-list-max);
    margin: 0 auto;
}

/* ⚠ No border-top on the first card, and none on .news-empty below. The index
   header already draws a rule at exactly that position, and the two together
   rendered as a pair of lines with a gap between them — which reads as an empty
   container rather than a separator. Measured in the browser, not inferred:
   .news-index-head border-bottom 1px and .news-empty border-top 1px both
   computed to 1px at the same seam. */
.news-card { border-bottom: 1px solid var(--hair); }
.news-card > article { padding: 34px 0; }

.news-card-date {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--fog-1);
}

.news-card-title {
    margin-top: 12px;
    font-family: var(--news-display);
    font-weight: 400;
    font-size: clamp(26px, 3.4vw, 34px);
    line-height: 1.18;
    letter-spacing: -0.01em;
}

.news-card-title a {
    color: var(--fog-4);
    text-decoration: none;
    /* Underline on hover only; the card is already a large target and a
       permanently underlined display serif reads as a link farm. */
    background-image: linear-gradient(var(--fog-3), var(--fog-3));
    background-size: 0 1px;
    background-repeat: no-repeat;
    background-position: 0 100%;
    transition: background-size 0.28s ease, color 0.28s ease;
}
.news-card-title a:hover { color: var(--bone); background-size: 100% 1px; }

.news-card-summary { margin-top: 12px; max-width: 62ch; color: var(--fog-2); }

.news-card-more {
    display: inline-block;
    margin-top: 16px;
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--fog-1);
}

.news-empty {
    max-width: var(--news-list-max);
    margin: 0 auto;
    padding: 8px 0 56px;
    border-bottom: 1px solid var(--hair);
    color: var(--fog-1);
    font-size: 17px;
}

/* ── Article ───────────────────────────────────────────────────────────────── */

.news-article { max-width: var(--news-content); margin: 0 auto; }

.news-article-head {
    padding-bottom: 34px;
    margin-bottom: 44px;
    border-bottom: 1px solid var(--hair);
}

.news-dateline {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--fog-1);
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: baseline;
}
.news-dateline .news-updated { color: var(--fog-1); opacity: 0.8; }
.news-dateline .news-updated::before { content: "· "; }

.news-title {
    margin-top: 18px;
    font-family: var(--news-display);
    font-weight: 300;
    font-size: clamp(38px, 5.6vw, 62px);
    line-height: 1.06;
    letter-spacing: -0.015em;
    color: var(--bone);
}

.news-summary {
    margin-top: 18px;
    font-size: 19px;
    line-height: 1.65;
    color: var(--fog-3);
}

.news-body { max-width: var(--news-measure); }
.news-body > * + * { margin-top: 1.35em; }

.news-body h2 {
    margin-top: 2.4em;
    font-family: var(--news-display);
    font-weight: 400;
    font-size: 32px;
    line-height: 1.2;
    color: var(--fog-4);
}
.news-body h3 {
    margin-top: 2em;
    font-family: var(--font-ui);
    font-weight: 500;
    font-size: 18px;
    letter-spacing: 0.01em;
    color: var(--fog-4);
}

.news-body a {
    color: var(--fog-4);
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-color: var(--ink-7);
    transition: text-decoration-color 0.2s ease, color 0.2s ease;
}
.news-body a:hover { color: var(--bone); text-decoration-color: var(--fog-2); }

.news-body strong { color: var(--fog-4); font-weight: 600; }
.news-body em { font-style: italic; }

.news-body ul, .news-body ol { padding-left: 1.4em; }
.news-body li + li { margin-top: 0.5em; }

.news-body blockquote {
    padding-left: 22px;
    border-left: 2px solid var(--ink-6);
    color: var(--fog-3);
    font-style: italic;
}

.news-body code {
    font-family: var(--font-mono);
    font-size: 0.86em;
    padding: 2px 6px;
    background: var(--ink-3);
    border: 1px solid var(--ink-6);
    border-radius: 4px;
    color: var(--fog-3);
}
.news-body pre {
    padding: 18px 20px;
    background: var(--ink-2);
    border: 1px solid var(--ink-6);
    border-radius: 8px;
    /* Wide content scrolls inside its own box; the page body must never
       scroll horizontally. */
    overflow-x: auto;
}
.news-body pre code { padding: 0; background: none; border: 0; }

.news-body img {
    max-width: 100%;
    height: auto;
    display: block;
    border: 1px solid var(--ink-6);
    border-radius: 8px;
}

.news-body figure figcaption {
    margin-top: 10px;
    font-family: var(--font-ui);
    font-size: 13px;
    color: var(--fog-1);
}

.news-body hr { border: 0; border-top: 1px solid var(--hair); margin: 2.6em 0; }

.news-body table {
    width: 100%;
    border-collapse: collapse;
    font-family: var(--font-ui);
    font-size: 15px;
}
.news-body th, .news-body td {
    text-align: left;
    padding: 10px 12px;
    border-bottom: 1px solid var(--hair);
}
.news-body th { color: var(--fog-4); font-weight: 500; }
/* A table can exceed the measure; give it its own scroll container. */
.news-body .table-scroll { overflow-x: auto; }

.news-foot-nav {
    margin-top: 64px;
    padding-top: 28px;
    border-top: 1px solid var(--hair);
}

.news-back {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--fog-1);
    text-decoration: none;
    transition: color 0.2s ease;
}
.news-back:hover { color: var(--fog-3); }
.news-back::before { content: "← "; }

/* ── Responsive ────────────────────────────────────────────────────────────── */

@media (max-width: 820px) {
    .news-main { padding: 48px 20px 72px; }
    .news-index-head { margin-bottom: 40px; }
    .news-card > article { padding: 28px 0; }
    body.news-page { font-size: 16px; }
    .news-summary { font-size: 17px; }
}

@media (max-width: 520px) {
    .news-main { padding: 36px 16px 56px; }
    .news-index-lede { font-size: 16px; }
    .news-body h2 { font-size: 26px; }
}

/* ── Motion + print ────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    .news-page *,
    .news-page *::before,
    .news-page *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

@media print {
    body.news-page { padding-top: 0; background: #fff; color: #000; }
    .skip-link, .news-foot-nav, nav.top, .mobile-menu, footer.site { display: none !important; }
    .news-title, .news-index-title { color: #000; }
    .news-body a::after { content: " (" attr(href) ")"; font-size: 0.85em; color: #444; }
}
