/* ==========================================================================
   NJ-Eze Studio — base stylesheet
   Tokens per CLAUDE.md. Layout system per LAYOUT.md §1.
   ========================================================================== */

/* InterVariable — self-hosted, assets/fonts/InterVariable.woff2, OFL
   (see assets/fonts/LICENSE.txt). Variable axes: wght 100-900, opsz 14-32.
   The opsz axis is the "Inter Display" equivalent — browsers supporting
   font-optical-sizing:auto pick it automatically from rendered font-size,
   no separate display font file needed. Browsers without variable-font
   support still get static Inter via the fallback stack below. */
@font-face {
  font-family: 'InterVariable';
  src: url('../fonts/InterVariable.woff2') format('woff2-variations'),
       url('../fonts/InterVariable.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* JetBrains Mono — self-hosted (Legal Pages Pre-Publication Hardening),
   assets/fonts/JetBrainsMono.woff2, OFL (see
   assets/fonts/JetBrainsMono-LICENSE.txt). Removes the only remaining
   third-party network request the theme made (fonts.googleapis.com /
   fonts.gstatic.com). File and weights fetched directly from Google's
   own current serving of family=JetBrains+Mono:wght@400;500 — the exact
   "latin" subset a plain English-locale browser already received, not a
   new subsetting decision. Google itself points both the 400 and 500
   @font-face declarations at this same physical file (it's variable-
   weight-capable internally); replicated here as two static @font-face
   rules against one local file, matching Google's own approach exactly
   rather than needing two separate downloads. */
@font-face {
  font-family: 'JetBrains Mono';
  src: url('../fonts/JetBrainsMono.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../fonts/JetBrainsMono.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* Accent discipline (approved correction, 2026-08-16):
   --color-rust measured at 4.25:1 on paper / 3.48:1 on ink — both clear
   WCAG AA for LARGE text (>=3:1) but fail AA for normal-size text (needs
   4.5:1). Rule: rust must never be the color of ordinary small body or
   caption text. It's approved for large/bold display typography (e.g.
   the Outcome number treatment), graphical accents, borders, markers,
   icons, underlines, and other non-text or large-text treatments. Do not
   introduce a second, darker "accessible rust" shade unless a future
   design explicitly requires small rust text — use --color-ink or
   --color-muted for small text instead.

   --color-muted was #8B8175 (3.07:1 on paper, fails AA even at large
   text) — corrected to #6E665D, which clears 4.5:1 on both paper and
   white for its spec'd use as secondary text/captions. */
:root {
  --color-paper: #EDE6D6;
  --color-ink:   #17140F;
  --color-rust:  #B8472C;
  --color-muted: #6E665D;
  --color-white: #FFFFFF;

  --font-display: 'InterVariable', 'Inter', sans-serif;
  --font-body:    'InterVariable', 'Inter', sans-serif;
  --font-mono:    'JetBrains Mono', monospace;

  /* 8px spacing scale — use only these values for margin/padding */
  --space-1: 8px;
  --space-2: 16px;
  --space-3: 24px;
  --space-4: 32px;
  --space-5: 48px;
  --space-6: 64px;
  --space-7: 96px;
  --space-8: 128px;

  --content-max: 1200px;
}

/* -- Reset -------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
}

/* Sticky-footer shell: on any document shorter than the viewport (e.g.
   Insights Archive's genuine zero-Post state), #main grows to fill the
   leftover space so .site-footer lands at the true bottom edge instead
   of leaving --color-paper body background exposed beneath it. On any
   page whose real content already meets or exceeds viewport height —
   every other template today, and Insights itself once real Posts
   exist — flex-grow has nothing left to distribute, so layout is
   unaffected: no arithmetic, no JS, no fixed/absolute Footer. .skip-link
   is position:absolute (removed from flex layout entirely) and
   .site-header is position:sticky with no explicit sizing, so both are
   unaffected by body becoming a flex container. */
body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--color-paper);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-weight: 400;
  line-height: 1.5;
}

#main {
  flex: 1 0 auto;
}

/* #main flex-grows on short pages (see body above). Its own background
   is otherwise transparent, so any unused grown space exposes body's
   paper underneath it — invisible when the terminal section already
   happens to be a paper zone, but a real visible seam when it's ink or
   white. Painting #main with whatever register its own final direct
   child already carries closes that gap with the correct color instead
   of introducing per-template height math, a flex-grow child, or a
   Contact-specific rule — the terminal child's own zone class is
   already the right source of truth for what register the rest of the
   page has settled into by that point. */
#main:has(> :last-child.zone-ink) {
  background: var(--color-ink);
}

#main:has(> :last-child.zone-paper) {
  background: var(--color-paper);
}

#main:has(> :last-child.zone-white) {
  background: var(--color-white);
}

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

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

a {
  color: inherit;
  text-decoration: none;
}

ul,
ol {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Legal Pages Pre-Publication Hardening: the global reset above is
   correct everywhere else in the theme (nav lists, cards, etc. all
   supply their own visual treatment) but left Privacy Policy/Terms of
   Service list content — plain WordPress Page prose — with no marker at
   all, indistinguishable from surrounding paragraphs. Scoped to
   .legal-document (set conditionally in index.php, not to any hardcoded
   Page ID) rather than touching the reset itself. Existing spacing
   tokens only; no new colors, no custom markers. */
.legal-document ul {
  list-style: disc;
  padding-left: var(--space-3);
}

.legal-document ol {
  list-style: decimal;
  padding-left: var(--space-3);
}

.legal-document li {
  margin-bottom: var(--space-1);
}

/* -- Typography ----------------------------------------------------------- */

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 800;
  line-height: 1.1;
  /* Lets the opsz axis track rendered size — the display optical cut at
     large heading sizes, progressively enhanced; no-op where unsupported. */
  font-optical-sizing: auto;
}

.eyebrow,
.meta,
.badge {
  font-family: var(--font-mono);
}

/* -- Layout system (LAYOUT.md §1) ----------------------------------------- */

.container {
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--space-2);
}

.zone-ink {
  background: var(--color-ink);
  color: var(--color-paper);
}

.zone-paper {
  background: var(--color-paper);
  color: var(--color-ink);
}

.zone-white {
  background: var(--color-white);
  color: var(--color-ink);
}

/* -- Accessibility --------------------------------------------------------- */

:focus-visible {
  outline: 2px solid var(--color-rust);
  outline-offset: 2px;
}

.skip-link {
  position: absolute;
  top: -999px;
  left: 0;
  background: var(--color-ink);
  color: var(--color-paper);
  padding: var(--space-1) var(--space-2);
  z-index: 1000;
}

.skip-link:focus {
  top: 0;
}

/* Background-scroll lock while the full-screen mobile nav is open (JS
   toggles this on <html> — see main.js). overflow:hidden alone doesn't
   reliably stop iOS Safari's touch-driven rubber-band scroll; pairing it
   with touch-action:none does, without a scroll-position repositioning
   trick that would fight the Header's own position:sticky. */
html.nav-open,
html.nav-open body {
  overflow: hidden;
  touch-action: none;
}

/* -- Site header (LAYOUT.md §2) -------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: transparent;
  color: var(--color-ink);
  transition: background-color 200ms ease, color 200ms ease;
}

.site-header.is-scrolled {
  background: var(--color-paper);
  color: var(--color-ink);
}

/* Generalized (was Home-only): on any template whose opening section is
   marked data-header-zone (Home's Hero, About's Intro, ...) the header
   overlaps that ink zone directly beneath it (LAYOUT.md §2 — "transparent
   over the hero, matches whatever zone is directly behind it" — read as
   the section's role, not a name literally scoped to Home's own "Hero"),
   rather than sitting above it in normal flow. :has() keys this off the
   marked section itself rather than a per-template body class, so it
   never needs a new selector added for the next template that gets this
   same treatment — templates with no marked zone are untouched, same as
   before. Fixed header height (--space-6) makes the overlap math exact
   instead of depending on font-metric-driven height, and is reused as-is
   here (About defines no header/overlap geometry of its own). Reverts
   automatically once .is-scrolled is added (real page content, not the
   transparent overlay). */
body:has([data-header-zone]) .site-header:not(.is-scrolled) {
  color: var(--color-paper);
  margin-bottom: calc(-1 * var(--space-6));
}

/* Case Studies' Intro is the first data-header-zone opener that isn't
   ink — --color-paper (#EDE6D6) on true white measures ~1.24:1, an
   almost total contrast failure. This zone-aware override wins by
   selector specificity/source order for zone-white openers only; every
   existing ink-zone template (Home/About/Expertise/Products) has no
   .zone-white element to match, so their computed Header color is
   completely unaffected. */
