/* Project-wide style overrides on top of BeerCSS (Material 3).

   Design system: "le dossier annoté" — a newspaper's comment section, clipped
   and annotated. Tokens below are the single source of truth; BeerCSS's own
   Material variables are remapped onto them so every framework component
   re-skins at once. Both themes are first-class (dark is the default).
   Contrast: ink/ink-2 on paper/surface >= 7:1, accent on surface >= 7:1,
   marker (amber + near-black) >= 11:1, flag >= 6:1 in both themes. */

/* ---- Display face: Newsreader (OFL), one variable-weight latin file. ---- */
/* Icon font: BeerCSS declares the full Material Symbols Outlined face
   (~360 KB). This later declaration with identical descriptors wins, so the
   browser only fetches our 2 KB subset (the 9 ligatures the site uses:
   menu, close, dark_mode, light_mode, arrow_drop_down, chevron_left/right,
   expand_more/less). Regenerate with fontTools if a new icon is added. */
@font-face {
    font-family: "Material Symbols Outlined";
    src: url("../fonts/material-symbols-lm2p.a9804400d666.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Newsreader";
    src: url("../fonts/newsreader-latin.175a37868200.woff2") format("woff2");
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
    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;
}

/* ---- Tokens: light ---- */
:root,
body.light {
    --paper: #f3f5f8;          /* page: cool newsprint grey, not cream */
    --surface: #ffffff;        /* cards, tables */
    --surface-2: #eaeef3;      /* table heads, chips, quiet fills */
    --ink: #1c2128;            /* body text */
    --ink-2: #4b5563;          /* secondary text (replaces opacity tricks) */
    --rule: #d5dae2;           /* borders, table rules */
    --accent: #2f4fb5;         /* cobalt: links, actions, focus */
    --on-accent: #ffffff;
    --accent-soft: #e3e8f8;    /* accent containers */
    --marker: #ffd54f;         /* highlighted passages */
    --on-marker: #1c1b1f;
    --flag: #b3261e;           /* deletions, bans, errors — nothing else */
    --on-flag: #ffffff;
    --flag-soft: #fbe4e2;
    /* per-author identity tints (see .author-tint) */
    --tint-sat: 62%;
    --tint-light: 27%;
    --stripe: #f6f8fa;        /* zebra rows */

    --font-display: "Newsreader", Georgia, "Times New Roman", serif;
    --link: var(--accent);

    /* BeerCSS (Material 3) variables remapped onto the tokens. */
    --primary: var(--accent);
    --on-primary: var(--on-accent);
    --primary-container: var(--accent-soft);
    --on-primary-container: var(--ink);
    --secondary: var(--ink-2);
    --on-secondary: var(--surface);
    --secondary-container: var(--surface-2);
    --on-secondary-container: var(--ink);
    --tertiary: var(--accent);
    --on-tertiary: var(--on-accent);
    --tertiary-container: var(--accent-soft);
    --on-tertiary-container: var(--ink);
    --error: var(--flag);
    --on-error: var(--on-flag);
    --error-container: var(--flag-soft);
    --on-error-container: var(--flag);
    --background: var(--paper);
    --on-background: var(--ink);
    --surface-variant: var(--surface-2);
    --on-surface-variant: var(--ink-2);
    --outline: #7b8494;
    --outline-variant: var(--rule);
    --surface-dim: var(--paper);
    --surface-bright: var(--surface);
    --surface-container-lowest: var(--surface);
    --surface-container-low: #f8f9fb;
    --surface-container: var(--surface);
    --surface-container-high: var(--surface-2);
    --surface-container-highest: #dfe4ea;
    --inverse-surface: var(--ink);
    --inverse-on-surface: var(--surface);
    --inverse-primary: #8fa8ff;
    --on-surface: var(--ink);
}

/* ---- Tokens: dark (default) ---- */
body.dark {
    --paper: #12161c;
    --surface: #1a2028;
    --surface-2: #232b35;
    --ink: #e8ecf1;
    --ink-2: #a7b0bc;
    --rule: #2e3742;
    --accent: #8fa8ff;
    --on-accent: #0f1630;
    --accent-soft: #27335a;
    --marker: #ffd54f;
    --on-marker: #1c1b1f;
    --flag: #ff8a80;
    --on-flag: #2a0000;
    --flag-soft: #4a1f1c;
    --tint-sat: 75%;
    --tint-light: 72%;
    --stripe: #1f2731;

    --link: var(--accent);

    --primary: var(--accent);
    --on-primary: var(--on-accent);
    --primary-container: var(--accent-soft);
    --on-primary-container: var(--ink);
    --secondary: var(--ink-2);
    --on-secondary: var(--paper);
    --secondary-container: var(--surface-2);
    --on-secondary-container: var(--ink);
    --tertiary: var(--accent);
    --on-tertiary: var(--on-accent);
    --tertiary-container: var(--accent-soft);
    --on-tertiary-container: var(--ink);
    --error: var(--flag);
    --on-error: var(--on-flag);
    --error-container: var(--flag-soft);
    --on-error-container: var(--flag);
    --background: var(--paper);
    --on-background: var(--ink);
    --surface-variant: var(--surface-2);
    --on-surface-variant: var(--ink-2);
    --outline: #6b7686;
    --outline-variant: var(--rule);
    --surface-dim: var(--paper);
    --surface-bright: var(--surface-2);
    --surface-container-lowest: #0e1217;
    --surface-container-low: #161b22;
    --surface-container: var(--surface);
    --surface-container-high: var(--surface-2);
    --surface-container-highest: #2c3540;
    --inverse-surface: var(--ink);
    --inverse-on-surface: var(--paper);
    --inverse-primary: #2f4fb5;
    --on-surface: var(--ink);
}

/* ---- Type scale: 17px base, 1.125 ratio, display face for titles ---- */
html {
    font-size: 106.25%; /* 17px */
}

body {
    background: var(--paper);
    color: var(--ink);
    line-height: 1.55;
}

main.responsive h1,
main.responsive h2 {
    font-family: var(--font-display);
    font-weight: 600;
    letter-spacing: -0.01em;
    line-height: 1.15;
    color: var(--ink);
}

main.responsive h1 {
    font-size: 2.1rem;
    margin: 0.6rem 0 0.8rem;
}

main.responsive h2 {
    font-size: 1.45rem;
    margin: 1.4rem 0 0.6rem;
}

main.responsive h3 {
    font-size: 1.1rem;
    font-weight: 600;
    line-height: 1.3;
    margin: 0.6rem 0 0.4rem;
}

.eyebrow {
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-2);
}

