/* ============================================================
   LawnBeast V2 — ARTICLE SYSTEM, shared layer
   ------------------------------------------------------------
   One component vocabulary behind all three content surfaces:

     .art--announcement   /news?id=<slug>      "what changed"
     .art--guide          /guides/<slug>       "how do I do it"
     .art--feature        /features/<slug>     "what is this"

   This file owns everything the three have in common: the type
   scale, the reading column, and every body block a fragment can
   use (callout, figure, table, FAQ, quote, KPI, cards, CTA...).
   Each surface skin then layers on only its own chrome.

   Article fragments must never ship their own <style>, <h1> or
   stylesheet link — the shell owns all of it. `manage.py
   check_articles` enforces that; the component menu an author
   writes against is the _STARTER.html in each fragment directory.

   MOBILE-FIRST: base styles = phone; desktop layered on at 768px.
   Depends on css/v2/base.css + css/v2/public-base.css for tokens.
   ============================================================ */

:root {
    /* ---- Tokens the design system defines but v2/base.css does not.
       The status palette currently lives in quote-board.css and the
       lime/featured set nowhere at all, and neither loads on public
       pages. Scoped here so the article system is self-contained. ---- */
    --art-font-sans: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, sans-serif;
    --art-font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace;

    --art-info:      #2563eb;   --art-info-bg:  #e7effd;  --art-info-deep:  #1d4ed8;
    --art-warn:      #f59e0b;   --art-warn-bg:  #fcefd7;  --art-warn-deep:  #b45309;
    --art-info-line: #cfe0fb;   --art-warn-line: #f4dcae;

    --art-lime: #8bc34a;
    --art-lime-bright: #a5d66a;
    --art-featured-ink: #1f3f20;
    --art-featured-grad: linear-gradient(160deg, #2d5a2e 0%, #1f3f20 100%);
    --art-featured-shadow: 0 16px 40px rgba(30, 38, 32, .28);
    /* The lime used for text and icons ON the featured band, as opposed to
       --art-lime-bright which is the lime anywhere. It is a separate token
       because it has to move with --art-featured-grad: the same lime that
       clears AA on the house green fails on a lighter accent band. See the
       accent block below. */
    --art-featured-accent: var(--art-lime-bright);

    /* reading column — the body text never gets wider than this.
       A skin can release it (see .art--guide in guide.css, which sets it to
       100% so prose runs the full width of its grid cell too). */
    --art-measure: 680px;

    /* diagram column — blocks that aren't prose (matrices, stage chains,
       relationship flows) fill the whole body column instead of being pinned
       to the measure, because a table is scanned, not read line by line. 100%,
       not a length: on a phone, and on any column narrower than the measure,
       it resolves to exactly what a measure-capped block already did. */
    --art-wide: 100%;
}

/* ---------- Per-post accents ----------
   A fragment puts one of these on a block that already paints itself with
   --art-featured-grad — in practice .art-showcase, the dark brand card a post
   presents its record on — and that block takes the accent instead of the
   house green.

   They override the TOKEN, not `background`. That is the whole design: every
   element keyed to --art-featured-grad (.art-showcase and .art-cta--dark here,
   .art-hero-card in announcement.css, .art-bleed in feature.css) follows
   without being named, a future consumer of the token is accented for free,
   and nothing already written has to change. A custom property declared on an
   element wins over the inherited :root value on that element regardless of
   source order, and inherits on down, so a nested consumer takes the accent
   too — the class can sit on the block itself or on a wrapper.

   Each one keeps the house gradient's exact form —
   linear-gradient(160deg, <dark> 0%, <darker> 100%) — so the accents differ
   from it in hue only, never in treatment. Everything painted on this band is
   white text, so every stop is held above 7:1 against white; the house green's
   lighter stop is 8.0:1 and these run 7.25–8.40:1 (AAA for body text), with
   the darker stops at 11.6–13.1:1.

   The accent does NOT reach the shell-rendered hero (.art-hero-card), which is
   outside the fragment: a post with a hero image opens on the house green and
   accents from its showcase down. That is deliberate — the accent is a
   property of the block, not of the page.

   White body text is safe on all of them, but the LIME is not: the band also
   carries small lime text (.art-showcase-bar .flag, 11px — "CARD ONLY",
   "DEEP SEARCH"), and #a5d66a measures 4.75:1 on the house green but only
   4.29:1 on amber and rust, which are the two lightest bands. That fails
   WCAG AA for small text. So those two lift --art-featured-accent to #b5df80
   (4.78:1 / 4.77:1) alongside the gradient — same reason the gradient is a
   token: anything painting lime on the band follows without being named.
   Indigo (4.83:1) and crimson (4.97:1) already clear AA and keep house lime.
   ---- */
.art-accent--indigo  { --art-featured-grad: linear-gradient(160deg, #3b4a91 0%, #262e5c 100%); }
.art-accent--amber   { --art-featured-grad: linear-gradient(160deg, #7a4d0f 0%, #513209 100%);
                       --art-featured-accent: #b5df80; }
.art-accent--rust    { --art-featured-grad: linear-gradient(160deg, #8b421f 0%, #5a2913 100%);
                       --art-featured-accent: #b5df80; }
.art-accent--crimson { --art-featured-grad: linear-gradient(160deg, #8f2637 0%, #5d1621 100%); }

/* ============================================================
   1. Shell scaffolding
   ============================================================ */

.art {
    font-family: var(--art-font-sans);
    color: var(--text);
    background: var(--surface);
}

/* ---------- Breadcrumb bar ---------- */
.art-crumbs {
    border-bottom: 1px solid var(--border-light);
    background: var(--surface);
}
.art-crumbs nav {
    display: flex;
    align-items: center;
    gap: 7px;
    flex-wrap: wrap;
    padding-top: 12px;
    padding-bottom: 12px;
    font-size: 12px;
    color: var(--text-muted);
}
.art-crumbs a { color: var(--text-muted); }
.art-crumbs a:hover { color: var(--accent-dark); }
.art-crumbs .sep { font-size: 9px; opacity: .6; }
.art-crumbs .current {
    color: var(--text);
    font-weight: 600;
    /* long titles must not push the bar wide on a phone */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---------- Head: eyebrow / headline / lede / meta ---------- */
.art-head { padding-top: 28px; padding-bottom: 4px; }

.art-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--accent-dark);
    margin-bottom: 10px;
}

.art-pill {
    display: inline-flex;
    align-items: center;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    padding: 3px 9px;
    border-radius: 999px;
    background: var(--accent-bg);
    color: var(--accent-dark);
}

.art-title {
    margin: 0 0 12px;
    font-size: 30px;
    line-height: 1.1;
    letter-spacing: -.02em;
    font-weight: 700;
    color: var(--text);
    text-wrap: balance;
}

/* .art .art-lede, not .art-lede: the guide skin nests its header inside
   .art-body, where the plain `.art-body p` rule would otherwise out-specify it. */
.art .art-lede {
    margin: 0 0 14px;
    max-width: var(--art-measure);
    font-size: 16px;
    line-height: 1.65;
    color: var(--text-secondary);
    text-wrap: pretty;
}

.art-meta {
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
    font-size: 11.5px;
    color: var(--text-muted);
    font-family: var(--art-font-mono);
}
.art-meta .dot {
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: var(--border);
}
.art-byline {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 12.5px;
    color: var(--text-muted);
}
.art-byline .avatar {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--accent-bg);
    color: var(--accent-dark);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .02em;
}

/* ---------- Layout: rail + body ---------- */
/* Mobile = one column, rail collapses to a sticky pill strip (guide,
   announcement) or is hidden (feature). Desktop grid is set per skin. */
.art-layout { display: block; }

.art-body { min-width: 0; padding-bottom: 40px; }

/* ---------- Rail ---------- */
.art-rail { min-width: 0; }

/* The two skins that HAVE a rail (guide, feature) drew the same desktop grid
   twice: display:grid + align-items:start on the layout, and the sticky rail
   offset. Only which side the rail sits on, the gap and the body cap actually
   differ, so those stay in the skins (guide.css / feature.css) and the shared
   half lives here. .art--announcement has no .art-layout in its shell, so
   nothing else picks this up. */
@media (min-width: 1000px) {
    .art-layout {
        display: grid;
        align-items: start;
    }
    .art-rail {
        position: sticky;
        top: calc(var(--nav-h) + 24px);
        align-self: start;
    }
}

.art-toc {
    position: sticky;
    top: var(--nav-h);
    z-index: 20;
    background: var(--surface);
    border-bottom: 1px solid var(--border-light);
    margin-left: calc(var(--gutter) * -1);
    margin-right: calc(var(--gutter) * -1);
    padding: 8px var(--gutter);
}
.art-toc-head {
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 8px;
    display: none;              /* label wastes a line on the phone strip */
}
.art-toc-nav {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}
.art-toc-nav::-webkit-scrollbar { display: none; }
.art-toc-nav a {
    flex: none;
    padding: 5px 11px;
    border-radius: 999px;
    background: var(--surface-alt);
    border: 1px solid var(--border-light);
    font-size: 12px;
    color: var(--text-secondary);
    white-space: nowrap;
}
.art-toc-nav a:hover { color: var(--accent-dark); }
.art-toc-nav a.active {
    background: var(--accent-bg);
    border-color: var(--accent-border);
    color: var(--accent-dark);
    font-weight: 600;
}

.art-share { display: none; }   /* desktop-only affordance */
.art-share-label {
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 8px;
}
.art-share-btns { display: flex; gap: 8px; }
.art-share-btns a {
    width: 30px;
    height: 30px;
    border-radius: 7px;
    border: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
    font-size: 14px;
}
.art-share-btns a:hover {
    border-color: var(--accent-border);
    background: var(--accent-bg);
    color: var(--accent-dark);
}

/* At a Glance card — plan / setup time / roles */
.art-glance {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface-alt);
    padding: 16px;
}
.art-glance-head {
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 10px;
}
.art-glance dl {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 9px;
    font-size: 12px;
}
.art-glance dl > div {
    display: flex;
    justify-content: space-between;
    gap: 12px;
}
.art-glance dt { color: var(--text-muted); }
.art-glance dd {
    margin: 0;
    color: var(--text);
    font-weight: 600;
    text-align: right;
}
.art-glance dd.mono { font-family: var(--art-font-mono); }

/* ============================================================
   2. Body typography — what a fragment writes directly
   ============================================================ */

/* Descendant, not a child selector: jobs-vs-invoices deep-links twelve
   sub-anchors (#use-case-1..7, #setup-*) that are nested one level down so
   article.js keeps them out of the rail — promoting them would give that page
   a nineteen-entry TOC. Without this they land under the fixed nav. */
.art-body section { scroll-margin-top: calc(var(--nav-h) + 56px); }

.art-body h2 {
    margin: 34px 0 12px;
    font-size: 21px;
    line-height: 1.25;
    letter-spacing: -.015em;
    font-weight: 700;
    color: var(--text);
    text-wrap: balance;
}
.art-body > section:first-child > h2 { margin-top: 8px; }

.art-secnum {
    display: inline-block;
    margin-right: 10px;
    font-family: var(--art-font-mono);
    font-size: 13px;
    font-weight: 700;
    color: var(--accent);
    vertical-align: 2px;
}

.art-body h3 {
    margin: 22px 0 8px;
    font-size: 16px;
    line-height: 1.3;
    letter-spacing: -.01em;
    font-weight: 600;
    color: var(--text);
}

.art-body p {
    margin: 0 0 14px;
    max-width: var(--art-measure);
    font-size: 15px;
    line-height: 1.75;
    color: var(--text-secondary);
    text-wrap: pretty;
}
.art-body p.art-lead,
.art-body > .art-lead {
    font-size: 17px;
    line-height: 1.7;
    color: var(--text);
    margin-bottom: 24px;
}

.art-body a:not(.art-btn):not(.art-card):not(.art-related a) {
    color: var(--accent-dark);
    font-weight: 500;
    text-decoration: underline;
    text-decoration-color: var(--accent-border);
    text-underline-offset: 2px;
}
.art-body a:not(.art-btn):hover { text-decoration-color: var(--accent-dark); }

.art-body ul,
.art-body ol {
    margin: 0 0 16px;
    padding-left: 22px;
    max-width: var(--art-measure);
}
.art-body li {
    margin-bottom: 7px;
    font-size: 15px;
    line-height: 1.7;
    color: var(--text-secondary);
}
.art-body li::marker { color: var(--accent); }
.art-body b, .art-body strong { color: var(--text); font-weight: 600; }
.art-body code {
    font-family: var(--art-font-mono);
    font-size: .88em;
    background: var(--surface-alt);
    border: 1px solid var(--border-light);
    border-radius: 4px;
    padding: 1px 5px;
    color: var(--accent-dark);
}
.art-body hr {
    border: 0;
    border-top: 1px solid var(--border-light);
    margin: 30px 0;
}

/* Aside note — a caveat too small for a callout, too easy to miss inline.
   A one-line "Requires: ..." aside doesn't get visually wider by widening
   it, it just stops wrapping — so let it run to the block above it instead
   of pinning it to the measure. .art-body p.art-note re-states max-width
   because .art-body p (0,1,1) would otherwise out-specify the bare class. */
.art-note {
    margin: 0 0 14px;
    padding-left: 12px;
    border-left: 2px solid var(--border);
    max-width: var(--art-wide);
    font-size: 13.5px;
    line-height: 1.65;
    color: var(--text-muted);
}
.art-body p.art-note { font-size: 13.5px; color: var(--text-muted); max-width: var(--art-wide); }

/* ---------- Checklist (ticked capability list) ----------
   Every item is one scannable statement, not a paragraph — capping it at
   the measure just forces the longer ones to wrap for no reason. It's a
   <ul> itself, so .art-body ul (0,1,1) would otherwise out-specify the
   bare .art-checklist (0,1,0) below and win the max-width; same trap as
   .art-body p.art-note. */
.art-checklist {
    list-style: none;
    padding: 0;
    margin: 0 0 18px;
    display: flex;
    flex-direction: column;
    gap: 9px;
}
.art-body ul.art-checklist { max-width: var(--art-wide); }
.art-checklist > li {
    position: relative;
    margin: 0;
    padding-left: 27px;
    font-size: 15px;
    line-height: 1.65;
    color: var(--text-secondary);
}
.art-checklist > li::before {
    content: "\F26E";                  /* bi-check-circle-fill */
    font-family: 'bootstrap-icons';
    position: absolute;
    left: 0;
    top: 1px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--accent);
}

/* ---------- Wide opt-in utility ----------
   OPT-IN. Every component above already routes prose vs. scanned content to
   the right token on its own; this exists for the one-off case — a <p> or a
   <ul>/<ol> that a fragment author judges to be scanned, not read, but that
   doesn't warrant its own component. Compound selector, not a bare class:
   .art-body p and .art-body ul are both (0,1,1) and would otherwise win.
   Never use this on running prose — it is not a substitute for choosing the
   right component. */
.art-body .art-wide { max-width: var(--art-wide); }

/* ============================================================
   3. Body blocks
   ============================================================ */

/* ---------- Callout ---------- */
.art-callout {
    display: flex;
    gap: 12px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface-alt);
    padding: 14px 16px;
    margin: 0 0 20px;
    max-width: var(--art-measure);
}
.art-callout > i {
    flex: none;
    font-size: 16px;
    line-height: 1.5;
    color: var(--text-muted);
}
.art-callout-body { min-width: 0; }
.art-callout p {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.65;
    color: var(--text-secondary);
    max-width: none;
}
.art-callout p + p { margin-top: 8px; }
.art-callout-title {
    display: block;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 3px;
}

.art-callout--info {
    background: var(--art-info-bg);
    border-color: var(--art-info-line);
}
.art-callout--info > i { color: var(--art-info-deep); }

.art-callout--warn {
    background: var(--art-warn-bg);
    border-color: var(--art-warn-line);
}
.art-callout--warn > i { color: var(--art-warn-deep); }

.art-callout--key {
    background: var(--accent-subtle);
    border: 0;
    border-left: 3px solid var(--accent);
    border-radius: 0 8px 8px 0;
}
.art-callout--key > i { color: var(--accent); }
.art-callout--key p { color: var(--text); }

/* Inline-title variant. The stacked title above a body is right when the title
   names a topic ("Before you start") and the reader may skip the paragraph. It
   is wrong when the title *is* the first clause of the sentence — the break
   turns one thought into a heading plus an orphan. This drops the icon and lets
   the title run into the copy as one flowing paragraph, so the block reads as a
   single asserted statement against the accent bar.

   Strictly a modifier: every callout in the other fragments omits it and is
   untouched. Works with the title inside the <p> or as the sibling <span> the
   other variants use — hence the adjacent-sibling rule. */
.art-callout--inline { display: block; }
.art-callout--inline > i { display: none; }
.art-callout--inline .art-callout-title {
    display: inline;
    margin-bottom: 0;
}
.art-callout--inline .art-callout-title::after { content: ' '; }
.art-callout--inline .art-callout-title + p { display: inline; }

/* ---------- Figure ---------- */
.art-figure {
    margin: 0 0 22px;
    /* full-bleed on the phone: screenshots are the point, gutters are not */
    margin-left: calc(var(--gutter) * -1);
    margin-right: calc(var(--gutter) * -1);
}
.art-figure img {
    display: block;
    width: 100%;
    height: auto;
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    background: var(--surface-alt);
}
.art-figure figcaption {
    margin-top: 9px;
    padding: 0 var(--gutter);
    font-size: 12.5px;
    line-height: 1.6;
    color: var(--text-muted);
}
/* placeholder used while a screenshot is still to be captured */
.art-figure--todo .art-figure-ph {
    border: 1px dashed var(--border);
    border-radius: 8px;
    background: var(--surface-alt);
    padding: 26px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    margin: 0 var(--gutter);
}
.art-figure--todo i { font-size: 22px; color: var(--text-muted); }
.art-figure--todo .art-figure-ph div {
    font-size: 11px;
    color: var(--text-muted);
    font-family: var(--art-font-mono);
    text-align: center;
}

/* ---------- Table ---------- */
.art-table-wrap {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow-x: auto;                  /* wide tables scroll, the page never does */
    margin: 0 0 24px;
    -webkit-overflow-scrolling: touch;
}
.art-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
    color: var(--text-secondary);
}
.art-table thead th {
    background: var(--surface-alt);
    text-align: left;
    padding: 9px 14px;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--text-muted);
    border-bottom: 2px solid var(--border);
    white-space: nowrap;
}
.art-table td {
    padding: 9px 14px;
    border-bottom: 1px solid var(--border-light);
    vertical-align: top;
}
.art-table tbody tr:last-child td { border-bottom: 0; }
.art-table td:first-child { font-weight: 600; color: var(--text); }
.art-table td.mono {
    font-family: var(--art-font-mono);
    color: var(--accent-dark);
    font-weight: 500;
    white-space: nowrap;
}

/* ---------- FAQ ---------- */
.art-faq { margin: 0 0 22px; max-width: var(--art-measure); }
.art-faq-item {
    border-bottom: 1px solid var(--border-light);
    padding-bottom: 13px;
    margin-bottom: 13px;
}
.art-faq-item:last-child { border-bottom: 0; margin-bottom: 0; }
.art-faq-item h3 {
    margin: 0 0 5px;
    font-size: 14.5px;
    font-weight: 600;
    color: var(--text);
}
.art-faq-item p {
    margin: 0;
    font-size: 14px;
    line-height: 1.7;
    max-width: none;
}

/* ---------- Pull quote ---------- */
.art-quote {
    margin: 0 0 24px;
    padding: 20px 22px;
    background: var(--accent-subtle);
    border-left: 3px solid var(--accent);
    border-radius: 0 10px 10px 0;
    max-width: var(--art-measure);
}
.art-quote p {
    margin: 0 0 10px;
    font-size: 16px;
    line-height: 1.6;
    font-style: italic;
    color: var(--text);
    max-width: none;
}
.art-quote footer {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
    font-style: normal;
}

/* ---------- Cards: gist / flow / troubleshooting ---------- */
.art-cards {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
    margin: 0 0 22px;
}
.art-card {
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 16px 18px;
    background: var(--surface);
}
.art-card-icon {
    width: 38px;
    height: 38px;
    border-radius: 9px;
    background: var(--accent-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 12px;
}
.art-card-icon i { color: var(--accent); font-size: 19px; }
.art-card-num {
    font-family: var(--art-font-mono);
    font-size: 13px;
    font-weight: 700;
    color: var(--accent);
    margin-bottom: 8px;
}
.art-card-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 5px;
    line-height: 1.35;
    display: flex;
    align-items: center;
    gap: 8px;
}
.art-card-title > i { color: var(--text-muted); font-size: 14px; }
.art-card-text {
    font-size: 13px;
    line-height: 1.6;
    color: var(--text-secondary);
}
/* Troubleshooting Q/A — the "common mixups" treatment from the Concept
   Explainer layout. The question is the thing being scanned for, so it gets a
   tinted bar of its own rather than being one bold line above the answer; the
   answer then hangs indented past the icon. Markup is unchanged from the plain
   card (.art-card-title + .art-card-text), so every existing Q/A block picks
   this up without an edit.

   The one card grid held to the measure: the others are 2- or 3-up, so a wide
   column narrows each cell, but this one is a single stack of answers and a
   wide column just makes every line longer. */
.art-cards--qa { max-width: var(--art-measure); }
.art-cards--qa .art-card { padding: 0; overflow: hidden; }
.art-cards--qa .art-card-title {
    align-items: flex-start;
    gap: 9px;
    margin: 0;
    padding: 11px 15px;
    background: var(--surface-alt);
    border-bottom: 1px solid var(--border-light);
    font-size: 13px;
    line-height: 1.5;
}
/* warn-deep, not the muted default: these mark a misconception */
.art-cards--qa .art-card-title > i {
    color: var(--art-warn-deep);
    font-size: 15px;
    margin-top: 1px;
}
.art-cards--qa .art-card-text {
    padding: 11px 15px 12px 39px;   /* 39 = 15 gutter + 15 icon + 9 gap */
    font-size: 12.5px;
    line-height: 1.65;
}

/* ---------- KPI strip ---------- */
.art-kpis {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
    margin: 0 0 22px;
}
.art-kpi {
    position: relative;
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 16px 18px;
    background: var(--surface);
    overflow: hidden;
}
.art-kpi::before {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 3px;
    background: var(--accent);
}
.art-kpi-label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 6px;
}
.art-kpi-value {
    font-family: var(--art-font-mono);
    font-size: 26px;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--text);
    line-height: 1.1;
}
.art-kpi-sub {
    margin-top: 4px;
    font-size: 11.5px;
    color: var(--text-muted);
}

