/* ============================================================
   FONTS — self-hosted and subset.
   Google Fonts cost two extra third-party origins on the critical path:
   the browser had to resolve + TLS fonts.googleapis.com, parse its CSS,
   and only THEN learn the fonts.gstatic.com URLs. Two chained handshakes
   before the first word could paint in its real face. Same-origin removes
   both, and subsetting to the glyphs this page can render cut 109.7 KB to
   69.7 KB. The subset is Basic Latin plus the marks these faces render
   (· – — ' ' " " …); regenerate with tools/build-fonts.sh if the copy ever
   needs a character outside it, or the glyph silently falls back.
   ============================================================ */
@font-face{font-family:'Archivo Black';font-style:normal;font-weight:400;font-display:swap;
  src:url('/fonts/archivo-black-400.woff2') format('woff2')}
@font-face{font-family:'Special Elite';font-style:normal;font-weight:400;font-display:swap;
  src:url('/fonts/special-elite-400.woff2') format('woff2')}
@font-face{font-family:'Permanent Marker';font-style:normal;font-weight:400;font-display:swap;
  src:url('/fonts/permanent-marker-400.woff2') format('woff2')}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url('/fonts/ibm-plex-mono-400.woff2') format('woff2')}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:700;font-display:swap;
  src:url('/fonts/ibm-plex-mono-700.woff2') format('woff2')}

/* ============================================================
   THE DIMAS BOARD — Washington State Republican Party
   Design: investigator's corkboard. Pinned documents, tape, red string.
   Her case is a pile of receipts that connect — so the site is the board.
   ============================================================ */

:root{
  --cork:#221c15;
  --marker:#e8323f;      /* scrawl red — needs to clear the dark ground */
  --string-lit:#dd2337;  /* string reads brighter than card red on black */
  --paper:#f6f2e6;
  --paper-2:#eae3d1;
  --card:#fdfaf1;
  --ink:#1a1712;
  --string:#c8102e;
  --hi:#ffe14a;
  --muted:#665e4e;      /* 5.0:1 on paper-2 — .up-sub at .6rem was 4.42 */
  --tape:rgba(238,232,205,.72);

  /* the pushpin, the one object this whole board repeats.
     --pin-size is set per component; this default keeps calc() valid if a new
     pinned surface ever forgets to set it. */
  --pin-size:16px;
  --red-lift:#ff6b5e;      /* the light catching the head            */
  --red-deep:#7d0a1c;      /* its base, and the string's shadow side */
  --pin-head:radial-gradient(circle at 34% 30%,
              var(--red-lift),var(--string) 62%,var(--red-deep));

  /* Secondary prose on paper. Two near-identical warm greys were doing this
     same job, three times and twice; the darker one wins on every ground. */
  --ink-2:#3a3226;
  /* Red TYPE, as opposed to red surfaces. --string is tuned to be a thread and
     a filled band; used as small label type on paper it landed at 4.54 and 4.60
     against a 4.5 requirement, across seven places. This is the same red with
     actual headroom (6.1:1), and it stays red at 10px. */
  --red-ink:#a30d24;
  --paper-muted:#a59d8d;   /* muted type on the ink ground */
  --card-now:#fff6f2;      /* the this-election tint       */

  --hand:'Permanent Marker',cursive;
  --type:'Special Elite',Courier,monospace;
  --display:'Archivo Black',Impact,sans-serif;
  /* body copy is deliberately quiet here — the character lives in the three
     display faces, so a system stack saves 142 KB at no visual cost */
  --body:system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
  --mono:'IBM Plex Mono',ui-monospace,Menlo,monospace;

  /* Type roles. Before this there were 26 fixed sizes and 16 fluid clamps —
     11 of them crammed between .55 and .75rem, a band the eye cannot separate.
     Roles are named for the job they do, not the value they hold. */
  --t-micro:.60rem;    /* stamps, tiny legal            */
  --t-label:.66rem;    /* mono labels, case numbers     */
  --t-label-lg:.72rem; /* section eyebrows, meta        */
  --t-small:.88rem;    /* dense card copy               */
  --t-body:.95rem;     /* secondary prose               */

  /* Tracking roles. Was 20 distinct values. */
  --track-display:-.025em;
  --track-tight:-.015em;
  --track-mono:.06em;
  --track-label:.14em;
  --track-wide:.20em;

  --wrap:1180px;
  --ease:cubic-bezier(.16,.84,.34,1);
}

