/* ============================================
   barrievotes.ca — shared styles

   Design intent: read as a public utility, not a campaign. High contrast,
   generous line length limits, one accent used only for wayfinding, and no
   colour that codes partisan. Light and dark both first-class.

   Sections:
     1. Tokens
     2. Reset + base
     3. Layout
     4. Header + nav
     5. Breadcrumbs
     6. Stub pages
     7. Section indexes
     8. Home
     9. Footer
    10. Utilities
   ============================================ */

/* ── 1. Tokens ───────────────────────────────────────────────────────────── */
:root {
    /* Accent: a slate teal. Chosen to sit clear of federal and provincial
       party palettes — red, true blue, orange, and green all carry meaning
       on a ballot-adjacent site. */
    --accent:        #0b6b6b;
    --accent-hover:  #085252;
    --accent-soft:   #e3f2f1;

    --ink:           #14181b;
    --ink-2:         #3d474e;
    --ink-3:         #626d75;

    --bg:            #ffffff;
    --bg-2:          #f5f7f8;
    --bg-3:          #eceff1;

    --line:          #d6dbde;
    --line-strong:   #b3bbc0;

    /* Status hues. Distinct in both themes, and distinguishable without
       relying on colour alone — every status also carries a text label. */
    --st-live:       #0b6b6b;
    --st-live-bg:    #e3f2f1;
    --st-progress:   #1f5f9e;
    --st-progress-bg:#e5eff8;
    --st-waiting:    #8a5a00;
    --st-waiting-bg: #fbf0d9;
    --st-blocked:    #5b5266;
    --st-blocked-bg: #efecf3;

    /* Seventh categorical chart hue — the six status colours run out on the
       budget-split and renewal-gap stacks, and wrapping into an accent
       variant made the last segment read as the first. */
    --chart-7:       #a1583c;
    /* Eighth categorical hue — the career timelines give each office CLASS
       (councillor, mayor, trustee, MP, MPP) a fixed colour, which needs one
       more hue than the status set provides. */
    --chart-8:       #9c5a86;

    /* Type scale for the small text. Headings use clamp() and stay literal. */
    --fs-xs:         .6875rem; /* 11px  marks, chips */
    --fs-sm:         .8125rem; /* 13px  source lines, notes, table body */
    --fs-md:         .875rem;  /* 14px  captions, notes beside prose */
    --fs-lg:         .9375rem; /* 15px  lead text, profile links */

    --radius:        6px;
    --wrap:          72rem;
    --measure:       38rem;   /* comfortable line length for body copy */

    --shadow: 0 1px 2px rgba(20, 24, 27, .06), 0 2px 8px rgba(20, 24, 27, .04);
}

@media (prefers-color-scheme: dark) {
    :root {
        --accent:        #4fc4bd;
        --accent-hover:  #7ad8d2;
        --accent-soft:   #10312f;

        --ink:           #eef2f4;
        --ink-2:         #b9c3c9;
        --ink-3:         #8b979e;

        --bg:            #0e1214;
        --bg-2:          #161c1f;
        --bg-3:          #1e262a;

        --line:          #2b3438;
        --line-strong:   #3f4b51;

        --st-live:       #4fc4bd;
        --st-live-bg:    #10312f;
        --st-progress:   #7fb3e8;
        --st-progress-bg:#152633;
        --st-waiting:    #e0b354;
        --st-waiting-bg: #302713;
        --st-blocked:    #b6a8c9;
        --st-blocked-bg: #241f2b;

        --shadow: none;
    }
}

/* ── 2. Reset + base ─────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--font-text);
    font-size: 1.0625rem;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

h1, h2, h3, h4 { line-height: 1.25; margin: 0 0 .5em; font-weight: 650; letter-spacing: -.01em; }
h1 { font-size: clamp(1.75rem, 1.3rem + 2vw, 2.5rem); }
h2 { font-size: clamp(1.3rem, 1.1rem + 1vw, 1.6rem); }
h3 { font-size: 1.125rem; }

p  { margin: 0 0 1rem; }
ul, ol { margin: 0 0 1rem; padding-left: 1.25rem; }

/* The note family: small muted text beside a table, a figure or a list.
   One base rule; the per-class rules further down carry only their deltas
   (spacing, a status colour, a block/inline choice). */
.note, .table-note, .table-source, .provenance-src, .acclaim-src, .source-note,
.race-note, .cand-incumbent-note {
    font-size: var(--fs-sm); color: var(--ink-3);
}
.note, .table-note, .table-source { max-width: var(--measure); }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: .15em; }
a:hover { color: var(--accent-hover); }

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

img, svg { max-width: 100%; height: auto; }

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    background: var(--accent);
    color: #fff;
    padding: .65rem 1rem;
    z-index: 100;
}
.skip-link:focus { left: 0; }

/* ── 3. Layout ───────────────────────────────────────────────────────────── */
.wrap {
    width: 100%;
    max-width: var(--wrap);
    margin-inline: auto;
    padding-inline: 1.25rem;
}

main {
    flex: 1 0 auto;
    width: 100%;
    max-width: var(--wrap);
    margin-inline: auto;
    padding: 1.5rem 1.25rem 4rem;
}

/* Anything wide scrolls inside itself so the page body never scrolls
   sideways on a phone. */
