/* ------------------------------------------------------------------
   Self-hosted fonts. Previously loaded from fonts.googleapis.com, which
   transmitted every visitor's IP to Google on page load (a GDPR concern in
   the EU/UK). Serving the files ourselves removes that third-party request
   entirely — and is faster, with no extra DNS/TLS round trip. Both families
   are variable fonts; the weight range covers every weight the site uses
   (Inter 400–700, EB Garamond 400–700 roman / 400–600 italic). Latin and
   Latin-Extended subsets only — enough for the English copy and accented
   names. Files live in assets/fonts/; URLs are relative to this stylesheet.
   ------------------------------------------------------------------ */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'EB Garamond';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('fonts/ebgaramond-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'EB Garamond';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('fonts/ebgaramond-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'EB Garamond';
  font-style: italic;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/ebgaramond-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'EB Garamond';
  font-style: italic;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/ebgaramond-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --deep-navy: #0B0A6E;
  --blueprint-indigo: #121479;
  --electric-blue: #0000C0;
  --vitruvian-chalk: #D3F3FF;
  --bone: #F4F1E8;
  --signal-amber: #B8860B;
  --slate: #4A5563;
  --white: #FFFFFF;

  /* Surfaces. Large fields are deliberately LOW chroma so the saturated brand
     colours — the neon mark, Electric Blue, Signal Amber — are the only
     high-chroma things on screen and actually read as accents. The previous
     values ran 72–83% saturation, which flattened everything against them.
     These keep a faint cool cast so the blueprint character survives. */
  --ink: #0B0D13;            /* page background */
  --ink-soft: #10131B;       /* section alternate */
  --panel: #161A24;          /* card fill */
  --line: #272C39;           /* borders */
  --surface-deep: #161A26;   /* footer, support CTA */
  --surface-band: #1B2130;   /* in-article CTA band */
  --chalk-dim: rgba(211, 243, 255, 0.72);

  /* Light-surface tokens, derived by shading/tinting Slate per the guidelines'
     "no new colors" rule. The palette names Slate as *secondary* text, so a
     darker shade is needed for primary body copy on white. */
  --body-ink: #21252B;       /* Slate shaded — body text on white */
  --rule-light: #D9DCE1;     /* Slate tinted — hairlines on white */

  --serif: 'EB Garamond', Garamond, 'Cormorant Garamond', Georgia, serif;
  /* Inter first, and it is the face actually downloaded. The previous stack led
     with Calibri while the page fetched Source Sans 3, so Windows visitors got
     Calibri, Mac visitors got Source Sans 3, and the download was wasted for
     anyone with Office installed. */
  --sans: 'Inter', 'Source Sans 3', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono: Consolas, 'SF Mono', Menlo, monospace;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  background: var(--ink);
  color: var(--vitruvian-chalk);
  font-family: var(--sans);
  font-size: 1.05rem;
  line-height: 1.6;
}

.wrap {
  max-width: 880px;
  margin: 0 auto;
  padding: 0 24px;
}

/* Masthead */
.masthead {
  background: var(--ink);
  border-bottom: 3px solid var(--signal-amber);
}

.masthead .wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 16px;
  padding-top: 14px;
  padding-bottom: 14px;
}

.masthead .brand {
  display: block;
  line-height: 0;
}

.masthead .brand img {
  /* iu-logo.png is the supplied header lockup with its padding trimmed. The
     baked tagline is 11.3% of the artwork height, so the box needs to reach
     ~100px for that line to render at a readable ~11px. */
  height: clamp(72px, 8vw, 100px);
  width: auto;
  display: block;
  /* The logo PNG has no alpha — it carries a solid black background. `screen`
     drops black to fully transparent while leaving the neon strokes intact, so
     the artwork sits on the masthead without a visible box around it. */
  mix-blend-mode: screen;
  /* The neon is blue, which reads dimmer than pure-white heading text at equal
     "brightness"; this lifts the strokes to match. Measured: core luminance
     205 → 247, vs white text at 255. */
  filter: brightness(1.3);
}

.masthead nav {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px;
  margin-top: 2px;
}

.masthead nav a {
  font-family: var(--sans);
  font-size: 0.82rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--chalk-dim);
  text-decoration: none;
  padding: 6px 10px;
  border-bottom: 2px solid transparent;
}

.masthead nav a:hover { color: var(--white); }

/* Hamburger — hidden above the breakpoint, where the full nav fits one row
   (the links need ~583px including .wrap padding). */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: 1px solid var(--line);
  cursor: pointer;
}

.nav-toggle span {
  display: block;
  width: 20px;
  height: 2px;
  margin: 0 auto;
  background: var(--vitruvian-chalk);
  transition: transform 0.25s, opacity 0.2s;
}

.nav-toggle:hover { border-color: var(--vitruvian-chalk); }

.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 640px) {
  .nav-toggle { display: flex; }

  /* The header lockup is wide (~5.4:1); at its minimum height it is wider than
     a phone screen and would touch both edges. Cap its width to what's left
     after the wrap padding, the hamburger, and the gap, and let the height
     scale so the aspect ratio holds. */
  .masthead .brand img {
    height: auto;
    width: auto;
    max-width: calc(100vw - 110px);
  }

  .masthead nav {
    display: none;
    flex-direction: column;
    align-items: center;
    gap: 0;
    margin-top: 10px;
  }

  .masthead nav.is-open { display: flex; }

  .masthead nav a {
    width: 100%;
    text-align: center;
    padding: 12px 10px;          /* comfortable tap target */
    border-bottom: 1px solid var(--line);
  }

  .masthead nav a:last-child { border-bottom: none; }

  .masthead nav a.active {
    border-bottom-color: var(--line);
    color: var(--white);
  }
}

@media (prefers-reduced-motion: reduce) {
  .nav-toggle span { transition: none; }
}

.masthead nav a.active {
  color: var(--white);
  border-bottom-color: var(--vitruvian-chalk);
}

/* Cover / hero */
.cover {
  position: relative;
  background: var(--ink);
  color: var(--white);
  text-align: center;
  padding: clamp(3.5rem, 7vw, 6rem) 24px clamp(3.5rem, 6vw, 5rem);
}

/* ------------------------------------------------------------------
   Home page: one photographic backdrop, fixed to the viewport and visible
   behind every section as the page scrolls. A fixed pseudo-element is used
   rather than background-attachment:fixed, which iOS Safari ignores. A dark
   scrim keeps text legible over it; the page's own sections go transparent
   so the image shows through.
   ------------------------------------------------------------------ */
body.home::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(rgba(11, 13, 19, 0.5), rgba(11, 13, 19, 0.58)),
    url('home-bg.jpg') center / cover no-repeat;
}

body.home .cover,
body.home .carousel,
body.home section { background: transparent; }

body.home .carousel::before { display: none; }   /* drop the radial glow */
/* No dividers over the photo: the sections float on one continuous backdrop,
   so a rule between them would read as a seam across the image. */
body.home section { border-top: 0; }

/* Even vertical rhythm between the four floating blocks (~70px each). The
   compositions differ — B carries the carousel stage's fixed 56px top padding,
   D carries the footer's 48px top padding — so the outer paddings below are set
   to bring every transition to roughly the same gap. The cover's top padding is
   also capped here so it doesn't balloon on wide screens (its default scales
   with vw). */
/* A: masthead → hero. The top padding is matched to the interior pages'
   hero band (.page-cover: clamp(2.5rem, 6vw, 3.75rem)) so every page's hero
   begins at the same offset below the masthead — no more home-vs-rest drift.
   padding-bottom is left tighter than the top on purpose, so the hero still
   sits close to the carousel below (that gap is tuned separately at B). */
