/* stephenkelman.co.uk — replica stylesheet
   Type scale + palette are the measured values from docs/design-reference/.

   SPACING SOURCE (2026-08-05): the live site's own compiled theme stylesheet is
   cached at docs/design-reference/theme.css. Every metric it declares is copied
   verbatim below — including its two real breakpoints, **932px and 540px**
   (the earlier 1000/768/520 were guesses). Anything Adobe applied at RUNTIME
   via JS — project/about module rhythm, page-header offsets, per-page
   backgrounds — is NOT in that file and stays at its live-measured value. */

:root {
  --font-sans: "neue-haas-unica", "Helvetica Neue", Arial, sans-serif;
  --font-serif: "le-monde-livre-std", Georgia, "Times New Roman", serif;

  --c-text: #282828;      /* primary */
  --c-secondary: #636569; /* h1, body, project titles */
  --c-muted: #939393;     /* nav */
  --c-faint: #b9b9b9;     /* footer */
  --c-accent: #ef4023;    /* CTA outline/text */
  --c-bg: #ffffff;

  /* body line-height — the unit for "a line of space" (matches the blank-line
     gaps authored inside the text modules themselves) */
  --line: 24px;
  /* air above AND below the project-page title; halves at the 932 breakpoint */
  --title-gap: 48px;

  --maxw-page: 1400px;
  --maxw-project: 1200px;
  --maxw-narrow: 700px;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
/* No letter-spacing anywhere (live uses none) */
body, h1, h2, h3, p, a, nav, .btn, .masthead-title, .project-title { letter-spacing: normal; }
body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 24px;
  color: var(--c-secondary);
  background: var(--c-bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }

.visually-hidden {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: -9999px; top: 0; background: #fff;
  padding: 8px 16px; z-index: 100;
}
.skip-link:focus { left: 8px; top: 8px; }

/* ---------- Header ---------- */
.site-header {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
  /* live: height 60, padding 0 3% (the old 38px was 3% frozen at a 1280 window) */
  height: 60px;
  padding: 0 3%;
  position: sticky;
  top: 0;
  z-index: 50;
  background: #fff;   /* header stays white even on dark pages (live) */
}
.primary-nav { justify-self: start; }
.nav-menu {
  /* live: nav items carry padding-right 20px (last-child 0) */
  display: flex; gap: 20px; list-style: none; margin: 0; padding: 0;
}
.nav-menu a {
  font-size: 15px; line-height: 24px; color: var(--c-muted);
}
.nav-menu a:hover, .nav-menu a[aria-current="page"] { color: var(--c-text); }

.logo { justify-self: center; }
/* Live: .logo-image { max-width: 50px } with the image scaling to it —
   at the logo's intrinsic 104x87 that renders 50x41.8 (was 52x44 here). */
.logo img { width: 50px; height: auto; }

.social {
  justify-self: end;
  /* Live: 25px icons on a 35px pitch → 10px gap (measured 1280). */
  display: flex; gap: 10px; list-style: none; margin: 0; padding: 0;
  align-items: center;
}
.social a { color: var(--c-muted); display: inline-flex; }
.social a:hover { color: var(--c-text); }
.social svg { width: 25px; height: 25px; fill: currentColor; }

.nav-toggle { display: none; }

/* ---------- Dark pages ----------
   Live keeps the WHITE header + grey nav on dark pages (only the content area
   below goes black). So the header is unchanged; just the project title on the
   black content lifts to #bfbfbf. */
.theme-dark .project-title { color: #bfbfbf; }

/* ---------- Masthead (home) ---------- */
/* live .masthead: padding 95px 0% 72px. Our header is in flow (sticky) and
   takes the first 60px, so the top padding is 95-60=35. .masthead-contents caps
   the whole stack at 650px — applied here per child. */
.masthead {
  text-align: center;
  margin: 0 auto;
  padding: 35px 0 72px;
}
.masthead-title {
  font-family: var(--font-serif);
  font-weight: 300;
  font-size: 31px;
  line-height: 42px;
  color: var(--c-secondary);
  margin: 0 auto;
  max-width: 650px;
}
.masthead-sub {
  font-size: 15px; line-height: 24px; color: var(--c-secondary);
  margin: 25px auto 5px;   /* live .masthead p: margin 25px top / 5px bottom */
  max-width: 650px;
}
.masthead-buttons {
  /* live: .masthead-buttons padding-top 27px; buttons 17px apart. PADDING, not
     margin — a top margin would collapse with the subtitle's 5px bottom margin
     and swallow it, putting the buttons 5px high. */
  display: flex; justify-content: center; gap: 17px; margin: 0 auto;
  padding-top: 27px; max-width: 650px; flex-wrap: wrap;
}
.btn {
  /* live .masthead-button-1/2: height 40, padding 0 15px, 1px border.
     Live sets line-height:40 to centre the label, but that centres the EM box —
     and Unica's ascent (16px at 15px type) is far taller than its cap height
     (10.7px), so the letterforms land ~1.7px low. Centring with flex and
     trimming 2px off the bottom puts the cap block on the optical centre
     instead. Height and padding are unchanged, so the pill matches live. */
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 15px; height: 40px; line-height: 1;
  color: var(--c-accent);
  border: 1px solid var(--c-accent);
  border-radius: 20px;
  padding: 0 15px 2px;
  transition: background .15s ease, color .15s ease;
}
.btn:hover { background: var(--c-accent); color: #fff; }

/* ---------- Project grid (home) ---------- */
/* Live structure (measured 2026-08-04 at 1280/768/375): the cell is 400×315 and
   the cover sits inside it with `margin: 10px 5px 0`. That margin — not a grid
   gap — is what separates the thumbnails, so the grid itself stays gap-0 and
   unpadded, and the 5px sides inset the outer edges of the grid too. */
.project-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;                 /* gutters come from the cover margins, as on live */
  max-width: 1200px;      /* 3 × 400px, centred (live) */
  margin: 0 auto;
  padding: 0;             /* live .project-covers: padding 0 at every width —
                             the footer's 60px top padding is the only gap */
  --cover-inset-y: 10px;  /* live cover margin-top */
  --cover-inset-x: 5px;   /* live cover margin left/right */
}
.grid-item { position: relative; display: block; background: transparent; }
/* The cover's own aspect ratio drives the cell height at every width (live's
   in-flow <img> mechanism): cell = cover height + top margin. 409/320 is the
   covers' intrinsic ratio; yields live's measured cells at 1280/768/375
   (400x315 / 384x301 / 375x300). */
.grid-cover {
  display: block; overflow: hidden;
  margin: var(--cover-inset-y) var(--cover-inset-x) 0;
  aspect-ratio: 409 / 320;
}
.grid-cover picture { display: block; width: 100%; height: 100%; }
.grid-item img { width: 100%; height: 100%; object-fit: cover; }
/* Rollover (matches live): a near-white panel fades in over the cover, inset
   0.65em from the cover on ALL FOUR sides — bottom included — with the project
   title centred in #565656 and padded 15% each side. */
.grid-title {
  position: absolute;
  top: calc(var(--cover-inset-y) + .65em); bottom: .65em;
  left: calc(var(--cover-inset-x) + .65em); right: calc(var(--cover-inset-x) + .65em);
  display: flex; align-items: center; justify-content: center;
  /* Live pads the title 15% of the PANEL width; a bare 15% here would resolve
     against the cell instead, so subtract the panel's own insets first. */
  padding: 0 calc(.15 * (100% - 2 * (var(--cover-inset-x) + .65em)));
  text-align: center;
  font-size: 15px; line-height: 24px; color: #565656;
  background: rgba(255, 255, 255, .97);
  opacity: 0; transition: opacity .15s ease;
  /* Widow control: balance evens the whole rag on this short centred text
     (and prevents a lone last word). Unsupported browsers keep old wrapping. */
  text-wrap: balance;
}
.grid-item:hover .grid-title, .grid-item:focus-visible .grid-title { opacity: 1; }

/* ---------- Project page ---------- */
/* Live (measured at 900/1440): images are FULL-BLEED — no side padding below
   the 1200px cap; each image module carries 14px bottom padding; text modules
   are a 500px box with 45px internal side padding (410px measure); buttons
   pad 14px 45px. Module spacing is per-module, not a flex gap. */
/* The project title sits in equal air: --title-gap above (as the page's own top
   padding, under the 60px header) and the same below (Stephen, 2026-08-05 —
   was 48/20 desktop and 24/14 mobile; equalised to the LARGER of the pair). */
.project { padding: var(--title-gap) 0 64px; }
.project-title {
  text-align: center;
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 15px;
  line-height: 24px;
  color: var(--c-secondary);
  margin: 0 0 var(--title-gap);
}
.project-modules {
  max-width: var(--maxw-project);
  margin: 0 auto;
  display: flex; flex-direction: column; gap: 0;
}
.project-image { margin: 0; padding-bottom: 20px; }
.project-image img { width: 100%; cursor: zoom-in; }

/* Text + button modules (interleaved with images).
   Block is centred (max-width + auto margins); text itself reads left — Adobe's
   align-center centres the block, not the copy. */
/* Every module carries its own TRAILING space — that's what replaced the flex
   gap. Text modules were missing theirs, so a text block had 20px above it
   (the previous image's) and 0 below, and the next image butted straight up. */
/* One blank line of air above AND below the copy (Stephen, 2026-08-05).
   The space above already carries the preceding module's 20px trailing rhythm,
   so the text only adds its own line on top; below it must supply both. Net
   result is symmetric: 20+24 = 44px each side (14+24 = 38px under 932). */
.project-text { font-size: 15px; line-height: 24px; margin: 0 auto; padding: var(--line) 45px calc(20px + var(--line)); width: 100%; max-width: 500px; text-align: left; }
.project-text a, .about-text a, .contact-intro a { color: inherit; text-decoration: underline; }
/* FAQ block (variant B, Stephen 2026-08-06): a standard text module whose
   questions take one step of emphasis — #282828 on light pages, white on
   dark. Answers inherit the module colour (page text_color on dark). */
/* FAQ top gap = its bottom gap (Stephen 2026-08-06): space from the preceding
   module to "Questions" matches last line -> related band. Band gap totals
   88px desktop / 68px <=932; preceding module's trailing pad is 20/14, so the
   FAQ tops up the difference. */
.project-faq { padding-top: 68px; }
.project-faq .faq-q { color: var(--c-text); margin: var(--line) 0 0; }
.project-faq .faq-q:first-of-type { margin-top: 0; }
.project-faq .faq-a { margin: 0; }
.theme-dark .project-faq .faq-q { color: #ffffff; }
.project-text.align-right { text-align: right; }
.project-text p { margin: 0; }
.project-button { text-align: center; margin: 0; padding: 20px 0; }
.project-embed { margin: 0 auto; padding-bottom: 20px; width: 100%; }
.project-embed .embed-ratio { position: relative; height: 0; }
.project-embed iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/* Video captions replicate Behance's treatment (the copy source): small,
   grey, centred under the embed. #939393 reads on both white and the dark
   page grounds (same as nav/socials there). */
.embed-caption { margin-top: 10px; font-size: 13px; line-height: 20px; color: var(--c-muted); text-align: center; }

/* ---------- Narrow pages (about / contact) ---------- */
.page-narrow { max-width: 548px; margin: 0 auto; padding: 24px 24px 80px; }
.about-image { margin: 0 0 32px; }
/* Match live rhythm: headings sit TIGHT above their body (big gap above to
   separate sections, none below); paragraphs/links are one blank line (24px)
   apart; consecutive lines within a para (award/education lists) stay tight. */
.about-text p, .about-text h2 { font-size: 15px; line-height: 24px; color: var(--c-secondary); }
/* Unica Medium (500) now in the kit — matches live's subheading weight. */
/* Measured live rhythm (2026-08-04): heading sits 28px below the previous
   block (mt 28 collapses over the para's mb 24); the big "—" section
   separators get 52px above AND below. */
.about-text h2 { font-weight: 500; margin: 28px 0 0; }
/* Services headings carry 2 authored blank lines on live (52px); the CV-tail
   headings carry 1 (28px, the default above). Flag comes from about.json. */
.about-text h2.gap-wide { margin-top: 52px; }
.about-text .about-para { margin: 0 0 24px; }
.about-text h2 + .about-para { margin-top: 0; }   /* body tight under its heading */
.about-text .about-link { margin: 0 0 24px; }
.about-text .about-divider { color: var(--c-muted); margin: 52px 0; }
.contact-intro p { margin: 0 0 20px; }
.contact-heading { font-size: 15px; font-weight: 500; color: var(--c-secondary); margin: 0 0 20px; }

/* ---------- Contact form ---------- */
.contact-form { display: flex; flex-direction: column; gap: 12px; margin-top: 28px; }
.contact-form input, .contact-form textarea {
  font-family: var(--font-sans); font-size: 15px; color: var(--c-text);
  padding: 14px 16px; border: 1px solid #dadada; border-radius: 3px; width: 100%;
}
.contact-form textarea { resize: vertical; }
.contact-form button {
  align-self: flex-start;
  font-family: var(--font-sans); font-size: 15px; color: var(--c-secondary);
  background: none; border: 1px solid #dadada; border-radius: 3px;   /* match inputs */
  padding: 12px 28px; cursor: pointer;
}
.contact-form button:hover { border-color: var(--c-text); color: var(--c-text); }

/* ---------- 404 ---------- */
.error-page { text-align: center; max-width: 560px; margin: 0 auto; padding: 80px 24px 100px; }
.error-title { font-family: var(--font-serif); font-weight: 300; font-size: 31px; line-height: 42px; color: var(--c-secondary); margin: 0 0 16px; }
.error-page .btn { margin-top: 24px; }

/* ---------- Footer ---------- */
/* live .site-footer: padding 60px 0 (28px at <=932, 25px at <=540) */
.site-footer { text-align: center; padding: 60px 0; }
.site-footer p { font-size: 12px; line-height: 20px; color: var(--c-faint); margin: 0; }

/* ---------- Lightbox ---------- */
.lightbox {
  position: fixed; inset: 0; background: rgba(255,255,255,.97);
  display: none; align-items: center; justify-content: center; z-index: 200;
  cursor: zoom-out;
}
.lightbox.open { display: flex; }
.lightbox img { max-width: 92vw; max-height: 92vh; width: auto; height: auto; }
.lightbox-close {
  position: absolute; top: 20px; right: 24px; font-size: 28px;
  background: none; border: 0; color: var(--c-text); cursor: pointer; line-height: 1;
}

/* ---------- Responsive ----------
   Live has exactly TWO breakpoints, both from theme.css: 932px and 540px. */

@media (max-width: 932px) {
  /* Masthead ladder (live): padding 79px 5% 32px, h1 18/24, p 14/20 with
     15px above and 5px below, buttons 15px under that at 38px tall.
     79px is measured from the page top; our header takes the first 60. */
  .masthead { padding: 19px 5% 32px; }
  .masthead-title { font-size: 18px; line-height: 24px; }
  .masthead-sub { font-size: 14px; line-height: 20px; margin-top: 15px; }
  .masthead-buttons { padding-top: 15px; }
  .btn { font-size: 14px; height: 38px; }   /* line-height stays 1: see .btn */

  /* Project pages drop to live's mobile rhythm: 24px under the header, 14px
     modules, 14/20 title. Measured on live at 800/375 — Adobe applies module
     spacing via JS, so theme.css can't confirm it; the 932 boundary is
     inherited from every rule that IS in the file. */
  /* --title-gap drives both the space above the title and the space below it */
  :root { --title-gap: 24px; }
  .project-title { font-size: 14px; line-height: 20px; }
  .project-image, .project-embed { padding-bottom: 14px; }
  .project-text { padding-bottom: calc(14px + var(--line)); }
  .project-faq { padding-top: 54px; }  /* band gap 68 minus the 14px trailing pad */
  .project-button { padding: 14px 0; }

  /* live .site-footer at <=932: 28px top/bottom, 5% sides */
  .site-footer { padding: 28px 5%; }

  /* Live mobile header: 60px tall, 5% padding, logo CENTRED at 48x40 (live
     caps .logo-image img to max-height 40), hamburger RIGHT, socials hidden. */
  .site-header { grid-template-columns: 1fr auto 1fr; padding: 0 5%; height: 60px; align-items: center; }
  .primary-nav { grid-column: 3; grid-row: 1; justify-self: end; }
  .logo { grid-column: 2; grid-row: 1; }
  .logo img { width: 48px; height: 40px; }
  .social { display: none; }

  /* Live glyphs (measured): burger = three 24x2 bars, 4px gaps, GREY #939393
     (var(--c-muted)); close = two 2x20 strokes at ±45°, same grey, 20x20 box. */
  .nav-toggle {
    display: inline-flex; flex-direction: column; justify-content: center; gap: 4px;
    width: 44px; height: 44px; align-items: center;
    background: none; border: 0; cursor: pointer; padding: 0;
    position: relative; z-index: 210;   /* stays above the open menu overlay */
  }
  .nav-toggle span { display: block; height: 2px; background: var(--c-muted); width: 24px; transition: transform .2s ease, opacity .2s ease, width .2s ease; }
  /* Open state: the bars become live's close button, which is its own fixed
     element at top 40px / right 5% in a 20x20 box (top 30px under 540). */
  .primary-nav.open .nav-toggle {
    position: fixed; top: 40px; right: 5%; width: 20px; height: 20px; gap: 0;
  }
  .primary-nav.open .nav-toggle span { position: absolute; }
  .primary-nav.open .nav-toggle span:nth-child(1) { width: 20px; transform: rotate(45deg); }
  .primary-nav.open .nav-toggle span:nth-child(2) { opacity: 0; }
  .primary-nav.open .nav-toggle span:nth-child(3) { width: 20px; transform: rotate(-45deg); }

  /* Live's open menu is a FULL-SCREEN white overlay: .responsive-nav pads
     50px 5% 0 and centres the link block, which itself carries an 80px bottom
     padding to clear the social bar. Links are 22/32 with 30px under EACH
     (including the last) -> a 62px pitch. */
  .nav-menu {
    display: none; position: fixed; inset: 0;
    flex-direction: column; align-items: center; justify-content: center;
    gap: 0; padding: 50px 5% 80px; background: #fff; z-index: 200;
  }
  .nav-menu li { padding-bottom: 30px; }
  .primary-nav.open .nav-menu { display: flex; }
  /* live's overlay shows no current-page highlight — every link is the same grey */
  .nav-menu a, .nav-menu a[aria-current="page"] { font-size: 22px; line-height: 32px; color: var(--c-muted); }
  .nav-menu a:hover { color: var(--c-text); }

  /* ...with the social icons centred along the bottom, above a hairline. Live:
     min-height 80, padding 5%, 1px rgba(0,0,0,.08) top border, and icons on a
     62px pitch (25px glyph + 20px li padding + the svg's own letterboxing). */
  .primary-nav.open ~ .social {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 205;
    /* the <ul> is a grid item of the header, and its justify-self:end beats the
       left/right:0 stretch — pin the width so the hairline spans edge to edge */
    width: 100%; justify-self: stretch;
    justify-content: center; gap: 37px; padding: 5%; min-height: 80px;
    background: #fff; border-top: 1px solid rgba(0, 0, 0, .08); margin: 0;
  }

  /* Live is full-bleed here (grid padding 0) with a shallower cover margin. */
  .project-grid { grid-template-columns: repeat(2, 1fr); --cover-inset-y: 8px; }
  .grid-title { font-size: 14px; line-height: 20px; }
}

@media (max-width: 540px) {
  /* live at <=540: masthead padding-bottom 28, h1 16/22, p margin-top 14,
     buttons 14px under it, stacked with a 17px spacer, 35px tall. */
  .masthead { padding-bottom: 28px; }
  .masthead-title { font-size: 16px; line-height: 22px; }
  .masthead-sub { margin-top: 14px; }
  .masthead-buttons { padding-top: 14px; flex-direction: column; align-items: center; gap: 17px; }
  .btn { height: 35px; }
  .primary-nav.open .nav-toggle { top: 30px; }
  .site-footer { padding: 25px 5%; }
  /* Single column on live drops the side margins entirely. */
  .project-grid { grid-template-columns: 1fr; --cover-inset-y: 7px; --cover-inset-x: 0px; }
}

/* asset rev: turnstile-invisible-gap
   NB the ?v= cache-buster is an md5 of this file (+ site.js + image-manifest),
   and /assets/* ships `immutable, max-age=31536000` via _headers. So a request
   made in the propagation window right after `wrangler pages deploy` — new HTML
   with the new hash, old asset bytes still at the edge — pins STALE content
   under the NEW url for a year. Wait ~60s after deploying before fetching, or
   the verification request itself poisons the cache. Bump this comment to mint
   a fresh hash if that happens. */

/* Contact form result message (post-submit redirect) */
.contact-result { color: var(--c-secondary); margin: 0 0 24px; }

/* Anti-spam honeypot — off-screen rather than display:none, which the cruder
   bots check for. Never focusable, never announced. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
/* Turnstile widget sits in the form's flex column; the iframe carries its own
   box, so it only needs the column's rhythm. */
.contact-form .cf-turnstile { margin-top: 4px; }

/* In Invisible mode Turnstile renders NO iframe — the container is left at
   zero height but still occupies a flex item, so it ate a gap either side and
   put 28px above Send where every other field gap is 12px. Take it out of
   flow when it has nothing to show. Deliberately position:absolute rather
   than display:none: the element stays rendered and scriptable (Turnstile
   still populates the hidden token input from it) and keeps its static
   position, it just stops consuming a gap. Managed/Non-interactive modes DO
   render an iframe, so they keep their slot and this rule never applies —
   flipping the widget mode back needs no CSS change. Browsers without :has()
   simply keep the old 28px. */
.contact-form .cf-turnstile:not(:has(iframe)) { position: absolute; margin-top: 0; }

/* ---------- Related-projects strip (2026-08-05, prototype for art direction) ----------
   Foot-of-page cross-links on product pages: 3 related grids + the free Colours
   card; top sellers on the colours page and the 404. Reuses the home-grid tile
   classes — the cover-inset vars are zeroed here so the grid gap, not cover
   margins, makes the gutters. */
.related {
  max-width: var(--maxw-project);
  margin: 0 auto;
  padding: 64px 0 0;
}
.related-heading {
  font-size: 15px;
  line-height: 24px;
  font-weight: 400;
  color: var(--c-secondary);
  margin: 0 0 16px;
}
.theme-dark .related-heading { color: #bfbfbf; }
.related-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  --cover-inset-y: 0px;
  --cover-inset-x: 0px;
}
/* Anchor the rollover panel to the COVER, not the grid item: the Colours
   card's tag makes its item the tallest in the row, the others stretch to
   match, and a panel anchored to the item bottom overshoots the cover by
   the tag height. */
.related-grid .grid-cover { position: relative; }
.related-grid .grid-item { position: static; }
.related-grid .grid-title {
  top: .65em; right: .65em; bottom: .65em; left: .65em;
  padding: 0 15%;
}
.related-grid .grid-cover { aspect-ratio: 409 / 320; }
/* The free-download tag under the Colours card */
.tile-tag {
  display: block;
  margin-top: 8px;
  font-size: 13px;
  line-height: 18px;
  color: var(--c-accent);
}
@media (max-width: 932px) {
  .related { padding-top: 40px; }
  .related-grid { grid-template-columns: repeat(2, 1fr); }
}
/* The band (ported from the prototype): a near-page ground — 5% black on
   light pages, 90% black on dark — running full-bleed from below the last
   module to the base of the page, footer included. The pill sits centred in
   a 64/64 field: above it the image's trailing 20 + the button's 44 top
   padding; below it the button's 20 + the band's 44 margin. */
.has-strip .project { padding-bottom: 0; }
.has-strip .project-modules > .project-button:last-child { padding-top: 44px; }
.has-strip .related {
  margin-top: 44px;
  max-width: none;
  padding: 64px 0;                 /* inner column matches the 1200px module box */
  background: #f2f2f2;
}
.theme-dark.has-strip .related { background: #1a1a1a; }
.has-strip .related-heading,
.has-strip .related-grid {
  max-width: var(--maxw-project);
  margin-left: auto;
  margin-right: auto;
}
/* carry the field through to the page base */
.has-strip .site-footer { background: #f2f2f2; }
.theme-dark.has-strip .site-footer { background: #1a1a1a; }
@media (max-width: 932px) {
  .has-strip .project-modules > .project-button:last-child { padding-top: 30px; }
  .has-strip .related { margin-top: 30px; }
}

/* 404: the strip sits below the narrow error card */
.page-404 .related { padding: 24px 5% 0; }

/* 'Features' promoted to a real h2 — pixel-identical to the body copy it was:
   same size/leading/weight, bottom margin standing in for the authored blank
   line, so the rendered rhythm is unchanged. */
.project-text-heading {
  font-size: inherit;
  line-height: inherit;
  font-weight: inherit;
  /* Module headings take the FAQ-question step of emphasis (Stephen
     2026-08-06): #282828 on light pages, white on dark; body stays grey. */
  color: var(--c-text);
  /* Features sits directly on its bullets (Stephen 2026-08-06); the FAQ
     keeps a line between "Questions" and the first question. */
  margin: 0;
}
.project-faq .project-text-heading { margin-bottom: var(--line); }
.theme-dark .project-text-heading { color: #ffffff; }

/* ---------- Journal (2026-08-06, new section — not part of the replica) ----------
   Composed from existing tokens only: masthead serif for titles, body 15/24,
   the about-page 548px measure, muted grey for dates. */
.journal-index .article-title {
  font-family: var(--font-serif);
  font-weight: 300;
  font-size: 31px;
  line-height: 42px;
  color: var(--c-secondary);
  margin: 24px 0 0;
}
/* Article header = the landing entry stack verbatim (measured: 18/26 #282828
   title, date 4px under, standfirst as the 15/24 excerpt 11px under that). */
.journal-article .article-title { font-size: 18px; line-height: 26px; font-weight: 400; color: var(--c-text); margin: 24px 0 0; }
.article-date { font-size: 13px; line-height: 20px; color: var(--c-muted); margin: 4px 0 0; }  /* 4px = the landing entry's measured gap */
.article-body { margin-top: 48px; }
.article-body p { margin: 0 0 var(--line); }
.article-figure { margin: calc(var(--line) * 2) 0; }
.article-back { margin-top: 48px; font-size: 13px; }
.article-back a { color: var(--c-muted); }
.article-back a:hover { color: var(--c-text); }

.journal-list { list-style: none; margin: 48px 0 0; padding: 0; }
.journal-entry { margin: 0 0 40px; }
.journal-entry a { display: block; }
.journal-entry-title { display: block; font-size: 18px; line-height: 26px; color: var(--c-text); }
.journal-entry a:hover .journal-entry-title { color: var(--c-accent); }
.journal-entry-excerpt { display: block; margin-top: 8px; font-size: 15px; line-height: 24px; color: var(--c-secondary); }

@media (max-width: 932px) {
  .journal-index .article-title { font-size: 24px; line-height: 32px; }
  .article-body { margin-top: 28px; }
}
.article-standfirst { font-size: 15px; line-height: 24px; font-style: italic; color: var(--c-secondary); margin: 8px 0 0; }
.article-list { list-style: none; margin: 0 0 var(--line); padding: 0; }
/* Flex marker: wrapped lines align exactly with the first word of the item —
   not past it (the old 28px hanging indent) and not under the dash. */
.article-list li { display: flex; gap: 8px; }
.article-list li::before { content: "\2014"; color: var(--c-muted); flex: none; }
.article-figure .embed-caption { color: var(--c-secondary); }  /* body colour; video captions keep muted */
.article-figure .embed-caption a { text-decoration: none; }
.article-figure .embed-caption a:hover { color: var(--c-text); }
.article-newsletter { margin-top: 48px; font-size: 15px; line-height: 24px; color: var(--c-secondary); }
.article-newsletter a { text-decoration: underline; white-space: nowrap; }

/* Journal body voice (Stephen 2026-08-06): standfirst + body copy in Le Monde
   Livre Light (kit serves 300/400/700), one size up from the site's 15px on
   the unchanged 24px line, 100% black. Titles/captions stay sans.
   (A Typotheque Lava trial was evaluated and removed pre-ship — licensed
   files would be needed before any Lava returns.) */
.journal-article .article-standfirst,
.journal-article .article-body p,
.journal-article .article-list,
.journal-article .article-newsletter {
  font-family: var(--font-serif);
  font-weight: 300;
  font-size: 17px; line-height: 24px;
  color: #000000;
}