body:has([data-header-zone].zone-white) .site-header:not(.is-scrolled) {
  color: var(--color-ink);
}

/* Insights Archive's Intro is the first data-header-zone opener that's
   --color-paper — the generic ink-opener default above (color: paper on
   paper) would be an almost total contrast failure over it, same
   category of problem the zone-white override above already exists to
   solve. Same pattern, one more zone case: ink foreground reads clearly
   on paper (see this phase's contrast measurement), so this reuses the
   zone-white override's resolved color rather than inventing a third
   value. */
body:has([data-header-zone].zone-paper) .site-header:not(.is-scrolled) {
  color: var(--color-ink);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: var(--space-6);
}

.site-header__wordmark {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.1rem;
  letter-spacing: 0.02em;
  font-optical-sizing: auto;
}

.site-nav__list {
  display: flex;
  gap: var(--space-3);
}

.site-nav__toggle {
  display: none;
}

@media (max-width: 767px) {
  /* Scoped to .site-header: the Footer repeats this same shared
     .site-nav__list markup (nj_eze_footer_nav()) but has no .site-nav
     toggle wrapper or is-open mechanism of its own — a bare .site-nav__list
     selector here would hide the Footer's copy permanently on mobile with
     no way to reveal it. LAYOUT.md requires the Footer nav to stay present
     (stacked, not collapsed) at every width. */
  .site-header .site-nav__list {
    display: none;
  }

  /* Footer's own copy of .site-nav__list stays visible at mobile — a plain
     stacked list, not the Header's full-panel takeover treatment, since
     it's a secondary nav subordinate to the Contact CTA directly above it. */
  .site-footer__nav .site-nav__list {
    flex-direction: column;
    gap: var(--space-2);
  }

  .site-nav.is-open .site-nav__list {
    display: flex;
    flex-direction: column;
    /* Fixed (not absolute + top:100%): a short dropdown sized to its
       content would land right where the Hero headline sits on Home,
       slicing across it. Anchoring to the viewport and running to the
       bottom makes the panel a deliberate full takeover of everything
       below the header — it never partially overlaps the Hero, and
       never touches Hero document flow/geometry either way. */
    position: fixed;
    inset-inline: 0;
    top: var(--space-6);
    bottom: 0;
    overflow-y: auto;
    background: var(--color-paper);
    /* Always a solid paper panel regardless of scroll position, so it
       needs its own ink text — the header it's nested in may currently be
       set to paper text (unscrolled, over the Hero on Home). */
    color: var(--color-ink);
    /* Deliberate top offset: the block starts partway down the panel
       instead of flush under the Header, so it reads as positioned
       rather than just "whatever's next in the markup." Left/right stay
       on the shared 16px mobile grid. */
    padding: var(--space-7) var(--space-2) var(--space-2);
    gap: var(--space-4);
  }

  .site-nav.is-open .site-nav__list a {
    /* Moderately more presence than body copy — still text, not a
       heading treatment — plus the wider letter-spacing/weight pairing
       gives the block its own deliberate voice instead of reading as a
       default stacked WordPress menu. */
    font-size: 1.375rem;
    font-weight: 600;
  }

  .site-nav__toggle {
    /* .site-header__inner is justify-content:space-between across three
       flex items (wordmark, toggle, .site-nav) — .site-nav__list being
       display:none doesn't remove .site-nav itself from that flex line,
       so its zero-width box still claims the "last item" slot and
       space-between leaves the toggle stranded mid-row instead of flush
       against the right gutter. Reordering it after .site-nav (a true
       layout fix, not an offset) makes the toggle the actual last item,
       so it gets the flush-end treatment the wordmark gets at the start. */
    order: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    /* Zero right/vertical padding: the icon sits flush against the
       button's own right and top/bottom edges, which are flush against
       the container's 16px gutter and the wordmark's vertical center —
       neither may move. The button's own unpadded box is only ~21px
       wide though, well under a comfortable touch target — padding-left
       grows the hit area inward (toward the wordmark) only, so the
       right-flush icon position is untouched. */
    padding: var(--space-1) 0 var(--space-1) var(--space-3);
    font-size: 1.5rem;
    cursor: pointer;
  }
}

/* -- Home: Hero (LAYOUT.md §5 row 2) --------------------------------------- */

.hero {
  position: relative;
  min-height: 88svh;
}

.hero > .container {
  /* Absolutely positioned, not a flex/grid item of .hero: a flex/grid
     item's margin-inline:auto resolves as a leftover-space-absorbing
     alignment margin instead of ordinary block centering, silently
     shifting .container's left edge off the Header wordmark's (the bug
     this replaced). Out-of-flow positioning keeps .container's own
     centering math identical to the Header's — same box, same width,
     same auto-margin split — while `bottom` places it toward the
     lower-middle of the Hero: a controlled, deliberate gap under the
     content instead of an equally large, unstructured void. */
  position: absolute;
  inset-inline: 0;
  bottom: var(--space-6);
}

.hero__headline {
  max-width: 16ch;
  margin-bottom: var(--space-4);
  font-size: 2.25rem;
  line-height: 1.05;
  /* Avoids awkward multi-line wraps (e.g. a single dangling word) as an
     editor changes this copy later — content-agnostic, not tied to
     today's specific string. No-op, graceful fallback to normal wrap
     where unsupported. */
  text-wrap: balance;
}

.hero__subhead {
  max-width: 42ch;
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.5;
}

@media (min-width: 768px) {
  .hero__headline {
    max-width: 18ch;
    font-size: 3.25rem;
  }

  .hero__subhead {
    font-size: 1.125rem;
  }
}

@media (min-width: 1024px) {
  .hero > .container {
    bottom: var(--space-7);
  }

  .hero__headline {
    max-width: 20ch;
    font-size: 4.5rem;
  }

  .hero__subhead {
    font-size: 1.25rem;
  }
}

/* -- Home: Method (LAYOUT.md §5 row 3) ------------------------------------- */

.method {
  padding-block: var(--space-6);
}

.method__eyebrow {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-muted);
  margin-bottom: var(--space-5);
}

.method__stages {
  display: flex;
  flex-direction: column;
}

.method__stage {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  padding-block: var(--space-4);
  /* Same --color-muted token throughout (mobile top rule and desktop
     left rule below both inherit this), just mixed toward transparent
     so it organizes the four stages without competing with the content —
     no new/arbitrary line color introduced. */
  border-top: 1px solid color-mix(in srgb, var(--color-muted) 55%, transparent);
}

.method__index {
  /* Not rust: small mono text fails AA at this size/weight (see the
     "Accent discipline" note near the top of this file), and the icons
     already carry this section's one rust accent per CLAUDE.md's
     Iconography spec — a second rust use here would be exactly the
     "reaching for rust twice" the design system warns against. */
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.method__icon {
  width: 40px;
  height: 40px;
  color: var(--color-rust);
}

.method__name {
  font-size: 1.375rem;
}

.method__descriptor {
  max-width: 32ch;
  color: var(--color-muted);
}

@media (min-width: 1024px) {
  .method {
    padding-block: var(--space-8);
  }

  .method__eyebrow {
    /* Tighter than the mobile gap (space-5, unchanged below) rather than
       looser — pulls the label and the stage row into one composition
       instead of two isolated elements at wider viewports. */
    margin-bottom: var(--space-4);
  }

  .method__stages {
    flex-direction: row;
  }

  .method__stage {
    flex: 1 1 0;
    padding-block: 0;
    padding-inline: var(--space-4);
    border-top: none;
    border-left: 1px solid color-mix(in srgb, var(--color-muted) 55%, transparent);
  }

  .method__icon {
    width: 48px;
    height: 48px;
  }

  .method__name {
    font-size: 1.75rem;
  }

  .method__stage:first-child {
    padding-inline-start: 0;
    /* No leading divider before Stage 01 — separators sit only between
       stages (Diagnose | Architect | Build | Sustain), never in front of
       the first one. */
    border-left: none;
  }

  .method__stage:last-child {
    padding-inline-end: 0;
  }
}

/* -- Home: Products teaser (LAYOUT.md §5 row 4) ---------------------------- */

.products {
  padding-block: var(--space-6);
}

.products__heading {
  max-width: 20ch;
  margin-bottom: var(--space-5);
  font-size: 1.75rem;
  line-height: 1.15;
}

.products__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
}

.products__card {
  display: block;
}

.products__image {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  margin-bottom: var(--space-3);
  object-fit: cover;
}

