/* ============================================================
   BRAND TOKENS  ·  swap these to rebrand the whole site
   ============================================================ */
:root {
  --paper:  #F5F3EE;             /* page background */
  --ink:    #17191F;             /* primary text */
  --muted:  #6A6D75;             /* secondary text */
  --line:   #E1DDD3;             /* hairlines */
  --accent: #1B34D8;             /* single accent: links, tags, CTA */
  --on-accent: #F5F3EE;

  --display: "Space Grotesk", system-ui, sans-serif;
  --serif:   "Newsreader", Georgia, serif;
  --mono:    "IBM Plex Mono", ui-monospace, monospace;

  --wrap: 1180px;

  /* One full loop of the news ticker. Higher is slower. */
  --ticker-speed: 78s;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  line-height: 1.5;
  font-size: 17px;
}
a { color: inherit; text-decoration: none; }
a:hover .hl { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }
a:focus-visible, button:focus-visible, input:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 3px;
}
img { max-width: 100%; display: block; }
.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }

/* eyebrow / telemetry signature ------------------------------ */
.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.eyebrow::before {
  content: "";
  width: 7px; height: 7px;
  background: var(--accent);
  display: inline-block;
}
.stamp {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--muted);
  text-transform: uppercase;
}

/* headings --------------------------------------------------- */
.h-display { font-family: var(--display); font-weight: 600; line-height: 1.05; letter-spacing: -0.01em; margin: 0; }