.scroll-x {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* ── 4. Header + nav ─────────────────────────────────────────────────────── */
.site-head {
    border-bottom: 1px solid var(--line);
    background: var(--bg);
    position: sticky;
    top: 0;
    z-index: 20;
}
.site-head .wrap {
    display: flex;
    align-items: center;
    gap: 1rem;
    min-height: 4rem;
    flex-wrap: wrap;
}

.brand {
    display: flex;
    align-items: center;
    gap: .6rem;
    text-decoration: none;
    color: var(--ink);
    margin-right: auto;
    padding: .5rem 0;
    /* Pin the first header row's height. The wrap's 4rem minimum is
       distributed by align-content across flex LINES, so when the mobile nav
       opens onto a second line the brand row loses its stretched share and
       everything shifts up a couple of pixels. A fixed-height tallest item
       keeps the row identical whether the menu is open or not. */
    min-height: 4rem;
}
.brand-mark { line-height: 0; }
.brand-mark img { display: block; width: 28px; height: 28px; }
.brand-text { display: flex; flex-direction: column; }
.brand-name { font-weight: 700; font-size: 1.0625rem; letter-spacing: -.015em; }
.brand-sub  { font-size: .75rem; color: var(--ink-3); letter-spacing: .01em; }

.nav-toggle {
    display: flex;
    align-items: center;
    gap: .5rem;
    background: none;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    color: var(--ink);
    font: inherit;
    font-size: .9rem;
    padding: .45rem .7rem;
    cursor: pointer;
}
.nav-toggle-bars { display: inline-flex; flex-direction: column; gap: 3px; }
.nav-toggle-bars span {
    display: block; width: 16px; height: 2px;
    background: currentColor; border-radius: 1px;
}

.primary-nav { display: none; width: 100%; }
.primary-nav.is-open { display: block; }
.primary-nav ul {
    list-style: none;
    margin: 0 0 .75rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .125rem;
}
.primary-nav a {
    display: block;
    padding: .6rem .5rem;
    text-decoration: none;
    color: var(--ink-2);
    border-radius: var(--radius);
    font-weight: 550;
}
.primary-nav a:hover { background: var(--bg-2); color: var(--ink); }
.primary-nav a.is-current { color: var(--accent); background: var(--accent-soft); }

@media (min-width: 48rem) {
    .nav-toggle { display: none; }
    .primary-nav { display: block; width: auto; }
    .primary-nav ul { flex-direction: row; gap: .25rem; margin-bottom: 0; }
    .primary-nav a { padding: .5rem .75rem; }
}

/* ── 5. Breadcrumbs ──────────────────────────────────────────────────────── */
.crumbs { margin-bottom: 1.5rem; font-size: var(--fs-md); }
.crumbs ol {
    list-style: none; margin: 0; padding: 0;
    display: flex; flex-wrap: wrap; gap: .35rem;
}
.crumbs li + li::before { content: "›"; color: var(--ink-3); margin-right: .35rem; }
.crumbs a { color: var(--ink-3); }
.crumbs a:hover { color: var(--accent); }
.crumbs [aria-current] { color: var(--ink-2); }

/* ── 6. Stub pages ───────────────────────────────────────────────────────── */
.stub { max-width: 44rem; }

.stub-flag {
    display: inline-block;
    margin: 0 0 1rem;
    padding: .3rem .6rem;
    border-radius: 100px;
    font-size: .75rem;
    font-weight: 650;
    letter-spacing: .02em;
    text-transform: uppercase;
}
.stub-flag[data-status="live"]                            { color: var(--st-live);     background: var(--st-live-bg); }
.stub-flag[data-status="in-progress"]                     { color: var(--st-progress); background: var(--st-progress-bg); }
.stub-flag[data-status="awaiting-source"]                 { color: var(--st-waiting);  background: var(--st-waiting-bg); }
.stub-flag[data-status="blocked-until-nominations-close"],
.stub-flag[data-status="blocked-until-election-day"]      { color: var(--st-blocked);  background: var(--st-blocked-bg); }

.stub-lede {
    font-size: 1.1875rem;
    line-height: 1.55;
    color: var(--ink-2);
    max-width: var(--measure);
}

.stub-body { margin-top: 2rem; }

.stub-facts {
    margin: 0 0 1.5rem;
    border-top: 1px solid var(--line);
}
.stub-facts > div {
    display: grid;
    gap: .2rem;
    padding: 1rem 0;
    border-bottom: 1px solid var(--line);
}
.stub-facts dt {
    font-size: .75rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--ink-3);
}
.stub-facts dd { margin: 0; color: var(--ink-2); max-width: var(--measure); }

@media (min-width: 40rem) {
    .stub-facts > div { grid-template-columns: 12rem 1fr; gap: 1.5rem; align-items: start; }
}

.stub-promise {
    background: var(--bg-2);
    border-left: 3px solid var(--accent);
    padding: 1rem 1.15rem;
    border-radius: 0 var(--radius) var(--radius) 0;
    color: var(--ink-2);
    font-size: var(--fs-lg);
    margin: 0;
}

.stub-siblings { margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--line); }
.stub-siblings h2 { font-size: var(--fs-sm); text-transform: uppercase; letter-spacing: .05em; color: var(--ink-3); }
.stub-siblings ul {
    list-style: none; padding: 0; margin: 0;
    display: flex; flex-wrap: wrap; gap: .5rem 1rem;
}
.stub-siblings li { display: flex; align-items: center; gap: .4rem; }

.pill {
    display: inline-block;
    white-space: nowrap;
    font-size: var(--fs-xs); font-weight: 650; text-transform: uppercase;
    letter-spacing: .03em; padding: .1rem .4rem; border-radius: 3px;
}
.pill-live { color: var(--st-live); background: var(--st-live-bg); }

/* ── 7. Section indexes ──────────────────────────────────────────────────── */
.section-head { max-width: var(--measure); margin-bottom: 2.5rem; }
.section-lede { font-size: 1.1875rem; line-height: 1.55; color: var(--ink-2); }

.group-head {
    font-size: var(--fs-sm);
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ink-3);
    margin: 2.5rem 0 1rem;
    padding-bottom: .5rem;
    border-bottom: 1px solid var(--line);
}
.group-head:first-of-type { margin-top: 0; }