.products__image--fallback {
  display: flex;
  /* Bottom-left anchored, not centered: a "system plate" stamp rather
     than a placeholder graphic — the same deliberate-position-over-
     dead-centering move the Hero already uses for its own content. */
  align-items: flex-end;
  padding: var(--space-3);
  background: var(--color-ink);
}

.products__image-label {
  font-family: var(--font-mono);
  font-size: 1rem;
  line-height: 1.2;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--color-paper);
}

.products__status {
  display: block;
  margin-bottom: var(--space-1);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.products__name {
  margin-bottom: var(--space-1);
  font-size: 1.375rem;
}

.products__card:hover .products__name {
  text-decoration: underline;
}

.products__tagline {
  max-width: 34ch;
  color: var(--color-muted);
}

@media (min-width: 1024px) {
  .products {
    padding-block: var(--space-8);
  }

  .products__heading {
    max-width: 24ch;
    margin-bottom: var(--space-6);
    font-size: 2.5rem;
  }

  .products__grid {
    gap: var(--space-5);
  }

  /* One real Product today shouldn't read as a small leftover card in a
     mostly-empty row — it's the whole proof point, so it gets a
     deliberate feature width instead of the multi-column card size.
     Bounded (not stretched to the full container) per spec. */
  .products__grid--count-1 {
    grid-template-columns: minmax(0, 480px);
  }

  .products__grid--count-2 {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-6);
  }

  .products__grid--count-3 {
    grid-template-columns: repeat(3, 1fr);
  }

  .products__image-label {
    font-size: 1.375rem;
  }

  .products__name {
    font-size: 1.75rem;
  }

  .products__tagline {
    max-width: 40ch;
  }
}

/* -- Home: Section break (LAYOUT.md §5 row 5) ------------------------------ */

/* Dot-matrix/halftone gradient, per CLAUDE.md's Design reference — "instead
   of a hard rule or blank space." No exact dot size/spacing/height is
   specified anywhere in PRD/CLAUDE/LAYOUT; approximated in pure CSS (no
   image asset — stays lean, per PRD's load-time requirement) as a fixed
   dot grid whose visibility is masked into a gradient, the closest
   hand-written-CSS equivalent of a print halftone's density gradient.
   Background stays --color-paper throughout — true white is reserved for
   the Proof section that follows, not introduced here. */
.section-break {
  height: var(--space-8);
  background-color: var(--color-paper);
  background-image: radial-gradient(var(--color-ink) 1px, transparent 1px);
  background-size: 12px 12px;
  -webkit-mask-image: linear-gradient(to bottom, transparent, black);
  mask-image: linear-gradient(to bottom, transparent, black);
}

/* -- Home: Proof teaser (LAYOUT.md §5 row 6) -------------------------------- */

/* .zone-white supplies the background/text color (--color-white bg,
   --color-ink text) — the first legitimate use of true white on Home,
   reserved for this section alone. */
.proof {
  padding-block: var(--space-6);
}

.proof__heading {
  max-width: 20ch;
  margin-bottom: var(--space-5);
  font-size: 1.75rem;
  line-height: 1.15;
}

.proof__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
}

.proof__card {
  display: block;
}

.proof__media {
  position: relative;
  margin-bottom: var(--space-3);
}

.proof__image {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.proof__image--fallback {
  display: flex;
  /* Centered, not the Products fallback's bottom-left "stamp" — evidence
     reads calmer/more documentary than a product's system-plate treatment,
     a deliberate register difference within the same typographic family
     (still ink panel + font-mono, per LAYOUT.md §4's exact fallback). */
  align-items: center;
  justify-content: center;
  padding: var(--space-3);
  background: var(--color-ink);
  text-align: center;
}

.proof__image-label {
  font-family: var(--font-mono);
  font-size: 1rem;
  line-height: 1.2;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--color-paper);
}

.proof__status {
  /* LAYOUT.md §4: "status badge ... small, corner of the card" — an
     explicit position, unlike Products' in-flow status line.
     Case Studies Phase 02 completion (approved shared correction): a
     solid ink backing so the label stays legible over a real
     hero_image photograph, not only over the ink fallback it happened
     to always sit on while no real image existed. Square corners, no
     pill — an editorial label, not a SaaS badge. Over the fallback
     itself (still ink), the backing visually disappears into it,
     leaving only the same paper text this rule already had. Currently
     invisible in Home's own real output (zero published Case Studies
     means .proof never renders there today), so this shared-class
     change carries no current Home regression risk. */
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  padding: var(--space-1);
  background: var(--color-ink);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--color-paper);
}

.proof__industry {
  display: block;
  margin-bottom: var(--space-1);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  /* Rust here is explicit in LAYOUT.md §4 ("Industry tag ... --color-rust"),
     not a default reach for the accent — and unlike on --color-paper
     (4.25:1, fails AA for small text), rust on --color-white measures
     5.28:1, clearing AA for normal text. Verified in-browser, not just
     computed — see phase report. */
  color: var(--color-rust);
}

.proof__client {
  margin-bottom: var(--space-1);
  color: var(--color-muted);
}

.proof__outcome {
  /* LAYOUT.md §4: outcome is "a one-line teaser ... lead with the
     result" on the card — not the large font-display treatment reserved
     for the Case Study single page's own Outcome section (§8, a
     different, later-phase component). Real h3 for correct heading
     hierarchy; overridden away from the global h1-h4 bold/display default
     specifically so the result reads as calm evidence, not a shouted
     number. Weight/size sit a step above the industry tag/status
     metadata (clearly the lead content) and a step below .proof__heading
     (2.5rem/800 at desktop) — never competing with the section heading. */
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 1.25rem;
  line-height: 1.35;
}

@media (min-width: 1024px) {
  .proof {
    padding-block: var(--space-8);
  }

  .proof__heading {
    max-width: 24ch;
    margin-bottom: var(--space-6);
    font-size: 2.5rem;
  }

  .proof__grid {
    gap: var(--space-5);
  }

  /* Same count-responsive logic as the Products grid: one real Case
     Study today is the whole proof point, not a leftover card. */
  .proof__grid--count-1 {
    grid-template-columns: minmax(0, 480px);
  }

  .proof__grid--count-2 {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-6);
  }

  .proof__grid--count-3 {
    grid-template-columns: repeat(3, 1fr);
  }

  .proof__image-label {
    font-size: 1.375rem;
  }

  .proof__outcome {
    font-size: 1.5rem;
  }
}

/* -- Home: Insights teaser (LAYOUT.md §5 row 7) ----------------------------- */

.insights {
  padding-block: var(--space-6);
}

.insights__heading {
  max-width: 20ch;
  margin-bottom: var(--space-5);
  font-size: 1.75rem;
  line-height: 1.15;
}

.insights__list {
  /* A list, not a grid — LAYOUT.md §5 row 7: "Simple list, not cards ...
     keep visually lighter than the proof section." Single column at
     every width is the point, not a desktop grid collapsed for mobile. */
  display: flex;
  flex-direction: column;
}

.insights__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding-block: var(--space-4);
  /* Same softened muted-token divider as Method/Proof — organizes the
     list without competing with the content. */
  border-top: 1px solid color-mix(in srgb, var(--color-muted) 55%, transparent);
}