*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%;overflow-x:clip}
html,body{overscroll-behavior-x:none}
body{
  margin:0;color:var(--ink);overflow-x:clip;
  background:var(--paper);
  font-family:var(--body);font-size:17px;line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
img,canvas,svg{max-width:100%;display:block}
a{color:inherit}
/* max() with env() so a notch or a rounded corner widens the gutter instead of
   sitting on top of the type. Falls back to the plain gutter everywhere else. */
.wrap{width:min(100% - 2.5rem,var(--wrap));margin-inline:auto;
  padding-inline:max(0px,env(safe-area-inset-left) - 1.25rem) max(0px,env(safe-area-inset-right) - 1.25rem)}

.skip{position:absolute;top:.5rem;left:.5rem;z-index:999;background:var(--ink);color:var(--paper);
  padding:.8rem 1.2rem;clip-path:inset(50%);width:1px;height:1px;overflow:hidden;white-space:nowrap}
.skip:focus{clip-path:none;width:auto;height:auto}
/* announced by screen readers, invisible on screen — same clip-path trick as
   .skip, which is the one that does not widen the layout box on iOS */
.vh{position:absolute;clip-path:inset(50%);width:1px;height:1px;overflow:hidden;white-space:nowrap}
:focus-visible{outline:3px solid var(--string);outline-offset:3px}

/* ---------- the file tab: board furniture, not an eyebrow above the h1 ---------- */
.filetab{
  position:relative;z-index:7;display:inline-block;rotate:-1.2deg;
  margin:0 0 1.6rem;padding:.5rem 1.05rem .5rem;
  background:#d9c8a0;color:#241e16;
  font-family:var(--mono);font-weight:700;font-size:var(--t-label);
  letter-spacing:var(--track-label);text-transform:uppercase;line-height:1.15;
  border-radius:3px 14px 0 0;
  box-shadow:0 8px 18px rgba(0,0,0,.5);
}
.filetab span{
  display:block;font-weight:400;font-size:var(--t-micro);
  letter-spacing:var(--track-mono);color:#574c39;margin-bottom:.2rem;
}
/* the folded corner of a real manila tab */
.filetab::after{
  content:"";position:absolute;top:0;right:0;width:14px;height:14px;
  background:linear-gradient(225deg,#b8a475 50%,transparent 50%);
  border-radius:0 14px 0 0;
}

/* ---------- cork ---------- */
.cork{
  position:relative;
  background-color:var(--cork);
  /* Cork weave, tone-on-tone: texture you feel, not brown you fight.
     This is the biggest painted surface on the page (~670,000px on a phone),
     so it is deliberately cheap: the vignette lives in this stack instead of
     in a separate full-size ::after layer, and it replaces a 160px inset blur
     that was darkening the same edges twice. Two dot layers, not four —
     23 and 41 are coprime, so the weave still never visibly repeats. */
  background-image:
    radial-gradient(120% 90% at 50% 40%, transparent 52%, rgba(0,0,0,.42) 100%),
    radial-gradient(circle at 20% 30%, rgba(255,246,228,.042) 0 1.5px, transparent 2.5px),
    radial-gradient(circle at 44% 78%, rgba(0,0,0,.26) 0 1.5px, transparent 2.5px),
    linear-gradient(160deg,#2a2219,#1a150f 60%,#251e16);
  background-size:100% 100%,23px 23px,41px 41px,100% 100%;
}
.cork-frame{border-top:10px solid #14110c;border-bottom:10px solid #14110c}

/* ---------- pinned things ---------- */
.pin{
  position:relative;background:var(--card);
  box-shadow:0 14px 28px rgba(0,0,0,.42),0 2px 0 rgba(0,0,0,.18);
}
/* The pushpin was written out three times — on .pin, .stat and .card — with
   the same gradient at three sizes. One rule now, driven by --pin-size, so the
   board's signature object cannot drift apart. */
.pin::before,
.stat::before,
.card::before{
  content:"";position:absolute;left:50%;
  top:calc(var(--pin-size) * -.55);
  width:var(--pin-size);height:var(--pin-size);
  transform:translateX(-50%);border-radius:50%;
  background:var(--pin-head);
  box-shadow:0 calc(var(--pin-size) * .15) calc(var(--pin-size) * .3) rgba(0,0,0,.48);
  z-index:4;
}
.pin{--pin-size:20px}
.stat,.card{--pin-size:16px}
.pin.tape::before{display:none}
.pin.tape::after{                   /* masking tape instead of a pin */
  content:"";position:absolute;top:-14px;left:50%;transform:translateX(-50%) rotate(-3deg);
  width:104px;height:30px;background:var(--tape);
  box-shadow:0 2px 5px rgba(0,0,0,.28);z-index:4;
}
.tilt-l{transform:rotate(-1.8deg)}
.tilt-r{transform:rotate(1.5deg)}
.tilt-l2{transform:rotate(-.9deg)}
.tilt-r2{transform:rotate(2.4deg)}

/* handwriting on the board */
.scrawl{
  font-family:var(--hand);color:var(--marker);
  text-transform:uppercase;line-height:1.05;letter-spacing:var(--track-mono);
  text-shadow:0 1px 0 rgba(0,0,0,.18);
}

/* ============================================================
   THE BOARD (hero)
   ============================================================ */
.board{padding:0;overflow:hidden}
.board-inner{position:relative;padding:2.6rem 0 3.4rem}
.board-title{position:relative;z-index:7;margin:0}
.board-title h1{
  margin:0;font-family:var(--display);text-transform:uppercase;
  font-size:clamp(min(2rem,9vw),6vw,4.4rem);line-height:.98;letter-spacing:var(--track-display);
  overflow-wrap:break-word;
  color:#fff;text-shadow:0 3px 0 rgba(0,0,0,.42);
  text-wrap:balance;
}
.board-title h1 em{font-style:normal;color:var(--hi)}
.board-title p{
  margin:.9rem 0 0;max-width:44ch;color:#efe7db;font-size:1.04rem;
  line-height:1.68;letter-spacing:.006em;
  text-shadow:0 1px 2px rgba(0,0,0,.5);
}

/* the string layer sits over the cork, under the labels */
/* Behind the cards (grid is z-index 5): the string shows across the cork gaps
   and passes behind each document, so it never sits on top of body text.
   The pin heads live inside the cards' own stacking context, so they stay visible. */
.strings{position:absolute;inset:0;z-index:4;pointer-events:none;overflow:visible}
/* The GL canvas sits in the same slot as the SVG it replaces. Its own shadow
   pass is drawn into the texture, so it needs no CSS filter. */
.strings-gl{display:block;width:100%;height:100%}
.strings path{
  fill:none;stroke:var(--string-lit);stroke-width:2.6;stroke-linecap:round;
  filter:drop-shadow(0 2px 3px rgba(0,0,0,.55));
}
/* pin heads ride on top of the string where they meet */
.board-grid{
  position:relative;z-index:5;
  display:grid;grid-template-columns:repeat(12,1fr);gap:1.4rem;
  margin-top:.6rem;
}

/* Hub-and-spoke: she sits at the top centre and every document hangs off her.
   Explicit placement so the fan reads the same at every desktop width. */
/* title fills the top-left, she pins top-right, evidence cascades below-left.
   Placed by name, not by nth-child: reordering the markup must not scramble
   the board, and the string sequencer already owns the chronological order. */
.board-grid > .board-title{grid-row:1;grid-column:1 / span 8;align-self:center}
.board-grid > .ev-photo  {grid-row:1;grid-column:9 / span 4;justify-self:end;width:100%;max-width:228px}
.board-grid > .ev-quote  {grid-row:2;grid-column:5 / span 8}   /* Jan 2023 — the post */
.board-grid > .c-2021    {grid-row:2;grid-column:1 / span 4}
.board-grid > .c-2024    {grid-row:3;grid-column:1 / span 4}
.board-grid > .c-jan25   {grid-row:3;grid-column:5 / span 4}
.board-grid > .c-apr25   {grid-row:3;grid-column:9 / span 4}
.board-grid{row-gap:2.6rem}

/* the mugshot */
.ev-photo{align-self:start}
.ev-photo .pin{padding:.55rem .55rem 0}
.ev-photo img{width:100%;height:auto;display:block}
.ev-photo figcaption{
  font-family:var(--type);font-size:var(--t-label-lg);text-align:center;text-wrap:balance;
  padding:.5rem .3rem .6rem;color:var(--ink-2);
}
/* the real enforcement case numbers, printed like a file label */
.ev-cases{
  display:block;margin-top:.45rem;padding-top:.4rem;
  border-top:1px solid rgba(26,23,18,.28);
  font-family:var(--mono);font-size:var(--t-micro);letter-spacing:var(--track-mono);color:#8a2230;
}

/* the quote, torn from a printout */
.ev-quote{}
.ev-quote .pin{padding:1.5rem 1.6rem 1.3rem}
.ev-quote blockquote{
  margin:0;font-family:var(--type);font-size:clamp(1.02rem,2vw,1.32rem);
  line-height:1.5;color:#211d16;
}
.ev-quote .hl{background:var(--hi);padding:0 .12em;box-decoration-break:clone}
.ev-quote cite{
  display:block;margin-top:1rem;font-family:var(--mono);font-size:var(--t-label);
  letter-spacing:var(--track-mono);text-transform:uppercase;color:var(--muted);font-style:normal;
}
.ev-quote .stampword{
  position:absolute;right:-.4rem;bottom:-1.1rem;transform:rotate(-7deg);
  border:4px solid var(--string);color:var(--red-ink);
  font-family:var(--display);font-size:var(--t-body);text-transform:uppercase;
  padding:.3rem .7rem;background:rgba(253,250,241,.82);
  letter-spacing:var(--track-mono);
}

/* the four case cards */
.ev-case{}
.ev-case .pin{padding:1rem 1.1rem 1.1rem;min-height:100%}
.ev-case .no{
  font-family:var(--mono);font-size:var(--t-micro);letter-spacing:var(--track-label);color:var(--red-ink);
  font-weight:700;display:block;margin-bottom:.4rem;
}
.ev-case h3{
  margin:0 0 .4rem;font-family:var(--display);text-transform:uppercase;
  font-size:1rem;line-height:1.1;letter-spacing:var(--track-tight);
}
.ev-case p{margin:0;font-family:var(--type);font-size:var(--t-small);line-height:1.45;color:#393226}
.ev-case.now .pin{background:var(--card-now);outline:3px solid var(--string);outline-offset:-3px}
.ev-case.now .no{color:#8a0f22}

/* scrawled annotations */
.ann{position:absolute;z-index:7;pointer-events:none}
/* bottom-right cork — the only patch clear of her card, the strings and the CTAs */
.ann-1{bottom:2rem;right:2.5rem;top:auto;font-size:clamp(1.05rem,2.1vw,1.62rem);rotate:-5deg}
/* Each current-cycle case carries its own stamp, on its own card — a stamp
   floating in the gap between two cards reads as a label, not a stamp. */
.ev-case.now .pin::after{
  content:"This election";
  position:absolute;right:-.55rem;bottom:-.75rem;transform:rotate(-6deg);
  border:3px solid var(--string);color:var(--red-ink);
  background:rgba(253,250,241,.92);
  font-family:var(--display);text-transform:uppercase;letter-spacing:var(--track-mono);
  font-size:var(--t-label);line-height:1;padding:.3rem .55rem .26rem;
  box-shadow:0 2px 7px rgba(0,0,0,.28);
}
.circle-note{
  border:4px solid var(--marker);border-radius:50%;padding:.5rem 1rem;
  background:transparent;
}

.board-cta{position:relative;z-index:7;display:flex;gap:.9rem;flex-wrap:wrap;margin-top:2.4rem}

/* ---------- buttons ---------- */
.btn{
  display:inline-block;font-family:var(--mono);font-weight:700;font-size:var(--t-small);
  letter-spacing:var(--track-label);text-transform:uppercase;text-decoration:none;
  padding:1rem 1.6rem;border:2px solid var(--ink);background:var(--ink);color:var(--paper);
  box-shadow:0 3px 8px rgba(0,0,0,.3);
  transition:transform .16s var(--ease),box-shadow .16s var(--ease);
}
/* it lifts off the board and drops back under the thumb */
/* Only where a pointer can actually hover. On a phone this fired on tap and
   then stuck until the next tap somewhere else. */
@media (hover:hover) and (pointer:fine){
  .btn:hover{transform:translateY(-3px);box-shadow:0 11px 22px rgba(0,0,0,.45)}
}
.btn:active{transform:translateY(1px);box-shadow:0 2px 5px rgba(0,0,0,.36)}
.btn-primary{background:var(--string);border-color:var(--red-deep);color:#fff}
.btn-ghost{background:rgba(253,250,241,.92);color:var(--ink);border-color:var(--ink)}
.btn-outline{background:var(--card);color:var(--ink)}

/* ============================================================
   SHARED TYPE
   ============================================================ */
.section-head{
  font-family:var(--display);text-transform:uppercase;
  font-size:clamp(min(2rem,9vw),5.4vw,3.9rem);line-height:1.02;letter-spacing:var(--track-display);margin:0 0 1rem;
  overflow-wrap:break-word;
}
.section-head .red{color:var(--string)}
.section-sub{font-size:clamp(1rem,1.8vw,1.18rem);max-width:60ch;margin:0 0 2.4rem;color:var(--ink-2)}
.src{font-family:var(--mono);font-size:var(--t-label);letter-spacing:var(--track-mono);text-transform:uppercase;
  color:var(--muted);margin:.9rem 0 0;line-height:1.5}
.red{color:var(--string)}
mark{background:var(--hi);color:var(--ink);padding:0 .12em}

/* ============================================================
   TICKER
   ============================================================ */
.ticker{background:var(--ink);color:var(--paper);overflow:hidden;padding:.7rem 0;touch-action:pan-y}
.ticker-track{display:flex;gap:1.5rem;align-items:center;white-space:nowrap;
  width:max-content;animation:roll 52s linear infinite}
.ticker-track span{font-family:var(--mono);font-weight:700;font-size:var(--t-label-lg);
  letter-spacing:var(--track-label);text-transform:uppercase}
.ticker-track i{font-style:normal;color:var(--string)}
@keyframes roll{from{transform:translateX(0)}to{transform:translateX(-50%)}}

/* ============================================================
   AT A GLANCE — index cards
   ============================================================ */
.glance{padding:4.6rem 0;background:var(--paper-2)}
/* Four stats. auto-fit gave 3 + 1 at tablet width, which reads as a mistake.
   The ladder for a fixed set of four is 4 -> 2x2 -> 1, never 3 + 1. */
.stat-grid{display:grid;gap:1.6rem;grid-template-columns:repeat(4,minmax(0,1fr));margin-top:2.4rem}
.stat{background:var(--card);padding:1.7rem 1.3rem 1.5rem;position:relative;
  box-shadow:0 8px 18px rgba(0,0,0,.14);border:1px solid rgba(26,23,18,.14)}
.stat:nth-child(odd){rotate:-.8deg}
.stat:nth-child(even){rotate:.7deg}
/* tabular figures: the count-up rewrites this text every frame, and with
   proportional digits the number's width jitters through the whole run */
.stat-num{font-family:var(--display);font-variant-numeric:tabular-nums;
  font-size:clamp(2.6rem,6vw,3.9rem);line-height:.9;
  color:var(--string);letter-spacing:var(--track-display)}
.stat-label{font-family:var(--type);font-size:var(--t-small);color:var(--ink-2);margin-top:.7rem;line-height:1.4}

/* ============================================================
   HER WORDS
   ============================================================ */
.feature{padding:4.6rem 0}
.exhibit-grid{display:grid;grid-template-columns:1fr .9fr;gap:3rem;align-items:start}
.exhibit-copy h2{font-family:var(--display);text-transform:uppercase;
  font-size:clamp(1.6rem,3.8vw,2.6rem);line-height:1.04;letter-spacing:var(--track-tight);margin:0 0 1.1rem}
.exhibit-copy p{font-size:1.04rem;margin:0 0 1.1rem}
.quote-block{padding:1rem 0 1.1rem;margin:1.5rem 0;
  border-top:2px solid var(--ink);border-bottom:2px solid var(--ink);
  font-family:var(--type);font-size:clamp(1.02rem,2.1vw,1.28rem);line-height:1.45}
.law{background:var(--paper-2);border:2px solid var(--ink);padding:1.2rem 1.4rem;margin-top:1.5rem}
.law h3{font-family:var(--mono);font-size:var(--t-label-lg);letter-spacing:var(--track-label);margin:0 0 .5rem;
  text-transform:uppercase;color:var(--red-ink)}
.law p{margin:0;font-size:var(--t-body)}
/* The print's mat is white and the screenshot inside it is white, so on the
   cream page the top edge had nothing to define it (1.12:1) and the corner read
   as a stray white block. A hairline gives the print an edge, and the drop
   shadow only ever separated the bottom. */
.shot{position:relative;background:#fff;padding:.5rem;
  border:1px solid rgba(26,23,18,.2);
  box-shadow:0 16px 30px rgba(0,0,0,.24);rotate:-1.2deg}

/* tape sits right of centre so it never lands on the label */
.shot::before{content:"";position:absolute;top:-12px;left:auto;right:2.4rem;transform:rotate(-4deg);
  width:110px;height:30px;background:var(--tape);box-shadow:0 2px 5px rgba(0,0,0,.24);z-index:3}
/* the exhibit label — its own red tab, clear of the tape */
.shot-tag{
  position:absolute;top:-.85rem;left:1rem;z-index:4;
  background:var(--string);color:#fff;
  font-family:var(--mono);font-size:var(--t-micro);letter-spacing:var(--track-label);text-transform:uppercase;
  padding:.38rem .8rem;font-weight:700;box-shadow:0 2px 6px rgba(0,0,0,.32);
}
/* the inner hairline keeps the mat readable as mat, not as more screenshot */
.shot img{width:100%;height:auto;display:block;outline:1px solid rgba(26,23,18,.14)}
.shot-cap{font-family:var(--mono);font-size:var(--t-label);letter-spacing:var(--track-mono);text-transform:uppercase;
  color:var(--muted);margin-top:1rem;text-align:center}

/* ============================================================
   LEDGER
   ============================================================ */
.ledger{padding:4.6rem 0;background:var(--paper-2)}
.ledger-frame{background:var(--card);border:1px solid rgba(26,23,18,.2);
  box-shadow:0 14px 30px rgba(0,0,0,.16);position:relative}
.ledger-head{display:flex;justify-content:space-between;gap:1rem;align-items:center;
  padding:.8rem 1.1rem;border-bottom:2px solid var(--ink);
  font-family:var(--mono);font-size:var(--t-label);letter-spacing:var(--track-label);text-transform:uppercase;font-weight:700}
.ledger-head b{color:var(--red-ink)}
#ledgerCanvas{width:100%;height:auto;display:block}
/* Only rendered if <canvas> is unsupported; the same four cases, as text. */
.canvas-fallback{margin:0;padding:1.2rem 1.4rem 1.4rem 2.4rem;font-size:var(--t-small);line-height:1.55}
.canvas-fallback li{margin:0 0 .6rem}
.canvas-fallback li:last-child{margin:0}
.ledger-foot{padding:.8rem 1.1rem;border-top:1px solid rgba(26,23,18,.2);
  font-family:var(--mono);font-size:var(--t-label);letter-spacing:var(--track-mono);text-transform:uppercase;
  color:var(--muted);display:flex;gap:1.2rem;flex-wrap:wrap;align-items:center}
.ledger-foot em{font-style:normal;margin-left:auto}
.lg-pen,.lg-warn{width:11px;height:11px;display:inline-block;flex:0 0 auto}
.lg-pen{background:var(--string)}
.lg-warn{background:var(--ink)}
.lg-item{display:inline-flex;align-items:center;gap:.5rem}

.unpaid-punch{display:grid;grid-template-columns:1fr auto 1fr;gap:1rem;align-items:stretch;margin-top:1.6rem}
.up-side{background:var(--card);border:2px solid var(--ink);padding:1.3rem 1.4rem}
.up-side.bad{border-color:var(--string)}
.up-tag{display:block;font-family:var(--mono);font-size:var(--t-micro);letter-spacing:var(--track-label);
  text-transform:uppercase;color:var(--muted);margin-bottom:.4rem}
.up-side b{display:block;font-family:var(--display);text-transform:uppercase;
  font-size:clamp(1rem,2.5vw,1.55rem);line-height:1.06;letter-spacing:var(--track-tight)}
.up-side.bad b{color:var(--string)}
.up-note{display:block;margin-top:.5rem;font-size:var(--t-small);color:var(--ink-2)}
.up-mid{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.3rem;padding:0 .4rem}
.up-dist{font-family:var(--hand);font-size:clamp(1.4rem,3.4vw,2.1rem);line-height:1;color:var(--string)}
.up-line{width:3px;flex:1;min-height:26px;background:var(--string)}
.up-sub{font-family:var(--mono);font-size:var(--t-micro);letter-spacing:var(--track-label);text-transform:uppercase;color:var(--muted)}

/* ============================================================
   CASE CARDS
   ============================================================ */
.cases{padding:4.6rem 0}
/* Same four-item rule; these carry more text, so they go 2x2 sooner. */
.cards{display:grid;gap:1.6rem;grid-template-columns:repeat(4,minmax(0,1fr));margin-top:2.2rem}
.card{background:var(--card);padding:1.6rem 1.4rem;position:relative;
  border:1px solid rgba(26,23,18,.16);box-shadow:0 10px 22px rgba(0,0,0,.14)}
.card:nth-child(odd){rotate:-.7deg}
.card:nth-child(even){rotate:.8deg}
.card-no{font-family:var(--mono);font-size:var(--t-label);letter-spacing:var(--track-label);color:var(--red-ink);
  font-weight:700;display:block;margin-bottom:.6rem}
.card h3{font-family:var(--display);text-transform:uppercase;font-size:1.1rem;
  line-height:1.1;letter-spacing:var(--track-tight);margin:0 0 .6rem}
.card p{margin:0;font-family:var(--type);font-size:var(--t-small);line-height:1.5}
.card.is-now{background:var(--card-now);outline:3px solid var(--string);outline-offset:-3px}

/* ============================================================
   TIMELINE
   ============================================================ */
.timeline-sec{padding:4.6rem 0;background:var(--paper-2)}
.timeline{list-style:none;margin:2rem 0 0;padding:0;max-width:820px;border-top:1px solid rgba(26,23,18,.22)}
.timeline li{display:grid;grid-template-columns:140px 1fr;gap:1.4rem;padding:1.2rem 0;
  border-bottom:1px solid rgba(26,23,18,.22)}
.tl-date{font-family:var(--mono);font-size:var(--t-label-lg);letter-spacing:var(--track-label);text-transform:uppercase;
  color:var(--red-ink);font-weight:700;padding-top:.2rem}
.timeline p{margin:0;font-size:1rem}
.timeline .tl-key{background:rgba(255,225,74,.3)}

/* ============================================================
   DOCUMENTS
   ============================================================ */
.docs{padding:4.6rem 0;background:var(--ink);color:var(--paper)}
/* --string is tuned for paper. Against the ink ground it falls to 3.04 with a
   3.0 floor, so the dark sections take the marker red — the one already chosen
   to clear this exact background (4.22). */
.docs .red,.ticker-track i{color:var(--marker)}
.docs .section-head{color:var(--paper)}
.docs .section-sub{color:#b9b1a1;line-height:1.68;letter-spacing:.006em}
.docs .doc-title{letter-spacing:.004em}
.doc-list{display:grid;border-top:1px solid rgba(246,242,230,.22)}
.doc-item{display:grid;grid-template-columns:auto 1fr auto;gap:.3rem 1.2rem;align-items:center;
  text-decoration:none;padding:1.2rem .2rem;border-bottom:1px solid rgba(246,242,230,.22);
  transition:background .15s,transform .15s var(--ease)}
@media (hover:hover) and (pointer:fine){
  .doc-item:hover{background:rgba(246,242,230,.06);transform:translateX(.55rem)}
}
/* touch gets the same acknowledgement, on press, where it belongs */
.doc-item:active{background:rgba(246,242,230,.10);transform:translateX(.3rem)}
/* a coarse pointer needs the row to be comfortably tappable */
@media (pointer:coarse){
  .doc-item{padding-block:1.4rem}
  .btn{padding:1.1rem 1.6rem}
}
.doc-tag{grid-column:1;grid-row:1/3;font-family:var(--mono);font-size:var(--t-micro);letter-spacing:var(--track-label);
  text-transform:uppercase;color:var(--ink);background:var(--hi);padding:.35rem .55rem;
  font-weight:700;align-self:center;white-space:nowrap}
.doc-title{grid-column:2;grid-row:1;font-weight:700;font-size:1rem}
.doc-meta{grid-column:2;grid-row:2;font-family:var(--mono);font-size:var(--t-label);color:var(--paper-muted)}
.doc-arrow{grid-column:3;grid-row:1/3;font-size:1.4rem;color:var(--hi);align-self:center}

/* ============================================================
   VOTE NO
   ============================================================ */
.voteno{background:var(--string);color:#fff;padding:4.2rem 0;text-align:center}
.vn-line{margin:0;font-family:var(--display);text-transform:uppercase;
  font-size:clamp(3rem,12vw,8rem);line-height:.92;letter-spacing:var(--track-display)}
.vn-name{font-family:var(--display);text-transform:uppercase;
  font-size:clamp(1.3rem,4.4vw,2.8rem);line-height:1.04;margin:.5rem 0 .3rem;letter-spacing:var(--track-tight)}
.vn-dist{font-family:var(--mono);font-size:clamp(.7rem,1.8vw,.92rem);letter-spacing:var(--track-label);
  text-transform:uppercase;margin:0;color:#fff}   /* .85 white on the red band was 4.19 — under AA */
.vn-date{font-family:var(--body);font-weight:700;font-size:clamp(.92rem,2vw,1.1rem);margin:1.3rem 0 0}
.vn-date b{border-bottom:3px solid #fff;padding-bottom:2px}

/* ============================================================
   BALLOT
   ============================================================ */
.ballot{padding:4.6rem 0}
.ballot-card{border:3px solid var(--ink);background:#fff;max-width:840px;
  box-shadow:0 14px 30px rgba(0,0,0,.16)}
.bc-head{background:var(--ink);color:var(--hi);font-family:var(--mono);font-size:var(--t-label);
  letter-spacing:var(--track-wide);text-transform:uppercase;padding:.7rem 1.1rem;font-weight:700}
.bc-row{display:grid;grid-template-columns:auto auto 1fr auto;gap:1rem;align-items:center;
  padding:1.4rem 1.2rem;border-bottom:2px solid rgba(26,23,18,.16)}
.bc-row:last-child{border-bottom:0}
.bc-box{width:36px;height:30px;border:3px solid var(--ink);display:grid;place-items:center;flex:0 0 auto}
/* she gets the case-file treatment; Gloria does not */
.bc-photo{width:70px;height:70px;object-fit:cover;border:3px solid var(--ink);flex:0 0 auto}
.bc-photo-no{filter:grayscale(1) contrast(1.2) brightness(.9);opacity:.8}
.bc-photo-yes{border-color:var(--string);object-position:50% 22%}
.bc-checked svg{width:24px;height:20px;overflow:visible}
.bc-name{font-family:var(--display);text-transform:uppercase;
  font-size:clamp(1.05rem,2.8vw,1.55rem);line-height:1.06;letter-spacing:var(--track-tight)}
.bc-cand{display:block}
.bc-name em{display:block;font-family:var(--body);font-style:normal;font-weight:600;
  font-size:var(--t-label-lg);text-transform:none;color:var(--muted);margin-top:.2rem;letter-spacing:0}
.bc-verdict{font-family:var(--mono);font-size:var(--t-label);letter-spacing:var(--track-label);text-transform:uppercase;
  font-weight:700;text-align:right;line-height:1.5}
.bc-no{background:rgba(200,16,46,.05)}
/* Struck out, but still a candidate's name on a ballot — it has to stay
   readable. At 16.8px on a phone the old grey was 3.48:1 against a 4.5
   requirement; it only passed on desktop because the clamp made it large text. */
.bc-no .bc-cand{text-decoration:line-through;text-decoration-color:var(--string);
  text-decoration-thickness:4px;color:var(--muted)}
.bc-no .bc-name em{text-decoration:none}
.bc-no .bc-verdict{color:var(--red-ink)}
.bc-yes .bc-verdict{color:var(--ink)}
.bc-yes .bc-verdict b{font-family:var(--display);font-size:1.18rem;color:var(--string);
  display:inline-block;vertical-align:-2px;margin:0 .1em}
.ballot-cta{margin:2.2rem 0 0;display:flex;gap:1rem;align-items:center;flex-wrap:wrap}
.ballot-cta span{font-size:var(--t-small);color:var(--ink-2);max-width:34ch}

/* ============================================================
   CLOSER + FOOTER
   ============================================================ */
.closer{padding:3.6rem 0;background:var(--paper-2)}
.closer-grid{display:grid;gap:2rem;grid-template-columns:1.1fr 1fr;align-items:center}
/* the ballot-check motif, sized — without this the raw SVG renders enormous */
.closer-copy{display:flex;gap:1.3rem;align-items:center}
.check{flex:0 0 auto;width:58px;color:var(--ink)}
.check svg{width:100%;height:auto;overflow:visible}
.closer-copy h2{font-family:var(--display);text-transform:uppercase;
  font-size:clamp(1.4rem,3.4vw,2.2rem);line-height:1.06;margin:0;letter-spacing:var(--track-tight)}
.closer-note{border:2px solid var(--ink);background:#fff;padding:1.3rem 1.4rem}
.closer-note p{margin:0;font-size:var(--t-body)}
.site-footer{background:var(--ink);color:var(--paper-muted);font-family:var(--mono);
  padding:2.4rem 0 max(3rem,env(safe-area-inset-bottom))}
.paidfor{margin:0 0 .8rem;font-size:var(--t-label-lg);letter-spacing:var(--track-mono);color:#d9d3c5;line-height:1.7}
.foot-meta{margin:0;font-size:var(--t-label);letter-spacing:var(--track-mono);line-height:1.7}

/* ============================================================
   MOTION
   ============================================================ */
/* EVERY hiding rule below is scoped to .js, which the inline script in <head>
   sets before first paint. Without it — script blocked, script errored, script
   never arrived — none of these match and the whole page is simply visible.
   Nothing on this site is worth hiding behind a working JavaScript engine. */

/* `translate`, not `transform`: the pinned cards carry their own `rotate`, and a
   shared `transform` meant whichever rule won erased the other. */
.js .reveal{opacity:0;translate:0 18px;
  transition:opacity .46s var(--ease),translate .46s var(--ease)}
.js .reveal.in{opacity:1;translate:none}
.js .reveal[data-d="1"]{transition-delay:.05s}
.js .reveal[data-d="2"]{transition-delay:.10s}
.js .reveal[data-d="3"]{transition-delay:.16s}
.js .reveal[data-d="4"]{transition-delay:.22s}
.js .reveal[data-d="5"]{transition-delay:.28s}

/* board nodes are revealed by the string sequencer, one at a time */
.js .node{opacity:0}
.js .node.lit{animation:drop .4s cubic-bezier(.22,1,.36,1) both}
.js .node.tilt-l.lit{animation-name:dropL}
.js .node.tilt-r.lit{animation-name:dropR}
.js .node.tilt-l2.lit{animation-name:dropL2}
.js .node.tilt-r2.lit{animation-name:dropR2}

@keyframes drop{
  0%{opacity:0;transform:translateY(-26px) scale(1.05) rotate(0deg)}
  100%{opacity:1}
}
@keyframes dropL{0%{opacity:0;transform:translateY(-26px) rotate(3deg)}100%{opacity:1;transform:rotate(-1.8deg)}}
@keyframes dropR{0%{opacity:0;transform:translateY(-26px) rotate(-3deg)}100%{opacity:1;transform:rotate(1.5deg)}}
@keyframes dropL2{0%{opacity:0;transform:translateY(-26px) rotate(3deg)}100%{opacity:1;transform:rotate(-.9deg)}}
@keyframes dropR2{0%{opacity:0;transform:translateY(-26px) rotate(-4deg)}100%{opacity:1;transform:rotate(2.4deg)}}

.js .slam{opacity:0;transform:scale(1.5) rotate(-7deg)}
.js .slam.in{animation:slam .32s cubic-bezier(.22,1,.36,1) both}
@keyframes slam{
  0%{opacity:0;transform:scale(1.5) rotate(-7deg)}
  60%{opacity:1;transform:scale(.97) rotate(1deg)}
  100%{opacity:1;transform:none}
}
.js .slam[data-d="1"]{animation-delay:.05s}
.js .slam[data-d="2"]{animation-delay:.16s}
.js .slam[data-d="3"]{animation-delay:.3s}
.js .slam[data-d="4"]{animation-delay:.42s}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width:1180px){
  .cards{grid-template-columns:repeat(2,minmax(0,1fr))}
}
/* Tablet portrait and half-screen laptop windows used to get the phone board —
   her photo dropped below the headline and the hub-and-spoke read was lost.
   She stays pinned top-right here; only the evidence reflows. */
@media (max-width:1000px){
  .board-grid > .board-title{grid-row:1;grid-column:1 / span 8;align-self:center}
  .board-grid > .ev-photo  {grid-row:1;grid-column:9 / span 4;justify-self:end;width:100%;max-width:196px}
  .board-grid > .ev-quote  {grid-row:2;grid-column:1 / span 12}
  .board-grid > .c-2021    {grid-row:3;grid-column:1 / span 6}
  .board-grid > .c-2024    {grid-row:3;grid-column:7 / span 6}
  .board-grid > .c-jan25   {grid-row:4;grid-column:1 / span 6}
  .board-grid > .c-apr25   {grid-row:4;grid-column:7 / span 6}
  .stat-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .cards{grid-template-columns:repeat(2,minmax(0,1fr))}
}

@media (max-width:900px){
  .exhibit-grid,.closer-grid{grid-template-columns:1fr}
  .unpaid-punch{grid-template-columns:1fr;gap:.6rem}
  .up-mid{flex-direction:row;gap:.7rem;padding:.2rem 0}
  .up-line{width:auto;height:3px;flex:1;min-height:0}
}
/* below this the board finally stacks: she goes centred above the evidence */
@media (max-width:700px){
  .board-grid > .board-title{grid-row:1;grid-column:1 / span 12}
  .board-grid > .ev-photo  {grid-row:2;grid-column:1 / span 12;max-width:200px;justify-self:center}
  .board-grid > .ev-quote  {grid-row:3;grid-column:1 / span 12}
  .board-grid > .c-2021    {grid-row:4;grid-column:1 / span 6}
  .board-grid > .c-2024    {grid-row:4;grid-column:7 / span 6}
  .board-grid > .c-jan25   {grid-row:5;grid-column:1 / span 6}
  .board-grid > .c-apr25   {grid-row:5;grid-column:7 / span 6}
}
@media (max-width:640px){
  body{font-size:16px}
  .board-inner{padding:2rem 0 2.6rem}
  .board-grid{grid-template-columns:1fr;gap:1.9rem;margin-top:1.6rem}
  .ev-photo,.ev-quote,.ev-case{grid-column:1 / -1}
  .ev-photo{max-width:210px}
  .strings{display:none}          /* string needs room to read */
  .ann{display:none}
  .board-cta .btn{width:100%;text-align:center}
  .timeline li{grid-template-columns:1fr;gap:.4rem}
  .doc-item{grid-template-columns:1fr auto}
  .doc-tag{grid-column:1;grid-row:1;justify-self:start}
  .doc-title{grid-column:1;grid-row:2}
  .doc-meta{grid-column:1;grid-row:3}
  .doc-arrow{grid-column:2;grid-row:1/4}
  .bc-row{grid-template-columns:auto auto 1fr;gap:.7rem .9rem}
  .bc-photo{width:52px;height:52px}
  .bc-verdict{grid-column:1/-1;text-align:left}
  .ledger-foot em{margin-left:0;flex-basis:100%}
  .stat:nth-child(odd),.stat:nth-child(even),
  .card:nth-child(odd),.card:nth-child(even){transform:none}
}
@media (max-width:560px){
  /* the case cards carry paragraphs, so they go single-file here */
  .cards{grid-template-columns:1fr}
}
/* The stats stay 2x2 on a phone: the whole point of "at a glance" is seeing
   4 / 2 / $1,150 / 3 together, which a four-tall stack destroys. */
@media (max-width:360px){
  .stat-grid{grid-template-columns:1fr}
}


/* ============================================================
   PRINT — this is a "pull the records yourself" page, so someone will
   print it and hand it round. Ink-cheap, and every external link
   prints its URL so the paper is as checkable as the screen.
   ============================================================ */
@media print{
  html,body{background:#fff;color:#000}
  .cork,.cork::before,.cork::after{background:#fff!important;color:#000}
  .board-title h1,.board-title p,.filetab{color:#000!important;text-shadow:none}
  .filetab{border:1px solid #000}
  .ticker,.strings,.ann,.board-cta,.ballot-cta,.skip{display:none}
  .docs{background:#fff;color:#000}
  .docs .section-head,.docs .section-sub,.doc-title,.doc-meta{color:#000}
  .doc-tag{border:1px solid #000;background:none;color:#000}
  .voteno{background:#fff;color:#000;border-block:3px solid #000}
  .site-footer{background:#fff;color:#000;border-top:1px solid #000}
  .pin,.card,.stat,.ledger-frame,.ballot-card,.closer-note,.up-side,.shot{
    box-shadow:none;border:1px solid #666;rotate:none}
  .pin::before,.stat::before,.card::before{display:none}
  .reveal,.node,.slam,.js .reveal,.js .node,.js .slam{
    opacity:1!important;translate:none!important;transform:none!important;animation:none!important}
  /* an external link is worthless on paper unless it prints its address */
  .doc-item[href^="http"]::after{content:" (" attr(href) ")";
    font-size:.7em;word-break:break-all;display:block;grid-column:1/-1}
  .doc-arrow{display:none}
  section,.card,.stat,.timeline li,.doc-item,.ballot-card{break-inside:avoid}
  .section-head{break-after:avoid}
  main section{padding:1.2rem 0}
}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .js .reveal,.js .slam,.js .node{opacity:1;transform:none;translate:none;animation:none;transition:none}
  .ticker-track{animation:none}
  .btn:hover,.doc-item:hover,.btn:active,.doc-item:active{transform:none}
  .strings path{stroke-dasharray:none!important;stroke-dashoffset:0!important}
}