/* masthead / nav --------------------------------------------- */
header.top { border-bottom: 1.5px solid var(--ink); }
.masthead { display: flex; align-items: baseline; justify-content: space-between; gap: 24px; padding: 22px 0 16px; }
.wordmark { font-family: var(--display); font-weight: 700; font-size: 34px; letter-spacing: -.02em; }
.masthead .tagline { font-family: var(--mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.actions { display: flex; align-items: center; gap: 14px; }
.btn {
  font-family: var(--display); font-weight: 600; font-size: 13px; letter-spacing: .02em;
  background: var(--accent); color: var(--on-accent);
  border: none; padding: 10px 16px; cursor: pointer;
}
.btn.ghost { background: transparent; color: var(--ink); border: 1.5px solid var(--ink); }
.iconbtn { background: none; border: none; cursor: pointer; font-family: var(--mono); font-size: 12px; letter-spacing: .08em; text-transform: uppercase; }

nav.cats { border-top: 1px solid var(--line); }
nav.cats ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 26px; }
nav.cats a { font-family: var(--display); font-weight: 500; font-size: 14px; padding: 12px 0; display: inline-block; letter-spacing: .01em; }
nav.cats a:hover, nav.cats a.active { color: var(--accent); }

.navtoggle { display: none; white-space: nowrap; }

/* placeholder image ------------------------------------------ */
.ph {
  position: relative;
  background:
    repeating-linear-gradient(135deg, rgba(23,25,31,.06) 0 2px, transparent 2px 11px),
    linear-gradient(180deg, #E9E5DC, #DED9CE);
  background-size: cover;
  background-position: center;
  overflow: hidden;
}
.ph::after { content: ""; }
.r-16-9 { aspect-ratio: 16/9; }
.r-4-3  { aspect-ratio: 4/3; }
.r-1-1  { aspect-ratio: 1/1; }
.r-3-2  { aspect-ratio: 3/2; }

/* generic tag row -------------------------------------------- */
.tags { display: flex; gap: 12px; flex-wrap: wrap; }
.tag { font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--accent); }

/* HERO ------------------------------------------------------- */
.hero { display: grid; grid-template-columns: 1.6fr 1fr; gap: 40px; padding: 40px 0; border-bottom: 1px solid var(--line); }
.hero .lead .h-display { font-size: 46px; margin: 14px 0 12px; }
.hero .lead .dek { font-size: 20px; color: #33363E; margin: 0 0 12px; max-width: 40ch; }
.hero .side { display: flex; flex-direction: column; gap: 22px; border-left: 1px solid var(--line); padding-left: 40px; }
.hero .side article { display: grid; grid-template-columns: 1fr 92px; gap: 14px; padding-bottom: 22px; border-bottom: 1px solid var(--line); }
.hero .side article:last-child { border-bottom: none; padding-bottom: 0; }
.hero .side h3 { font-family: var(--display); font-weight: 600; font-size: 17px; line-height: 1.15; margin: 8px 0 0; }

/* section headers -------------------------------------------- */
.sec-head { display: flex; align-items: baseline; justify-content: space-between; border-bottom: 1.5px solid var(--ink); padding-bottom: 8px; margin: 0 0 22px; }
.sec-head h2 { font-family: var(--display); font-weight: 700; font-size: 15px; letter-spacing: .14em; text-transform: uppercase; margin: 0; }
.sec-head a { font-family: var(--mono); font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.sec-head a:hover { color: var(--accent); }
section.block { padding: 44px 0; border-bottom: 1px solid var(--line); }

/* latest strip ----------------------------------------------- */
.latest { display: grid; grid-template-columns: repeat(4, 1fr); gap: 26px; }
.latest article h3 { font-family: var(--display); font-weight: 500; font-size: 16px; line-height: 1.2; margin: 10px 0 8px; }

/* newsletter band -------------------------------------------- */
.promo { background: var(--ink); color: var(--paper); }
.promo .wrap { display: grid; grid-template-columns: 1.2fr 1fr; gap: 40px; align-items: center; padding: 40px 24px; }
.promo h2 { font-family: var(--display); font-weight: 600; font-size: 30px; line-height: 1.1; margin: 0 0 8px; }
.promo p { color: #B9BBC2; margin: 0; max-width: 34ch; }
.promo form { display: flex; gap: 10px; }
.promo input { flex: 1; background: transparent; border: 1.5px solid #43464E; color: var(--paper); padding: 13px 14px; font-family: var(--serif); font-size: 16px; }
.promo input::placeholder { color: #8A8D95; }

/* card grid -------------------------------------------------- */
.grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 30px; }
.card h3 { font-family: var(--display); font-weight: 600; font-size: 20px; line-height: 1.15; margin: 12px 0 8px; }
.card .dek { color: #40434B; font-size: 16px; margin: 0 0 10px; }

/* two-column category lists ---------------------------------- */
.cols2 { display: grid; grid-template-columns: 1fr 1fr; gap: 48px; }
.feedlist { display: flex; flex-direction: column; }
.feedlist article { display: grid; grid-template-columns: 1fr 96px; gap: 16px; padding: 18px 0; border-bottom: 1px solid var(--line); align-items: start; }
.feedlist article:first-child { padding-top: 0; }
.feedlist h3 { font-family: var(--display); font-weight: 500; font-size: 17px; line-height: 1.18; margin: 6px 0 0; }

/* Interviews -------------------------------------------------------- */
.qa { display: grid; grid-template-columns: repeat(3,1fr); gap: 30px; }
.qa article h3 { font-family: var(--display); font-weight: 600; font-size: 20px; line-height: 1.2; margin: 14px 0 6px; }

/* single article page ----------------------------------------- */
.article-head { padding: 40px 0 28px; border-bottom: 1px solid var(--line); max-width: 74ch; }
/* On an article page the head's rules should run as wide as the hero image
   below them, so the divider does not stop short of the picture. The headline
   block keeps the 74ch reading measure on its own. Standalone pages (About,
   Contact, sign-in) have no .head-text and are left as they were. */
article:not(.standalone) .article-head { max-width: none; }
.article-head .head-text { max-width: 74ch; }
.article-head .h-display { font-size: 40px; margin: 14px 0 12px; }
.article-head .dek { font-size: 20px; color: #33363E; margin: 0 0 14px; }
.article-body { max-width: 74ch; padding: 34px 0; font-size: 18px; }
.article-body p { margin: 0 0 20px; }
.article-body h2 { font-family: var(--display); font-weight: 600; font-size: 26px; margin: 34px 0 14px; }
.article-body h3 { font-family: var(--display); font-weight: 600; font-size: 21px; margin: 28px 0 12px; }
.article-body a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.article-body ul { margin: 0 0 20px; padding-left: 22px; }
.article-body li { margin-bottom: 8px; }
.article-body blockquote { margin: 0 0 20px; padding-left: 18px; border-left: 3px solid var(--accent); color: #33363E; font-style: italic; }
.article-body hr { border: none; border-top: 1px solid var(--line); margin: 30px 0; }
.article-hero { margin: 26px 0 0; }
.empty-note { font-family: var(--mono); font-size: 12px; letter-spacing: .04em; color: var(--muted); text-transform: uppercase; padding: 10px 0 30px; }

/* footer ----------------------------------------------------- */
footer.site { background: var(--paper); border-top: 1.5px solid var(--ink); padding: 44px 0 60px; }
footer.site .top { display: flex; justify-content: space-between; align-items: flex-start; gap: 40px; flex-wrap: wrap; }
footer.site .wordmark { font-size: 26px; }
footer .flinks { display: flex; gap: 30px; flex-wrap: wrap; }
footer .flinks a { font-family: var(--display); font-weight: 500; font-size: 14px; }
footer .flinks a:hover { color: var(--accent); }
footer .legal { margin-top: 34px; padding-top: 18px; border-top: 1px solid var(--line); display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap; font-family: var(--mono); font-size: 11px; letter-spacing:.05em; color: var(--muted); text-transform: uppercase; }

/* responsive ------------------------------------------------- */
@media (max-width: 900px) {
  .hero { grid-template-columns: 1fr; }
  .hero .side { border-left: none; padding-left: 0; border-top: 1px solid var(--line); padding-top: 22px; }
  .hero .lead .h-display { font-size: 34px; }
  .latest { grid-template-columns: repeat(2,1fr); }
  .grid3, .qa { grid-template-columns: 1fr 1fr; }
  .cols2 { grid-template-columns: 1fr; gap: 8px; }
  .promo .wrap { grid-template-columns: 1fr; }
  nav.cats ul { display: none; }
  nav.cats ul.open { display: flex; flex-direction: column; gap: 0; }
  nav.cats ul.open li { border-top: 1px solid var(--line); }
  .navtoggle { display: inline-block; }
}
@media (max-width: 560px) {
  .latest, .grid3, .qa { grid-template-columns: 1fr; }
  .hero .lead .h-display { font-size: 30px; }
  .article-head .h-display { font-size: 28px; }
}
@media (prefers-reduced-motion: reduce) { * { scroll-behavior: auto; } }

/* ===== NEWS TICKER ===== */
.ticker{display:flex;align-items:stretch;background:var(--paper);border-bottom:1px solid var(--line);font-family:var(--display);font-weight:500;font-size:14px;letter-spacing:0;overflow:hidden}
/* the label stays mono, like every other small uppercase label on the site */
.ticker-tag{background:var(--accent);color:var(--on-accent);display:flex;align-items:center;padding:0 14px;font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.14em;white-space:nowrap;font-weight:600;flex:none}
.ticker-view{overflow:hidden;position:relative;flex:1}
.ticker-track{display:inline-flex;white-space:nowrap;padding:9px 0;animation:ticker var(--ticker-speed) linear infinite;will-change:transform}
.ticker-track span{padding:0 16px;color:var(--ink)}
.ticker-track .sep{color:var(--accent);padding:0}
.ticker-track a{color:inherit;text-decoration:none}
.ticker-track a:hover span{color:var(--accent)}
.ticker:hover .ticker-track{animation-play-state:paused}
@keyframes ticker{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media (prefers-reduced-motion: reduce){.ticker-track{animation:none}}

/* ===== PLACEHOLDER PICTURES (self-contained SVG, no external files) ===== */
:root{
  --img-radar:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='400' height='400'><rect width='400' height='400' fill='%230b1a1e'/><g fill='none' stroke='%233ad07f' stroke-width='1.4' opacity='0.55'><circle cx='200' cy='200' r='60'/><circle cx='200' cy='200' r='120'/><circle cx='200' cy='200' r='180'/><line x1='20' y1='200' x2='380' y2='200'/><line x1='200' y1='20' x2='200' y2='380'/></g><path d='M200 200 L200 30 A170 170 0 0 1 330 120 Z' fill='%233ad07f' opacity='0.16'/><g fill='%2371f0a8'><circle cx='250' cy='140' r='4'/><circle cx='150' cy='260' r='3'/><circle cx='285' cy='235' r='3'/></g></svg>");
  --img-drone:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='800' height='450'><defs><linearGradient id='s' x1='0' y1='0' x2='0' y2='1'><stop offset='0' stop-color='%23c3d6e6'/><stop offset='1' stop-color='%237e9ab2'/></linearGradient></defs><rect width='800' height='450' fill='url(%23s)'/><rect y='372' width='800' height='78' fill='%2360778e' opacity='0.55'/><g fill='%231b2430'><rect x='362' y='206' width='76' height='22' rx='6'/><rect x='250' y='196' width='300' height='6'/><circle cx='258' cy='196' r='9'/><circle cx='542' cy='196' r='9'/><circle cx='344' cy='196' r='9'/><circle cx='456' cy='196' r='9'/><ellipse cx='258' cy='190' rx='32' ry='5' opacity='0.45'/><ellipse cx='542' cy='190' rx='32' ry='5' opacity='0.45'/><ellipse cx='344' cy='190' rx='32' ry='5' opacity='0.45'/><ellipse cx='456' cy='190' rx='32' ry='5' opacity='0.45'/><rect x='388' y='228' width='5' height='24'/><rect x='407' y='228' width='5' height='24'/></g></svg>");
  --img-sea:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='600' height='400'><defs><linearGradient id='k' x1='0' y1='0' x2='0' y2='1'><stop offset='0' stop-color='%23aebfcb'/><stop offset='0.55' stop-color='%237d94a5'/><stop offset='0.56' stop-color='%23274050'/><stop offset='1' stop-color='%23162a36'/></linearGradient></defs><rect width='600' height='400' fill='url(%23k)'/><g fill='%230f1f28'><rect x='210' y='196' width='180' height='20'/><path d='M210 216 L390 216 L360 236 L240 236 Z'/><rect x='250' y='170' width='60' height='26'/><rect x='320' y='178' width='16' height='18'/></g><g stroke='%23bcceda' opacity='0.22'><line x1='0' y1='250' x2='600' y2='250'/><line x1='0' y1='300' x2='600' y2='300'/></g></svg>");
  --img-sat:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='400' height='400'><rect width='400' height='400' fill='%230a0f1e'/><g fill='%23ffffff' opacity='0.7'><circle cx='60' cy='70' r='1.5'/><circle cx='320' cy='50' r='1.5'/><circle cx='140' cy='120' r='1'/><circle cx='360' cy='200' r='1.5'/><circle cx='90' cy='300' r='1'/></g><circle cx='120' cy='330' r='150' fill='%231c3a6e' opacity='0.5'/><g fill='%23c9d3e0'><rect x='230' y='150' width='40' height='24' rx='3'/><rect x='196' y='156' width='30' height='12'/><rect x='274' y='156' width='30' height='12'/></g></svg>");
  --img-compute:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='400' height='300'><rect width='400' height='300' fill='%23111826'/><g stroke='%234a7dff' stroke-width='1.3' fill='none' opacity='0.6'><path d='M40 60 H160 V140 H300'/><path d='M40 150 H120 V230 H360'/><path d='M200 40 V120 H340'/></g><g fill='%236f9dff'><rect x='150' y='120' width='40' height='40' rx='4' opacity='0.85'/><circle cx='40' cy='60' r='4'/><circle cx='300' cy='140' r='4'/><circle cx='360' cy='230' r='4'/><circle cx='340' cy='120' r='4'/></g></svg>");
  --img-map:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='400' height='300'><rect width='400' height='300' fill='%23e7e1d4'/><g fill='none' stroke='%23a89f89' stroke-width='1.3' opacity='0.8'><path d='M-20 90 Q120 40 200 90 T420 80'/><path d='M-20 130 Q120 80 200 130 T420 120'/><path d='M-20 175 Q120 125 210 175 T420 165'/><path d='M-20 220 Q140 170 210 220 T420 210'/></g><circle cx='210' cy='150' r='5' fill='%23c4271c'/></svg>");
  --img-wave:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='400' height='225'><rect width='400' height='225' fill='%23161a26'/><g fill='%234a7dff'><rect x='24' y='92' width='8' height='40'/><rect x='41' y='77' width='8' height='70'/><rect x='58' y='57' width='8' height='110'/><rect x='75' y='37' width='8' height='150'/><rect x='92' y='67' width='8' height='90'/><rect x='109' y='82' width='8' height='60'/><rect x='126' y='47' width='8' height='130'/><rect x='143' y='27' width='8' height='170'/><rect x='160' y='62' width='8' height='100'/><rect x='177' y='85' width='8' height='55'/><rect x='194' y='52' width='8' height='120'/><rect x='211' y='32' width='8' height='160'/><rect x='228' y='65' width='8' height='95'/><rect x='245' y='80' width='8' height='65'/><rect x='262' y='42' width='8' height='140'/><rect x='279' y='22' width='8' height='180'/><rect x='296' y='57' width='8' height='110'/><rect x='313' y='77' width='8' height='70'/><rect x='330' y='47' width='8' height='130'/><rect x='347' y='37' width='8' height='150'/><rect x='364' y='67' width='8' height='90'/><rect x='381' y='87' width='8' height='50'/></g></svg>");
  --img-portrait:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='400' height='300'><rect width='400' height='300' fill='%23b5432f'/><circle cx='200' cy='120' r='58' fill='%23e9e3d8'/><path d='M110 300 C110 210 290 210 290 300 Z' fill='%23e9e3d8'/></svg>");
}
.ph { background-image: var(--img-radar); }


/* ===== PAYWALL GATE =====
   Lifted from mockups/paywall.html once the design settled. The gate
   is what a reader sees in place of a paid article's body; the body
   itself is never written to the page. ===== */
  /* ---- teaser: article fades out into the paywall ---------------------- */
  .teaser { position: relative; max-width: 74ch; }
  /* Sized to swallow the second paragraph while leaving the first one fully
     legible, so the free excerpt is exactly one paragraph. */
  .teaser .fade {
    position: absolute; left: 0; right: 0; bottom: 0; height: 132px;
    background: linear-gradient(to bottom, rgba(245,243,238,0) 0%, var(--paper) 72%);
    pointer-events: none;
  }

  /* ---- the gate -------------------------------------------------------- */
  .gate {
    border: 1.5px solid var(--ink);
    background: var(--paper);
    max-width: 74ch;
    /* auto sides so the gate sits centred in the page rather than aligned to
       the article column it interrupts */
    margin: -30px auto 60px;
    position: relative;
    text-align: center;
    padding: 8px 34px 34px;
  }
  .gate h2 {
    font-family: var(--display); font-weight: 600;
    font-size: 27px; line-height: 1.15; margin: 4px 0 10px;
  }
  .gate .sub { color: #40434B; margin: 0 auto 4px; max-width: 46ch; font-size: 17px; }

  /* ---- drone crash ----------------------------------------------------- */
  /* The box has to fit the whole fall plus clearance, otherwise the drone
     ends up sitting on the headline. */
  .crash { width: 200px; height: 216px; margin: 6px auto 14px; position: relative; }
  .crash svg { overflow: visible; display: block; }

  /* Plays once and stops. The wreck is the resting state of the page, so
     nothing loops in the reader's peripheral vision while they weigh up a
     subscription. Impact lands at 71.5% of 5.4s, about 3.86s in. */
  .drone      { animation: fall 5.4s cubic-bezier(.5,0,.75,1) forwards; transform-origin: 50% 50%; }

  /* Fast while flying, then slow for good: 32 turns at .12s reaches 3.84s,
     where the slow spin picks up. This is the rotor left pointing skyward. */
  .rotor-good { animation: spin .12s linear 0s 32, spinSlow 2.8s linear 3.84s infinite; }
  .rotor-dead { animation: sputter 5.4s linear forwards; }

  .puff { animation: puff 5.4s ease-out forwards; transform-origin: 50% 100%; opacity: 0; }

  /* disturbed earth where the airframe went in */
  .mound { opacity: 0; animation: moundIn 5.4s linear forwards; }
  @keyframes moundIn {
    0%, 71.5% { opacity: 0; }
    76%, 100% { opacity: 1; }
  }

  .boom-core, .boom-ring, .boom-spikes {
    transform-box: fill-box; transform-origin: 50% 50%; opacity: 0;
  }
  .boom-core   { animation: boomCore   5.4s ease-out forwards; }
  .boom-ring   { animation: boomRing   5.4s ease-out forwards; }
  .boom-spikes { animation: boomSpikes 5.4s ease-out forwards; }

  /* Hover, rotor dies, spiral down, blast, then the wreck is left behind.
     The drone blanks out under the flash and reappears as the flash fades,
     so it reads as having been blown apart rather than simply landing. */
  /* Scaled to 0.8 throughout. At full size, rotating a shape this wide makes
     it tall enough that burying half of it would push the nose past the
     headline. Ground line sits at y=170; the drone's centre finishes on it,
     which is what puts exactly half below ground. */
  @keyframes fall {
    0%   { transform: translate(0,0) rotate(0deg) scale(.8); opacity: 1; }
    14%  { transform: translate(0,-5px) rotate(0deg) scale(.8); }     /* hovering */
    22%  { transform: translate(-4px,-1px) rotate(-7deg) scale(.8); } /* rotor quits */
    32%  { transform: translate(6px,10px) rotate(12deg) scale(.8); }
    44%  { transform: translate(-7px,26px) rotate(-20deg) scale(.8); }
    56%  { transform: translate(8px,42px) rotate(26deg) scale(.8); }
    66%  { transform: translate(-3px,48px) rotate(-30deg) scale(.8); }
    71.5% { transform: translate(1px,51px) rotate(50deg) scale(.8); opacity: 1; } /* touches down */
    73%  { transform: translate(2px,70px) rotate(50deg) scale(.8); opacity: 0; }  /* driven in, under the flash */
    80%  { transform: translate(2px,83px) rotate(50deg) scale(.8); opacity: 1; } /* half buried, revealed */
    100% { transform: translate(2px,83px) rotate(50deg) scale(.8); opacity: 1; } /* and it stays */
  }
  @keyframes spin   { to { transform: rotate(360deg); } }
  /* one rotor coughs, stalls, and stops */
  @keyframes sputter {
    0%   { transform: rotate(0deg); }
    18%  { transform: rotate(900deg); }
    21%  { transform: rotate(960deg); }
    24%  { transform: rotate(975deg); }
    30%, 100% { transform: rotate(978deg); }
  }
  @keyframes puff {
    0%, 70%   { opacity: 0; transform: scale(.25); }
    74%       { opacity: .85; transform: scale(1); }
    88%, 100% { opacity: 0; transform: scale(1.7); }
  }
  /* the surviving rotor, freewheeling in the wreckage */
  @keyframes spinSlow { to { transform: rotate(360deg); } }
  @keyframes boomCore {
    0%, 71%   { opacity: 0; transform: scale(.2); }
    73%       { opacity: 1; transform: scale(1); }
    77%       { opacity: .75; transform: scale(1.25); }
    83%, 100% { opacity: 0; transform: scale(1.45); }
  }
  @keyframes boomRing {
    0%, 71%   { opacity: 0; transform: scale(.3); }
    74%       { opacity: .65; }
    86%, 100% { opacity: 0; transform: scale(2.3); }
  }
  @keyframes boomSpikes {
    0%, 71%   { opacity: 0; transform: scale(.3); }
    74%       { opacity: 1; transform: scale(1); }
    81%, 100% { opacity: 0; transform: scale(1.55); }
  }

  /* Held at the first frame until the reader scrolls to it, so the crash
     isn't already over by the time they arrive. Pausing rather than swapping
     the animation keeps every timing above intact, delays included. */
  .crash * { animation-play-state: paused; }
  .crash.is-playing * { animation-play-state: running; }

  /* Motion is decorative. Skip straight to the wreck, which is where the
     animation ends up anyway, and leave the rotor still. */
  @media (prefers-reduced-motion: reduce) {
    .drone { animation: none; transform: translate(2px,83px) rotate(50deg) scale(.8); opacity: 1; }
    .rotor-good, .rotor-dead { animation: none; opacity: .5; }
    .puff { animation: none; opacity: .45; transform: scale(1); }
    .mound { animation: none; opacity: 1; }
    .boom-core, .boom-ring, .boom-spikes { animation: none; opacity: 0; }
  }

  /* ---- pricing --------------------------------------------------------- */
  .plans { display: grid; grid-template-columns: repeat(3,1fr); gap: 14px; margin: 26px 0 6px; text-align: left; }
  .plan { border: 1px solid var(--line); padding: 20px 18px 22px; background: #fff; display: flex; flex-direction: column; }
  .plan.pick { border: 1.5px solid var(--accent); position: relative; }
  .plan .flag {
    position: absolute; top: -1px; right: -1px;
    background: var(--accent); color: var(--on-accent);
    font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em;
    text-transform: uppercase; padding: 4px 8px;
  }
  .plan .name { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
  .plan .price { font-family: var(--display); font-weight: 700; font-size: 30px; line-height: 1; margin: 12px 0 2px; letter-spacing: -.02em; }
  .plan .price small { font-family: var(--display); font-weight: 500; font-size: 13px; letter-spacing: 0; color: var(--muted); }
  .plan .then { font-family: var(--mono); font-size: 10.5px; color: var(--muted); margin-bottom: 14px; min-height: 15px; }
  .plan ul { list-style: none; margin: 0 0 18px; padding: 0; font-size: 14.5px; flex: 1; }
  .plan li { padding: 5px 0 5px 17px; position: relative; color: #40434B; line-height: 1.35; }
  .plan li::before { content: ""; position: absolute; left: 0; top: 12px; width: 7px; height: 1.5px; background: var(--accent); }
  .plan .btn { width: 100%; text-align: center; }
  .plan .btn.ghost { background: transparent; color: var(--ink); border: 1.5px solid var(--ink); }

  .gate .signin { font-size: 14.5px; color: var(--muted); margin: 18px 0 0; }
  .gate .signin a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
  .gate .smallprint { font-family: var(--mono); font-size: 10px; letter-spacing: .04em; color: var(--muted); margin: 16px 0 0; }

  @media (max-width: 720px) {
    .plans { grid-template-columns: 1fr; }
    .gate { padding: 8px 20px 26px; }
    .gate h2 { font-size: 22px; }
  }
.premium-tag{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--on-accent);background:var(--accent);padding:2px 6px;margin-left:8px;vertical-align:2px}

/* Premium marker beside a paid headline in listings. Deliberately quieter
   than the badge on the article page itself: in a list it is a label, not a
   heading. */
.premium-dot{
  display:inline-block; vertical-align:2px; margin-left:8px;
  font-family:var(--mono); font-size:9px; letter-spacing:.1em;
  text-transform:uppercase; color:var(--on-accent);
  background:var(--accent); padding:2px 5px;
}

/* sign-in form */
#signin-form { max-width: 34rem; margin: 6px 0 18px; }
#signin-form label { display:block; font-family:var(--mono); font-size:11px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--muted); margin-bottom:7px; }
#signin-form input { width:100%; padding:13px 14px; border:1.5px solid var(--ink);
  background:#fff; font-family:var(--serif); font-size:16px; margin-bottom:12px; }
/* The profile fields space themselves off their labels and carry no bottom
   margin, so without this the button sits flush against the last one. */
#signin-form .btn { cursor:pointer; margin-top:22px; }
#signin-form .note { font-size:15px; color:var(--muted); margin:12px 0 0; min-height:1.4em; }

/* social sign-in + profile questions */
#auth-social { max-width:34rem; margin:6px 0 4px; }
#auth-social .oauth { display:block; width:100%; text-align:center; margin-bottom:10px; cursor:pointer; }
#auth-social .or { font-family:var(--mono); font-size:11px; letter-spacing:.1em;
  text-transform:uppercase; color:var(--muted); text-align:center; margin:16px 0 10px; }
#profile-fields { margin:2px 0 0; }
#profile-fields label { display:block; font-family:var(--mono); font-size:11px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--muted); margin:16px 0 7px; }
#profile-fields input, #profile-fields select { width:100%; padding:13px 14px;
  border:1.5px solid var(--ink); background:#fff; font-family:var(--serif); font-size:16px; }

#profile-fields .lead { font-size:15px; color:var(--muted); margin:0 0 14px; }
#auth-social .oauth[disabled] { opacity:.45; cursor:not-allowed; }
#auth-social .soon { font-size:14px; color:var(--muted); margin:2px 0 0; }

/* Sign-in page: centre the whole column. Scoped with :has() so the other
   standalone pages (About, Contact) keep their normal left-aligned reading
   measure, where centred body text would be harder to read. */
.standalone .article-head:has(+ .article-body #signin-form),
.standalone .article-body:has(#signin-form) { margin-inline: auto; text-align: center; }
.standalone .article-body:has(#signin-form) > p { max-width: 46ch; margin-inline: auto; }
#auth-social, #signin-box { margin-inline: auto; }
#signin-form label, #profile-fields label { text-align: left; }
#profile-fields { text-align: left; }
/* the form's own `margin: 6px 0 18px` was overriding the centring above */
#signin-form { margin-inline: auto; max-width: 34rem; }

/* share + save row under the byline */
.tools { display:flex; flex-wrap:wrap; align-items:center; gap:10px; margin:16px 0 0;
  padding-top:14px; border-top:1px solid var(--line); }
.tools-label { font-family:var(--mono); font-size:10px; letter-spacing:.12em;
  text-transform:uppercase; color:var(--muted); }
.share { display:inline-flex; align-items:center; justify-content:center;
  /* flex items shrink by default, which was collapsing these to the width of
     the icon and losing the square button */
  flex:0 0 auto; width:32px; height:32px; color:var(--ink); border:1px solid var(--line);
  background:#fff; cursor:pointer; padding:0; transition:color .12s, border-color .12s; }
.share:hover { color:var(--accent); border-color:var(--accent); }
.share svg { display:block; }
.share.is-saved { background:var(--accent); color:var(--on-accent); border-color:var(--accent); }
.share.copied { color:var(--accent); border-color:var(--accent); }
#profile-fields .opt { font-family:var(--mono); font-size:9.5px; letter-spacing:.08em;
  color:var(--muted); text-transform:uppercase; margin-left:6px; }
/* sign-in mode switches */
#signin-form .alt { margin:14px 0 0; font-size:14px; color:var(--muted); }
#signin-form .linky { background:none; border:none; padding:0; cursor:pointer;
  font-family:var(--serif); font-size:14px; color:var(--accent);
  text-decoration:underline; text-underline-offset:3px; }
#signin-form .sepdot { color:var(--line); margin:0 6px; }
/* these wrap block-level rows, so spell the hiding out rather than
   relying on the UA [hidden] rule surviving any later display change */
#pw-row[hidden], #email-row[hidden], #profile-fields[hidden], .alt[hidden] { display:none; }

/* confirmation + account pages */
#confirm-wait .big { font-size:19px; }
#confirm-wait .note { color:var(--muted); font-size:15px; }
.acct-block { border-top:1px solid var(--line); padding-top:22px; margin-top:30px; }
.acct-block:first-child { border-top:none; margin-top:0; padding-top:0; }
.acct-block h2 { font-family:var(--display); font-weight:700; font-size:14px;
  letter-spacing:.14em; text-transform:uppercase; margin:0 0 14px; }
.acct-line { margin:0 0 6px; color:#33363E; }
#account-body .btn { margin-top:14px; }
.acct-actions { display:flex; gap:12px; flex-wrap:wrap; align-items:center; }
.acct-actions .btn { margin-top:14px; }
.plans .plan .btn[disabled] { opacity:.5; cursor:not-allowed; }
.pay-note { border:1px solid var(--line); padding:12px 14px; background:#fff; }

/* contact and advertise forms ------------------------------------------- */
.pageform { max-width: 34rem; margin: 22px 0 10px; }
.pageform label { display:block; font-family:var(--mono); font-size:11px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--muted);
  margin:18px 0 7px; }
.pageform input, .pageform select, .pageform textarea {
  width:100%; padding:13px 14px; border:1.5px solid var(--ink); background:#fff;
  font-family:var(--serif); font-size:16px; color:var(--ink); }
.pageform textarea { line-height:1.5; resize:vertical; min-height:120px; }
.pageform .btn { margin-top:22px; cursor:pointer; }
.pageform .opt { font-family:var(--mono); font-size:9.5px; letter-spacing:.08em;
  color:var(--muted); text-transform:uppercase; margin-left:6px; }
/* The honeypot. Hidden from people, still filled in by the kind of bot that
   fills every field, which is what flags the submission as spam. Not
   display:none, because some bots skip those. */
.pageform .hp { position:absolute; left:-9999px; width:1px; height:1px;
  overflow:hidden; }

/* remove an article from the saved list, on the account page. Quiet by
   default so it never competes with the headline it sits under. */
.unsave { background:none; border:none; padding:0; margin:8px 0 0; cursor:pointer;
  font-family:var(--mono); font-size:11px; letter-spacing:.08em;
  text-transform:uppercase; color:var(--muted); }
.unsave:hover { color:var(--accent); }
.unsave[disabled] { opacity:.5; cursor:default; }

/* A button that happens to be a link, inside body copy. `.article-body a`
   paints links in the accent colour, which outranks `.btn` and rendered the
   label the same blue as its own background: an invisible button. */
.article-body a.btn { color: var(--on-accent); text-decoration: none; }
.article-body a.btn.ghost { color: var(--ink); }
.article-body a.btn:hover { text-decoration: none; }

/* Share sits left with its label, save sits alone on the right, all buttons
   the same size. Save is set apart by position rather than by being bigger. */
.tools { justify-content:space-between; }
.tools-share { display:flex; flex-wrap:wrap; align-items:center; justify-content:flex-start; gap:10px; }
.save-article {
  flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center;
  width:32px; height:32px; padding:0; cursor:pointer;
  background:#fff; border:1px solid var(--line); color:var(--ink);
  transition:color .12s, border-color .12s;
}
/* `display:inline-flex` above outranks the browser's own `[hidden]{display:none}`,
   so without this the button still rendered for signed-out readers, who have
   nowhere to save to. */
.save-article[hidden] { display:none; }
.save-article:hover { color:var(--accent); border-color:var(--accent); }
/* one path, two states: outline until saved, then filled in */
.save-article svg { width:17px; height:17px; display:block; }
.save-article svg path { fill:none; stroke:currentColor; stroke-width:1.8;
  stroke-linejoin:round; }
.save-article.is-saved { color:var(--accent); border-color:var(--accent); }
.save-article.is-saved svg path { fill:currentColor; }

/* search ----------------------------------------------------------------- */
.visually-hidden { position:absolute; width:1px; height:1px; margin:-1px;
  padding:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
/* the nav row is a flex list; the box sits at its end and stays out of the
   way until used */
nav.cats { display:flex; align-items:center; justify-content:space-between; gap:20px; }
nav.cats ul { flex:1 1 auto; }
.navsearch { flex:0 0 auto; margin:0; display:flex; align-items:center;
  justify-content:flex-end; }
/* Collapsed to the icon until asked for. Width rather than display:none, so
   the field is still focusable the moment it opens and the transition has
   something to animate. */
.navsearch input { width:0; min-width:0; padding:6px 0; border:1px solid transparent;
  background:#fff; font-family:var(--serif); font-size:14px; color:var(--ink);
  opacity:0; transition:width .18s ease, opacity .14s ease, padding .18s ease; }
.navsearch.open input { width:210px; padding:6px 10px; opacity:1;
  border-color:var(--ink); }
.navsearch input:focus { outline:none; }
.navsearch input::placeholder { color:var(--muted); }
.navsearch-btn { flex:0 0 auto; display:inline-flex; align-items:center;
  justify-content:center; width:34px; height:34px; margin-left:6px; padding:0;
  background:none; border:none; cursor:pointer; color:var(--ink);
  transition:color .12s; }
.navsearch-btn:hover { color:var(--accent); }
.navsearch-btn svg { width:19px; height:19px; display:block; }
.navsearch.open .navsearch-btn { color:var(--accent); }

.searchpage { display:flex; gap:10px; align-items:center; max-width:34rem;
  margin:0 0 6px; }
.searchpage label { position:absolute; width:1px; height:1px; overflow:hidden;
  clip:rect(0 0 0 0); }
.searchpage input { flex:1 1 auto; padding:13px 14px; border:1.5px solid var(--ink);
  background:#fff; font-family:var(--serif); font-size:16px; color:var(--ink); }
.searchpage .btn { flex:0 0 auto; margin-top:0; cursor:pointer; }
#search-results .feedlist article { grid-template-columns:1fr; }
#search-results .snip { margin:8px 0 0; font-size:15px; line-height:1.5;
  color:#33363E; }
#search-results mark { background:#FDF3B4; color:inherit; padding:0 1px; }

@media (max-width: 700px) {
  /* toggle on the left, magnifier on the right, one row. The field opens
     across whatever width is going rather than pushing itself onto a
     second line. */
  nav.cats { flex-wrap: nowrap; gap: 12px; }
  .navsearch.open input { width: 46vw; }
  .navsearch-panel { width: 88vw; }
}

/* the header search dropdown */
.navsearch { position:relative; }
.navsearch-panel { position:absolute; top:calc(100% + 6px); right:0; z-index:40;
  width:360px; max-width:78vw; background:#fff; border:1px solid var(--ink);
  padding:4px; }
.navsearch-panel[hidden] { display:none; }
.navsearch-hit { display:block; padding:9px 10px; border-bottom:1px solid var(--line);
  text-decoration:none; }
.navsearch-hit:last-of-type { border-bottom:none; }
.navsearch-hit:hover, .navsearch-hit.on { background:var(--paper); }
.navsearch-cat { font-family:var(--mono); font-size:9.5px; letter-spacing:.12em;
  text-transform:uppercase; color:var(--accent); }
.navsearch-title { display:block; margin:3px 0 2px; font-family:var(--display);
  font-weight:500; font-size:14.5px; line-height:1.25; color:var(--ink); }
.navsearch-date { font-family:var(--mono); font-size:10px; color:var(--muted); }
.navsearch-empty { margin:0; padding:12px 10px; font-size:14px; color:var(--muted); }
.navsearch-all { display:block; padding:9px 10px; border-top:1px solid var(--ink);
  font-family:var(--mono); font-size:10.5px; letter-spacing:.1em;
  text-transform:uppercase; color:var(--accent); }
.navsearch-all:hover { background:var(--paper); }
.navsearch-panel mark { background:#FDF3B4; color:inherit; padding:0 1px; }

/* nameplate: the mark beside the name -------------------------------------- */
.nameplate { display:inline-flex; align-items:center; gap:20px; }
/* The drawing is tall and narrow, roughly 1:2.3, so height drives it and the
   ratio sets the width. It needs this much height to read as a figure: at
   58px it was 25px wide and turned into an unidentifiable squiggle. */
.mastlogo { height:150px; width:auto; display:block; flex:0 0 auto; }
.mastlogo.small { height:84px; }
/* A didone for the nameplate only. Headlines and UI stay Space Grotesk: this
   is the masthead's voice, not a second body face. */



/* masthead proportions ---------------------------------------------------- */
/* The name and the strapline are one block beside the mark, so the strapline
   sits under the name rather than under the whole lockup. Centre alignment
   keeps the buttons on the lockup's axis; baseline left them stranded low. */
.masthead { align-items: center; padding: 20px 0 18px; }
.nameplate { gap: 18px; align-items: center; }
.brandtext { display: flex; flex-direction: column; gap: 7px; }
.masthead .tagline { margin: 0; }
.mastlogo { height: 118px; }
.mastlogo.small { height: 72px; }

@media (max-width: 900px) {
  .masthead { align-items: flex-start; gap: 16px; }
  .mastlogo { height: 92px; }
  .masthead .wordmark { font-size: 34px; }
}
@media (max-width: 700px) {
  /* Name and drawing stay side by side all the way down: clamp has already
     shrunk both, so there is no need to stack them. */
  .masthead { flex-direction: row; align-items: center; gap: 16px;
              padding: 14px 0 12px; }
  .nameplate { gap: 14px; }
  .mastlogo { height: 76px; }
  .masthead .wordmark { font-size: 31px; }
  .brandtext { gap: 5px; }
  .masthead .tagline { font-size: 10px; letter-spacing: .09em; }
  nav.cats a { font-size: 15px; }
}
@media (max-width: 380px) {
  .mastlogo { height: 64px; }
  .masthead .wordmark { font-size: 26px; }
  /* an open field was squeezing SECTIONS onto two lines */
  .navsearch.open input { width: 36vw; }
}

/* the banner masthead ------------------------------------------------------ */
/* The artwork is 2.8:1 with a tall sword, so full width would make a 420px
   header. Height drives it instead, and the strapline stays as real text:
   baked into the image it was 2.4% of the height, which is 4px here. */
.brand { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.mastbanner { height: 200px; width: auto; display: block; max-width: 100%; }
.masthead .tagline { margin: 0; }
/* Height rather than width: at the wrap's full 1180px this artwork would be
   420px tall and push the whole front page below the fold. */
@media (max-width: 1100px) { .mastbanner { height: 168px; } }
@media (max-width: 900px)  { .mastbanner { height: 140px; } }
@media (max-width: 700px)  { .mastbanner { height: 112px; } }
@media (max-width: 380px)  { .mastbanner { height: 92px; } }

/* nameplate centred, controls in the nav row ------------------------------- */
/* The banner is a wide lockup. Sitting it left with the buttons far right
   left a dead gap across the middle; centred, it reads as a nameplate and
   the nav row carries the controls. */
.masthead { justify-content: center; padding: 26px 0 18px; }
.brand { align-items: center; gap: 10px; }
.masthead .tagline { text-align: center; }
.mastbanner { height: 210px; }

nav.cats { gap: 18px; }
nav.cats .actions { flex: 0 0 auto; margin-left: auto; gap: 10px; }
nav.cats .actions .btn { font-size: 12px; padding: 8px 14px; }
.navsearch { margin-left: 0; }

@media (max-width: 1100px) { .mastbanner { height: 176px; } }
@media (max-width: 900px) {
  .mastbanner { height: 148px; }
  /* Two tidy rows: the sections toggle with the magnifier beside it, then
     the buttons. Left to itself the search fell below the buttons and sat
     alone on a third line. */
  nav.cats { flex-wrap: wrap; row-gap: 10px; padding-bottom: 12px; }
  .navtoggle { order: 1; }
  .navsearch { order: 2; margin-left: auto; }
  nav.cats ul { order: 4; width: 100%; }
  nav.cats .actions { order: 3; width: 100%; margin-left: 0; gap: 10px; }
  nav.cats .actions .btn { flex: 1 1 0; text-align: center; }
}
@media (max-width: 700px) {
  .masthead { padding: 18px 0 14px; }
  .mastbanner { height: 118px; }
  nav.cats .actions .btn { font-size: 12px; padding: 8px 12px; }
}
@media (max-width: 380px) { .mastbanner { height: 96px; } }

/* masthead: name left, drawing right --------------------------------------- */
/* Two images rather than one banner, so the name and the strapline can share
   a left edge and the drawing can sit apart on the right. Both sized with
   clamp so they shrink with the viewport instead of stepping at breakpoints. */
.masthead { justify-content: space-between; align-items: center; gap: 24px;
            padding: 22px 0 18px; }
.brand { align-items: flex-start; gap: 12px; }
.masthead .tagline { text-align: left; }
.mastwordmark { height: clamp(44px, 6.4vw, 92px); width: auto; display: block; }
.mastfigure   { height: clamp(72px, 11vw, 176px); width: auto; display: block;
                flex: 0 0 auto; }

/* one centred lockup ------------------------------------------------------- */
/* The mark and the name arrive as a single 3.3:1 artwork, so it is centred
   as a nameplate with the strapline under it. Sized with clamp, so it
   shrinks continuously rather than stepping at breakpoints. */
.masthead { justify-content: center; align-items: center; padding: 20px 0 16px; }
.brand { align-items: center; gap: 10px; }
.masthead .tagline { text-align: center; }
.mastlockup { height: clamp(66px, 12vw, 184px); width: auto; display: block;
              max-width: 100%; }

/* search to the left of the buttons */
nav.cats .navsearch { margin-left: auto; }
nav.cats .actions { margin-left: 0; }
@media (max-width: 900px) {
  nav.cats .navsearch { order: 2; margin-left: auto; }
  nav.cats .actions { order: 3; }
}


/* the lockup again in the footer, so the brand is one artwork everywhere */
.footlockup { height: 62px; width: auto; display: block; }
@media (max-width: 700px) { .footlockup { height: 50px; } }

/* figures inside an article ----------------------------------------------- */
/* Figures sit at the reading measure. The lead image above the article is
   already full width, so the contrast between a wide opener and narrower
   figures in the text is the intended rhythm, not an oversight. */
.article-body figure { margin: 34px 0; }
.article-body figure img { width: 100%; height: auto; display: block; }
.article-body figcaption { font-family: var(--mono); font-size: 11px;
  line-height: 1.5; letter-spacing: .02em; color: var(--muted);
  margin-top: 10px; max-width: 74ch; }