body.home .cover {
  padding-top: clamp(2.5rem, 6vw, 3.75rem);
  padding-bottom: clamp(1.5rem, 3vw, 2rem);
}
/* Interior pages give the eyebrow a 0.4rem top margin via `.page-cover p`; the
   home cover has no `.cover p` rule, so its eyebrow (zeroed by the global reset)
   would sit 0.4rem higher. Add the same nudge so the masthead → eyebrow gap is
   pixel-identical on the home page and every interior page. */
body.home .cover .eyebrow { margin-top: 0.4rem; }
/* B measured to the ACTIVE card, not the side cards: the centre card is scaled
   1.36 so its top sits ~40px higher than its unscaled neighbours. This padding
   makes up that difference so the tagline clears the magnified card by the same
   32px the eyebrow clears the masthead. */
body.home .carousel {
  padding-top: 0.875rem;
  padding-bottom: clamp(1.25rem, 2.5vw, 1.5rem);
}
body.home #about {
  padding-top: clamp(1.75rem, 3.5vw, 2rem);   /* C: carousel → The Work */
  /* D measured to the footer's tinted EDGE, not to its icons — the edge is the
     visible boundary, so this must carry the full gap on its own. */
  padding-bottom: clamp(3rem, 5.5vw, 3.5rem);
}

/* Trim the footer's own top padding on home so the icons don't sit too far
   down now that the gap above the band carries the rhythm. */
body.home footer { padding-top: 2rem; }

/* Footer tinted rather than opaque, so the fixed backdrop reads through it. */
body.home footer { background: rgba(22, 26, 38, 0.58); }

/* ------------------------------------------------------------------
   Interior pages that use their hero photo as a full fixed backdrop
   (short pages only — Learn, Support, Community). Same idea as the home
   page: the image is pinned to the viewport behind every section, a scrim
   keeps text legible, and the page's own blocks go transparent so the photo
   shows through. Each page sets its own image via --page-bg on <body>.
   ------------------------------------------------------------------ */
body.bg-hero::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(rgba(11, 13, 19, 0.64), rgba(11, 13, 19, 0.78)),
    var(--page-bg) center / cover no-repeat;
}

/* Targets (unlisted) — a lighter scrim than the rest of the site, so the
   target-pool detail in the artwork still reads through. */
body.bg-hero--targets::before {
  background:
    linear-gradient(rgba(11, 13, 19, 0.34), rgba(11, 13, 19, 0.5)),
    var(--page-bg) center / cover no-repeat;
}

/* Reports — a lighter scrim than the default so "The Vault" artwork (the
   labelled binders) reads through more. Kept moderate because report copy
   scrolls over this backdrop the whole way down. */
body.bg-hero--reports::before {
  background:
    linear-gradient(rgba(11, 13, 19, 0.5), rgba(11, 13, 19, 0.64)),
    var(--page-bg) center / cover no-repeat;
}

/* Consult — a slightly heavier scrim than the default so the busy
   project-report artwork sits back a little further behind the copy. */
body.bg-hero--consult::before {
  background:
    linear-gradient(rgba(11, 13, 19, 0.74), rgba(11, 13, 19, 0.86)),
    var(--page-bg) center / cover no-repeat;
}

/* Feedback (unlisted) — a top-down desk with a bright open folder. It is a
   LIGHT image, so it needs a heavier scrim than the other backdrops for white
   text to hold, plus text-shadows on the readout (see .bg-hero--feedback rules
   further down). */
body.bg-hero--feedback::before {
  background:
    linear-gradient(rgba(11, 13, 19, 0.5), rgba(11, 13, 19, 0.66)),
    var(--page-bg) center / cover no-repeat;
}
body.bg-hero--feedback .trn-readout,
body.bg-hero--feedback .page-cover .eyebrow,
body.bg-hero--feedback .folder-note {
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85);
}

/* Thank-you — the addressed envelope is the focal point and sits low in the
   frame, exactly where the default scrim is heaviest. Flip the gradient so it
   lightens toward the bottom (envelope reads through) while the top stays dark
   enough for the white heading. */
body.bg-hero--thankyou::before {
  background:
    linear-gradient(rgba(11, 13, 19, 0.62), rgba(11, 13, 19, 0.32)),
    var(--page-bg) center / cover no-repeat;
}

body.bg-hero .page-cover,
body.bg-hero section { background: transparent; border-top: 0; }

/* The hero band no longer holds its own image or scrim — the fixed backdrop
   supplies both — so hide the inline photo and the band's local gradient. */
body.bg-hero .page-cover-img,
body.bg-hero .page-cover::after { display: none; }

/* Alt sections keep a faint tint so the section rhythm still reads over the
   photo; footer tinted so the backdrop shows through it too. */
body.bg-hero section.alt { background: rgba(22, 26, 38, 0.5); }
body.bg-hero footer { background: rgba(22, 26, 38, 0.6); }

/* About on mobile: the wide desktop crop (v2) loses its outer name-files when
   a narrow portrait screen forces a heavy side-crop, so phones get the taller
   3:2 version instead, shown whole (contain) so all seven names stay visible.
   The letterbox margins fall back to --ink, blending into the dark theme. */
@media (max-width: 640px) {
  body.bg-hero--about::before {
    background-image:
      linear-gradient(rgba(11, 13, 19, 0.58), rgba(11, 13, 19, 0.72)),
      url('pages/about-mobile.jpg');
    background-size: cover, contain;
    background-color: var(--ink);
  }
}

.cover img {
  width: min(300px, 70vw);
  height: auto;
  display: block;
  margin: 0 auto 2.5rem;
  box-shadow: 0 0 60px rgba(0, 0, 192, 0.45);
}

.eyebrow {
  font-family: var(--sans);
  font-size: 0.8rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--chalk-dim);
  margin-bottom: 1rem;
}

/* Hero lockup: the same sans as the eyebrow above it, so the eyebrow, title
   and tagline read as one designed unit — and so the title matches the logo's
   geometric wordmark rather than clashing with it. Sized to match the interior
   pages' hero titles (.page-cover h1) so the site title carries the same
   vertical weight as every other page head. */
.cover h1 {
  font-family: var(--sans);
  font-size: clamp(2.2rem, 5vw, 3.4rem);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  line-height: 1.1;
  /* Matches the eyebrow's 1rem bottom margin, so the tagline sits the same
     distance below the title as the eyebrow sits above it. */
  margin-bottom: 1rem;
  color: var(--white);
}

/* True italic serif under the sans caps — a drawn italic, not an oblique, so
   the slant carries real calligraphic character. Also ties the hero back to the
   EB Garamond used for headings and long-form text elsewhere. */
.cover .mission {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.3rem, 2.6vw, 1.75rem);
  font-weight: 400;
  letter-spacing: 0.01em;
  line-height: 1.45;
  color: var(--vitruvian-chalk);
  max-width: 34em;
  margin: 0 auto;
}

/* Page head (interior pages) */
/* Plain title block for interior pages without a hero image (About, Reports,
   Media until they get artwork). Pages that have a hero image use .page-cover
   below instead. */
.page-head {
  background:
    radial-gradient(ellipse 75% 90% at 50% 0%, rgba(24, 28, 168, 0.34), transparent 72%),
    var(--ink);
  padding: clamp(2rem, 3.5vw, 2.75rem) 0 clamp(1.5rem, 3vw, 2.25rem);
}

.page-head h1 {
  font-family: var(--serif);
  font-size: clamp(2.2rem, 5vw, 3.2rem);
  font-weight: 700;
  line-height: 1.1;
  color: var(--white);
  margin-bottom: 1rem;
}