.card-list {
    list-style: none; padding: 0; margin: 0 0 1rem;
    display: grid; gap: 1rem;
    grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
}
.card {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 1.15rem;
    background: var(--bg);
    display: flex;
    flex-direction: column;
    gap: .35rem;
}
.card:hover { border-color: var(--line-strong); box-shadow: var(--shadow); }
.card h3 { margin: 0; font-size: 1.0625rem; }
.card h3 a { text-decoration: none; }
.card h3 a:hover { text-decoration: underline; }
.card p:not(.card-status) { margin: 0; font-size: .9rem; color: var(--ink-2); }
.card-status {
    margin: auto 0 0;
    padding-top: .5rem;
    font-size: .75rem;
    font-weight: 600;
}
.card-status[data-status="live"]                            { color: var(--st-live); }
.card-status[data-status="in-progress"]                     { color: var(--st-progress); }
.card-status[data-status="awaiting-source"]                 { color: var(--st-waiting); }
.card-status[data-status="blocked-until-nominations-close"],
.card-status[data-status="blocked-until-election-day"]      { color: var(--st-blocked); }

/* ── 8. Home ─────────────────────────────────────────────────────────────── */
.hero { max-width: 42rem; margin-bottom: 1rem; }
.hero h1 { margin-bottom: .5rem; }
.hero-lede { font-size: 1.25rem; line-height: 1.5; color: var(--ink-2); }

.notice {
    border: 1px solid var(--line);
    border-left: 3px solid var(--st-waiting);
    background: var(--bg-2);
    border-radius: 0 var(--radius) var(--radius) 0;
    padding: 1rem 1.15rem;
    margin: 2rem 0;
    max-width: 42rem;
}
.notice h2 { font-size: 1rem; margin-bottom: .35rem; }
.notice p:last-child { margin-bottom: 0; }

.pillars {
    list-style: none; padding: 0; margin: 2.5rem 0 0;
    display: grid; gap: 1.25rem;
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
}
.pillar {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 1.6rem 1.5rem;
    display: flex;
    flex-direction: column;
    gap: .4rem;
}
.pillar h2 { font-size: 1.3rem; margin-bottom: 0; }
.pillar h2 a { text-decoration: none; }
.pillar h2 a:hover { text-decoration: underline; }
.pillar p { margin: 0; font-size: var(--fs-lg); color: var(--ink-2); }
/* The live figure on each card — what is behind the door, before the click. */
.pillar p.pillar-stat {
    margin-top: auto;
    padding-top: .6rem;
    font-weight: 650;
    color: var(--accent);
    font-variant-numeric: tabular-nums;
}

/* ── 9. Footer ───────────────────────────────────────────────────────────── */
.site-foot {
    flex-shrink: 0;
    border-top: 1px solid var(--line);
    background: var(--bg-2);
    padding: 2.5rem 0 2rem;
    font-size: var(--fs-md);
}
.foot-cols {
    display: grid;
    gap: 1.75rem;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    margin-bottom: 2rem;
}
.foot-col h2 { font-size: var(--fs-sm); text-transform: uppercase; letter-spacing: .05em; color: var(--ink-3); margin-bottom: .6rem; }
.foot-col h2 a { color: inherit; text-decoration: none; }
.foot-col h2 a:hover { color: var(--accent); }
.foot-col ul { list-style: none; padding: 0; margin: 0; display: grid; gap: .3rem; }
.foot-col a { color: var(--ink-2); text-decoration: none; }
.foot-col a:hover { color: var(--accent); text-decoration: underline; }