.insights__date {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.insights__title {
  font-size: 1.25rem;
}

.insights__title a:hover {
  text-decoration: underline;
}

.insights__excerpt {
  max-width: 56ch;
  color: var(--color-muted);
}

@media (min-width: 1024px) {
  .insights {
    padding-block: var(--space-8);
  }

  .insights__heading {
    max-width: 24ch;
    margin-bottom: var(--space-6);
    font-size: 2.5rem;
  }

  .insights__item {
    /* An editorial index, not a stack of blog cards: dates form their
       own column so the list reads as scannable rows, not repeated
       vertical stacks. */
    flex-direction: row;
    align-items: baseline;
    gap: var(--space-4);
  }

  .insights__date {
    flex: 0 0 auto;
    width: 112px;
  }

  .insights__content {
    flex: 1 1 auto;
  }
}

/* -- Home/global: Contact CTA (LAYOUT.md §5 row 8) -------------------------- */

/* .zone-ink supplies the background/text color — "bookends the page in
   the same dark register as the hero" (LAYOUT.md). Left-aligned to the
   same global grid as every other section, not centered — a centered
   treatment here would be the one place breaking the page's established
   alignment system, right at the most decisive moment. */
.contact-cta {
  padding-block: var(--space-7);
}

.contact-cta__heading {
  max-width: 16ch;
  font-size: 2.75rem;
  line-height: 1.05;
}

.contact-cta__heading a:hover {
  text-decoration: underline;
}

@media (min-width: 1024px) {
  .contact-cta {
    padding-block: var(--space-8);
  }

  .contact-cta__heading {
    font-size: 4rem;
  }
}

/* -- Site footer (LAYOUT.md §3) -------------------------------------------- */

.site-footer {
  background: var(--color-ink);
  color: var(--color-paper);
  padding-block: var(--space-6);
}

.site-footer__grid {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

@media (min-width: 1024px) {
  .site-footer__grid {
    flex-direction: row;
    justify-content: space-between;
  }

  /* .site-footer__nav wraps the shared .site-nav__list (nj_eze_footer_nav())
     as one of three default flex-shrink:1 columns in this row. Once the
     brand/contact columns push it below its natural content width, the row
     itself doesn't wrap (.site-nav__list has no flex-wrap) — instead an
     individual multi-word label ("Case Studies") wraps at its own word
     break, since it's the only item with one. Reserving this column's
     natural width and disabling the word-break fixes both symptoms without
     touching the shared .site-nav__list rules the Header also relies on. */
  .site-footer__nav {
    flex-shrink: 0;
  }

  .site-footer__nav .site-nav__list a {
    white-space: nowrap;
  }
}

/* Approved Footer social/legal navigation milestone: social row, legal
   row, then the pre-existing copyright line, stacked with one uniform
   rhythm. Reuses --space-4 — the exact value .site-footer__copyright
   used as its own standalone margin-top before this block existed — as
   this wrapper's gap, so the copyright line's spacing above it is
   unchanged and the two new rows above that get the same generous
   rhythm rather than a tighter, invented one. */
.site-footer__secondary {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* Restrained by design (LAYOUT.md's opening Footer spec plus this
   milestone's own approved intent: "secondary to the main Footer CTA/
   content... must not become visually dominant") — both rows share
   .site-footer__copyright's own existing muted/small treatment directly
   below them rather than a new, more prominent tier. flex-wrap prevents
   overflow at narrow widths without a dedicated breakpoint; one missing
   link (an unconfigured social URL, or Terms with no page assigned)
   never leaves a gap in the middle since each list only ever contains
   the links that actually rendered. */
.site-footer__social-list,
.site-footer__legal-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.site-footer__social a,
.site-footer__legal a {
  color: var(--color-muted);
  font-size: 0.85rem;
}

.site-footer__copyright {
  color: var(--color-muted);
  font-size: 0.85rem;
}

/* -- About: Intro (LAYOUT.md §6 row 2) ------------------------------------- */

/* .zone-ink supplies the background/text color. Padding-block rhythm
   matches .contact-cta, not .hero — LAYOUT.md calls this a "type-only
   hero, same restraint as Home" (i.e. no imagery, same discipline), not
   the same full-viewport (88svh) treatment; an internal page opening
   doesn't carry the same weight as the site's own Hero. */
.about-intro {
  padding-block: var(--space-7);
}

/* Font size matches the established section-heading rung (.products__heading
   and its siblings), not Hero's 72px scale — About's H1 is a real heading,
   deliberately subordinate to Home's Hero rather than competing with it. */
.about-intro__heading {
  max-width: 30ch;
  font-size: 1.75rem;
  line-height: 1.15;
  text-wrap: balance;
}

@media (min-width: 1024px) {
  .about-intro {
    padding-block: var(--space-8);
  }

  .about-intro__heading {
    font-size: 2.5rem;
  }
}

/* -- About: Why diagnostic (LAYOUT.md §6 row 3) ---------------------------- */

/* .zone-paper supplies the background/text color. No section-break device
   between this and the ink Intro above it — LAYOUT.md only authorizes
   that device for Home's Products->Proof register change; everywhere
   else on the site (including Home's own Hero->Method), the zone class
   boundary alone carries the transition. Padding-block matches .method,
   not .contact-cta/.about-intro — Method is the closest existing
   precedent for this role (explanatory paper section immediately
   following an ink opener), not a bookend section in its own right. */
.about-why {
  padding-block: var(--space-6);
}

/* Elevated body copy, not a second heading: font-size/line-height/
   max-width all reused as-is from .hero__subhead — the system's one
   existing "readable elevated paragraph" rung — rather than inventing a
   new size. Sits clearly below .about-intro__heading (1.75rem/2.5rem)
   and above ordinary body text. font-family inherits --font-body (the
   default for <p>), not --font-display — this is prose, not a headline. */
.about-why__paragraph {
  max-width: 42ch;
  font-size: 1.0625rem;
  line-height: 1.5;
}

@media (min-width: 768px) {
  .about-why__paragraph {
    font-size: 1.125rem;
  }
}

@media (min-width: 1024px) {
  .about-why__paragraph {
    font-size: 1.25rem;
  }
}

/* -- About: Who we work with (LAYOUT.md §6 row 4) --------------------------- */

/* Same zone as .about-why (--color-paper) — no zone change, so no
   transition device applies here either; this section and .about-why are
   two consecutive plain paragraphs on one continuous paper background,
   each getting its own section-level rhythm. Padding-block matches
   .about-why (not a new value) — same precedent Method/Products already
   set on Home for adjacent same-zone sections, each independently using
   --space-6 rather than one section inheriting the other's box. */
.about-who {
  padding-block: var(--space-6);
}

/* Same role as .about-why__paragraph (plain explanatory prose, same
   "Plain paragraph, no card/grid needed" note in LAYOUT.md) — font-size/
   line-height/max-width reused identically rather than diverging for no
   reason. Kept as its own rule block, not merged via a shared selector,
   matching this codebase's existing convention of one rule block per
   section even when values are identical (e.g. .products__heading /
   .proof__heading / .insights__heading). */
.about-who__paragraph {
  max-width: 42ch;
  font-size: 1.0625rem;
  line-height: 1.5;
}

@media (min-width: 768px) {
  .about-who__paragraph {
    font-size: 1.125rem;
  }
}

@media (min-width: 1024px) {
  .about-who__paragraph {
    font-size: 1.25rem;
  }
}

/* -- Expertise: Intro (LAYOUT.md §7 row 2) ---------------------------------- */

/* .zone-ink supplies the background/text color. Values reused as-is from
   .about-intro, not reinvented: same padding-block rhythm (ink-bookend
   pattern already shared by .contact-cta), same restrained internal-page
   heading rung (matches .products__heading and siblings, not Home's
   72px Hero scale) — this is a second internal page opening on the same
   ink register as About's, not a new visual treatment. Own selector
   names per-template, not a shared class, matching this codebase's
   existing convention (e.g. .products__heading / .proof__heading /
   .insights__heading are separate identical-value blocks, not one
   shared rule). */
.expertise-intro {
  padding-block: var(--space-7);
}

.expertise-intro__heading {
  max-width: 30ch;
  font-size: 1.75rem;
  line-height: 1.15;
  text-wrap: balance;
}

@media (min-width: 1024px) {
  .expertise-intro {
    padding-block: var(--space-8);
  }

  .expertise-intro__heading {
    font-size: 2.5rem;
  }
}

/* -- Expertise: Service tabs (LAYOUT.md §7 row 3, §9) ----------------------- */

/* .zone-paper supplies the section's own background/text color. Approved
   Phase 02 visual strategy: "color-coded" is read as state-coding within
   the existing palette (active = ink/paper inversion, inactive =
   paper/ink), not four new hues — see the Phase 02 design-decision
   checkpoint. No rust, no new tokens, no derived/tinted colors anywhere
   below. Visual state (width, rotation, color, panel reveal) is driven
   entirely by CSS attribute selectors reacting to the trigger's own
   aria-expanded — JS only ever sets that one attribute (assets/js/
   main.js), so accessibility state and visual state cannot drift apart.

   Mobile-first baseline below is also the literal spec breakpoint for
   the stacked accordion (LAYOUT.md §9: "Mobile (< 768px)... convert to
   a standard stacked accordion") — the vertical-band layout applies at
   >=768px, i.e. tablet AND desktop both get the vertical-band model;
   only sub-768px gets this accordion baseline. */
.expertise-services {
  padding-block: var(--space-6);
}

.expertise-services__list {
  display: flex;
  flex-direction: column;
}

/* Locked color treatment applies at every width, not desktop-only:
   inactive = paper background / ink text, active = ink background /
   paper text (approved Phase 02 design decision, §7 "MOBILE BEHAVIOR" —
   "Use the same approved color inversion"). */
.expertise-services__item {
  padding-inline: var(--space-2);
  border-bottom: 1px solid var(--color-ink);
  background: var(--color-paper);
  color: var(--color-ink);
  transition: background-color 200ms ease, color 200ms ease;
}

.expertise-services__item:last-child {
  border-bottom: none;
}

.expertise-services__item:has(.expertise-services__trigger[aria-expanded='true']) {
  background: var(--color-ink);
  color: var(--color-paper);
}

.expertise-services__label {
  margin: 0;
  font-size: 1rem;
}

.expertise-services__trigger {
  display: block;
  width: 100%;
  padding: var(--space-3) 0;
  background: none;
  border: none;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: inherit;
  text-align: left;
  color: inherit;
  cursor: pointer;
}

/* Reveal via CSS Grid's 0fr->1fr technique: animates true intrinsic
   height with no arbitrary max-height guess, and needs no JS-added
   class — it reacts to the trigger's own aria-expanded via the sibling
   combinator. */
.expertise-services__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 200ms ease;
}

/* The trigger lives inside .expertise-services__label (the <h3> wrapper —
   see the accordion heading pattern note in page-expertise.php), so it
   is not itself a sibling of .expertise-services__panel; :has() reaches
   through that wrapper to find the expanded trigger instead. */
.expertise-services__label:has(.expertise-services__trigger[aria-expanded='true']) ~ .expertise-services__panel {
  grid-template-rows: 1fr;
}

.expertise-services__panel-inner {
  min-height: 0;
  overflow: hidden;
}

.expertise-services__description {
  max-width: 42ch;
  padding-bottom: var(--space-3);
  font-size: 1.0625rem;
  line-height: 1.5;
}

@media (min-width: 768px) {
  .expertise-services__list {
    flex-direction: row;
    align-items: stretch;
  }

  /* Collapsed band width: the smallest defensible value driven by
     content fit, not an arbitrary pixel guess — a single rotated line
     of the label text (this component's own font-size) plus padding on
     both sides needs far less than 128px, but --space-8 is the nearest
     existing scale rung that comfortably clears every label's rotated
     footprint with real breathing room, so it's reused rather than
     introducing a new, narrower one-off value. 3 collapsed (384px) +
     gaps still leaves ~800px for the active band at the 1200px
     container width. */
  .expertise-services__item {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    width: var(--space-8);
    padding-inline: 0;
    overflow: hidden;
    border-bottom: none;
    border-right: 1px solid var(--color-ink);
    transition: width 200ms ease, background-color 200ms ease, color 200ms ease;
  }

  .expertise-services__item:last-child {
    border-right: none;
  }

  .expertise-services__item:has(.expertise-services__trigger[aria-expanded='true']) {
    width: auto;
    flex: 1 1 auto;
  }

  .expertise-services__label {
    flex-shrink: 0;
    margin: 0;
  }

  .expertise-services__trigger {
    width: auto;
    padding: var(--space-4) var(--space-2);
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    white-space: nowrap;
  }

  /* The trigger sits flush against .expertise-services__item's own
     overflow:hidden (needed to clip the band's width transition), so the
     global :focus-visible ring's positive outline-offset gets cut off on
     the sides that touch that edge. Pulling the ring inward keeps it
     fully visible without touching the shared global rule, the item's
     clipping, or anything mobile — mobile's item has no overflow:hidden,
     so it isn't affected by this and needs no equivalent override. */
  .expertise-services__trigger:focus-visible {
    outline-offset: -2px;
  }

  .expertise-services__item:has(.expertise-services__trigger[aria-expanded='true']) .expertise-services__trigger {
    writing-mode: horizontal-tb;
    transform: none;
    padding: var(--space-4) var(--space-3);
    white-space: normal;
  }

  .expertise-services__panel-inner {
    padding-right: var(--space-4);
  }

  .expertise-services__description {
    padding-top: var(--space-4);
    padding-bottom: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .expertise-services__item,
  .expertise-services__panel {
    transition: none;
  }
}

/* -- Expertise: Method recap (LAYOUT.md §7 row 4) --------------------------- */

/* .zone-paper — same register as Service tabs directly above it, so no
   transition device applies here either; two consecutive same-zone
   sections, each getting its own section-level rhythm, same reasoning
   already established for About's Why->Who. Padding-block matches
   .expertise-services (not .expertise-intro's ink-bookend rhythm) —
   this is a same-zone continuation, not a bookend. */
.expertise-method-recap {
  padding-block: var(--space-6);
}

/* Elevated body copy, not a heading: font-size/line-height/max-width
   reused as-is from the established "readable elevated paragraph" rung
   (.hero__subhead / .about-why__paragraph / .about-who__paragraph) —
   same role, same values, not reinvented. */
.expertise-method-recap__text {
  max-width: 42ch;
  font-size: 1.0625rem;
  line-height: 1.5;
}

/* The whole line is the link (LAYOUT.md's row 4 is one thing, "one line
   + link", not body text plus a separate sub-link) — a permanent
   underline is the discoverability affordance here, since unlike the
   Contact CTA's own link-as-heading treatment, this line has no scale
   or zone change of its own to signal interactivity at rest. Existing
   inherited ink text color and the global :focus-visible treatment are
   reused as-is — no new color. */
.expertise-method-recap__text a {
  text-decoration: underline;
}

@media (min-width: 768px) {
  .expertise-method-recap__text {
    font-size: 1.125rem;
  }
}

@media (min-width: 1024px) {
  .expertise-method-recap__text {
    font-size: 1.25rem;
  }
}

/* -- Products: Intro (LAYOUT.md §7b row 2) ---------------------------------- */

/* .zone-ink supplies the background/text color. Heading values reused as-
   is from .about-intro__heading/.expertise-intro__heading, not
   reinvented: same padding-block rhythm, same restrained internal-page
   heading rung — a third internal page opening on the same ink register,
   not a new visual treatment. Own selector names per-template, matching
   the existing convention (each is a separate identical-value block, not
   one shared rule). */
.products-intro {
  padding-block: var(--space-7);
}

/* margin-bottom (not the heading's usual bare rule on About/Expertise)
   because this Intro is the first one with a second element under the
   H1 — reuses .hero__headline's own heading->subhead spacing value
   rather than inventing a new one. */
.products-intro__heading {
  max-width: 30ch;
  margin-bottom: var(--space-4);
  font-size: 1.75rem;
  line-height: 1.15;
  text-wrap: balance;
}

/* Subordinate supporting line — LAYOUT.md's "one line on why" has no
   equivalent on About/Expertise's Intros, so this reuses the site's one
   existing precedent for "readable elevated paragraph directly under a
   headline in the same ink zone": .hero__subhead, reused verbatim (the
   same values already reused a second time for
   .expertise-method-recap__text) rather than inventing a new size. */
.products-intro__support {
  max-width: 42ch;
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.5;
}

@media (min-width: 768px) {
  .products-intro__support {
    font-size: 1.125rem;
  }
}

@media (min-width: 1024px) {
  .products-intro {
    padding-block: var(--space-8);
  }

  .products-intro__heading {
    font-size: 2.5rem;
  }

  .products-intro__support {
    font-size: 1.25rem;
  }
}

/* -- Products: Detail blocks (LAYOUT.md §7b row 3, §4c) --------------------- */

/* .zone-paper supplies the section's own background/text color. Padding-
   block matches the established zone-paper-directly-after-ink-Intro
   rhythm (.expertise-services, Home's .products), not the ink-bookend
   rhythm. */
.products-detail {
  padding-block: var(--space-6);
}

@media (min-width: 1024px) {
  .products-detail {
    padding-block: var(--space-8);
  }
}

/* Content-first, media-second in the DOM unconditionally — desktop
   alternation is CSS-only (order, below), so visual position, DOM order,
   and keyboard-focus order can never disagree, and mobile needs no
   special-casing: a single flex column already yields content-then-media
   for every article with nothing to override. Generous block-to-block
   spacing (--space-8, the largest existing rung) separates these
   substantial, self-contained compositions the way Method's own
   inter-item rhythm doesn't need to — each block here carries far more
   visual weight than a compact icon+label unit. */
.product-detail {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.product-detail + .product-detail {
  margin-top: var(--space-8);
}

.product-detail__content {
  order: 1;
}

.product-detail__media {
  order: 2;
}

/* font-mono/small/muted: exact reuse of Home's .products__status values
   (front-page.php's teaser card), not a new "badge" design — this
   codebase's own existing usage of LAYOUT.md's "Status badge" language
   already resolves to plain mono text with no container, so that's what
   "badge" means here too. Kept neutral (muted, not rust) specifically so
   rust isn't reached for twice within one Product article — the tagline
   below is this block's one rust element (CLAUDE.md's accent
   discipline). */
.product-detail__status {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--color-muted);
}

/* Reuses Home's .products__name size exactly — the surrounding two-
   column composition and generous spacing are what make this block read
   as "more substantial" (LAYOUT.md §4c), not a larger type rung; the
   identity treatment itself doesn't need to change. */
.product-detail__name {
  margin: 0;
  font-size: 1.375rem;
}

/* Small rust text directly under the name — LAYOUT.md §4c's own explicit
   spec for this component (unlike the Home teaser card's tagline, which
   stays --color-muted per §4b). This is the one rust element this
   article uses; status/CTA/media/name/description all stay off rust
   deliberately (CLAUDE.md: "reaching for rust twice in one section is a
   sign to stop"). Font-size inherited (already smaller than the heading
   above it) rather than introducing a new "small" number. */
.product-detail__tagline {
  margin: 0;
  color: var(--color-rust);
}

/* Elevated body copy: max-width/font-size/line-height reused as-is from
   the site's one "readable elevated paragraph" rung (.hero__subhead /
   .expertise-method-recap__text / .about-why__paragraph) — real
   paragraph room per LAYOUT.md §4c, not reinvented. */
.product-detail__description {
  max-width: 42ch;
  font-size: 1.0625rem;
  line-height: 1.5;
}

/* Plain text link with a permanent underline — same discoverability
   device already established for .expertise-method-recap__text a, since
   like that link (and unlike the Contact CTA's own heading-scale link)
   this action has no scale/zone change of its own to signal
   interactivity at rest. No new "button" shape: nothing else on this
   site uses a boxed/filled button, so introducing one here would be a
   new, unauthorized visual device. */
.product-detail__action {
  margin: 0;
}

.product-detail__action a {
  font-weight: 700;
  text-decoration: underline;
}

/* Locked media system (Phase 02 design-decision correction): 4:3, not
   3:2 — the ratio Home's Product Card already established, reused
   rather than introducing a second one. object-fit:cover matches the
   same precedent. */
.product-detail__image {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* No-image fallback: exact reuse of Home's .products__image--fallback
   vocabulary (front-page.php) at the same 4:3 geometry a real image
   would occupy — ink panel, bottom-left-anchored mono label, not a new
   device. */
.product-detail__image--fallback {
  display: flex;
  align-items: flex-end;
  padding: var(--space-3);
  background: var(--color-ink);
}

.product-detail__image-label {
  font-family: var(--font-mono);
  font-size: 1rem;
  line-height: 1.2;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--color-paper);
}

@media (min-width: 768px) {
  /* Two-column alternation begins here, matching the same breakpoint
     already established for Expertise Service Tabs' own two-column-vs-
     stacked switch (LAYOUT.md §9: tablet AND desktop both get the
     side-by-side model; only sub-768px gets the stacked baseline). */
  .product-detail {
    flex-direction: row;
    align-items: center;
    gap: var(--space-6);
  }

  .product-detail__content,
  .product-detail__media {
    flex: 1 1 0;
  }

  /* First article (and every odd one after it) alternates to media-left/
     content-right by swapping only the visual order — DOM stays
     content-first for every article regardless, so focus order never
     changes. Even articles need no override: initial content-first/
     media-second order already reads as content-left/media-right. */
  .product-detail:nth-child(odd) .product-detail__content {
    order: 2;
  }

  .product-detail:nth-child(odd) .product-detail__media {
    order: 1;
  }

  .product-detail__name {
    font-size: 1.75rem;
  }

  .product-detail__description {
    font-size: 1.125rem;
  }
}

@media (min-width: 1024px) {
  .product-detail__description {
    font-size: 1.25rem;
  }
}

/* -- Case Studies: Archive Intro (LAYOUT.md §8, Archive row 2) ------------- */

/* .zone-white supplies the background/text color. Padding-block/heading
   values reused as-is from .about-intro__heading/.expertise-intro__heading/
   .products-intro__heading, not reinvented: same restrained internal-page
   heading rung — this differs from those only by register (white evidence
   zone instead of ink), not by scale. Own selector name per-template,
   matching the existing convention. */
.case-studies-intro {
  padding-block: var(--space-7);
}

.case-studies-intro__heading {
  max-width: 30ch;
  font-size: 1.75rem;
  line-height: 1.15;
  text-wrap: balance;
}

@media (min-width: 1024px) {
  .case-studies-intro {
    padding-block: var(--space-8);
  }

  .case-studies-intro__heading {
    font-size: 2.5rem;
  }
}

/* -- Case Studies: Archive Grid (LAYOUT.md §8, Archive row 4) -------------- */

/* .zone-white continues the same register the Intro already opened —
   no separator/rule/background change between them, so the two
   sections read as one seamless white field (same pattern already used
   for Expertise's Service Tabs -> Method Recap and About's Why -> Who:
   adjacent same-zone sections, no transition device). padding-block
   matches Home's own .proof section rhythm, reused rather than
   reinvented, since this wrapper exists only to host the same card
   contract at its own spacing/QA scope — .proof__grid and its card
   classes are reused unchanged from front-page.php, not duplicated. */
.case-studies-grid-section {
  padding-block: var(--space-6);
}

@media (min-width: 1024px) {
  .case-studies-grid-section {
    padding-block: var(--space-8);
  }
}

/* -- Case Study Single: Hero (LAYOUT.md §8, Single row 2) ------------------ */

/* .zone-white supplies the section's own background/text color. The Hero
   is deliberately split into two independent regions rather than one
   data-header-zone spanning the whole thing: .__meta (industry/client)
   is the only part marked data-header-zone, since it's a known solid
   white the existing [data-header-zone].zone-white Header rule is
   already proven safe over (same mechanism as the Archive Intro) — an
   arbitrary uploaded hero_image has no such guarantee, so it sits
   below, outside the marked zone, where the Header has already
   geometry-transitioned to its scrolled state by the time it's
   reached. */
.case-study-single-hero__meta {
  padding-block: var(--space-7);
}

@media (min-width: 1024px) {
  .case-study-single-hero__meta {
    padding-block: var(--space-8);
  }
}

/* Values reused as-is from .proof__industry/.proof__client (the Case
   Study Card's own already-approved treatment) — same metadata role,
   not reinvented for the Hero. */
.case-study-single-hero__industry {
  display: block;
  margin-bottom: var(--space-1);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--color-rust);
}

.case-study-single-hero__client {
  margin: 0;
  color: var(--color-muted);
}

.case-study-single-hero__media {
  /* No .container wrapper by design (see the template) — this is the
     one element on the page that actually needs edge-to-edge width;
     LAYOUT.md §1 explicitly authorizes "Hero/zone backgrounds... run
     full-bleed edge-to-edge even when the text/content inside stays
     within the 1200px container," and this is that same rule applied
     to Hero media specifically, not just a background color. */
  display: block;
}

/* Real image: intrinsic/authored proportion preserved, only constrained
   to the viewport width — no invented cinematic crop ratio. */
.case-study-single-hero__image {
  display: block;
  width: 100%;
  height: auto;
}

/* Fallback: the same ink-panel + mono-label vocabulary already approved
   for the Case Study Card/Archive Grid, "now at Hero scale" — reusing
   its own 4:3 box shape is part of that same vocabulary (this is a
   solid placeholder graphic, not a photograph, so this ratio is not
   the "speculative cinematic crop" the real image must avoid). Full
   section width at this ratio already gives it real visual weight
   without a viewport-height trick. Centered, matching the Card's own
   established fallback alignment (not the Product fallback's
   different bottom-left "stamp" treatment). */
.case-study-single-hero__image--fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 4 / 3;
  padding: var(--space-3);
  background: var(--color-ink);
  text-align: center;
}

.case-study-single-hero__image-label {
  font-family: var(--font-mono);
  font-size: 1rem;
  line-height: 1.2;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--color-paper);
}

@media (min-width: 1024px) {
  .case-study-single-hero__image-label {
    font-size: 1.375rem;
  }
}

/* -- Case Study Single: The Problem / What We Built (Single rows 3-4) ------ */

/* .zone-white — same register as the Hero directly above, no transition
   device between them (same "seamless through whitespace alone"
   principle already proven on the Archive Intro->Grid and Expertise's
   own same-zone continuations). padding-block matches the established
   same-zone-continuation rhythm (.expertise-services /
   .case-studies-grid-section), not the Hero's own ink-bookend-style
   rhythm — these are content sections, not a page opener. */
.case-study-single-problem,
.case-study-single-solution {
  padding-block: var(--space-6);
}

@media (min-width: 1024px) {
  .case-study-single-problem,
  .case-study-single-solution {
    padding-block: var(--space-8);
  }
}

/* Small mono/muted "eyebrow" heading — reused as-is from
   .method__eyebrow, the site's one existing precedent for a real
   semantic heading that reads as a quiet structural label rather than
   a prominent title (matches "The Problem"/"What We Built" being
   source-given structural labels, not display copy, per LAYOUT.md §8). */
.case-study-single-problem__heading,
.case-study-single-solution__heading {
  margin-bottom: var(--space-3);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-muted);
}