.page-head p { max-width: 42em; }

/* Page cover: interior-page hero title over the page's fixed photographic
   backdrop. Spacing is driven by padding, not a centred min-height band, so
   every interior hero gets the same gaps above and below the title regardless
   of whether it carries a subtitle line — otherwise short-content pages
   (About, Community) inherit larger cushions than pages with a subtitle
   (Reports, Media). */
.page-cover {
  position: relative;
  overflow: hidden;
  text-align: center;
  color: var(--white);
  padding: clamp(2.5rem, 6vw, 3.75rem) 0 clamp(2.5rem, 5vw, 3.25rem);
}

.page-cover-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}

.page-cover::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(to bottom,
    rgba(11, 13, 19, 0.45) 0%,
    rgba(11, 13, 19, 0.5) 55%,
    rgba(11, 13, 19, 0.82) 100%);
}

.page-cover .wrap { position: relative; z-index: 2; }

.page-cover .eyebrow { color: var(--vitruvian-chalk); }

.page-cover h1 {
  font-family: var(--serif);
  font-size: clamp(2.2rem, 5vw, 3.4rem);
  font-weight: 700;
  line-height: 1.1;
  color: var(--white);
  margin: 0 auto 0.8rem;
  max-width: 20em;
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.6);
}

.page-cover p {
  color: var(--vitruvian-chalk);
  max-width: 40em;
  margin: 0.4rem auto 0;
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.55);
}

.page-cover .epigraph {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.35rem;
}

/* Consistent hero→section spacing: whatever the hero ends on — the <h1> or a
   description paragraph — its trailing margin must not add to the fixed gap
   below. Without this, pages with no description line inherit the <h1>'s
   0.8rem bottom margin and sit ~13px lower than the rest. */
.page-cover .wrap > :last-child { margin-bottom: 0; }

/* Sections */
/* Fluid vertical rhythm: adjacent sections each contribute this padding,
   so the visible gap between two of them is double the value below. */
section {
  padding: clamp(2.25rem, 4vw, 3.25rem) 0;
  border-top: 1px solid var(--line);
}

section.alt { background: var(--ink-soft); }

h2 {
  font-family: var(--serif);
  font-weight: 700;
  font-size: 2rem;
  color: var(--white);
  margin-bottom: 1.4rem;
}

h3 {
  font-family: var(--serif);
  font-weight: 700;
  font-size: 1.25rem;
  color: var(--white);
  margin: 1.8rem 0 0.5rem;
}

section p {
  color: var(--vitruvian-chalk);
  max-width: 42em;
}

section p + p { margin-top: 1em; }

/* Centre the reading column. Headings and body copy share one 42em measure,
   centred inside .wrap, so the text axis lines up with the centred masthead
   instead of sitting left of it. Grids and cards keep the full wrap width. */
section h2,
section h3,
section p,
.page-head h1,
.page-head p {
  /* rem, not em: `em` resolves against each element's own font-size, so a 32px
     heading and a 17px paragraph would get different measures and their left
     edges would not line up. */
  /* ~76 characters per line at this body face — the upper end of the
     comfortable 60–75 range, chosen to avoid the column feeling cramped. */
  max-width: 36rem;
  margin-left: auto;
  margin-right: auto;
}

.muted { color: var(--chalk-dim); }

/* Lists in general content sections (e.g. Consult) — aligned to the same
   centred reading column as the prose, with Signal Amber markers. */
section ul,
section ol {
  max-width: 36rem;
  margin: 0.4rem auto 0;
  padding-left: 1.4rem;
  color: var(--vitruvian-chalk);
}

section li { margin: 0.35rem 0; }
section li::marker { color: var(--signal-amber); }

section p a {
  color: var(--white);
  text-decoration: underline;
  text-decoration-color: var(--signal-amber);
  text-underline-offset: 3px;
}

section p a:hover { text-decoration-color: var(--vitruvian-chalk); }

/* Coverflow carousel */
.carousel {
  --cf-w: 360px;              /* base (unscaled) card width */
  /* Negative = a gap, not an overlap. Cards must never intersect: at the
     midpoint of a slide the outgoing and incoming cards are both at scale
     1.25 (450px), so the step has to exceed that or the stacking order flips
     across a wide band of overlapping artwork — which reads as the incoming
     card popping through the outgoing one. */
  --cf-overlap: -0.2;
  --cf-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  position: relative;
  background: var(--ink);
  border-top: 1px solid var(--line);
  /* Top is lighter than bottom on purpose: the scaled centre card overflows
     ~34px upward into .cf-stage's padding, so an equal value here would read
     as noticeably more space above the strip than below the controls. */
  padding: 2.75rem 0 4rem;
  overflow: hidden;
}

/* Depth glow behind the focused card */
.carousel::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 900px;
  height: 620px;
  transform: translate(-50%, -60%);
  background: radial-gradient(ellipse at center, rgba(24, 28, 168, 0.40) 0%, rgba(16, 18, 120, 0.18) 40%, transparent 70%);
  pointer-events: none;
}

.cf-stage {
  position: relative;
  overflow: hidden;
  padding: 3.5rem 0;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 14%, #000 86%, transparent 100%);
          mask-image: linear-gradient(to right, transparent 0%, #000 14%, #000 86%, transparent 100%);
}

.cf-track {
  display: flex;
  align-items: center;
  will-change: transform;
  transition: transform 0.75s var(--cf-ease);
}

.cf-card {
  position: relative;
  flex: 0 0 var(--cf-w);
  width: var(--cf-w);
  aspect-ratio: 16 / 10;
  display: block;
  cursor: pointer;
  border: 1px solid var(--line);
  background: var(--panel);
  filter: brightness(0.38) saturate(0.65);
  /* z-index is transitioned too: it interpolates as an integer, so the paint
     order crosses over mid-slide instead of snapping at t=0 (which flashed the
     incoming card in front of the still-larger outgoing one). */
  transition: transform 0.75s var(--cf-ease), filter 0.75s var(--cf-ease),
              opacity 0.75s var(--cf-ease), z-index 0.75s var(--cf-ease),
              border-color 0.3s;
}

.cf-card + .cf-card { margin-left: calc(var(--cf-w) * (0 - var(--cf-overlap))); }

.cf-card img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Position on the arc (transform + z-index) is set per-card from JS in
   paint(); these rules only carry the look, not the placement. */
.cf-card.is-near {
  filter: brightness(0.62) saturate(0.85);
}

.cf-card.is-active {
  filter: none;
  border-color: var(--signal-amber);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.65);
}

.cf-card:focus-visible {
  outline: 2px solid var(--vitruvian-chalk);
  outline-offset: 4px;
}

/* Caption under the focused card */
/* min-height reserves room for the longest (two-line) title so the controls
   never shift as slides change. Centring the content means a one-line title
   splits that slack above and below instead of dumping it all underneath. */
.cf-caption {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  margin-top: 0.25rem;
  min-height: 8.75em;   /* tallest item measures 8.34em — see cf-desc */
  transition: opacity 0.3s ease;
}

.cf-caption.is-swapping { opacity: 0; }

.cf-kind {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.15rem;
  color: var(--chalk-dim);
  /* auto side margins: this inherits `section p { max-width: 42em }`, and as a
     flex item a capped width would otherwise sit against the left edge once the
     window grows past that cap. */
  margin: 0 auto 0.5rem;
}

.cf-title {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.4rem, 3.2vw, 2.1rem);
  line-height: 1.25;
  margin: 0 auto;
  max-width: 22em;
}

.cf-title a {
  color: var(--white);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s;
}

.cf-title a:hover { border-bottom-color: var(--signal-amber); }