/* ---- Utilities ---- */
.muted {
    color: var(--ink-2);
}

.tabular {
    font-variant-numeric: tabular-nums;
}

.sr-only {
    position: absolute !important;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Skip link: first focusable element, visible only on focus. */
/* Non-prod ribbon (settings.ENV_LABEL): impossible to miss, on every page. */
/* Fixed overlay (outside the body grid, which BeerCSS lays out with named
   areas); the body gets matching top padding and the sticky nav moves down. */
:root {
    --env-ribbon-h: 2.2rem;
}

.env-ribbon {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--env-ribbon-h);
    box-sizing: border-box;
    z-index: 1000;
    background: #c62828;
    color: #fff;
    font-weight: 700;
    font-size: 0.95rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    text-align: center;
    padding: 0.55rem 1rem;
    line-height: 1.1;
}

body:has(.env-ribbon) {
    padding-top: var(--env-ribbon-h);
}

body:has(.env-ribbon) nav.top {
    top: var(--env-ribbon-h);
}

.skip-link {
    position: absolute;
    left: -999px;
    top: 0.5rem;
    z-index: 1000;
    padding: 0.55rem 1rem;
    border-radius: 0.4rem;
    background: var(--accent);
    color: var(--on-accent);
    font-weight: 600;
    text-decoration: none;
}

.skip-link:focus {
    left: 0.5rem;
    outline: 3px solid var(--marker);
    outline-offset: 2px;
}

/* Keyboard focus: one ring everywhere, only for keyboard (focus-visible). */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
    border-radius: 0.25rem;
}

/* Motion: respect the OS setting (BeerCSS transitions + our own). */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

main.responsive {
    min-height: 70vh;
    /* BeerCSS sets overflow:hidden here, which makes <main> a clipping box
       that position:sticky (the section nav) can't escape. `clip` keeps the
       clipping without creating a scroll container, so sticky works against
       the viewport. */
    overflow: clip;
    /* <body> is a CSS grid and this is a grid item. Without min-width:0 the
       item's default min-width:auto lets a wide child (e.g. a stats table with
       a min-width) blow the whole page out horizontally instead of scrolling
       inside its own wrapper — unreadable on mobile. This lets the item shrink
       to its column so the .table-scroll wrappers below become the scroller. */
    min-width: 0;
}