.foot-meta { border-top: 1px solid var(--line); padding-top: 1.5rem; }
.foot-mission { color: var(--ink-3); max-width: 48rem; font-size: var(--fs-sm); line-height: 1.55; }
.foot-build { color: var(--ink-3); font-size: var(--fs-sm); margin: 0; display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.foot-build a { color: var(--ink-2); }
.foot-build .sep { color: var(--line-strong); }
.build-status { font-variant-numeric: tabular-nums; }

/* ── 10. Utilities ───────────────────────────────────────────────────────── */
.visually-hidden {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.measure { max-width: var(--measure); }
/* The About page is disclosure prose, not data commentary: it reads better
   in longer lines than the narrow measure the data pages use. */
.about-page .measure { max-width: 54rem; }

/* ── 11. Candidates ──────────────────────────────────────────────────────── */

/* Provenance banner. Appears on every candidate view. The list is a moving
   target until nominations close, so the date and the uncertified status are
   part of the content, not a disclaimer tucked at the bottom. */
.provenance {
    border: 1px solid var(--line);
    border-left: 3px solid var(--st-waiting);
    background: var(--bg-2);
    border-radius: 0 var(--radius) var(--radius) 0;
    padding: 1rem 1.15rem;
    margin: 0 0 2.5rem;
    max-width: 46rem;
}
.provenance-lead { margin-bottom: .5rem; }
.provenance-src  { margin: 0; }
.provenance-src a { color: var(--ink-2); }

/* Jump nav — ward numbers abbreviated so 12 targets fit on a phone. */
.jump {
    display: flex; flex-wrap: wrap; gap: .4rem;
    margin: 0 0 2.5rem;
}
.jump a {
    display: inline-block;
    padding: .3rem .6rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    font-size: var(--fs-sm);
    text-decoration: none;
    color: var(--ink-2);
}
.jump a:hover { border-color: var(--accent); color: var(--accent); }

.race { margin: 0 0 2.5rem; scroll-margin-top: 5rem; }
.race h2 {
    display: flex; align-items: baseline; gap: .6rem;
    padding-bottom: .5rem;
    border-bottom: 1px solid var(--line);
}
.race-count {
    font-size: var(--fs-sm); font-weight: 600;
    color: var(--ink-3);
    font-variant-numeric: tabular-nums;
}
.race-note { color: var(--st-waiting); margin: .75rem 0 0; }

.board { margin: 0 0 2.5rem; }
.board h3 { display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem; margin-bottom: .25rem; }
.board-kind {
    font-size: .75rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: .04em; color: var(--ink-3);
    background: var(--bg-3); padding: .1rem .4rem; border-radius: 3px;
}
.board h4 {
    font-size: var(--fs-sm); text-transform: uppercase; letter-spacing: .05em;
    color: var(--ink-3); margin: 1.25rem 0 .5rem;
}

.cand-list {
    list-style: none; padding: 0; margin: 1rem 0 0;
    display: grid; gap: .75rem;
    grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
}
.cand {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: .9rem 1rem;
}
.cand-name { font-weight: 650; margin: 0 0 .15rem; display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
/* The miniature election record on a card: every mark the profile chart
   draws, on one strip, so a ward's field can be compared at a glance. */
.cand-mini { margin: .3rem 0 .45rem; }
.cand-mini svg { display: block; }
.cand-filed { font-size: .75rem; color: var(--ink-3); margin: 0 0 .5rem; }
.cand-links { list-style: none; padding: 0; margin: 0; display: grid; gap: .15rem; font-size: var(--fs-sm); }
.cand-links a { word-break: break-word; }
.cand-social { color: var(--ink-3); }

/* A withdrawal stays on the page. Removing the name would make it look like
   the person was never there, and the record is the point. */
.cand-withdrawn { opacity: .6; }
.cand-withdrawn .cand-name { text-decoration: line-through; text-decoration-thickness: 1px; }
.pill-withdrawn { color: var(--st-blocked); background: var(--st-blocked-bg); text-decoration: none; }

/* Incumbency. Two distinct states, because the ward redraw makes a single
   "Incumbent" badge inaccurate: someone can sit on council today and be running
   in a differently-numbered ward. The detail line carries the qualification —
   a badge alone would imply a seat continuity the boundary change broke. */
.pill-incumbent { color: var(--st-progress); background: var(--st-progress-bg); }
.cand-incumbent { border-color: var(--st-progress); }
.cand-incumbent-note { font-size: .75rem; color: var(--st-progress); margin: 0 0 .35rem; }

/* Acclamation warning. Deliberately prominent: a race with one candidate is on
   track to be decided without anyone voting, and that is precisely the thing a
   reader would never learn from a bare list of names. */
.acclaim-warn {
    border: 1px solid var(--st-waiting);
    border-left-width: 3px;
    background: var(--st-waiting-bg);
    border-radius: 0 var(--radius) var(--radius) 0;
    padding: .9rem 1.1rem;
    margin: 1rem 0 0;
    max-width: 46rem;
    font-size: var(--fs-lg);
}
.acclaim-head {
    font-weight: 650;
    color: var(--st-waiting);
    margin: 0 0 .35rem;
}
.acclaim-warn p { margin: 0 0 .5rem; }
.acclaim-warn p:last-child { margin-bottom: 0; }

/* Inline acclamation flag: sits INSIDE the candidate list, directly above the
   one candidate it concerns, so the warning and the name read as one unit. */
.acclaim-flag {
    border: 1px solid var(--st-waiting);
    border-left-width: 3px;
    background: var(--st-waiting-bg);
    border-radius: 0 var(--radius) var(--radius) 0;
    padding: .7rem .95rem;
    font-size: var(--fs-md);
    list-style: none;
}
.acclaim-flag .acclaim-head { margin: 0 0 .25rem; }
.acclaim-flag p { margin: 0; max-width: var(--measure); }

/* ── 12. Content pages ───────────────────────────────────────────────────── */
.data-page h2 { margin-top: 2.5rem; }
.data-page h2:first-of-type { margin-top: 2rem; }

blockquote.quotes {
    margin: 1.25rem 0;
    padding: .25rem 0 .25rem 1.15rem;
    border-left: 3px solid var(--line-strong);
    max-width: var(--measure);
}
blockquote.quotes p { color: var(--ink-2); font-style: italic; }
blockquote.quotes p:last-child { margin-bottom: 0; }
blockquote.quotes strong { font-style: normal; color: var(--ink); }

/* Numbered walkthroughs. Counter rather than <ol> markers so the number can
   sit beside a heading. */
.steps { list-style: none; counter-reset: step; padding: 0; margin: 2rem 0; max-width: 46rem; }
.steps > li {
    counter-increment: step;
    position: relative;
    padding: 0 0 1.5rem 3rem;
    border-left: 2px solid var(--line);
    margin-left: 1rem;
}
.steps > li:last-child { border-left-color: transparent; padding-bottom: 0; }
.steps > li::before {
    content: counter(step);
    position: absolute; left: -1.05rem; top: 0;
    width: 2rem; height: 2rem;
    display: grid; place-items: center;
    background: var(--accent); color: #fff;
    border-radius: 50%;
    font-size: var(--fs-md); font-weight: 700;
    font-variant-numeric: tabular-nums;
}
@media (prefers-color-scheme: dark) { .steps > li::before { color: var(--bg); } }
.steps h2 { font-size: 1.125rem; margin: .15rem 0 .4rem; }
.steps p { margin-bottom: .6rem; }
.steps p:last-child { margin-bottom: 0; }
.steps .note, p.note {
    font-size: var(--fs-md); color: var(--ink-3);
    border-left: 2px solid var(--line); padding-left: .75rem;
}

/* Headline figures. Tabular so a row of them lines up. */
.stat-row {
    list-style: none; padding: 0;
    margin: 0 0 1.5rem;
    display: grid; gap: 1rem;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    max-width: 46rem;
}
.stat-row li {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: .9rem 1rem;
}
.stat-value {
    display: block;
    font-size: 1.75rem; font-weight: 700; line-height: 1.1;
    letter-spacing: -.02em;
    color: var(--accent);
}
.stat-label { display: block; font-size: var(--fs-sm); color: var(--ink-3); margin-top: .2rem; }

/* A caution that belongs beside the data, not in a footnote. */
.warn-note {
    border: 1px solid var(--st-waiting);
    border-left-width: 3px;
    background: var(--st-waiting-bg);
    border-radius: 0 var(--radius) var(--radius) 0;
    padding: .9rem 1.1rem;
    margin: 1.5rem 0;
    max-width: 46rem;
    font-size: var(--fs-lg);
}
.warn-note p:last-child { margin-bottom: 0; }

.table-note { margin: -.25rem 0 2rem; }

/* Results table styling lives in the "Data tables" section at the end of this
   file, so table rules there win cleanly instead of relying on selector weight. */

/* ── 13. Profiles and race context ───────────────────────────────────────── */
.profile h2 { margin-top: 2.5rem; }
.profile h3 { margin-top: 2rem; font-size: 1rem; color: var(--ink-2); }
.profile-links { font-size: var(--fs-lg); margin-bottom: .75rem; }

/* The context block sits between the candidate list and the page footer, so it
   needs a visible boundary without competing with the h1. */
.race-context {
    margin-top: 3rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--line);
}
.context-head {
    font-size: var(--fs-sm);
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ink-3);
    margin-bottom: 1rem;
}

/* Previous/next navigation between election pages. */
.year-nav {
    display: flex; flex-wrap: wrap; gap: 1rem;
    align-items: center; justify-content: space-between;
    margin-top: 3rem; padding-top: 1.5rem;
    border-top: 1px solid var(--line);
    font-size: var(--fs-lg);
}
.year-nav .year-index { color: var(--ink-3); }

/* ── 14. Ward lookup ─────────────────────────────────────────────────────── */
/* Plain server-rendered form — no JavaScript. Someone may be loading this on a
   bad connection outside a voting location. */
.ward-form {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--bg-2);
    padding: 1.25rem;
    margin: 0 0 2rem;
    max-width: 42rem;
}
.ward-form label { display: block; font-weight: 650; margin-bottom: .5rem; }
.ward-form-row { display: flex; flex-wrap: wrap; gap: .6rem; }
.ward-form input[type="text"] {
    flex: 1 1 16rem;
    min-width: 0;
    font: inherit;
    padding: .6rem .75rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    background: var(--bg);
    color: var(--ink);
}
.ward-form button {
    font: inherit; font-weight: 650;
    padding: .6rem 1.1rem;
    border: 0; border-radius: var(--radius);
    background: var(--accent); color: #fff;
    cursor: pointer;
}
@media (prefers-color-scheme: dark) { .ward-form button { color: var(--bg); } }
.ward-form button:hover { background: var(--accent-hover); }
.ward-form-note { font-size: var(--fs-sm); color: var(--ink-3); margin: .75rem 0 0; }