.cf-desc {
  max-width: 46em;
  margin: 0.7rem auto 0;
  color: var(--chalk-dim);
  font-size: 0.95rem;
  line-height: 1.55;
}

/* Controls */
.cf-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.6rem;
  margin-top: 1.5rem;
}

.cf-btn {
  background: none;
  border: 1px solid var(--line);
  color: var(--vitruvian-chalk);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1;
  width: 42px;
  height: 42px;
  cursor: pointer;
  transition: border-color 0.25s, color 0.25s, background 0.25s;
}

.cf-btn:hover {
  border-color: var(--vitruvian-chalk);
  color: var(--white);
  background: rgba(211, 243, 255, 0.06);
}

.cf-counter {
  font-family: var(--mono);
  font-size: 0.82rem;
  letter-spacing: 0.1em;
  color: var(--chalk-dim);
  min-width: 5.5em;
  text-align: center;
}

.cf-counter b { color: var(--vitruvian-chalk); font-weight: 400; }

.cf-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  margin-top: 1.8rem;
}

/* Equal-width buttons: both sized to fit the longer label ("Read All Reports"). */
.cf-actions .btn {
  min-width: 13.5rem;
  text-align: center;
}

@media (max-width: 720px) {
  .carousel { --cf-w: 240px; padding: 1.5rem 0 2.5rem; }
  .cf-stage { padding: 2.5rem 0; }
}

/* Applied for a single frame while the strip teleports between copies, so the
   jump is not animated. Without it the outgoing card animates its scale and
   fade from the old position and reads as a ghost. */
.carousel.cf-instant .cf-track,
.carousel.cf-instant .cf-card,
.carousel.cf-instant .cf-caption { transition: none !important; }

@media (prefers-reduced-motion: reduce) {
  .cf-track, .cf-card, .cf-caption { transition: none; }
}

/* Published work */
.work-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 1.4rem;
  margin-top: 2.2rem;
}

.report {
  background: var(--panel);
  border: 1px solid var(--line);
  border-top: 3px solid var(--vitruvian-chalk);
  padding: 1.5rem;
}

.report .kind {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--chalk-dim);
}

.report h3 {
  margin: 0.6rem 0 0.5rem;
  font-size: 1.2rem;
}

.report p {
  font-size: 0.95rem;
  color: var(--chalk-dim);
}

.report .meta {
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--chalk-dim);
  margin-top: 1.1rem;
  border-top: 1px solid var(--line);
  padding-top: 0.7rem;
}

/* Report index (Reports page) */
.report-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

.report-controls input[type="search"],
.report-controls select {
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--vitruvian-chalk);
  font-family: var(--sans);
  font-size: 0.95rem;
  padding: 0.6em 0.9em;
}

.report-controls input[type="search"] {
  flex: 1 1 260px;
  min-width: 200px;
}

.report-controls input[type="search"]::placeholder { color: var(--chalk-dim); }

.report-controls input[type="search"]:focus,
.report-controls select:focus {
  outline: none;
  border-color: var(--vitruvian-chalk);
}

.report-controls select { cursor: pointer; }
.report-controls select option { background: var(--panel); }

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 1.2rem;
}

.chip {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--chalk-dim);
  font-family: var(--sans);
  font-size: 0.84rem;
  letter-spacing: 0.05em;
  padding: 0.45em 1em;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}

.chip:hover { border-color: var(--vitruvian-chalk); color: var(--white); }

.chip.active {
  background: var(--panel);
  border-color: var(--vitruvian-chalk);
  color: var(--white);
}

/* Faceted filter groups (Media: Type + Subject), each with a small heading. */
.chip-group { margin-top: 1.4rem; }
.chip-group-label {
  display: block;
  font-family: var(--sans);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--chalk-dim);
  margin-bottom: 0.55rem;
}
.chip-group .chips { margin-top: 0; }

.results-count {
  font-size: 0.88rem;
  color: var(--chalk-dim);
  margin-top: 1.6rem;
}

.report-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(330px, 1fr));
  gap: 1.4rem;
  margin-top: 1.2rem;
}

.rcard {
  background: var(--panel);
  border: 1px solid var(--line);
  display: flex;
  flex-direction: column;
}

.rcard .banner {
  display: block;
  width: 100%;
  height: 170px;
  object-fit: cover;
  border-bottom: 1px solid var(--line);
}

/* Full-infographic banners (charts/graphs) show complete, letterboxed on
   black instead of cropped like a photo. */
.rcard .banner.contain {
  object-fit: contain;
  background: #000;
}

.rcard .embed {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  border-bottom: 1px solid var(--line);
  background: #000;
}

/* Click-to-load video facade — poster + play button standing in for the
   YouTube iframe until the user clicks (see media.html render()). Shares the
   .embed sizing above; adds the poster fill and the play affordance. */
.video-facade {
  position: relative;
  padding: 0;
  cursor: pointer;
  background-color: #000;
  background-size: cover;
  background-position: center;
}

/* Faint scrim so the play button reads over bright thumbnails; lifts on hover. */
.video-facade::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(11, 13, 19, 0.3);
  transition: background 0.2s;
}

.video-facade:hover::after,
.video-facade:focus-visible::after { background: rgba(11, 13, 19, 0.12); }

.video-facade .play-btn {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1;
  width: 68px;
  height: 48px;
  border-radius: 14px;
  background: rgba(0, 0, 0, 0.62);
  transition: background 0.2s, transform 0.2s;
}

/* The triangle, nudged right of centre so it reads as centred in the pill. */
.video-facade .play-btn::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-38%, -50%);
  border-style: solid;
  border-width: 10px 0 10px 17px;
  border-color: transparent transparent transparent var(--white);
}

.video-facade:hover .play-btn,
.video-facade:focus-visible .play-btn {
  background: var(--signal-amber);
  transform: translate(-50%, -50%) scale(1.06);
}

.video-facade:focus-visible {
  outline: 2px solid var(--vitruvian-chalk);
  outline-offset: 3px;
}

.rcard-body { padding: 1.3rem 1.4rem 1.4rem; }

.rcard .cats {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--chalk-dim);
}

.rcard h3 { margin: 0.5rem 0 0.4rem; font-size: 1.25rem; }

.rcard h3 a {
  color: var(--white);
  text-decoration: none;
}

.rcard h3 a:hover { text-decoration: underline; }

.rcard .summary {
  font-size: 0.95rem;
  color: var(--chalk-dim);
}

.rcard .meta {
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--chalk-dim);
  margin-top: 1rem;
  border-top: 1px solid var(--line);
  padding-top: 0.7rem;
}

.empty-note {
  margin-top: 1.6rem;
  color: var(--chalk-dim);
}

/* ------------------------------------------------------------------
   Targets (unlisted) — a grid of target cards. Each card shows ONLY the
   target reference number (TRN) as an amber readout; clicking it reveals the
   target's folder (the designated-target PDF and any reference material).
   Built as <details> so the reveal is deliberate: a viewer works the TRN
   blind, then opens the folder to check against it.
   ------------------------------------------------------------------ */
/* Two tiers per page (Beginner–Intermediate, Advanced–Operational). */
.target-section { margin-top: 2.25rem; }
.target-section + .target-section { margin-top: 3rem; }
.target-section-title { margin-bottom: 0.15rem; }
.target-section .results-count { margin: 0; }

/* Targets page is centred throughout — the hero, the intro, the tier titles,
   the counts, and the card rows all share one centre axis. */
body.bg-hero--targets section p,
body.bg-hero--targets .target-section-title,
body.bg-hero--targets .results-count,
body.bg-hero--targets .empty-note {
  text-align: center;
}