/* Wide data tables scroll horizontally on narrow screens instead of cramming
   their columns. Wrap a table in <div class="table-scroll"> to make the
   wrapper (not the page) the horizontal scroller, with momentum on iOS. */
.table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    max-width: 100%;
}

/* Default readable floor; an inline min-width on the table (e.g. the
   aggregated table's 52rem) overrides this. Below the floor it scrolls. */
.table-scroll > table {
    min-width: 40rem;
}

/* Comment tables: the content column carries the value, so it gets a real
   width floor — the table grows and pans horizontally instead of wrapping the
   text into a skyscraper column. On phones the floor tracks the viewport
   (~one screenful of comfortable reading) and the article column tightens so
   it steals less of the pan distance. */
.table-scroll .col-comment {
    min-width: 24rem;
}
.table-scroll .col-article {
    max-width: 16rem;
}
@media (max-width: 600px) {
    .table-scroll .col-comment { min-width: 82vw; }
    .table-scroll .col-article { max-width: 9rem; }
}

/* Content links — make links obvious everywhere EXCEPT the menu bar. The nav,
   banner and footer live outside <main>, so scoping to `main` leaves them
   untouched. Buttons/chips rendered as <a> are excluded so they keep their
   BeerCSS look. */
main.responsive a:not(.button):not(.chip):not(.nav-link):not([role="button"]) {
    color: var(--link);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
}

main.responsive a:not(.button):not(.chip):not(.nav-link):not([role="button"]):hover {
    text-decoration-thickness: 2px;
}

/* External links get a small outward arrow so they're distinguishable. */
main.responsive a[href^="http"]:not(.button):not(.chip):not([role="button"])::after {
    content: " \2197"; /* ↗ */
    font-size: 0.85em;
    line-height: 0;
    vertical-align: baseline;
}

/* Site banner — full-width strip ABOVE the menu. BeerCSS makes <body> a grid
   and pins nav.top to row 1, so we place the banner in row 1 (spanning all
   columns) and push the sticky nav to row 2. Scoped with :has() so pages
   without a banner keep the nav in its default row. */
.site-banner {
    grid-column: 1 / -1;
    grid-row: 1;
    width: 100%;
    line-height: 0;
}

body:has(.site-banner) nav.top {
    grid-row: 2;
}

.site-banner-img {
    /* Show the full image (no cropping). Natural aspect ratio; cap height
       on very tall images with contain-fit letterboxing. */
    display: block;
    width: 100%;
    height: auto;
    max-height: 380px;
    object-fit: contain;
    object-position: center;
}

/* Top nav */
nav.top {
    background: var(--surface);
    border-bottom: 1px solid var(--rule);
    /* BeerCSS fixes the bar at 4.5rem; let it grow when the items wrap onto
       a second row (1000-1250px with the full menu + social cluster). The
       body grid's top row is `auto`, so content moves down instead of being
       overlapped. */
    block-size: auto;
    min-block-size: calc(var(--top) + 4.5rem);
    padding-block-end: 0.25rem;
    gap: 0.35rem;
    align-items: center;
    /* Span the full body-grid width like the banner does — BeerCSS otherwise
       drops the bar into the main column, leaving a ~230px gap on the left
       (a reserved drawer column) that pushes the menu off-centre. */
    grid-column: 1 / -1;
    /* Centre the menu in the bar (aligns with the centred banner on wide
       screens). !important beats BeerCSS's justify-content:space-around; the
       mobile block overrides this back to flex-start. `safe` keeps the first
       items reachable when the menu is wider than the viewport (900-1100px):
       it falls back to start instead of clipping them off the left edge. */
    justify-content: safe center !important;
    flex-wrap: wrap;
}

/* Per-item menu styling chosen in the admin (colour + bold). Targets the
   element AND its inner span/icon with !important so it reliably beats
   BeerCSS's <button> styles (dropdown toggles are buttons). */
nav.top .nav-colored,
nav.top .nav-colored > span,
nav.top .nav-colored > i {
    color: var(--nav-item-color) !important;
}

nav.top .nav-bold,
nav.top .nav-bold > span {
    font-weight: 700 !important;
}