/* Everything on the lookup page shares the form's column width — the page
   otherwise mixes 38/42/46rem text with full-width tables, which reads as
   three different pages stacked. */
.ward-page .table-wrap,
.ward-page .card-list,
.ward-page .warn-note,
.ward-page .notice,
.ward-page .stat-row { max-width: 42rem; }

/* The answer. Large because it is the single thing the visitor came for. */
.ward-result {
    border: 1px solid var(--accent);
    border-left-width: 3px;
    border-radius: 0 var(--radius) var(--radius) 0;
    background: var(--accent-soft);
    padding: 1.25rem;
    margin: 0 0 1.5rem;
    max-width: 42rem;
}
.ward-result-lead { margin: 0; font-size: var(--fs-lg); color: var(--ink-2); }
.ward-result-ward {
    margin: .1rem 0;
    font-size: clamp(2rem, 1.4rem + 3vw, 2.75rem);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -.02em;
    color: var(--accent);
}
.ward-result-sub { margin: 0; font-size: var(--fs-md); color: var(--ink-3); }

/* When two sections share a footer column (Charts above About), space the
   second heading off the first list. */
.foot-col ul + h2 { margin-top: 1.1rem; }
/* Column one carries three shelves; give them room to read as three. */
.foot-col-stacked ul + h2 { margin-top: 2rem; }


/* ============================================
   Data tables, charts, provenance
   ============================================
   Formerly assets/data-tables.css, once opt-in per page; merged here because
   shared renderers (candidate cards, results, sources, statements) emit these
   classes on nearly every page. Rules the data layer follows:

     · Every table scrolls inside its own container. The page body must never
       scroll sideways on a phone.
     · Numbers are tabular so columns of digits align vertically.
     · Every table carries a <caption> and a source line. A number on this
       site without a visible provenance is a bug.
   ============================================ */

.table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    margin: 0 0 .75rem;
}

/* Mobile: tables keep their 32rem minimum and scroll sideways inside the
   wrapper. Below the width where that minimum must overflow, say so above
   the table instead of hoping the affordance gets discovered. Pure CSS by
   viewport width; nav.js refines it per table when it runs, removing the
   hint from tables that do fit. */
@media (max-width: 36rem) {
    .table-wrap::before {
        content: "scroll sideways to see the full table \2192";
        display: block;
        /* Sticky, so the strip rides along during horizontal scroll. A plain
           block is only as wide as the visible area and scrolls away with
           the content, leaving a blank gap above the header. */
        position: sticky;
        left: 0;
        padding: .4rem .6rem;
        font-size: .75rem;
        color: var(--ink-3);
        background: var(--bg-2);
        border-bottom: 1px solid var(--line);
    }
    .table-wrap.fits::before { content: none; }
}

table.data {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--fs-lg);
    min-width: 32rem;   /* below this, scrolling beats crushing the columns */
}

table.data caption {
    text-align: left;
    padding: .85rem 1rem;
    font-weight: 650;
    border-bottom: 1px solid var(--line);
    background: var(--bg-2);
}

table.data th,
table.data td {
    padding: .55rem 1rem;
    text-align: right;
    border-bottom: 1px solid var(--line);
    white-space: nowrap;
}

table.data th:first-child,
table.data td:first-child {
    text-align: left;
    position: sticky;
    left: 0;
    background: var(--bg);
    white-space: normal;
    min-width: 9rem;
    /* Forces its own compositing layer. Without it, a sticky first cell
       whose content wraps to more lines than usual (a long location name at
       the mobile 11rem cap, not just a short year) can paint on first load
       with the cells beside it left unpainted until the next scroll or
       repaint — a Chromium sticky-in-table quirk, not a layout bug: the
       DOM and geometry are already correct at that point. */
    will-change: transform;
}