.target-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 280px));
  justify-content: center;
  gap: 1.2rem;
  margin-top: 1.4rem;
}

/* Each card is a translucent "door" to a target's folder. The fill is kept
   low-opacity so the fixed backdrop reads through it, and every card is
   identical — the listing never reveals which targets carry reference
   material. The TRN gets a text-shadow so it stays legible over the artwork. */
a.tcard {
  display: block;
  text-align: center;
  padding: 1.7rem 0.9rem;
  background: rgba(16, 19, 27, 0.42);
  border: 1px solid rgba(211, 243, 255, 0.16);
  font-family: var(--mono);
  font-size: clamp(1.3rem, 4.5vw, 1.55rem);
  letter-spacing: 0.04em;
  white-space: nowrap;
  color: var(--white);
  text-decoration: none;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.75);
  transition: background 0.15s ease, border-color 0.15s ease;
}
a.tcard:hover,
a.tcard:focus-visible {
  background: rgba(16, 19, 27, 0.62);
  border-color: var(--vitruvian-chalk);
  outline: none;
}

/* The brackets and slash — the readout's punctuation — in Signal Amber. */
.tcard .brk,
.trn-readout .brk { color: var(--signal-amber); }

/* Folder page (target-folder.html) */
.trn-readout {
  font-family: var(--mono);
  letter-spacing: 0.06em;
  color: var(--white);
}
.folder-note {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--chalk-dim);
}
.target-folder { max-width: 540px; }

/* File links (folder contents) — translucent fill so they read over the
   fixed backdrop, matching the cards. */
.file-link {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.8rem 0.9rem;
  background: rgba(16, 19, 27, 0.42);
  border: 1px solid rgba(211, 243, 255, 0.16);
  color: var(--vitruvian-chalk);
  text-decoration: none;
  font-size: 0.92rem;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.file-link + .file-link { margin-top: 0.7rem; }
.file-link:hover {
  border-color: var(--vitruvian-chalk);
  color: var(--white);
  background: rgba(16, 19, 27, 0.62);
}
.file-link svg { flex: 0 0 auto; width: 20px; height: 20px; color: var(--signal-amber); }
.file-link .fl-label { font-weight: 600; }
.file-link .fl-kind {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--chalk-dim);
}

/* Support page */
.btn {
  display: inline-block;
  font-family: var(--sans);
  font-size: 0.85rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--vitruvian-chalk);
  text-decoration: none;
  border: 1px solid var(--line);
  background: transparent;
  padding: 0.6em 1.4em;
  cursor: pointer;
  transition: border-color 0.2s, color 0.2s;
}

.btn:hover { border-color: var(--vitruvian-chalk); color: var(--white); }

/* Gold buttons: the donate/join CTAs, plus the newsletter signup and contact
   submit buttons (both use .signup-form), so every primary form action reads
   as the same gold call to action. */
.btn-gold,
.signup-form .btn {
  background: var(--signal-amber);
  border-color: var(--signal-amber);
  color: var(--ink);
  font-weight: 700;
}

.btn-gold:hover,
.signup-form .btn:hover {
  /* tinted Signal Amber (guidelines: derive by tint/shade) */
  background: #d6a213;
  border-color: #d6a213;
  color: var(--ink);
}

.btn-icon {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
}

.btn-icon svg {
  height: 1.15em;
  width: auto;
  flex-shrink: 0;
}

.epigraph {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.35rem;
  color: var(--vitruvian-chalk);
}

/* auto-fit + justify-content, not a fixed 2 columns: the support page has six
   cards and still lays out in two, while the community page's single card
   centres instead of sitting in an empty left half. */
.donate-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 400px));
  justify-content: center;
  gap: 1.4rem;
  margin-top: 2rem;
}

/* Logo + button cards (Blogs, Community, Support). Translucent so the page's
   fixed backdrop reads through them — every page these appear on is a bg-hero
   page. Forms and image cards (.rcard) stay opaque by contrast. */
.donate-card {
  background: rgba(16, 19, 27, 0.42);
  border: 1px solid rgba(211, 243, 255, 0.16);
  padding: 1.6rem 1.4rem;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.8rem;
}

a.donate-card.card-link:hover { background: rgba(16, 19, 27, 0.6); }

.donate-card .logo {
  height: 64px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--white);
  border-radius: 3px;
  padding: 10px;
}

.donate-card .logo img,
.donate-card .logo svg {
  max-height: 44px;
  max-width: 80%;
}

.donate-card h3 { margin: 0; }

.donate-card p {
  font-size: 0.88rem;
  color: var(--chalk-dim);
  margin: 0;
}

.donate-card .btn { margin-top: auto; }

a.card-link {
  text-decoration: none;
  color: inherit;
  transition: border-color 0.2s;
}

a.card-link:hover { border-color: var(--vitruvian-chalk); }

a.card-link:hover .btn { border-color: var(--vitruvian-chalk); color: var(--white); }

/* Disabled button look (e.g. a blog that has no link yet). */
.btn.is-disabled { opacity: 0.45; pointer-events: none; }

/* Earth-Eye logo on the Learn training card (background already dropped to
   transparent, so it floats on the translucent card). */
.rvt-logo {
  display: block;
  width: 150px;
  max-width: 60%;
  height: auto;
  margin: 0 auto 0.3rem;
}

a.card-link:hover .btn-gold {
  background: #d6a213;
  border-color: #d6a213;
  color: var(--ink);
}

.donate-card .qr {
  width: min(170px, 55%);
  display: block;
  background: var(--white);
  padding: 8px;
}

.donate-card .addr {
  width: 100%;
  display: block;
  background: var(--white);
  padding: 6px;
  margin-top: auto;
}

.donate-card .label {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--chalk-dim);
  margin: 0;
}

@media (max-width: 560px) {
  .donate-grid { grid-template-columns: 1fr; }
}

/* Lexicon entry — the mock dictionary definition at the top of About. Styled
   as a reference card pulled onto the page: solid panel so it reads over the
   fixed photo backdrop, mono phonetics to echo the site's declassified/
   technical register, Signal Amber as the sole accent. */
.lexicon {
  max-width: 40rem;
  margin: 0 auto;
  /* Translucent, matching the team/bios band (section.alt) so the fixed photo
     backdrop reads through it. A slight backdrop blur keeps the dense
     definition text crisp over the busy "confidential files" image. */
  background: rgba(22, 26, 38, 0.5);
  -webkit-backdrop-filter: blur(3px);
          backdrop-filter: blur(3px);
  border: 1px solid var(--line);
  border-top: 3px solid var(--signal-amber);
  padding: clamp(1.6rem, 4vw, 2.5rem);
}

.lexicon dt {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(1.6rem, 4vw, 2.15rem);
  line-height: 1.2;
  color: var(--white);
}

.lexicon dd { margin: 0; }

/* Cancel the section reading-measure (36rem, centred) inherited by these <p>s
   so they fill the card and their hairlines span its full width. */
.lexicon p { max-width: none; margin-left: 0; margin-right: 0; }

.lex-pron {
  margin: 0.55rem 0 1.4rem;
  padding-bottom: 1.3rem;
  border-bottom: 1px solid var(--line);
}

.lex-phon {
  font-family: var(--mono);
  font-size: 0.95rem;
  color: var(--chalk-dim);
}

.lex-pos {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.02rem;
  color: var(--chalk-dim);
  margin-left: 0.7rem;
}

.lex-senses {
  margin: 0;
  padding-left: 1.6rem;
  display: grid;
  gap: 0.95rem;
}

.lex-senses li {
  color: var(--vitruvian-chalk);
  padding-left: 0.4rem;
  line-height: 1.6;
}