/* Hamburger toggle: hidden on wide screens, shown on narrow ones. Filled with
   the primary colour so it reads clearly as a control instead of a bare icon
   fading into the nav background. */
.nav-hamburger {
    display: none;
    /* Fixed brand blue rather than var(--primary): BeerCSS reassigns --primary
       to a pale purple in dark mode, which left white-on-pale (washed out).
       !important beats BeerCSS's nav-button reset (bare circle buttons render
       transparent in the top nav otherwise). */
    background: var(--accent) !important;
    color: var(--on-accent) !important;
}

.nav-hamburger > i {
    color: var(--on-accent) !important;
}

.nav-items {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    flex-wrap: wrap;
}

@media (max-width: 900px) {
    /* BeerCSS spreads nav children with justify-content:space-around and
       centres their text; override so the collapsed menu is a clean, left
       aligned, full-width vertical list. */
    nav.top {
        flex-wrap: wrap;
        justify-content: flex-start !important;
        text-align: left !important;
    }
    .nav-hamburger {
        display: inline-flex;
    }
    /* The menu collapses under the bar and expands on tap. !important on the
       basis/width beats BeerCSS's flex:0 0 auto on nav children, which
       otherwise keeps this from taking its own full-width row. */
    .nav-items {
        display: none;
        flex-basis: 100% !important;
        width: 100% !important;
        order: 10;
        flex-direction: column;
        align-items: stretch;
        gap: 0.1rem;
        padding: 0.3rem 0 0.5rem;
    }
    /* Open menu is a solid dropdown panel so page content never shows through
       (the sticky nav sits in a fixed-height grid row, so the expanded items
       overflow on top of <main>). */
    nav.top.nav-open .nav-items {
        display: flex;
        background: var(--surface-container-high, #2a2930);
        box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.35);
        border-radius: 0 0 0.6rem 0.6rem;
        padding: 0.3rem 0.5rem 0.6rem;
        position: relative;
        z-index: 40;
    }
    .nav-items .nav-link,
    .nav-items .nav-dropdown,
    .nav-items .trolls-menu {
        width: 100%;
    }
    .nav-items .nav-link {
        padding: 0.7rem 0.8rem;
        border-radius: 0.4rem;
        /* BeerCSS renders nav links as centred flex boxes; start-align them so
           every row's text lines up at the left. */
        justify-content: flex-start;
        text-align: left;
    }
    .nav-items .nav-dropdown > button,
    .nav-items .trolls-menu > button {
        /* Fill the row so the arrow can sit at the right edge. width/min-width
           carry !important because the Dossiers toggle also has .nav-link,
           whose min-width:max-content + flex:0 0 auto would otherwise shrink it
           to its text. */
        width: 100% !important;
        min-width: 0 !important;
        justify-content: flex-start;
        /* Match the plain links' left padding so every row's text starts at
           the same x — the Trolls toggle lacks the .nav-link class. margin:0
           drops BeerCSS's 8px button margin that would over-indent them. */
        padding: 0.7rem 0.8rem;
        margin: 0;
        text-align: left;
    }
    /* Push the dropdown arrow to the right edge instead of hugging the label. */
    .nav-items .nav-dropdown > button > i,
    .nav-items .trolls-menu > button > i {
        margin-left: auto;
    }
    /* Dropdown panels flow inline inside the open menu instead of overlaying. */
    .nav-dropdown,
    .trolls-menu {
        position: static;
    }
    .nav-dropdown-panel,
    .trolls-dropdown {
        position: static;
        left: auto;
        right: auto;
        width: auto;
        max-height: none;
        box-shadow: none;
        margin: 0 0 0.3rem 0.75rem;
        border-left: 2px solid rgba(128, 128, 128, 0.35);
    }
}

/* General mobile polish: smaller headings, no accidental overflow. */
@media (max-width: 600px) {
    main.responsive h3 {
        font-size: 1.5rem;
        line-height: 1.2;
    }
    main.responsive h4 {
        font-size: 1.2rem;
    }
}

main.responsive img {
    max-width: 100%;
    height: auto;
}

main.responsive pre {
    overflow-x: auto;
}

nav.top .nav-link {
    /* Override BeerCSS's fixed-width icon-button sizing for text links */
    flex: 0 0 auto;
    width: auto;
    min-width: max-content;
    padding: 0.4rem 0.8rem;
    border-radius: 0.5rem;
    font-weight: 500;
    white-space: nowrap;
}