/* Elevated body copy: max-width/font-size/line-height reused as-is from
   the site's one "readable elevated paragraph" rung (.hero__subhead /
   .expertise-method-recap__text / .about-why__paragraph /
   .product-detail__description) — "plain paragraph" per LAYOUT.md §8,
   not reinvented. */
.case-study-single-problem__text,
.case-study-single-solution__text {
  max-width: 42ch;
  font-size: 1.0625rem;
  line-height: 1.5;
}

@media (min-width: 768px) {
  .case-study-single-problem__text,
  .case-study-single-solution__text {
    font-size: 1.125rem;
  }
}

@media (min-width: 1024px) {
  .case-study-single-problem__text,
  .case-study-single-solution__text {
    font-size: 1.25rem;
  }
}

/* -- Case Study Single: The Outcome / Status (Single rows 5-6) ------------- */

.case-study-single-outcome {
  padding-block: var(--space-6);
}

@media (min-width: 1024px) {
  .case-study-single-outcome {
    padding-block: var(--space-8);
  }
}

/* Heading + Status share one row (LAYOUT.md §8: "Status — inline with
   Outcome"); DOM order stays heading, then status, then statement — this
   is a flex row for wide viewports, wrapping naturally at mobile widths,
   not a grid/order trick. */
.case-study-single-outcome__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