.lex-senses li::marker {
  font-family: var(--mono);
  font-size: 0.9rem;
  color: var(--signal-amber);
}

.lex-ety {
  margin-top: 1.5rem;
  padding-top: 1.35rem;
  border-top: 1px solid var(--line);
  font-size: 0.95rem;
  line-height: 1.65;
  color: var(--chalk-dim);
}

.lex-ety .lex-label {
  display: block;
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--vitruvian-chalk);
  margin-bottom: 0.45rem;
}

.lex-ety em { font-style: italic; }

/* Meet the team — name in a narrow left column, bio + quote in a wider right
   column. Fills the horizontal space with structure while each bio stays a
   single readable column. Collapses to one stacked column below 720px. */
.team-list {
  display: grid;
  gap: 2.75rem;
  margin: 2rem auto 0;
  max-width: 48rem;
}

.member {
  display: grid;
  grid-template-columns: 11rem minmax(0, 33rem);
  column-gap: 2.5rem;
  align-items: start;
}

.member h3 {
  grid-column: 1;
  margin: 0;
  max-width: none;
  font-size: 1.4rem;
}

/* Override the section reading-measure so the bio fills its column rather than
   capping and centring inside it. */
.member p {
  grid-column: 2;
  max-width: none;
  margin-left: 0;
  margin-right: 0;
}

.member .quote {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.08rem;
  line-height: 1.55;
  color: var(--vitruvian-chalk);
  border-left: 2px solid var(--signal-amber);
  padding-left: 1.1rem;
  margin-top: 1rem;
}

@media (max-width: 720px) {
  .member {
    grid-template-columns: 1fr;
    row-gap: 0.6rem;
  }
  .member h3,
  .member p { grid-column: 1; }
  /* Restore the reading measure once stacked — the two-column override above
     removed it, which would otherwise let the bio run the full width. */
  .member p { max-width: 33rem; }
}

/* Footer social links */
.social {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 22px;
  list-style: none;
  margin: 0 0 1.8rem;
  padding: 0;
}

.social a {
  display: block;
  color: var(--chalk-dim);
  transition: color 0.2s, transform 0.2s;
}

.social a:hover {
  color: var(--vitruvian-chalk);
  transform: translateY(-2px);
}

.social svg {
  width: 22px;
  height: 22px;
  fill: currentColor;
  display: block;
}

/* Signup form */
.signup-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  max-width: 520px;
  margin-top: 2rem;
}

.signup-form input,
.signup-form textarea {
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--vitruvian-chalk);
  font-family: var(--sans);
  font-size: 0.95rem;
  padding: 0.7em 0.9em;
  /* Grid items default to min-width:auto and won't shrink below the input's
     intrinsic width, so two side-by-side fields overflow a phone. */
  min-width: 0;
}

.signup-form input::placeholder,
.signup-form textarea::placeholder { color: var(--chalk-dim); }

.signup-form input:focus,
.signup-form textarea:focus { outline: none; border-color: var(--vitruvian-chalk); }

.signup-form textarea {
  resize: vertical;
  min-height: 8em;
}

.signup-form input[type="email"],
.signup-form textarea,
.signup-form .btn { grid-column: 1 / -1; }

/* Stack the name fields on narrow screens rather than cramming two per row. */
@media (max-width: 480px) {
  .signup-form { grid-template-columns: 1fr; }
}

.form-note {
  font-size: 0.85rem;
  color: var(--chalk-dim);
  margin-top: 1rem;
}

/* Individual report / article */
/* The banner image sits above this block, so the page runs dark masthead →
   image → light title → light body. One transition instead of two, with the
   image doing the work of the handover. */
.article-head {
  background: var(--bone);
  /* No bottom padding: the byline's own padding + rule supplies the gap. */
  padding: 3rem 0 0;
}

/* Same measure and axis as the body prose, so the title block and the article
   read as one continuous surface. */
.article-head .wrap { max-width: 720px; }

.article-head .cats,
.article-head h1,
.article-head .subtitle,
.article-head .byline {
  max-width: 34rem;
  margin-left: auto;
  margin-right: auto;
}

.article-head .cats {
  font-family: var(--sans);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--slate);
  margin-bottom: 1rem;
}

.article-head h1 {
  font-family: var(--serif);
  font-size: clamp(2rem, 4.5vw, 3rem);
  font-weight: 700;
  line-height: 1.12;
  color: var(--deep-navy);
  margin-bottom: 0.6rem;
}

.article-head .subtitle {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.3rem;
  color: var(--slate);
  margin-bottom: 1.4rem;
}

.article-head .byline {
  font-family: var(--sans);
  font-size: 0.9rem;
  color: var(--slate);
  padding-bottom: 1.6rem;
  border-bottom: 1px solid var(--rule-light);
}

.article-head .byline .dates {
  font-family: var(--mono);
  display: block;
  margin-top: 0.4rem;
}

/* No rules: the image now butts straight against the masthead above and the
   light title block below, and a dark hairline would read as a seam. */
.article-banner { border: 0; }

.article-banner img {
  display: block;
  width: 100%;
  max-height: 420px;
  object-fit: cover;
}

/* Infographic hero (charts/graphs): show the whole image, letterboxed on
   black rather than cropped. */
.article-banner.graph img {
  max-height: 520px;
  object-fit: contain;
  background: #000;
}

/* Contained cover variant (square marks, logos) */
.article-banner.contained {
  background: var(--ink-soft);
  padding: 2.5rem 0;
  text-align: center;
}

.article-banner.contained img {
  width: min(460px, 82%);
  max-height: none;
  object-fit: none;
  margin: 0 auto;
  box-shadow: 0 0 60px rgba(0, 0, 192, 0.4);
}

/* Reading column. Top padding is light because .article-head sits directly
   above on the same surface and already supplies breathing room. */
.article {
  padding: 2rem 0 4rem;
}

/* The first heading already has the padding above it; its own top margin
   would double the gap. */
.article .wrap > *:first-child { margin-top: 0; }

.article .wrap { max-width: 720px; }

.article h2 {
  font-family: var(--serif);
  font-size: 1.7rem;
  color: var(--white);
  margin: 2.6rem 0 1rem;
}

.article h3 {
  font-family: var(--serif);
  font-size: 1.25rem;
  color: var(--white);
  margin: 2rem 0 0.6rem;
}

.article p {
  color: var(--vitruvian-chalk);
  margin-bottom: 1.1rem;
}

.article em { font-style: italic; }

.article hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 2.4rem 0;
}

.article blockquote {
  border-left: 3px solid var(--signal-amber);
  padding-left: 1.2rem;
  margin: 1.6rem 0;
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.1rem;
  color: var(--chalk-dim);
}

.article .lead {
  font-size: 1.15rem;
  color: var(--vitruvian-chalk);
}

/* Metadata table */
.article table {
  width: 100%;
  border-collapse: collapse;
  margin: 1.4rem 0 2rem;
  font-size: 0.92rem;
}

.article th,
.article td {
  text-align: left;
  vertical-align: top;
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--line);
}

.article th {
  font-family: var(--sans);
  color: var(--white);
  white-space: nowrap;
  width: 34%;
}

.article td { color: var(--chalk-dim); font-family: var(--mono); font-size: 0.86rem; }

/* Figures */
.article figure {
  margin: 2rem 0;
  background: var(--panel);
  border: 1px solid var(--line);
  padding: 1rem;
}

.article figure img {
  display: block;
  width: 100%;
  height: auto;
  background: var(--white);
}

.article figcaption {
  font-family: var(--sans);
  font-size: 0.82rem;
  color: var(--chalk-dim);
  margin-top: 0.8rem;
  line-height: 1.5;
}