nav.top .nav-link:hover {
    background: var(--accent-soft);
}

nav.top .nav-link.active {
    color: var(--ink);
    box-shadow: inset 0 -2px 0 var(--accent);
    border-radius: 0.5rem 0.5rem 0 0;
}

/* Static pages */
.static-page img.responsive-img {
    max-width: 100%;
    height: auto;
    margin: 1rem 0;
}

.static-page {
    max-width: 72ch;
}

/* Author page sections */
.author-section {
    margin: 1.5rem 0 2rem;
    scroll-margin-top: 88px; /* under the sticky nav */
}

.author-section > h2 {
    margin: 0.5rem 0 0.75rem;
    padding-bottom: 0.25rem;
    border-bottom: 1px solid var(--rule);
}

.section-nav {
    font-size: 0.85rem;
    margin-bottom: 0.5rem;
    text-align: right;
}

.biography-body {
    max-width: 72ch;
    line-height: 1.55;
}

.biography-body img {
    max-width: 100%;
    height: auto;
    border-radius: 0.5rem;
    margin: 0.75rem 0;
}

.biography-body h2,
.biography-body h3,
.biography-body h4 {
    margin-top: 1.25rem;
}

/* Quoted comment box ([[comment:ID]] token, site-wide) */
.comment-quote {
    /* The coupure: a clipping, annotated. Left rule = the author's identity
       hue (--ah set on the element), marks = the highlighter. */
    max-width: 72ch;
    margin: 1rem 0;
    padding: 0.75rem 1rem 0.8rem;
    border: 1px solid var(--rule);
    border-left: 4px solid hsl(var(--ah, 210), var(--tint-sat), var(--tint-light));
    border-radius: 0 0.5rem 0.5rem 0;
    background: var(--surface);
}

.comment-quote.is-missing {
    border-left-color: var(--flag);
}

.comment-quote .cq-head {
    display: flex;
    gap: 0.6rem;
    align-items: baseline;
    flex-wrap: wrap;
}

.comment-quote .cq-author {
    font-family: var(--font-display);
    font-size: 1.08rem;
    font-weight: 600;
    line-height: 1.2;
}

/* Per-author identity color: the author_hue template filter derives a stable
   hue (--ah) from the name, so one author keeps one color across every card
   and table site-wide. Lightness flips with the theme for contrast. */
.author-tint {
    font-weight: 700;
    color: hsl(var(--ah, 210), var(--tint-sat), var(--tint-light));
}

.comment-quote .cq-meta {
    font-size: 0.82rem;
    color: var(--ink-2);
}

.comment-quote .cq-article {
    margin: 0.15rem 0 0.45rem;
    font-size: 0.9rem;
}

.comment-quote .cq-body {
    line-height: 1.55;
}

.comment-quote .cq-missing {
    color: var(--flag);
    font-size: 0.85rem;
}

/* Highlighted passages in comment cards (match_highlighted SQL block).
   Fixed amber + near-black text so it pops identically on light AND dark
   backgrounds (no theme-dependent colors to get wrong). */
.comment-quote mark.cq-match {
    background: var(--marker);
    color: var(--on-marker);
    padding: 0 0.15em;
    border-radius: 3px;
}

/* Embedded video ([[video:slug]] token, site-wide) */
.video-embed {
    max-width: 52rem;
    margin: 1rem 0;
}

.video-embed video {
    display: block;
    width: 100%;
    border-radius: 0.5rem;
    background: #000;
}

.video-embed .ve-caption {
    margin-top: 0.35rem;
    font-size: 0.85rem;
    opacity: 0.7;
}

.video-embed .ve-missing {
    color: var(--flag);
    font-size: 0.85rem;
}

/* Top-nav dropdowns: the dynamic Trolls menu and admin-defined menu groups */
.trolls-menu,
.nav-dropdown {
    position: relative;
}

.trolls-dropdown,
.nav-dropdown-panel {
    position: absolute;
    top: 100%;
    z-index: 50;
    min-width: 14rem;
    max-height: 70vh;
    overflow-y: auto;
    padding: 0.5rem 0;
}

/* Trolls sits at the right end (align right); admin groups align left under
   their button. */
.trolls-dropdown {
    right: 0;
}

.nav-dropdown-panel {
    left: 0;
}

.trolls-dropdown a,
.nav-dropdown-panel a {
    display: block;
    padding: 0.5rem 1rem;
    white-space: nowrap;
}