/* ---------- Before / after compare strip ---------- */
.art-compare {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--border);
    border-radius: 12px;
    overflow: hidden;
    margin: 0 0 22px;
}
.art-compare-side {
    flex: 1;
    padding: 18px 22px;
    text-align: center;
}
.art-compare-label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 8px;
}
.art-compare-value {
    font-family: var(--art-font-mono);
    font-size: 28px;
    font-weight: 600;
    letter-spacing: -.02em;
    color: var(--text-muted);
    line-height: 1.1;
}
.art-compare-sub { margin-top: 4px; font-size: 11.5px; color: var(--text-muted); }
.art-compare-arrow {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 6px;
    background: var(--surface-alt);
    color: var(--accent);
    font-size: 20px;
}
.art-compare-arrow i { transform: rotate(90deg); }   /* stacked on mobile */
/* The "after" half carries a real mint fill, not the near-white wash. Against a
   white "before" and inside a white card, --accent-subtle was close enough to
   the surface that the strip read as one undivided box and the improvement had
   to be inferred from the copy. --accent-bg is the point of the component. */
.art-compare-side--after { background: var(--accent-bg); }
.art-compare-side--after .art-compare-label { color: var(--accent-dark); }
.art-compare-side--after .art-compare-value { color: var(--accent-dark); font-weight: 700; }
.art-compare-side--after .art-compare-sub { color: var(--positive); font-weight: 600; }