.article figcaption b {
  color: var(--vitruvian-chalk);
  font-weight: 700;
}

/* In-article video embed (video reports) */
.article .video-embed {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line);
  background: #000;
  margin: 2rem 0;
}

/* ------------------------------------------------------------------
   Report reading surface — light.
   Brand Guidelines §4, Usage rules: "Most documents should sit on white
   or Bone. Reserve Deep Navy and Blueprint Indigo for covers, headers,
   callouts, and the masthead." So the article body is white with dark
   text, while the masthead, the article cover, the callout bands and the
   footer stay navy. Long-form reading is easier dark-on-light.
   ------------------------------------------------------------------ */
.article {
  background: var(--bone);
  color: var(--body-ink);
}

/* Narrow the prose to a readable measure (~74 characters) while leaving the
   wrap wide, so tables, figures and callout bands keep the extra width. */
.article p,
.article h2,
.article h3,
.article ul,
.article ol,
.article blockquote,
.article .lead {
  max-width: 34rem;
  margin-left: auto;
  margin-right: auto;
}

.article h2,
.article h3 { color: var(--deep-navy); }

.article p,
.article .lead,
.article li { color: var(--body-ink); }

.article a {
  color: var(--deep-navy);
  text-decoration: underline;
  text-decoration-color: var(--signal-amber);
  text-underline-offset: 3px;
}

.article a:hover { text-decoration-color: var(--deep-navy); }

.article hr { border-top-color: var(--rule-light); }

.article blockquote { color: var(--slate); }

.article th,
.article td { border-color: var(--rule-light); }

.article th { color: var(--deep-navy); }
.article td { color: var(--slate); }

/* White frames on the warmer page surface, so the pen-on-paper session
   sketches still read as paper rather than blending into the background. */
.article figure {
  background: var(--white);
  border-color: var(--rule-light);
}

.article figcaption { color: var(--slate); }
.article figcaption b { color: var(--deep-navy); }

/* A figure floated within the reading column so the prose wraps around it.
   The wrapper shares the ~34rem prose measure and contains the float; its
   paragraph fills the wrapper (overriding the centred-column defaults) so the
   text hugs the figure. Below a narrow breakpoint the figure un-floats and
   stacks full width, keeping the text legible. */
.article .figwrap {
  max-width: 34rem;
  margin: 2rem auto;
}
.article .figwrap::after { content: ""; display: block; clear: both; }
.article .figwrap p { max-width: none; margin: 0; }

.article figure.figure-inline {
  float: right;
  width: 44%;
  max-width: 240px;
  margin: 0.3rem 0 0.9rem 1.4rem;
}

@media (max-width: 560px) {
  .article figure.figure-inline {
    float: none;
    width: auto;
    max-width: none;
    margin: 1.6rem 0;
  }
}

/* In-article call-to-action bands */
.cta-band {
  margin: 3rem 0;
  padding: 2rem 1.8rem;
  background: var(--surface-band);
  border: 1px solid var(--line);
  text-align: center;
}

.cta-band.support { background: var(--surface-deep); }

.cta-band h3 {
  font-family: var(--serif);
  font-size: 1.5rem;
  color: var(--white);
  margin: 0 auto 0.6rem;
}

.cta-band p {
  color: var(--vitruvian-chalk);
  max-width: 34em;
  margin: 0 auto 1.4rem;
}

.cta-band .signup-form { margin: 1.4rem auto 0; }

/* Legal / policy pages (Disclaimer, Privacy, Terms) — long-form documents on
   the same light reading surface as reports (.article). `.callout` styles the
   all-caps emphasis notices in the source: a bold navy notice with a Signal
   Amber edge, matching the site's callout treatment. */
.legal .callout {
  max-width: 34rem;
  margin: 1.6rem auto;
  padding: 1rem 1.15rem;
  background: var(--white);
  border: 1px solid var(--rule-light);
  border-left: 3px solid var(--signal-amber);
  color: var(--deep-navy);
  font-weight: 700;
}

.legal .callout p {
  margin: 0;
  max-width: none;
  color: var(--deep-navy);
}

.legal ul { padding-left: 1.4rem; }

.legal .doc-end {
  margin-top: 2.4rem;
  font-size: 0.9rem;
  color: var(--slate);
}

/* Digital-display face for the 404 "SIGNAL LOST" readout (14-segment LED). */
@font-face {
  font-family: 'DSEG14';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/dseg14.woff2') format('woff2');
}

/* 404 / error page — "Signal Lost". A brand logo band, then a green radar
   readout, the SIGNAL LOST digital headline, a line of copy, and a way back. */
.logo-band {
  text-align: center;
  /* Bottom padding is the gap above the radar; it matches the reticle's bottom
     margin so the radar sits with equal breathing room above and below. */
  padding: clamp(2.5rem, 7vw, 4.5rem) 24px clamp(1.9rem, 4.5vw, 2.6rem);
}

.logo-word {
  display: inline-block;
  font-family: 'DSEG14', var(--mono);
  font-size: clamp(1.3rem, 4vw, 2.3rem);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  line-height: 1.35;
  color: #35e07a;
  text-decoration: none;
  text-shadow: 0 0 16px rgba(53, 224, 122, 0.45);
}
.logo-word:hover { color: #5cff96; }

.error-page {
  min-height: 52vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Flow from the top (no centering slack) so the gap above the radar is the
     logo band's bottom padding, not a variable amount. Extra height falls below
     the button, keeping the footer down. */
  justify-content: flex-start;
  text-align: center;
  padding: 0 24px clamp(3rem, 8vw, 5rem);
  /* All 404 copy is the digital readout face by default. */
  font-family: 'DSEG14', var(--mono);
}

/* Radar scope — phosphor green. Faint range rings + axes (SVG, currentColor),
   with a smooth conic sweep beneath them. */
.reticle {
  --radar-bright: #5cff96;
  position: relative;
  width: clamp(130px, 24vw, 180px);
  aspect-ratio: 1;
  color: rgba(53, 224, 122, 0.42);
  /* Matches the logo band's bottom padding, so spacing above == below. */
  margin-bottom: clamp(1.9rem, 4.5vw, 2.6rem);
}
.reticle svg { position: relative; z-index: 1; width: 100%; height: auto; display: block; }
.radar-disc { fill: rgba(53, 224, 122, 0.06); }
.reticle .core { fill: var(--radar-bright); }

/* Smooth sweep: a conic-gradient wedge fading cleanly from the bright leading
   edge to transparent, rotating beneath the rings. A thin line marks the edge. */
.radar-sweep {
  position: absolute;
  inset: 5%;
  z-index: 2;                 /* over the rings, so the sweep line reads clearly */
  border-radius: 50%;
  background: conic-gradient(from 0deg,
    rgba(92, 255, 150, 0) 300deg,
    rgba(92, 255, 150, 0.5) 360deg);
  animation: radar-sweep 4s linear infinite;
}
/* The spinning sweep line — a bright radial hand from the centre to the edge. */
.radar-sweep::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  width: 2px;
  height: 50%;
  transform: translateX(-50%);
  background: var(--radar-bright);
  box-shadow: 0 0 6px rgba(92, 255, 150, 0.85);
}

@keyframes radar-sweep { to { transform: rotate(360deg); } }

.error-page .eyebrow {
  margin-bottom: 0.5rem;
  color: #35e07a;
  font-family: 'DSEG14', var(--mono);
}

.signal-lost {
  font-family: 'DSEG14', var(--mono);
  font-size: clamp(1.5rem, 5vw, 2.9rem);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  line-height: 1.15;
  color: #35e07a;
  text-shadow: 0 0 18px rgba(53, 224, 122, 0.5);
  margin: 0 0 1.1rem;
}