table.data thead th {
    background: var(--bg-2);
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--ink-3);
    position: sticky;
    top: 0;
}
table.data thead th:first-child { background: var(--bg-2); z-index: 1; }

table.data tbody tr:hover td { background: var(--bg-2); }
table.data tbody tr:hover td:first-child { background: var(--bg-3); }
table.data tbody tr:last-child td { border-bottom: 0; }

/* A figure we could not verify is shown as unavailable, never as zero and
   never silently dropped. */
table.data td.na { color: var(--ink-3); font-style: italic; }

/* Charts. Always a visual repeat of a table on the same page — the table is
   the record, the chart is the shape of it. Caveats render in the
   figcaption, on the figure itself, never in a distant footnote. */
figure.chart { margin: 0 0 1rem; }
figure.chart svg { display: block; }

/* Every chart ships two orientations: vertical bars for wide screens, and a
   horizontal variant with a narrower viewBox for phones — a 640-unit SVG
   scaled to a 375px screen shrinks its labels below legibility, which is
   the actual mobile failure. CSS picks one; both are in the markup. */
.chart-h { display: none; }
@media (max-width: 40rem) {
    .chart-v { display: none; }
    .chart-h { display: block; }
}
figure.chart figcaption {
    font-size: var(--fs-sm);
    color: var(--ink-3);
    margin-top: .35rem;
    max-width: var(--measure);
}

/* SVG text and rules inside a chart. Series colours come from data and stay
   inline; everything that is the same on every chart is a class. Font size is
   set once on the <svg> root and inherited; an element states its own size
   only where it differs. */
.ax-label     { fill: var(--ink-3); }
.ax-note      { fill: var(--ink-3); font-style: italic; }
.v-label      { fill: var(--ink-2); font-weight: 650; }
.in-bar       { fill: var(--bg);    font-weight: 650; }
.gridline     { stroke: var(--line); stroke-width: 1; }
.gridline-dot { stroke: var(--line); stroke-width: 1; stroke-dasharray: 1 4; }
.sep          { stroke: var(--bg);   stroke-width: 1; }

/* Colour-box legend above a stacked chart. */
.chart-legend {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem 1.25rem;
    margin: 0 0 .4rem;
    font-size: var(--fs-sm);
    color: var(--ink-2);
}
.chart-legend .chart-key { white-space: nowrap; }
.chart-legend .swatch, .bucket-badge .swatch {
    display: inline-block;
    width: .75em;
    height: .75em;
    border-radius: 2px;
    margin-right: .4em;
}

/* Spending-type bucket badge — same swatch shape/colour as the chart legend
   above it, in an itemized-expense table's "Bucket" column. */
.bucket-badge { white-space: nowrap; }

/* Source line. Required under every table. */
/* Two related charts sharing a row on wide screens, stacking on small ones —
   built for the water/wastewater pair, reusable for any pair. */
/* The Ex-[Role] pill: formerly elected, holds no seat now. Muted relative
   to the incumbent pill — a record, not a status. */
.pill-ex { border: 1px solid var(--line-strong); color: var(--ink-2); background: var(--bg-2); }

.chart-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1.25rem; }
@media (max-width: 44rem) { .chart-pair { grid-template-columns: 1fr; } }

.table-source { margin: 0 0 2rem; }
.table-source strong { color: var(--ink-2); font-weight: 600; }

/* Flags a series that spans a definitional or boundary change — stated on
   the table itself rather than buried in a footnote. */
.series-break {
    display: inline-block;
    font-size: .75rem;
    font-weight: 650;
    color: var(--st-waiting);
    background: var(--st-waiting-bg);
    padding: .1rem .4rem;
    border-radius: 3px;
}

/* ── Results tables ──────────────────────────────────────────────────────── */
/* Text columns. Declared here rather than in styles.css because this sheet
   loads second — alignment should not depend on winning a specificity race
   against the base `table.data td { text-align: right }` rule above. */
table.data td.cell-left,
table.data th.cell-left { text-align: left; white-space: normal; }

.row-elected th, .row-elected td { font-weight: 650; }
.row-elected th[scope="row"] { box-shadow: inset 3px 0 0 var(--accent); }
.pill-elected { color: var(--st-live); background: var(--st-live-bg); margin-left: .4rem; }

/* An acclamation is a result, not a missing number. */
.acclaimed-cell { color: var(--st-waiting); font-weight: 650; }

/* Row-level status washes. Two states colour the WHOLE row, because they
   change how every figure in it should be read: an acclaimed seat (amber —
   the acclamation hue used sitewide) had no vote behind any of its numbers,
   and a race not yet run (the in-progress blue) has no numbers at all yet.
   Declared after the sticky-first-column and zebra rules so the wash wins
   the equal-specificity tie. Not used where every row would carry it (the
   acclamations page) — a table fully highlighted highlights nothing. */
table.data .row-acclaimed th,
table.data .row-acclaimed td { background: var(--st-waiting-bg); }

/* Comparison tables: the subject of the comparison, clustered and tinted so
   it reads apart from the comparator rows above it, and a computed summary
   row (an average) that belongs to neither group. The summary row's top
   border draws the boundary between the comparators and the cluster. */
table.data .row-summary th,
table.data .row-summary td { background: var(--bg-2); font-style: italic;
                             border-top: 2px solid var(--line); }
table.data .row-subject th,
table.data .row-subject td { background: var(--accent-soft); }
table.data .row-subject th[scope="row"] { box-shadow: inset 3px 0 0 var(--accent); }
table.data .row-pending th,
table.data .row-pending td   { background: var(--st-progress-bg); }

/* Vote-share bars. A visual repeat of the Share column — same number, same
   denominator, nothing the digits don't already say (the span is
   aria-hidden). Neutral grey for the field; the accent marks only the row
   already marked Elected, so no colour codes partisan. */