/* Same quiet structural-label values as The Problem/What We Built
   headings above (own rule, not grouped into theirs — Phase 01's rule
   stays untouched). */
.case-study-single-outcome__heading {
  margin-bottom: 0;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-muted);
}

/* Status: small, mono, neutral — subordinate to the Outcome statement
   below it. Deliberately not .proof__status: that treatment exists to
   guarantee contrast over an unpredictable media background, which
   doesn't apply here — Single Status sits in plain white content flow,
   so it gets none of the Card's ink-backing/pill/corner-overlay
   machinery. Values only (font-mono/small/muted), no shared selector. */
.case-study-single-outcome__status {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--color-muted);
}

/* The proof moment (LAYOUT.md §8 row 5: "give it real visual weight,
   don't treat it as just another paragraph"). Reuses the Contact CTA
   heading's own display-scale rung (2.75rem/4rem, --font-display, weight
   800) — the site's one existing precedent for a short high-authority
   statement — values only, not the .contact-cta__heading selector, and
   .contact-cta itself is untouched. max-width reuses the same restrained
   measure already used by every template's intro heading (30ch), not a
   new number. No rust, no quotation marks, no card/border/shadow — the
   field value alone carries the emphasis. */
.case-study-single-outcome__statement {
  max-width: 30ch;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 2.75rem;
  line-height: 1.1;
}