.error-msg {
  max-width: 40rem;
  color: #35e07a;
  margin: 0 auto 2rem;
  /* Matches the ERROR 404 eyebrow: same size and generous letter-spacing so the
     segment font stays legible instead of the glyphs running together. */
  font-size: 0.8rem;
  letter-spacing: 0.3em;
  line-height: 1.75;
}

/* "Return to Base" as a control on the readout: green digital face + edge. */
.error-page .btn {
  font-family: 'DSEG14', var(--mono);
  color: #35e07a;
  background: rgba(53, 224, 122, 0.10);
  border-color: #35e07a;
  letter-spacing: 0.08em;
  text-shadow: 0 0 10px rgba(53, 224, 122, 0.4);
}
.error-page .btn:hover {
  color: #5cff96;
  border-color: #5cff96;
  background: rgba(53, 224, 122, 0.16);
}

@media (prefers-reduced-motion: reduce) {
  .radar-sweep { animation: none; }
}

/* Footer */
footer {
  background: var(--surface-deep);
  color: var(--vitruvian-chalk);
  padding: 3rem 0 2.5rem;
}

/* Slim newsletter signup — one line of copy + an inline email field, centred.
   The full signup lives on newsletter.html; this is the low-friction version
   that rides along in the footer. Stacks on narrow screens. */
.footer-signup {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.8rem 1.4rem;
  max-width: 46rem;
  margin: 0 auto 2rem;
  padding-bottom: 2rem;
  border-bottom: 1px solid var(--line);
}

.footer-signup-label {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.05rem;
  color: var(--vitruvian-chalk);
  margin: 0;
}

.footer-signup-form {
  display: flex;
  gap: 8px;
  flex: 0 1 auto;
}

.footer-signup-form input {
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--vitruvian-chalk);
  font-family: var(--sans);
  font-size: 0.9rem;
  padding: 0.6em 0.9em;
  min-width: 0;
  flex: 1 1 auto;
}

.footer-signup-form input::placeholder { color: var(--chalk-dim); }
.footer-signup-form input:focus { outline: none; border-color: var(--vitruvian-chalk); }

.footer-signup-form .btn { white-space: nowrap; }

@media (max-width: 520px) {
  .footer-signup-form { width: 100%; }
}

/* ------------------------------------------------------------------
   EmailOctopus embedded newsletter form.

   The mailing list moved off Netlify Forms to EmailOctopus (an ESP that
   handles double opt-in and automatic unsubscribe). EmailOctopus injects its
   own form markup AND an inline <style> via an external <script>. That inline
   <style> themes the form through CSS custom properties (--field-colour,
   --button-colour, …) declared on the [data-form="…"] element, and it loads
   AFTER this file — so matching its selectors would lose on source order.

   Rather than fight that, we redefine EO's own theme variables at higher
   specificity: the doubled [data-form][data-form] selector scores (0,2,0),
   beating EO's own (0,1,0) [data-form] declarations regardless of load order,
   so the form recolours through EO's machinery to the site palette. A couple
   of non-variable cosmetics (corner radius) are flattened with !important.

   If EO renames these variables or classes, this is the block to update.
   Reference: EO markup is form.emailoctopus-form > .main-form; text fields use
   .form-control; submit uses .btn.btn-primary; honeypot is
   .emailoctopus-form-row-hp.
   ------------------------------------------------------------------ */
[data-form][data-form] {
  --field-colour: var(--panel);
  --field-border-colour: var(--line);
  --button-colour: var(--signal-amber);
  --button-text-colour: var(--ink);
  --primary-brand-colour: var(--signal-amber);
  --label-colour: var(--vitruvian-chalk);
  --text-colour: var(--vitruvian-chalk);
  --eo-form-font-color: var(--vitruvian-chalk);
  --eo-form-placeholder: var(--chalk-dim);
  --font-family: var(--sans);
}
/* EO redeclares these variables at several nesting levels inside [data-form],
   so the outer override above doesn't reach the fields, and it pins the submit
   background with a high-specificity rule. So we also set the actually-consumed
   properties directly with !important — the canonical way to override a
   third-party embed's own styles. Text fields → panel fill / chalk text; submit
   → Signal Amber / ink text; square corners throughout. */
[data-form] .emailoctopus-form input:not([type="submit"]),
[data-form] .emailoctopus-form .form-control {
  background: var(--panel) !important;
  border: 1px solid var(--line) !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  color: var(--vitruvian-chalk) !important;
  font-family: var(--sans) !important;
}
[data-form] .emailoctopus-form .form-control::placeholder { color: var(--chalk-dim) !important; }
[data-form] .emailoctopus-form .form-control:focus { border-color: var(--vitruvian-chalk) !important; }
[data-form] .emailoctopus-form input[type="submit"],
[data-form] .emailoctopus-form .btn-primary {
  background: var(--signal-amber) !important;
  border: 1px solid var(--signal-amber) !important;
  border-radius: 0 !important;
  color: var(--ink) !important;
  font-family: var(--sans) !important;
  font-weight: 700 !important;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
[data-form] .emailoctopus-form input[type="submit"]:hover,
[data-form] .emailoctopus-form .btn-primary:hover {
  background: #d6a213 !important;
  border-color: #d6a213 !important;
}

.emailoctopus-form { max-width: 520px; margin: 1.6rem auto 0; }
.emailoctopus-form .emailoctopus-form-row { margin-bottom: 12px; }
/* Belt-and-braces: keep the honeypot field off-screen even if EO's own rule
   fails to load. Real visitors never see it; bots that fill it are dropped. */
.emailoctopus-form .emailoctopus-form-row-hp {
  position: absolute !important;
  left: -5000px !important;
}
/* EO's success / error banners, restyled to read as site copy. */
.emailoctopus-success-message,
.emailoctopus-error-message {
  color: var(--vitruvian-chalk);
  font-family: var(--sans);
  text-align: center;
  margin-top: 1rem;
}
.emailoctopus-error-message { color: #e79aa0; }

/* Compact footer variant: EO stacks its rows, but the footer wants the fields
   and submit on one line (wrapping on narrow screens), matching the old inline
   footer form. */
.footer-signup .emailoctopus-form { margin: 0; max-width: none; }
.footer-signup .emailoctopus-form .main-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: start; }
.footer-signup .emailoctopus-form [eo-form-fields-container] { display: contents; }
.footer-signup .emailoctopus-form .emailoctopus-form-row { margin-bottom: 0; flex: 1 1 12rem; }
.footer-signup .emailoctopus-form input[type="submit"],
.footer-signup .emailoctopus-form .btn-primary { width: auto; white-space: nowrap; flex: 0 0 auto; }

/* Footer link menu — mirrors the masthead nav styling; wraps and centres. */
.footer-nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px 4px;
  margin-bottom: 2.2rem;
}

.footer-nav a {
  font-family: var(--sans);
  font-size: 0.8rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--chalk-dim);
  text-decoration: none;
  padding: 6px 12px;
  border-bottom: 2px solid transparent;
  transition: color 0.2s;
}

.footer-nav a:hover { color: var(--white); }

/* Pending links (Blogs, Disclaimer, Privacy, Terms) — no page yet, so they
   render dimmed and non-interactive until a real href is added. */
.footer-nav a.pending {
  color: var(--slate);
  pointer-events: none;
  cursor: default;
}

footer .legal {
  font-family: var(--sans);
  font-size: 0.85rem;
  color: var(--chalk-dim);
  text-align: center;
}

footer .legal a {
  color: var(--vitruvian-chalk);
  text-decoration: underline;
}