td.share-cell { min-width: 7.5rem; }
.share-bar {
    display: block;
    height: 3px;
    margin-top: .3rem;
    background: var(--bg-3);
    border-radius: 2px;
    overflow: hidden;
}
.share-bar > span {
    display: block;
    height: 100%;
    background: var(--ink-3);
    border-radius: 2px;
}
.row-elected .share-bar > span { background: var(--accent); }

/* Marks a figure that covers only part of the relevant area. */
.partial-mark {
    display: inline-block;
    white-space: nowrap;
    font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .03em;
    color: var(--st-waiting); background: var(--st-waiting-bg);
    padding: .05rem .3rem; border-radius: 3px; margin-left: .3rem;
}

table.data td .na, .na { color: var(--ink-3); font-style: italic; font-size: var(--fs-sm); }
.row-past th, .row-past td { opacity: .5; }

.who {
    display: inline-block;
    white-space: nowrap;
    font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .03em;
    padding: .05rem .3rem; border-radius: 3px; margin-left: .4rem;
    background: var(--bg-3); color: var(--ink-3);
}
.who-voters { color: var(--st-live); background: var(--st-live-bg); }

/* The row for the person whose page this is. Marked without colour alone —
   the profile's own name is also the only unlinked name in the table. */
.row-highlight th, .row-highlight td { background: var(--accent-soft); }
.row-highlight th[scope="row"] { background: var(--accent-soft); font-weight: 700; }

/* Shown when a document spelled the person's name differently from the one we
   publish — "Maria C. Hardie" on the 2014 certificate, "Maria Hardie" since. */
.as-recorded {
    display: block;
    font-size: .75rem;
    color: var(--ink-3);
    font-style: italic;
}

/* ── Evidence layer: money and indicator tables ──────────────────────────────
   Used by includes/finance.php and includes/indicators.php. */

/* Footnote markers, and the list that defines them. Mapping notes on a levy
   table and comparability notes on a series both use this: the note has to
   stay attached to the row it qualifies without crowding the column. */
.mark {
    font-size: .7em;
    font-weight: 650;
    color: var(--accent);
    margin-left: .15em;
}
.note-list {
    margin: 0 0 1rem;
    padding-left: 1.1rem;
    max-width: var(--measure);
    font-size: var(--fs-sm);
    color: var(--ink-3);
}
.note-list li { margin-bottom: .3rem; }

/* What a figure is measured against, printed with the figure rather than
   under the table. A "typical home" dollar amount and a capital estimate are
   both unreadable without their basis, and a reader scanning a column of
   numbers will not go looking for a footnote. */
.figure-basis {
    display: block;
    font-size: .75rem;
    font-weight: 400;
    color: var(--ink-3);
    white-space: normal;
}

/* The measurement note, above its table. Every count of people undercounts;
   this is where the page says so, before it says a number. */
.measure-note {
    border-left: 3px solid var(--line);
    padding: .1rem 0 .1rem .9rem;
    margin: 0 0 1rem;
    max-width: var(--measure);
    font-size: var(--fs-md);
    color: var(--ink-2);
}
.measure-note p { margin: 0; }

/* A series row where the measure changed under the series. The rule is the
   break; the .series-break badge beside it says what happened. */
.row-break > * { border-top: 2px solid var(--st-waiting) !important; }

/* Cost variance, rendered beside the numbers it belongs to. A bare delta
   implies mismanagement; the reason may be a scope decision council took
   deliberately. Both go in the same cell, explanation last and unmuted. */
.data-capital td { vertical-align: top; }
.variance-delta {
    margin: 0 0 .25rem;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
}
.variance-why {
    margin: 0;
    font-size: var(--fs-sm);
    color: var(--ink-2);
    white-space: normal;
}
/* Not knowing why is itself a finding, and reads as one. */
.variance-unknown { color: var(--ink-3); font-style: italic; }
/* Two figures on different bases are not a variance. */
.variance-warn {
    margin: 0 0 .25rem;
    font-size: var(--fs-sm);
    color: var(--st-waiting);
    white-space: normal;
}

/* ── The source index (/about/sources/) ──────────────────────────────────────
   A table of documents rather than of figures, so the cells are text and the
   whole table reads left-aligned and wraps. */

.data-sources td,
.data-sources th[scope="row"] { vertical-align: top; white-space: normal; }
.data-sources th[scope="row"] { font-weight: 600; }