/* ---------- Record showcase ----------
   An announcement that ships a *record* — a document the product now fills in
   by itself — has to show the record, not describe it. A screenshot would do
   it, but every record we ship is somebody's real data (customer-tipping's
   "Invoice INV-1058", pricing-calculator-upgrades-and-limits' "Property
   Details"), so a real capture is a capture of a real customer, and it goes
   stale the moment the underlying screen changes. So the record is authored as
   markup — invented values, no PII, edits with the copy — and presented on the
   dark brand card, the same framing the hero uses: the band is the product
   talking, the white card inside it is the artifact the product produced. */
.art-showcase {
    background: var(--art-featured-grad);
    box-shadow: var(--art-featured-shadow);
    padding: 16px;
    margin: 0 0 26px;
    /* full-bleed on the phone — the record is the widest thing on the page and
       a 16px gutter costs it a whole grid column. Same technique as .art-hero. */
    margin-left: calc(var(--gutter) * -1);
    margin-right: calc(var(--gutter) * -1);
}

/* Label row: who wrote the record (left) and what it is good for (right). */
.art-showcase-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}
.art-showcase-bar .ctx {
    display: flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
    color: #fff;
    font-size: 12px;
    font-weight: 600;
}
.art-showcase-bar .ctx i { flex: none; color: var(--art-featured-accent); }
.art-showcase-bar .ctx span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.art-showcase-bar .flag {
    flex: none;
    color: var(--art-featured-accent);
    font-family: var(--art-font-mono);
    font-size: 11px;
    /* 600, not 700: base_public_v2.html fetches IBM Plex Mono at 400/500/600
       only, so 700 synthesises a faux-bold that reads smeared next to real 600. */
    font-weight: 600;
    letter-spacing: .04em;
}