.trolls-dropdown a:hover,
.nav-dropdown-panel a:hover {
    background: rgba(0, 0, 0, 0.06);
}

.trolls-dropdown hr,
.nav-dropdown-panel hr {
    margin: 0.3rem 0;
}

/* ---- Stat tiles (author dashboard strip): numbers, not headings ---- */
.stat-value {
    font-family: var(--font-display);
    font-size: 1.7rem;
    font-weight: 600;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
    margin: 0.2rem 0 0.15rem;
}

.stat-value.date {
    font-size: 1.1rem;
    padding-top: 0.35rem;
}

/* ---- Tables: readable by default ---- */
.table-scroll table {
    border-color: var(--rule);
}

.table-scroll thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--surface-2);
    color: var(--ink);
    font-weight: 600;
}

.table-scroll td,
.table-scroll th {
    border-bottom: 1px solid var(--rule);
}

/* Deleted comments: dimmed text + the "Oui" flag chip — never opacity on the
   whole row, which pushed the text under contrast minimums. */
tr.row-deleted td {
    color: var(--ink-2);
}

tr.row-deleted td a {
    color: var(--ink-2);
}

/* ---- Chart data disclosure ("Voir les données") ---- */
.chart-data {
    margin-top: 0.6rem;
}

.chart-data > summary {
    cursor: pointer;
    color: var(--accent);
    width: max-content;
    padding: 0.2rem 0;
}

.chart-data .table-scroll {
    margin-top: 0.5rem;
    max-height: 22rem;
    overflow-y: auto;
}

.chart-data table {
    min-width: 0;
}

/* Zebra rows: a token tint instead of BeerCSS's 19% grey overlay (--active),
   which read as heavy slabs on white. */
/* `table.stripes` to out-specify BeerCSS's own rule (var(--active), a
   translucent grey) so zebra rows use the opaque --stripe token — which the
   frozen first column (freeze-first) relies on to match its row. */
table.stripes > tbody > tr:nth-child(odd) {
    background-color: var(--stripe);
}

/* ---- Wordmark (Home link) ---- */
nav.top .nav-wordmark {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ink);
}

/* ---- Prose: lists, quotes, paragraphs inside long-form containers ---- */
.static-page p,
.biography-body p {
    margin: 0 0 1rem;
}

.static-page ul,
.static-page ol,
.biography-body ul,
.biography-body ol {
    padding-left: 1.4rem;
    margin: 0 0 1rem;
}

.static-page li,
.biography-body li {
    margin-bottom: 0.3rem;
}

.static-page blockquote,
.biography-body blockquote {
    margin: 1rem 0;
    padding: 0.2rem 0 0.2rem 1rem;
    border-left: 3px solid var(--rule);
    color: var(--ink-2);
}

/* ---- Cards: surface + rule, no shadow; hover = rule darkens ---- */
.grid > article.border {
    background: var(--surface);
    border-color: var(--rule);
    box-shadow: none;
    transition: border-color var(--speed2);
}

.grid > article.border:hover {
    border-color: var(--outline);
}

/* ---- Stat tiles ---- */
.stat-label {
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-2);
}

/* ---- Filter labels wrapping a select ---- */
.filter-label {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

/* ---- Footer ---- */
.site-footer {
    border-top: 1px solid var(--rule);
    margin-top: 2.5rem;
    padding: 1.5rem 1rem 2rem;
    color: var(--ink-2);
}

.site-footer .footer-purpose {
    max-width: 72ch;
    margin: 0 0 0.6rem;
}

.site-footer .footer-wordmark {
    font-family: var(--font-display);
    font-weight: 600;
    color: var(--ink);
}

.site-footer .footer-copy {
    margin: 0;
}

/* ---- Home hero: the thesis ---- */
.hero {
    margin: 1rem 0 2.5rem;
    /* Match the inner padding of the BeerCSS <article> card that follows, so
       the headline, figures and the body text share one left edge. */
    padding-inline: 1rem;
}

.hero h1 {
    font-size: clamp(2rem, 4.2vw, 2.9rem);
    line-height: 1.08;
    margin: 0.35rem 0 1.2rem;
    max-width: 20ch;
}

.hero-figures {
    display: flex;
    flex-wrap: wrap;
    gap: 0.8rem 2rem;
    margin: 0 0 1.4rem;
}

.hero-figure {
    display: flex;
    flex-direction: column-reverse; /* value above its label, label first in DOM for <dl> */
}

.hero-figure dd {
    margin: 0;
}

.hero-figure .stat-value {
    font-size: 2rem;
}

.hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}