/* Jump links to each group. */
.source-jump { margin: 0 0 2rem; }
.source-jump ul {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem .5rem;
    list-style: none;
    margin: 0;
    padding: 0;
}
.source-jump a {
    display: inline-block;
    padding: .3rem .6rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    font-size: var(--fs-md);
    text-decoration: none;
    color: var(--ink-2);
}
.source-jump a:hover { background: var(--bg-2); color: var(--ink); }
.jump-count { color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* Marks a document that survives only in the Internet Archive. Not a warning —
   an archived URL is a legitimate citation — but the reader is owed the fact
   that the publisher no longer hosts it. */
.pill-archived {
    color: var(--st-waiting);
    background: var(--st-waiting-bg);
    margin-left: .4rem;
}

/* The one source that is not what the rest of the table implies. Louder than a
   note, because the 2003 figures are the single exception to the sourcing rule
   and this index would otherwise present them as equivalent to a certificate. */
/* Both drop back to the body face. The row header is monospaced so document
   titles line up as identifiers; a paragraph of prose set in that same face
   reads as code and is markedly harder to scan. */
.source-caution,
.source-note {
    display: block;
    margin-top: .3rem;
    font-family: var(--font-text);
    font-weight: 400;
    line-height: 1.45;
}
.source-caution { font-weight: 600; color: var(--st-waiting); }

/* Which pages a source holds up. Page names stay on one line — auto table
   layout otherwise squeezes this column to its narrowest word and breaks
   "Find your ward" over three rows. The wrapper scrolls if that costs width. */
.source-uses {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: var(--fs-md);
}
.source-uses li { margin-bottom: .15rem; white-space: nowrap; }

/* ── Mobile table density ────────────────────────────────────────────────────
   Phone-width tables live inside a scroll wrapper anyway, so generous cell
   padding and the 9rem sticky-column floor only waste the little width there
   is. Short first columns (a year, a ward number) shrink to their content;
   name columns still wrap. Declared LAST: the base padding and min-width
   rules above would otherwise win the equal-specificity tie. */
@media (max-width: 36rem) {
    table.data th,
    table.data td { padding: .5rem .6rem; }
    table.data th:first-child,
    table.data td:first-child { min-width: 0; }
}

/* A chart that renders one orientation at every width. */
.chart-full { display: block; }

/* The chart tooltip (assets/charts.js). Fixed palette both themes via vars. */
.bv-tip {
    position: absolute;
    z-index: 50;
    max-width: 20rem;
    padding: .35rem .6rem;
    font-size: var(--fs-sm);
    line-height: 1.35;
    color: var(--bg);
    background: var(--ink-2);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    pointer-events: none;
}
.chart [data-tip] { cursor: default; }
.chart [data-tip]:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Phones: let candidate names wrap instead of forcing a wide first column,
   so the vote and share columns stay on screen.

   max-width alone does not work here: table.data uses the default auto
   layout, where a cell's column still sizes to fit its longest unbroken
   content regardless of max-width — a known table-rendering quirk, not a
   typo. table-layout: fixed makes the browser honour an explicit width
   instead, but fixed layout takes its column widths from the FIRST row
   (the header), so the width has to be set on :first-child generally, not
   only on tbody's th[scope="row"], or the header row leaves the column
   unconstrained and every wrap rule below is silently ignored. */
@media (max-width: 34rem) {
    table.data { table-layout: fixed; }
    table.data th:first-child,
    table.data td:first-child {
        width: 11rem;
        max-width: 11rem;
        white-space: normal;
        overflow-wrap: anywhere;
        hyphens: auto;
    }
    table.data td.cell-left { white-space: normal; overflow-wrap: anywhere; hyphens: auto; }
    table.data { font-size: var(--fs-sm); }
    table.data th, table.data td { padding-left: .45rem; padding-right: .45rem; }
    /* The caption is the table's own label, and at the 32rem table
       min-width it was exactly as wide as the table — reading it meant
       scrolling sideways before seeing a single row. Pinned and wrapped
       like the "scroll sideways" hint above it, so the title is legible
       from the moment the table scrolls into view. */
    table.data caption {
        position: sticky;
        left: 0;
        width: calc(100vw - 2.5rem);
        white-space: normal;
        overflow-wrap: anywhere;
    }
}

/* ── Career timeline lists (/candidates/directory/) ─────────────────────────
   A two-column grid: name, then the compact timeline strip. The axis strip
   at the top of each list is sticky — it rides just under the site header
   once scrolling passes it — and shares the rows' column template, so its
   ticks align with the gridlines below by construction. Name and strip
   cells stretch to the same row height and both carry the bottom border,
   so the rules line up across the two columns. */
.tl-list {
    --tl-cols: minmax(9em, 14em) 1fr;
    display: grid;
    grid-template-columns: var(--tl-cols);
    column-gap: 0.75rem;
    margin: 1rem 0;
}
.tl-name, .tl-strip {
    display: flex;
    align-items: center;
    min-width: 0;
    padding: 1px 0;
    border-bottom: 1px solid var(--line);
}
.tl-name {
    justify-content: flex-end;
    text-align: right;
    font-size: 0.85rem;
    font-weight: 600;
    overflow-wrap: anywhere;
}
.tl-axis-wrap {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: var(--tl-cols);
    column-gap: 0.75rem;
    position: sticky;
    top: calc(4rem + 1px);   /* just under the sticky site header */
    z-index: 5;
    background: var(--bg);
    padding: 0.2rem 0 0.05rem;
}
@media (max-width: 640px) {
    .tl-list, .tl-axis-wrap { --tl-cols: 1fr; }
    .tl-axis-wrap > span { display: none; }
    .tl-name { justify-content: flex-start; text-align: left; padding-top: 0.4rem; border-bottom: none; }
}

/* ── Candidate statements (includes/positions.php) ──────────────────────
   Verbatim passages with their source line. The blockquote is the record;
   the tag says which kind of source it came from. */
.positions h3 { margin-top: 1.75rem; }
.positions h4 { margin: 1rem 0 .25rem; font-size: 1rem; }
.pos-list { list-style: none; margin: 0 0 1rem; padding: 0; }
.pos-row { margin: 0 0 1.25rem; }
.pos-issue { margin: 0 0 .25rem; font-size: var(--fs-md); font-weight: 600; }
.pos-quote {
    margin: 0 0 .35rem;
    padding: .5rem 0 .5rem 1rem;
    border-left: 3px solid var(--accent);
    max-width: var(--measure);
}
.pos-quote p { margin: 0; color: var(--ink); }
.pos-row .table-source { margin-top: 0; }
.pos-checked { color: var(--ink-3); font-size: var(--fs-md); }
.pos-passage { color: var(--ink-2); background: var(--bg-3); }
/* The collapse: the first two passages per candidate per issue are open, the
   rest behind a native <details>. The summary reads as a quiet control, not a
   heading, and the open list picks up the same left rule as the quotes. */
.pos-more { margin: -.5rem 0 1.25rem; max-width: var(--measure); }
.pos-more > summary {
    cursor: pointer; display: inline-block;
    padding: .2rem .6rem; border: 1px solid var(--line);
    border-radius: 999px; font-size: var(--fs-md); color: var(--ink-2);
    background: var(--bg-2);
}
.pos-more > summary:hover, .pos-more > summary:focus-visible { color: var(--ink); border-color: var(--ink-3); }
.pos-more[open] > summary { margin-bottom: .75rem; }
.pos-more[open] > summary::after { content: ' (open)'; color: var(--ink-3); }
@media print { .pos-more > summary { display: none; } .pos-more > .pos-list { display: block; } }