/* ---------- Split variant: the artifact beside its value lines ----------
   The design doc's announcement hero — screenshot on the left, three short
   value lines on the right, both inside the green card.

   It lives in the BODY and not in the shell, which is the whole point worth
   recording. Article.thumbnail is a single image with nowhere to put the three
   lines, and those lines are prose only the post's author can write, so a
   shell-rendered hero can never produce this card. views.news suppresses the
   shell hero for any post whose body carries this class — see the note there —
   so a post using this never stacks two green cards.

   Phone: one column, visual first. The lines then read as a caption for the
   screenshot above them, which is exactly what they are. */
.art-showcase--split {
    display: grid;
    grid-template-columns: 1fr;
    gap: 18px;
    align-items: center;
}
/* Sits first in .art-body, immediately under the dek, so it brings its own top
   margin — .art-showcase only carries a bottom one. */
.art-body > .art-showcase--split:first-child { margin-top: 22px; }

.art-showcase-visual {
    background: var(--surface);
    border-radius: 10px;
    overflow: hidden;
}
.art-showcase-visual img {
    display: block;
    width: 100%;
    height: auto;
}
/* .art-compare carries a 22px bottom margin for the prose flow it normally
   sits in. Inside the visual slot that margin lands INSIDE the white card
   (overflow: hidden above makes this a BFC, so it can't collapse out) and
   reads as a lopsided pad under the strip. */