.hero-actions .button {
    margin: 0; /* BeerCSS gives buttons an outer margin; the gap handles spacing */
}

.home-body {
    max-width: 72ch;
}

/* ---- Home: main column + "Nouvelles" column ---- */
.home-grid.has-news {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(16rem, 1fr);
    gap: 1.5rem 3rem;
    align-items: start;
}

@media (max-width: 900px) {
    .home-grid.has-news {
        grid-template-columns: 1fr;
    }
}

.home-main {
    min-width: 0;
}

.home-news {
    min-width: 0;
    margin-top: 1rem;
    padding: 0 1rem;
    border-left: 1px solid var(--rule);
}

@media (max-width: 900px) {
    .home-news {
        border-left: 0;
        border-top: 1px solid var(--rule);
        padding: 1.2rem 1rem 0;
    }
}

main.responsive .home-news h2.eyebrow {
    font-family: inherit;
    font-size: 0.78rem;
    margin: 0.2rem 0 0.8rem;
}

.news-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.news-item {
    padding: 0.8rem 0;
    border-top: 1px solid var(--rule);
}

.news-item:first-child {
    border-top: 0;
    padding-top: 0;
}

.news-date {
    display: inline-block;
    font-size: 0.82rem;
    color: var(--ink-2);
}

/* Pinned item: the marker amber as a left rule + a small tag, same device
   as the highlighted passages. */
.news-item.is-pinned {
    border-left: 3px solid var(--marker);
    padding-left: 0.7rem;
}

.news-pin {
    display: inline-block;
    margin-left: 0.5rem;
    padding: 0.05rem 0.45rem;
    border-radius: 999px;
    background: var(--marker);
    color: var(--marker-ink, #1c1b1f);
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    vertical-align: 1px;
}

main.responsive .news-title {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 600;
    line-height: 1.25;
    margin: 0.15rem 0 0.35rem;
}

.news-body {
    font-size: 0.95rem;
}

.news-body p {
    margin: 0 0 0.5rem;
}

.news-body p:last-child {
    margin-bottom: 0;
}

.news-all {
    margin: 0.9rem 0 0;
    font-size: 0.9rem;
}

/* Full list on /news/ */
.news-list-full {
    max-width: 72ch;
    margin-top: 1rem;
}

.news-list-full .news-item {
    padding: 1rem 0;
}

main.responsive .news-list-full .news-title {
    font-size: 1.4rem;
}

.news-lede {
    font-size: 1.1rem;
    color: var(--ink-2);
    margin: 0 0 1.2rem;
}

/* ---- Author page header: the author's rule, same device as the coupure ---- */
.author-head {
    border-left: 5px solid hsl(var(--ah, 210), var(--tint-sat), var(--tint-light));
    padding-left: 1rem;
    margin: 0.5rem 0 1rem;
}

.author-head h1 {
    margin: 0 0 0.3rem;
}

.author-head .author-sub {
    margin: 0;
    font-size: 0.95rem;
}

/* Sticky section nav under the top bar (top offset set by script). */
.section-jump {
    position: sticky;
    top: 0;
    z-index: 30;
    display: flex;
    gap: 0.2rem 1.2rem;
    overflow-x: auto;
    padding: 0.5rem 0;
    margin: 0 0 1rem;
    background: var(--paper);
    border-bottom: 1px solid var(--rule);
    font-size: 0.92rem;
}

main.responsive .section-jump a {
    color: var(--ink-2);
    text-decoration: none;
    white-space: nowrap;
    padding: 0.15rem 0;
}

main.responsive .section-jump a[aria-current],
main.responsive .section-jump a:hover {
    color: var(--ink);
    box-shadow: inset 0 -2px 0 var(--accent);
}

/* ---- Author index cards carry the author's rule ---- */
.grid > article.author-card {
    border-left: 4px solid hsl(var(--ah, 210), var(--tint-sat), var(--tint-light));
}

/* ---- Aggregated stats: author filter panel ---- */
.author-filter-panel {
    background: var(--surface);
    border: 1px solid var(--rule);
}

.author-filter-panel .author-filter-actions {
    padding: 0.35rem 0.6rem;
    border-bottom: 1px solid var(--rule);
    margin-bottom: 0.2rem;
}

/* ---- The one motion: marker highlights draw in on first view ---- */
.js .comment-quote mark.cq-match {
    background: linear-gradient(var(--marker), var(--marker)) left center / 0% 100% no-repeat;
    color: inherit;
    transition: background-size 0.45s ease-out, color 0.45s ease-out;
}

.js .comment-quote.is-seen mark.cq-match {
    background-size: 100% 100%;
    color: var(--on-marker);
}

/* ---- Sortable tables (static/js/sortable.js) ---- */
table[data-sortable] th .sort-btn {
    all: unset;
    cursor: pointer;
    display: inline-block;
    white-space: nowrap;
    font: inherit;
    color: inherit;
    text-align: inherit;
}

/* Kill BeerCSS's ripple pseudo on these header buttons (it's an absolute
   inset:0 box that would cover/trap the label). */
table[data-sortable] th .sort-btn::before,
table[data-sortable] th .sort-btn::after {
    content: none;
    display: none;
}

table[data-sortable] th .sort-arrow {
    display: inline-block;
    margin-left: 0.35em;
    opacity: 0.35;
    font-size: 0.85em;
}

table[data-sortable] th[aria-sort="ascending"] .sort-arrow,
table[data-sortable] th[aria-sort="descending"] .sort-arrow {
    opacity: 1;
    color: var(--accent);
}

table[data-sortable] th .sort-btn:hover,
table[data-sortable] th .sort-btn:focus-visible {
    color: var(--accent);
}

table[data-sortable] th .sort-btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* ---- Frozen first column (author name) while the table pans sideways ----
   Add class "freeze-first" to a table inside .table-scroll. Cells need an
   opaque background (the zebra shade on odd rows, the surface otherwise) so
   the scrolling columns slide underneath; the header corner stacks above
   both the sticky thead and the sticky column. */
.table-scroll > table.freeze-first > thead > tr > th:first-child,
.table-scroll > table.freeze-first > tbody > tr > td:first-child {
    position: sticky;
    left: 0;
    z-index: 2;
    background: var(--surface);
    box-shadow: 1px 0 0 var(--rule);
}

.table-scroll > table.freeze-first > thead > tr > th:first-child {
    z-index: 3;
    background: var(--surface-2);
}

.table-scroll > table.freeze-first.stripes > tbody > tr:nth-child(odd) > td:first-child {
    background: var(--stripe);
}

/* ---- Social icons (Settings -> Réseaux sociaux) ---- */
.social-links {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
}

.social-links a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    color: var(--ink-2);
    transition: color var(--speed2), background-color var(--speed2);
}