@media (min-width: 1024px) {
  .case-study-single-outcome__statement {
    font-size: 4rem;
  }
}

/* -- Case Study Single: Next case study (Single row 7) --------------------- */

.case-study-single-next {
  padding-block: var(--space-6);
}

@media (min-width: 1024px) {
  .case-study-single-next {
    padding-block: var(--space-8);
  }
}

/* Reuses the same internal-page-H1 rung already used by every other
   template's own intro heading (About/Expertise/Products/Case Studies
   Archive) — a real functional navigation moment, not another quiet
   eyebrow label. font-family/weight/line-height already come from the
   global h1-h4 rule; only size is set here. */
.case-study-single-next__heading {
  margin: 0;
  font-size: 1.75rem;
}

@media (min-width: 1024px) {
  .case-study-single-next__heading {
    font-size: 2.5rem;
  }
}

.case-study-single-next__heading a:hover {
  text-decoration: underline;
}

/* -- Insights Archive: Intro (LAYOUT.md §10, Archive row 2) ---------------- */

/* Values reused as-is from .about-intro/.about-intro__heading — the
   established "internal-page Intro, heading only, no supporting line"
   rung (own selectors, not a shared class — same anti-coupling
   discipline already used throughout Case Studies). */
.insights-archive-intro {
  padding-block: var(--space-7);
}

.insights-archive-intro__heading {
  max-width: 30ch;
  font-size: 1.75rem;
  line-height: 1.15;
  text-wrap: balance;
}

@media (min-width: 1024px) {
  .insights-archive-intro {
    padding-block: var(--space-8);
  }

  .insights-archive-intro__heading {
    font-size: 2.5rem;
  }
}

/* -- Insights Archive: Post list + Pagination (LAYOUT.md §10, rows 3-4) ---- */

/* Row rhythm/date-column values reused as-is from Home's own Insights
   teaser (.insights__item/.insights__date, front-page.php) — the site's
   one existing "list, not cards" precedent for this exact content
   shape, per LAYOUT.md's own "matches Home's Insights teaser" note.
   Home stays untouched; these are Archive-scoped selectors, not
   .insights__* reused directly. One deliberate deviation from that
   precedent: excerpt here is ink, not muted — this is the Archive's
   primary content, not a lightweight teaser, so it gets full body-text
   weight rather than Home's subordinate treatment. */
.insights-archive-list {
  padding-block: var(--space-6);
}

@media (min-width: 1024px) {
  .insights-archive-list {
    padding-block: var(--space-8);
  }
}

.insights-archive-list__items {
  display: flex;
  flex-direction: column;
}

.insights-archive-list__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding-block: var(--space-5);
  border-top: 1px solid color-mix(in srgb, var(--color-muted) 55%, transparent);
}

.insights-archive-list__item:last-child {
  border-bottom: 1px solid color-mix(in srgb, var(--color-muted) 55%, transparent);
}

.insights-archive-list__date {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--color-muted);
}

.insights-archive-list__title {
  font-size: 1.25rem;
}

.insights-archive-list__title a:hover {
  text-decoration: underline;
}

.insights-archive-list__excerpt {
  max-width: 56ch;
  margin-top: var(--space-1);
}

@media (min-width: 1024px) {
  .insights-archive-list__item {
    flex-direction: row;
    align-items: baseline;
    gap: var(--space-4);
  }

  .insights-archive-list__date {
    flex: 0 0 auto;
    width: 112px;
  }

  .insights-archive-list__content {
    flex: 1 1 auto;
  }
}

/* Native the_posts_pagination() output, restrained to read as ordinary
   editorial navigation — plain text links, no pill/button/filled-box
   treatment. Current page distinguished by weight + underline together,
   not color alone. Scoped under .insights-archive-list rather than the
   bare core .pagination class so no other future use of core pagination
   is affected. */
.insights-archive-list .pagination {
  margin-top: var(--space-6);
}

.insights-archive-list .pagination .nav-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
}

.insights-archive-list .pagination .page-numbers {
  color: var(--color-muted);
}

.insights-archive-list .pagination a.page-numbers:hover {
  color: var(--color-ink);
  text-decoration: underline;
}

.insights-archive-list .pagination .page-numbers.current {
  color: var(--color-ink);
  font-weight: 500;
  text-decoration: underline;
}

/* -- Insights Single: Post (LAYOUT.md §10, Single row 2) ------------------- */

/* Values reused as-is: title reuses the established internal-page-H1
   rung (About/Expertise/Products/Case Studies Archive/Insights
   Archive), no max-width constraint — unlike those fixed studio-written
   headings, an editorial article title's real length is unpredictable,
   so it wraps within the .container's own measure rather than a guessed
   ch value. Date reuses the same small/mono/muted metadata treatment
   already used throughout (Case Study Hero industry, Insights Archive
   list date). */
.insights-single-post {
  padding-block: var(--space-6);
}

@media (min-width: 1024px) {
  .insights-single-post {
    padding-block: var(--space-8);
  }
}

.insights-single-post__title {
  font-size: 1.75rem;
  line-height: 1.15;
  text-wrap: balance;
}

@media (min-width: 1024px) {
  .insights-single-post__title {
    font-size: 2.5rem;
  }
}

.insights-single-post__date {
  display: block;
  margin-top: var(--space-2);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--color-muted);
}

/* Article-body typography: the first genuine long-form the_content()
   surface in the theme. Minimum generic support for ordinary editor
   output, not a bespoke block-design system. Body copy reuses the
   site's one existing "elevated readable paragraph" rung
   (.hero__subhead and its several reuses) at the established 42ch
   measure; headings step down from the page H1 using already-existing
   font-size values elsewhere in this file (1.375rem, 1.125rem) rather
   than inventing new ones — font-family/weight/line-height for h2/h3
   already come from the global `h1,h2,h3,h4` rule. */