.art-showcase-visual > .art-compare:last-child { margin-bottom: 0; }

.art-showcase-points {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 16px;
}
/* Icon spans both rows of its own item so the title and the sentence under it
   stay in one column, hanging off the tile. */
.art-showcase-points li {
    display: grid;
    grid-template-columns: 26px minmax(0, 1fr);
    column-gap: 12px;
    row-gap: 3px;
}
.art-showcase-points i {
    grid-row: 1 / 3;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 7px;
    /* Lime at low alpha, not a solid fill: a solid tile on a dark card reads as
       a button and invites a click that goes nowhere. */
    background: rgba(165, 214, 106, .16);
    font-size: 13px;
    color: var(--art-featured-accent);
}
.art-showcase-points b {
    font-size: 14px;
    font-weight: 600;
    line-height: 1.35;
    color: #fff;
}
.art-showcase-points p {
    margin: 0;
    /* --art-measure caps prose in a reading column; this is a card column that
       is already narrow, and inheriting the cap would waste half of it. */
    max-width: none;
    font-size: 13px;
    line-height: 1.55;
    color: rgba(255, 255, 255, .72);
}

/* The artifact itself. Reads as a printed form, so it keeps a header strip
   with an id — that is what makes it legible as a record and not a panel. */
.art-record {
    background: var(--surface);
    border-radius: 10px;
    overflow: hidden;
}
.art-record-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    background: var(--surface-alt);
    border-bottom: 1px solid var(--border-light);
}
.art-record-title {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
}
.art-record-title i { flex: none; font-size: 14px; color: var(--text-muted); }
.art-record-id {
    flex: none;
    font-family: var(--art-font-mono);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: .01em;
    color: var(--text-muted);
}
.art-record-body { padding: 16px 14px; }