.social-links a:hover,
.social-links a:focus-visible {
    color: var(--ink);
    background: var(--surface-2);
}

.social-links svg {
    width: 1.05rem;
    height: 1.05rem;
    fill: currentColor;
}

/* Top bar: icon cluster + theme toggle sit together at the right end. */
nav.top .nav-end {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
    /* No auto margin: the cluster is simply the last centred item. An auto
       margin would swallow the free space on a wrapped second row and push
       the remaining links to the left edge. */
    margin-left: 0.35rem;
}

/* Let the items row shrink and wrap inside the bar — BeerCSS gives nav
   children flex:0 0 auto, which pushed the end cluster off-screen below
   ~1200px instead of wrapping. */
nav.top .nav-items {
    flex: 1 1 auto !important;
    min-width: 0 !important;
    /* The row grows to fill the bar, so the items must centre themselves
       inside it (otherwise they hug the left edge). */
    justify-content: center;
}

nav.top .social-links a {
    width: 2rem;
    height: 2rem;
}

nav.top .social-links svg {
    width: 0.95rem;
    height: 0.95rem;
}

@media (max-width: 900px) {
    /* In the collapsed menu the cluster becomes its own row of icons. */
    nav.top .nav-end {
        width: 100%;
        margin: 0.4rem 0 0;
        padding: 0.5rem 0.8rem 0;
        border-top: 1px solid var(--rule);
        justify-content: flex-start;
        gap: 0.4rem;
    }
}

/* Footer: slightly larger row under the purpose line. */
.site-footer .social-links {
    margin: 0.2rem 0 0.8rem;
    gap: 0.35rem;
}

.site-footer .social-links svg {
    width: 1.2rem;
    height: 1.2rem;
}