.insights-single-post__content {
  max-width: 42ch;
  margin-top: var(--space-5);
}

.insights-single-post__content > *:first-child {
  margin-top: 0;
}

.insights-single-post__content p,
.insights-single-post__content ul,
.insights-single-post__content ol,
.insights-single-post__content blockquote,
.insights-single-post__content figure {
  margin-top: var(--space-3);
  font-size: 1.0625rem;
  line-height: 1.5;
}

@media (min-width: 768px) {
  .insights-single-post__content p,
  .insights-single-post__content ul,
  .insights-single-post__content ol,
  .insights-single-post__content blockquote {
    font-size: 1.125rem;
  }
}

.insights-single-post__content h2 {
  margin-top: var(--space-5);
  margin-bottom: var(--space-1);
  font-size: 1.375rem;
  line-height: 1.2;
}

.insights-single-post__content h3 {
  margin-top: var(--space-4);
  margin-bottom: var(--space-1);
  font-size: 1.125rem;
  line-height: 1.3;
}

.insights-single-post__content ul {
  list-style: disc;
  padding-left: var(--space-3);
}

.insights-single-post__content ol {
  list-style: decimal;
  padding-left: var(--space-3);
}

.insights-single-post__content li + li {
  margin-top: var(--space-1);
}

.insights-single-post__content a {
  color: var(--color-ink);
  text-decoration: underline;
}

.insights-single-post__content blockquote {
  margin-left: 0;
  padding-left: var(--space-3);
  border-left: 2px solid color-mix(in srgb, var(--color-muted) 55%, transparent);
  font-style: italic;
  color: var(--color-muted);
}

.insights-single-post__content img {
  display: block;
  max-width: 100%;
  height: auto;
}

.insights-single-post__content figcaption {
  margin-top: var(--space-1);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--color-muted);
}

/* -- Insights Single: Back to Insights (LAYOUT.md §10, Single row 3) ------- */

/* Deliberately quiet: muted by default, ink only on hover/focus — reads
   as ordinary utility navigation, not a second call to action competing
   with the Contact CTA immediately below it. */
.insights-single-back {
  padding-block: var(--space-4);
}

.insights-single-back__link {
  color: var(--color-muted);
}

.insights-single-back__link:hover,
.insights-single-back__link:focus-visible {
  color: var(--color-ink);
  text-decoration: underline;
}

/* -- Contact: Headline (LAYOUT.md §11 row 2) -------------------------------- */

/* .zone-ink supplies the background/text color (paper-on-ink), same as
   every other ink section on the site. Values reused as-is from
   .contact-cta__heading (the shared CTA's own display-scale rung —
   values only, not the selector; .contact-cta__heading itself is
   untouched) — the phrase is identical short text, so the same measure
   applies here too, now as the page's own primary content rather than
   a closing bookend line. */
.contact-intro {
  padding-block: var(--space-7);
}

.contact-intro__heading {
  max-width: 16ch;
  font-size: 2.75rem;
  line-height: 1.05;
}

@media (min-width: 1024px) {
  .contact-intro {
    padding-block: var(--space-8);
  }

  .contact-intro__heading {
    font-size: 4rem;
  }
}

/* -- Contact: Direct contact (LAYOUT.md §11 row 4) -------------------------- */

/* Deliberately subordinate to the Headline through scale alone, not a
   new color pairing — inherits .zone-ink's own already-proven-safe
   paper-on-ink, at the established elevated-body-copy size rung
   (reused from .hero__subhead and its several prior reuses) rather
   than a new value. No separator between this and the Headline above —
   spacing alone establishes the boundary, matching this project's
   established same-zone-continuation discipline. */
.contact-direct {
  padding-block: var(--space-6);
}

@media (min-width: 1024px) {
  .contact-direct {
    padding-block: var(--space-7);
  }
}

.contact-direct__email {
  max-width: 42ch;
  font-size: 1.0625rem;
  line-height: 1.5;
}

@media (min-width: 768px) {
  .contact-direct__email {
    font-size: 1.125rem;
  }
}

/* -- Contact: Form (LAYOUT.md §11 row 3) ------------------------------------ */

/* .zone-ink supplies the section's own background/text color, same as
   Headline/Direct-contact. Field surfaces sit on --color-paper "cards"
   per LAYOUT.md — square, no radius, no shadow: a flat paper plane on
   ink, consistent with this brand's geometric system, not a rounded
   consumer-SaaS input. */
.contact-form {
  padding-block: var(--space-6);
}

@media (min-width: 1024px) {
  .contact-form {
    padding-block: var(--space-7);
  }
}

.contact-form__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: 720px;
}

.contact-form__row {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

@media (min-width: 1024px) {
  .contact-form__row {
    flex-direction: row;
  }

  .contact-form__row > .contact-form__field {
    flex: 1 1 0;
  }
}

.contact-form__field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.contact-form__field label,
.contact-form__field legend {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--color-paper);
}

.contact-form__field input[type='text'],
.contact-form__field input[type='email'],
.contact-form__field textarea {
  background: var(--color-paper);
  color: var(--color-ink);
  border: none;
  padding: var(--space-2);
  font-size: 1rem;
  line-height: 1.5;
}

.contact-form__field textarea {
  resize: vertical;
  min-height: 8rem;
}

.contact-form__field fieldset {
  border: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.contact-form__field legend {
  padding: 0;
  margin-bottom: var(--space-1);
}

.contact-form__radio {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.contact-form__radio label {
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--color-paper);
}

.contact-form__error {
  margin: 0;
  font-size: 0.875rem;
  color: var(--color-paper);
}

/* Honeypot: a real, normal-looking text input for naive bots to find and
   fill, removed from the visible layout and from the keyboard/AT path
   for real visitors — position off-canvas rather than display:none
   (some simple bots skip display:none) and rather than type="hidden"
   (bots commonly ignore that too); tabindex="-1" removes it from Tab
   order, aria-hidden="true" (on the wrapping div in the template) hides
   it from assistive technology entirely. */
.contact-form__honeypot {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  left: -9999px;
}

.contact-form__submit {
  align-self: flex-start;
  background: var(--color-paper);
  color: var(--color-ink);
  border: none;
  padding: var(--space-2) var(--space-4);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1rem;
  cursor: pointer;
}

.contact-form__submit:hover {
  background: var(--color-white);
}

/* Status/validation copy: restrained, part of the form system rather
   than a promotional card — no background panel, no rust (rust
   measured 3.48:1 on ink / 4.25:1 on paper as a button-style fill,
   which fails WCAG AA for normal text either way, so it is not used
   here as a status-text color either; identification comes from the
   text itself, not color). */
.contact-form__status {
  margin: 0 0 var(--space-3);
  max-width: 720px;
  font-size: 1.0625rem;
}

/* -- 404 (Not Found) -------------------------------------------------------- */

/* .zone-paper supplies the section's own background/text color (paper
   bg, ink text) — the same utility-page register Insights Archive's
   Intro already established. Padding-block and heading scale are the
   established internal-page opener rung, reused by value from
   .about-intro/.expertise-intro/.insights-archive-intro-heading (own
   selectors here, not shared classes — this is a 404-specific section,
   not a variant of any of those templates). */
.error-404 {
  padding-block: var(--space-7);
}

.error-404__heading {
  max-width: 30ch;
  font-size: 1.75rem;
  line-height: 1.15;
  text-wrap: balance;
}

@media (min-width: 1024px) {
  .error-404 {
    padding-block: var(--space-8);
  }

  .error-404__heading {
    font-size: 2.5rem;
  }
}

/* Supporting sentence: the established readable-body rung, reused by
   value from .about-why__paragraph. */
.error-404__support {
  max-width: 42ch;
  margin-top: var(--space-3);
  font-size: 1.0625rem;
  line-height: 1.5;
}

@media (min-width: 768px) {
  .error-404__support {
    font-size: 1.125rem;
  }
}

/* Back-to-home: deliberately quiet utility navigation, not a CTA — same
   muted-by-default/ink-on-interaction pattern reused by value from
   Insights Single's .insights-single-back__link. No rust as a text
   color; the global :focus-visible rust ring remains the only rust
   here. */
.error-404__back {
  margin-top: var(--space-4);
}

.error-404__link {
  color: var(--color-muted);
}

.error-404__link:hover,
.error-404__link:focus-visible {
  color: var(--color-ink);
  text-decoration: underline;
}