/* Field grid. One column on a phone — two 14px values side by side inside a
   card inside a gutter wraps mid-number, and a rate that wraps is unreadable. */
.art-record-fields {
    margin: 0;
    display: grid;
    grid-template-columns: 1fr;
    column-gap: 20px;
    row-gap: 14px;
}
.art-record-field { min-width: 0; }
.art-record-field dt {
    margin-bottom: 4px;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.art-record-field dd {
    margin: 0;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.4;
    color: var(--text);
}
/* .mono marks a value that is transcribed, not written — a registration number,
   a rate, an area. Same opt-in as .art-glance dd.mono and .art-table td.mono. */
.art-record-field dd.mono {
    font-family: var(--art-font-mono);
    font-size: 13.5px;
    font-weight: 500;
    letter-spacing: -.01em;
}

/* Re-entry note. Amber rather than green: it is the one line on the record that
   is a constraint on the customer, not a fact about the work. Tolerates being
   authored either after the grid or as a full-width cell inside it. */
.art-record-note {
    grid-column: 1 / -1;
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin: 16px 0 0;
    padding: 10px 12px;
    border: 1px solid var(--art-warn-line);
    border-radius: var(--radius-sm);
    background: #fdf7e6;
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--art-warn-deep);
}
.art-record-fields > .art-record-note { margin-top: 0; }   /* row-gap already spaced it */
.art-record-note i { flex: none; font-size: 13px; line-height: 1.5; color: var(--art-warn-deep); }
.art-record-note p {
    margin: 0;
    max-width: none;
    font-size: inherit;
    line-height: inherit;
    color: inherit;
}
.art-record-note b,
.art-record-note strong { font-weight: 600; color: inherit; }

@media (min-width: 768px) {
    /* rejoins the column and takes its corners back */
    .art-showcase {
        margin-left: 0;
        margin-right: 0;
        padding: 20px 22px;
        border-radius: 12px;
    }
    /* Two columns at the width the design draws it. minmax(0,1fr) twice rather
       than 1fr twice: the right column holds text that would otherwise refuse
       to shrink below its longest word and push the screenshot out of the card. */
    .art-showcase--split {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        gap: 26px;
        padding: 24px;
    }
    .art-record-body { padding: 18px 16px; }
    .art-record-fields {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        row-gap: 16px;
    }
}

/* ---------- Tag row ---------- */
.art-tags { display: flex; flex-wrap: wrap; gap: 7px; }
.art-tags span {
    font-size: 10px;
    font-weight: 600;
    color: var(--text-muted);
    background: var(--surface-alt);
    border: 1px solid var(--border);
    padding: 3px 9px;
    border-radius: 999px;
}

/* ---------- Buttons ---------- */
.art-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px 22px;
    border-radius: var(--radius-sm);
    font-size: 14px;
    font-weight: 600;
    border: 1px solid transparent;
    background: var(--accent);
    color: #fff;
    text-decoration: none;
}
.art-btn:hover { background: var(--accent-dark); color: #fff; }
.art-btn--ghost {
    background: transparent;
    border-color: var(--border);
    color: var(--text);
}
.art-btn--ghost:hover {
    background: var(--accent-bg);
    border-color: var(--accent-border);
    color: var(--accent-dark);
}
/* on the dark CTA band */
.art-cta--dark .art-btn {
    background: var(--art-lime);
    color: var(--art-featured-ink);
}
.art-cta--dark .art-btn:hover { background: var(--art-lime-bright); color: var(--art-featured-ink); }
.art-cta--dark .art-btn--ghost {
    background: transparent;
    border-color: rgba(255, 255, 255, .35);
    color: #fff;
}
.art-cta--dark .art-btn--ghost:hover { background: rgba(255, 255, 255, .1); color: #fff; }

/* ---------- CTA band ---------- */
.art-cta {
    margin: 30px 0 0;
    padding: 30px var(--gutter);
    border-top: 1px solid var(--border-light);
    text-align: center;
}
.art-cta h2 {
    margin: 0 0 8px;
    font-size: 22px;
    letter-spacing: -.02em;
    font-weight: 700;
    color: var(--text);
}
/* Both nestings, because the two skins wrap the band differently. A body
   fragment writes .art-cta and puts the dek straight inside it; the dark
   band is full-bleed, so its shell (tools/feature_article.html) has to put
   a .pub-container between the band and its contents to hold the gutter.
   Child-combinator-only, this rule missed the second shape entirely and the
   feature dek fell back to .art's inherited #1a1f1c on the green band —
   1.41:1 at the dark end of the gradient, 2.08:1 at the light end — losing
   its width cap and its 18px bottom margin with it. Kept as a child chain
   rather than a descendant
   selector so a <p> nested in some future card inside the band is still
   not swept up. .art-cta h2 / .art-cta-sub never had the bug: both are
   already descendant matches. */
.art-cta > p,
.art-cta > .pub-container > p {
    margin: 0 auto 18px;
    max-width: 440px;
    font-size: 14.5px;
    line-height: 1.65;
    color: var(--text-secondary);
}
.art-cta-actions {
    display: flex;
    flex-direction: column;
    gap: 10px;
    align-items: stretch;
}
.art-cta-sub {
    margin-top: 14px;
    font-size: 13px;
    color: var(--text-muted);
}
/* The dark band is a full-width strip: the shell places it OUTSIDE
   .pub-container and constrains its contents with an inner one, so it
   needs no negative-margin breakout of its own. */
.art-cta--dark {
    border-top: 0;
    padding-left: 0;
    padding-right: 0;
    background: var(--art-featured-grad);
}
.art-cta--dark h2 { color: #fff; }
/* Same two nestings as .art-cta > p above; in practice the dark band is
   always the .pub-container shape. rgba(255,255,255,.8) composited over the
   band is 8.19:1 on the #1f3f20 stop and 5.83:1 on the #2d5a2e one, so it
   clears AA across the whole gradient. */
.art-cta--dark > p,
.art-cta--dark > .pub-container > p { color: rgba(255, 255, 255, .8); }
.art-cta--dark .art-cta-sub { color: rgba(255, 255, 255, .65); }

/* ---------- Related cards ---------- */
.art-related {
    padding-top: 24px;
    margin-top: 26px;
    border-top: 1px solid var(--border-light);
}
.art-related-head {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 12px;
}
.art-related-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
}
.art-related a {
    display: block;
    position: relative;   /* anchors .art-related-flag to this card, not the grid */
    overflow: hidden;     /* clips the flag's square corner to the 10px radius below */
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 15px 16px;
    background: var(--surface);
    text-decoration: none;
}
.art-related a:hover {
    border-color: var(--accent-border);
    background: var(--accent-subtle);
}

/* Folded-corner flag. A zero-size box with only two border sides painted is
   a right triangle with no transform: a rotated square needs a transform
   origin fussed over to sit flush in the corner, and — the real reason —
   a rotated square's own corners poke a few px past the card's edge unless
   you also clip it; a border-triangle is already exactly the shape of the
   corner it fills, so overflow:hidden on .art-related a (above) clips it
   to the 10px radius for free with no extra math. */
.art-related-flag {
    position: absolute;
    top: 0;
    right: 0;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 0 26px 26px 0;
    border-color: transparent var(--accent) transparent transparent;
}
.art-related-kind {
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    margin-bottom: 7px;
    /* The flag above reaches 26px in from the card's right edge, but the
       card's own padding only insets content by 16px — so without help the
       kind label's box runs 10px under the triangle before either of them
       even starts drawing. Padding the label out past the flag's full
       reach (26px) plus a few px of breathing room keeps a long label like
       "ANNOUNCEMENT" clear of the corner at any card width; the title line
       below never gets this padding because it sits outside the flag's
       26px-tall zone once the label pushes it down. */
    padding-right: 30px;
}
.art-related-kind--announcement { color: var(--accent-dark); }
.art-related-kind--guide        { color: var(--art-info-deep); }
.art-related-kind--feature      { color: var(--art-warn-deep); }
.art-related-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    line-height: 1.35;
}

/* ---------- Previous / Next ----------
   Closes the article foot, one step past Related: not "more like this" but
   "the post immediately before/after this one in the announcement stream".
   Always exactly two direct children (a real link or an .art-prevnext-empty
   placeholder standing in for a missing side) — that fixed arity is what
   lets both sizes work off plain structural selectors instead of :nth-child
   bookkeeping, and is why the grid can stay two-up at every width.

   Two columns on the phone too: the pair is a single "where am I in the
   stream" control, and stacking it split one glance into two. What gives
   below 768px is the padding, the gap and the type size (see the step-up in
   the media query), not the layout. */
.art-prevnext {
    display: grid;
    grid-template-columns: 1fr 1fr;
    border-top: 1px solid var(--border-light);
}
.art-prevnext-link {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 16px 14px;
    color: var(--text);
    text-decoration: none;
    min-width: 0;
}
.art-prevnext-link:hover { background: var(--accent-subtle); }
.art-prevnext-link i {
    flex: none;
    font-size: 14px;
    color: var(--text-muted);
}
/* The two OUTER edges are the sheet's edges, so they take the page gutter and
   the copy lines up with the body text above; only the two inner edges, the
   ones facing the divider, run at the tighter 14px. Same value on both sides
   from 768px up, where --gutter has already clamped to 28px. */
.art-prevnext-link--prev { padding-left: var(--gutter); }
.art-prevnext-link--next { padding-right: var(--gutter); }
/* Next reads right-to-left off the page edge: arrow trailing, copy
   right-aligned, so the two sides mirror each other around the middle
   divider instead of both hugging the left. */
.art-prevnext-link--next {
    justify-content: flex-end;
    text-align: right;
}
.art-prevnext-text { min-width: 0; }
.art-prevnext-label {
    display: block;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 2px;
}
/* One line, cut short, on the phone: a half-width column on a 360px screen
   turned a long headline into five or six lines, and the grid stretches BOTH
   cells to the tallest — one wordy neighbour inflated the whole strip. Both
   links now sit on a single fixed-height row whatever they're pointing at.

   The cut is a max-width, not a character count, because this has to apply at
   one width and not the other and CSS is the only thing that knows the
   viewport. `ch` is the width of a "0", so 18ch is ~18 characters of digits
   but runs a few letters longer in lowercase — near enough, and it holds the
   ellipsis in the same place on both sides no matter the headline. The
   untruncated title stays in the DOM for screen readers. */
.art-prevnext-title {
    display: block;
    max-width: 18ch;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.35;
}
/* Holds its track open when there's no post on that side. Without it the one
   real link would stretch across both columns — a lone Next would slide into
   the LEFT half instead of staying right-aligned in its own. Occupies space
   at every width now that the grid is two-up at every width. */
.art-prevnext-empty { display: block; }
.art-prevnext > * + * { border-left: 1px solid var(--border-light); }

/* ---------- Simple link list (related guides, get started) ---------- */
.art-linklist {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.art-linklist a {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: 14px;
    font-weight: 500;
    color: var(--accent-dark);
}
.art-linklist a:hover { text-decoration: underline; }
.art-linklist i { color: var(--text-muted); font-size: 14px; }


/* ---------- Eyebrow above a body heading ----------
   .art-eyebrow is defined for the shell heads, where nothing follows it. In a
   body section the h2's 34px top margin lands under it and the label floats
   free of the heading it labels. */
.art-body .art-eyebrow + h2 { margin-top: 6px; }

/* ---------- Linked card ----------
   The body link rule already excludes .art-card, so a clickable card was
   visually identical to a static one. Mirrors .art-related a:hover. */
a.art-card { cursor: pointer; }
a.art-card:hover {
    border-color: var(--accent-border);
    background: var(--accent-subtle);
}

/* ---------- Two-up card grid ----------
   .art-cards is 3-up on desktop. A genuine PAIR ("AI form vs generic form",
   "short text vs long text") dropped into a 3-col grid leaves a dead third
   column and reads as if a card is missing. beast-forms-guide has seven. */
.art-cards--2 { grid-template-columns: minmax(0, 1fr); }

/* ---------- List inside a card ----------
   A bare <ul> in a card inherits .art-body li at 15px — LARGER than the 14px
   card title above it — and .art-body ul's 22px indent eats a third of the
   column at 3-up width. These cards are "description line + bullets"; the
   list is the card body, not decoration. */
.art-card-list {
    margin: 0;
    padding-left: 16px;
    list-style: disc;
}
.art-card-list > li {
    margin-bottom: 4px;
    font-size: 13px;
    line-height: 1.6;
    color: var(--text-secondary);
}
.art-card-list > li:last-child { margin-bottom: 0; }
.art-card-list ul { margin: 4px 0 0; padding-left: 15px; }
.art-card-list ul li { font-size: 12.5px; margin-bottom: 2px; }
.art-card .art-card-text + .art-card-list { margin-top: 8px; }
/* "pick" cards are a heading plus the list — no description line between */
.art-card .art-card-title + .art-card-list { margin-top: 8px; }
.art-callout .art-card-list { margin-top: 8px; }

/* ---------- Existing blocks nested inside a card ----------
   .art-tags / .art-checklist / .art-callout all inherit body-column type,
   which is too large inside a third-width card whose own text is 13px. These
   are nesting rules, not new components. */
.art-card .art-tags { margin-bottom: 8px; }
.art-card .art-checklist { margin-bottom: 12px; }
.art-card .art-checklist > li {
    font-size: 13px;
    line-height: 1.55;
    padding-left: 22px;
}
.art-card .art-checklist > li::before { font-size: 12px; }
.art-card .art-callout { margin-bottom: 0; padding: 11px 13px; }
.art-card .art-callout p { font-size: 12.5px; line-height: 1.55; }

/* ---------- Per-cell verdict on .art-table ----------
   The whole argument of a "X vs Y" matrix is which column wins each row, and
   .art-table has only td.mono. .art-compare holds exactly one before/after
   pair, so it cannot carry a nine-row matrix. Colour on the icon, ink on the
   text — no row backgrounds, so .art-table's density is unchanged. */
.art-table td.art-verdict-no    { color: var(--text-muted); }
.art-table td.art-verdict-no i  { color: var(--negative); margin-right: 6px; }
.art-table td.art-verdict-yes   { color: var(--text); }
.art-table td.art-verdict-yes i { color: var(--positive); margin-right: 6px; }

/* The relationship graph (.art-g-*), the concept blocks (3b), the disclosures
   (3c) and the decision engine (3d) moved to css/v2/article/concept.css — they
   are guide-only and base.css is render-blocking on every article page. */

/* ============================================================
   4. Desktop
   ============================================================ */
@media (min-width: 768px) {
    .art-head { padding-top: 40px; }

    .art-title { font-size: 38px; letter-spacing: -.025em; }
    .art-body h2 { font-size: 23px; }
    .art-body h3 { font-size: 17px; }

    /* figures rejoin the column and gain a frame */
    .art-figure { margin-left: 0; margin-right: 0; }
    .art-figure img { border: 1px solid var(--border); border-radius: var(--radius); }
    .art-figure figcaption { padding: 0; }
    .art-figure--todo .art-figure-ph { margin: 0; }

    /* the sticky pill strip becomes a real sidebar card */
    .art-toc {
        position: sticky;
        top: calc(var(--nav-h) + 16px);
        margin: 0;
        padding: 16px;
        border: 1px solid var(--border);
        border-radius: 10px;
        background: var(--surface);
    }
    .art-toc-head { display: block; }
    .art-toc-nav {
        flex-direction: column;
        gap: 2px;
        overflow: visible;
    }
    .art-toc-nav a {
        padding: 6px 10px;
        border-radius: 6px;
        border: 0;
        background: transparent;
        border-left: 3px solid transparent;
        font-size: 12.5px;
        white-space: normal;
    }
    .art-toc-nav a.active {
        background: var(--accent-bg);
        border-left-color: var(--accent);
    }

    .art-share {
        display: block;
        margin-top: 16px;
        padding-top: 14px;
        border-top: 1px solid var(--border-light);
    }

    .art-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .art-cards--qa { grid-template-columns: 1fr; }
    .art-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    /* Two-up, not three: the mock's Related Resources row is a pair of
       cards, and a third empty column would read as a missing card the
       way .art-cards--2 already documents for the body-level pair grid. */
    .art-related-grid { grid-template-columns: repeat(2, 1fr); }

    /* ---- Previous / Next ----
       The layout doesn't change here — it's two columns on the phone as
       well. Room does: the padding, the arrow gap and the title come back
       up to the size the rest of the article foot is set at. */
    .art-prevnext-link { gap: 12px; padding: 22px 28px; }
    .art-prevnext-link i { font-size: 15px; }
    /* Room for the whole headline here, so the phone's 18ch cut comes off and
       the title wraps normally. break-word guards the one case wrapping can't
       handle: an unspaced token longer than the column. */
    .art-prevnext-title {
        max-width: none;
        white-space: normal;
        overflow: visible;
        overflow-wrap: break-word;
        font-size: 14px;
    }

    .art-compare { flex-direction: row; align-items: stretch; }
    .art-compare-arrow { padding: 0 8px; }
    .art-compare-arrow i { transform: none; }
    .art-compare-value { font-size: 30px; }

    .art-cta { padding: 36px var(--gutter); }
    .art-cta h2 { font-size: 26px; }
    .art-cta-actions { flex-direction: row; justify-content: center; gap: 12px; }

    .art-cards--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
}
