/*
Theme Name: diginom
Theme URI: https://diginom.io
Author: DigiNom
Description: Bespoke theme for DigiNom — business, technology and digital transformation consultancy. Light by default with an explicit dark mode toggle. Built from the approved 2026 mockup.
Version: 1.0.0
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 8.0
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: diginom
WPVibe: yes
*/

/* ===========================================================================
   0. FONTS — deliberately NOT here
   The @font-face rules live in diginom_inline_font_face() in functions.php and
   print inline in <head>. They were in this file, which still left them one
   hop behind: the browser had to fetch and parse this stylesheet before it
   could discover the font URLs. Inline, the fetch starts as the HTML parses.

   If a font ever stops loading, that function is where to look — not here.
   =========================================================================== */

/* ===========================================================================
   1. DESIGN TOKENS — LIGHT (default)
   The 17 tokens below are the entire difference between light and dark.
   Dark overrides live in section 2. Never hard-code a colour outside here.
   =========================================================================== */

:root {
  --bg: #FFFFFF;
  --bg-alt: #F4F7FB;
  --surface: #FFFFFF;
  --surface-border: #E2E8F0;
  --text: #1A2433;
  --text-muted: #5B6B82;
  --navy: #1F3864;
  --accent: #2E75B6;
  --accent-soft: #EAF1FA;
  --divider: #E2E8F0;
  --nav-bg: rgba(255,255,255,0.85);
  --shadow: 0 10px 30px rgba(31,56,100,0.08);
  --shadow-hover: 0 16px 40px rgba(31,56,100,0.14);
  --btn-shadow: 0 8px 20px rgba(46,117,182,0.25);
  --btn-shadow-hover: 0 12px 26px rgba(46,117,182,0.35);
  --col-fill: #E4ECF7;
  --foundation-glow: drop-shadow(0 6px 16px rgba(46,117,182,0.35));
  --font-display: 'Space Grotesk', 'Arial Black', 'Helvetica Neue', sans-serif;
  --font-body: 'Inter', -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'IBM Plex Mono', 'SF Mono', Consolas, monospace;

  /* Logo depth ramp. The mark's gradients read these, so one inline SVG
     renders correctly in both themes instead of shipping two files. */
  --logo-hi: #5C9BDC;
  --logo-mid: #2E75B6;
  --logo-lo: #1B3159;

  /* -------------------------------------------------------------------------
     LAYOUT TOKENS
     These live here, with the colour tokens, because they are used from
     section 3 onwards — not just by the long-form components where they were
     first written.

     Vertical rhythm. Three steps, not nine:
       tight   — items inside one group (.lens)
       block   — a standalone feature sitting in the prose
       section — a page-level break; matches the h2 top margin (51.84px),
                 already the strongest rhythm signal on the page.

     Radius answers one question: is this a container? Two steps, both
     perceptible. There is deliberately no third step — an earlier 18px tier
     sat between these and read as drift rather than intent, because nobody
     can see 2px.
       block — a normal container: cards, in-prose blocks, images
       panel — an oversized or full-bleed panel, where a larger radius is
               proportionate rather than arbitrary

     Small chrome (code blocks, dropdowns, icon tiles, inputs) keeps its own
     smaller radii; those are a different scale, not the container scale.
     ------------------------------------------------------------------------- */
  --flow-tight: 22px;
  --flow-block: 36px;
  --flow-section: 52px;

  --rule: 4px;
  --radius-block: 16px;
  --radius-panel: 20px;

  /* Space above and below a full-width section. Adjacent sections each
     contribute this, so the gap a reader actually sees is DOUBLE the value —
     which is why it was previously 168px: two sections at 84px apiece. Set
     this against the gap you want to see, then halve it. */
  --section-pad: clamp(30px, 3.2vw, 40px);

  /* Space between a page hero and the copy beneath it. Smaller than
     --section-pad because the hero is already a deliberate visual stop; the
     copy should feel attached to it, not adrift below it. */
  --hero-gap: clamp(28px, 3.6vw, 44px);
}

/* ===========================================================================
   2. DESIGN TOKENS — DARK
   Applied only when the visitor explicitly opts in (html[data-theme="dark"]).
   Light stays the default for first-time visitors, per the approved design.
   To follow the visitor's OS preference instead, see the note in header.php.
   =========================================================================== */

:root[data-theme="dark"] {
  --bg: #0B1220;
  --bg-alt: #101B2E;
  --surface: #121D33;
  --surface-border: #23324E;
  --text: #E7ECF5;
  --text-muted: #93A3BE;
  --navy: #FFFFFF;
  --accent: #5B9BE0;
  --accent-soft: rgba(91,155,224,0.14);
  --divider: #23324E;
  --nav-bg: rgba(11,18,32,0.82);
  --shadow: 0 10px 30px rgba(0,0,0,0.45);
  --shadow-hover: 0 18px 44px rgba(0,0,0,0.55);
  --btn-shadow: 0 8px 22px rgba(91,155,224,0.35);
  --btn-shadow-hover: 0 14px 30px rgba(91,155,224,0.45);
  --col-fill: #1B2A45;
  --foundation-glow: drop-shadow(0 0 22px rgba(91,155,224,0.55));

  /* Lifted and brighter on dark — the light-theme ramp goes muddy against
     #0B1220, and the cast shadow does almost no work there. */
  --logo-hi: #BBD9F7;
  --logo-mid: #6FA9E4;
  --logo-lo: #2E5C96;
}

/* Dark-only structural tweaks (the hero glow needs more presence on dark). */
:root[data-theme="dark"] .hero::before {
  height: 620px;
  background: radial-gradient(55% 55% at 50% 8%, rgba(91,155,224,0.22), transparent 72%);
}
:root[data-theme="dark"] .diff-card,
:root[data-theme="dark"] .pillar-card,
:root[data-theme="dark"] .foundation { background: var(--surface); }

/* The node-flash keyframe flashes to white, which is invisible on a dark
   surface — flash to the pale surface tone instead. */
:root[data-theme="dark"] .net-node-primary { animation-name: nodeFlashDark; }
@keyframes nodeFlashDark {
  0%, 100% { fill: var(--accent); }
  50% { fill: #E7ECF5; }
}

/* Colour-scheme hint so form controls, scrollbars and the caret follow suit. */
:root { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

/* ===========================================================================
   3. BASE
   =========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { font-family: var(--font-display); color: var(--navy); margin: 0 0 .5em; line-height: 1.15; }
h1 { font-size: clamp(2.1rem, 4.6vw, 3.4rem); font-weight: 700; letter-spacing: -0.01em; }
h2 { font-size: clamp(1.6rem, 3.2vw, 2.25rem); font-weight: 700; }
h3 { font-size: 1.12rem; font-weight: 600; }
p { margin: 0 0 1em; color: var(--text); }
a { color: inherit; }
ul { margin: 0; padding: 0; list-style: none; }

.accent-text { color: var(--accent); }

.skip-link {
  position: absolute; left: -999px; top: 0; background: var(--accent); color: #fff;
  padding: .6em 1em; z-index: 200; border-radius: 0 0 8px 0;
}
.skip-link:focus { left: 0; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.section-inner { max-width: 1180px; margin: 0 auto; padding: 0 clamp(20px, 4vw, 48px); }

.eyebrow {
  font-family: var(--font-mono); font-size: .74rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent); margin: 0 0 .9em; font-weight: 600;
}
.section-lead { max-width: 640px; color: var(--text-muted); font-size: 1.05rem; }
.footnote { font-size: .82rem; color: var(--text-muted); font-style: italic; margin-top: .6em; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5em;
  padding: .85em 1.6em; border-radius: 999px; font-family: var(--font-body); font-weight: 600;
  font-size: .95rem; text-decoration: none; transition: transform .18s ease, box-shadow .18s ease, background .18s ease;
  white-space: nowrap;
  /* Most buttons here are <a>, which has no default border — but a real
     <button> gets the UA's `2px outset`, which draws as a broken ring against
     the pill radius. Reset it, and turn off native appearance so the control
     is ours rather than the platform's. .btn-ghost re-adds its own border
     below, and wins on source order. */
  border: none; cursor: pointer;
  -webkit-appearance: none; appearance: none;
}
.btn-primary { background: var(--accent); color: #fff; box-shadow: var(--btn-shadow); }
.btn-primary:hover { transform: translateY(-2px); box-shadow: var(--btn-shadow-hover); }
.btn-ghost { background: transparent; color: var(--navy); border: 1.5px solid var(--divider); }
.btn-ghost:hover { border-color: var(--accent); color: var(--accent); }
.btn-lg { padding: 1em 2em; font-size: 1rem; }

/* ---------- Nav ---------- */
.nav {
  position: sticky; top: 0; z-index: 100; background: var(--nav-bg); backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px); border-bottom: 1px solid var(--divider);
}
.nav-inner {
  max-width: 1180px; margin: 0 auto; padding: 16px clamp(20px, 4vw, 48px);
  display: flex; align-items: center; justify-content: space-between;
}
.brand {
  display: inline-flex; align-items: center; gap: 1px; font-family: var(--font-display); font-weight: 700;
  font-size: 1.2rem; text-decoration: none; color: var(--navy); letter-spacing: .01em; flex: 0 0 auto; margin-right: 20px;
}
/* Height-driven with auto width: the mark's viewBox is cropped tight to the
   artwork and is no longer square, so fixing both dimensions would letterbox
   it and reintroduce the gap before the wordmark. */
.brand-mark { height: 26px; width: auto; flex: none; }
.brand-word { line-height: 1; }
.nav-links { display: flex; align-items: center; flex-wrap: wrap; }
.nav-links a:not(.btn) {
  text-decoration: none; color: var(--text); font-size: .95rem; font-weight: 500; position: relative;
  margin-right: 22px;
}
.nav-links a:not(.btn)::after {
  content: ""; position: absolute; left: 0; bottom: -6px; width: 0; height: 2px; background: var(--accent);
  transition: width .2s ease;
}
.nav-links a:not(.btn):hover::after { width: 100%; }
.nav-cta-mobile { display: none; }

/* The menu is rendered by wp_nav_menu, so these selectors target WordPress's
   standard markup (ul.nav-menu > li.menu-item-has-children > ul.sub-menu)
   rather than hand-written HTML. That way any item added at
   Appearance → Menus is styled automatically, with no custom walker. */
.nav-menu { display: flex; align-items: center; flex-wrap: wrap; margin: 0; padding: 0; list-style: none; }
.nav-menu > li { position: relative; display: flex; align-items: center; }

/* Caret drawn in CSS — wp_nav_menu emits no icon markup of its own.
   It has to be ::before because ::after already draws the hover underline,
   so the anchor becomes a flex row and the caret is ordered after the label. */
.nav-menu > .menu-item-has-children > a { display: inline-flex; align-items: center; }
.nav-menu > .menu-item-has-children > a::before {
  content: ""; order: 2; flex: none; width: 6px; height: 6px; margin-left: 7px;
  border: solid currentColor; border-width: 0 1.8px 1.8px 0; transform: rotate(45deg) translateY(-2px);
  transition: transform .18s ease; opacity: .75;
}
.nav-menu > .menu-item-has-children:hover > a::before,
.nav-menu > .menu-item-has-children:focus-within > a::before {
  transform: rotate(-135deg) translate(-2px, 2px);
}

.nav-menu .sub-menu {
  position: absolute; top: 100%; left: 0; margin: 14px 0 0; min-width: 220px; z-index: 110;
  list-style: none; background: var(--surface); border: 1px solid var(--surface-border);
  border-radius: 12px; box-shadow: var(--shadow); padding: 8px;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .18s ease, transform .18s ease, visibility .18s;
}
.nav-menu > li:hover > .sub-menu,
.nav-menu > li:focus-within > .sub-menu { opacity: 1; visibility: visible; transform: translateY(0); }
.nav-menu .sub-menu li { display: block; }
.nav-menu .sub-menu a {
  display: block; margin: 0 !important; padding: 9px 12px; border-radius: 8px;
  font-size: .92rem; white-space: nowrap;
}
.nav-menu .sub-menu a::after { display: none; }
.nav-menu .sub-menu a:hover { background: var(--accent-soft); color: var(--accent); }

/* Current page indicator */
.nav-menu .current-menu-item > a,
.nav-menu .current-menu-ancestor > a,
.nav-menu .current_page_parent > a { color: var(--accent); }
.nav-menu .current-menu-item > a::after { width: 100%; }
.nav-toggle {
  display: flex; flex-direction: column; justify-content: center; width: 0; height: 30px; overflow: hidden;
  background: none; border: none; cursor: pointer; padding: 0; flex: none;
}
.nav-toggle span { display: block; height: 2px; width: 30px; flex: none; background: var(--navy); border-radius: 2px; transition: transform .25s ease, opacity .25s ease; }
.nav-toggle span:not(:last-child) { margin-bottom: 5px; }
.nav-toggle.active span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle.active span:nth-child(2) { opacity: 0; }
.nav-toggle.active span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ---------- Theme (light/dark) toggle ---------- */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 38px; height: 38px; margin-right: 14px; padding: 0;
  background: transparent; border: 1.5px solid var(--divider); border-radius: 50%;
  color: var(--navy); cursor: pointer;
  transition: border-color .18s ease, color .18s ease, transform .18s ease, background .18s ease;
}
.theme-toggle:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-1px); }
.theme-toggle svg { width: 18px; height: 18px; display: block; }
.theme-toggle .icon-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }
/* No-JS visitors can't persist a choice, so don't offer a dead control. */
html:not(.js) .theme-toggle { display: none; }

/* ---------- Hero ---------- */
.hero { padding-top: clamp(48px, 7vw, 88px); position: relative; overflow: hidden; }
.hero-inner { display: flex; flex-wrap: wrap; align-items: center; position: relative; z-index: 1; }
.hero-copy { flex: 1 1 480px; margin-right: 40px; }
.hero-sub { font-size: 1.1rem; color: var(--text-muted); max-width: 46ch; }
.hero-actions { display: flex; flex-wrap: wrap; margin: 8px -8px 0; }
.hero-actions .btn { margin: 8px; }
.hero-visual { flex: 1 1 320px; display: flex; justify-content: center; }
.pillars-svg { width: 100%; max-width: 460px; height: auto; }

.hero::before {
  content: ""; position: absolute; top: -8%; right: -10%; left: -10%; height: 560px;
  background: radial-gradient(60% 60% at 50% 0%, rgba(46,117,182,0.09), transparent 72%);
  z-index: 0; pointer-events: none;
}

.net-edge { stroke: var(--col-fill); stroke-width: 2.5; opacity: .8; }
.net-spoke { stroke: var(--accent); stroke-width: 3; opacity: .65; }
.net-node-primary { fill: var(--accent); stroke: var(--accent); stroke-width: 2; animation: nodeFlash 3.2s ease-in-out infinite; }
@keyframes nodeFlash {
  0%, 100% { fill: var(--accent); }
  50% { fill: #ffffff; }
}
.net-branch:nth-of-type(1) .net-node-primary { animation-delay: 0s; }
.net-branch:nth-of-type(2) .net-node-primary { animation-delay: .5s; }
.net-branch:nth-of-type(3) .net-node-primary { animation-delay: 1s; }
.net-branch:nth-of-type(4) .net-node-primary { animation-delay: 1.5s; }
.net-branch:nth-of-type(5) .net-node-primary { animation-delay: 2s; }
.net-branch:nth-of-type(6) .net-node-primary { animation-delay: 2.5s; }
.net-node-center { fill: var(--accent); filter: var(--foundation-glow); }
.net-pulse { fill: none; stroke: var(--accent); stroke-width: 2; opacity: .5; animation: netPulse 2.6s ease-out infinite; }
@keyframes netPulse {
  0% { transform: scale(1); opacity: .55; }
  100% { transform: scale(2.2); opacity: 0; }
}

.js .net-branch { opacity: 0; transform: scale(.85); transform-origin: 260px 172px; transition: opacity .6s ease, transform .6s ease; }
.hero-visual.is-visible .net-branch { opacity: 1; transform: scale(1); }
.pillars-svg .net-branch:nth-of-type(2) { transition-delay: .06s; }
.pillars-svg .net-branch:nth-of-type(3) { transition-delay: .12s; }
.pillars-svg .net-branch:nth-of-type(4) { transition-delay: .18s; }
.pillars-svg .net-branch:nth-of-type(5) { transition-delay: .24s; }
.pillars-svg .net-branch:nth-of-type(6) { transition-delay: .3s; }
.js .net-node-center, .js .net-pulse { opacity: 0; transition: opacity .5s ease .3s; }
.hero-visual.is-visible .net-node-center, .hero-visual.is-visible .net-pulse { opacity: 1; }

.stats-strip {
  margin-top: clamp(40px, 6vw, 72px); padding: 28px 0 8px; border-top: 1px solid var(--divider);
  display: flex; flex-wrap: wrap; margin-left: -10px; margin-right: -10px;
}
.stat { flex: 1 1 190px; display: flex; flex-direction: column; padding: 0 10px 20px; }
.stat .stat-num { margin-bottom: 4px; }
.stat-num { font-family: var(--font-display); font-size: clamp(1.5rem, 3vw, 2rem); font-weight: 700; color: var(--navy); }
.stat-label { font-size: .85rem; color: var(--text-muted); min-height: 2.6em; }

/* ---------- Generic sections ---------- */
.section { padding: var(--section-pad) 0; }
.section-alt { background: var(--bg-alt); }

/* ---------- Challenges ---------- */
.challenge-grid { display: flex; flex-wrap: wrap; justify-content: center; margin: 40px -12px 0; }
/* The whole card is a link to its service page, with no "read more" label —
   so the hover lift is the affordance, and the section lead tells the reader
   the cards are clickable. Keep the two together: a card that rises under the
   cursor has to actually go somewhere. */
.challenge-card {
  flex: 1 1 260px; max-width: 320px; margin: 12px; padding: 26px 24px; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--surface-border); border-radius: var(--radius-block); box-shadow: var(--shadow);
  text-decoration: none; color: inherit; transition: transform .25s ease, box-shadow .25s ease, border-color .25s ease;
}
.challenge-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-hover); border-color: var(--accent); }
.challenge-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.challenge-card:hover h3 { color: var(--accent); }
.challenge-icon { display: inline-flex; color: var(--accent); margin-bottom: 16px; }
.challenge-icon .icon { width: 28px; height: 28px; }
.challenge-card h3 { font-size: 1.02rem; margin-bottom: 8px; }
.challenge-card p { color: var(--text-muted); font-size: .92rem; flex: 1; margin: 0; }

/* ---------- Diff cards ---------- */
.diff-grid { display: flex; flex-wrap: wrap; justify-content: center; margin: 40px -12px 0; }
.diff-card { flex: 1 1 220px; max-width: 300px; margin: 12px; }
.diff-card {
  background: var(--surface); border: 1px solid var(--surface-border); border-radius: var(--radius-block); padding: 28px 24px;
  box-shadow: var(--shadow); transition: transform .25s ease, box-shadow .25s ease;
}
.diff-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-hover); }
/* 28px everywhere, matching the challenge cards. These were 30px, which left
   the page with two icon scales for no reason anyone could see on purpose. */
.diff-card .icon, .pillar-icon .icon { color: var(--accent); width: 28px; height: 28px; margin-bottom: 16px; }
.diff-card p { color: var(--text-muted); font-size: .95rem; margin: 0; }

/* ---------- Pillars ---------- */
/* Four across on desktop, not two-by-two. The flex fill below 1040px kept the
   four cards in two rows, which made this the tallest section on the page at
   1,342px. A single row halves it without dropping a word — the cards get
   narrower, not shorter in content. */
.pillar-grid {
  display: grid; gap: 24px; margin: 44px 0 0;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 1040px) { .pillar-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .pillar-grid { grid-template-columns: minmax(0, 1fr); } }
.pillar-card {
  margin: 0; max-width: none;
  background: var(--surface); border: 1px solid var(--surface-border); border-radius: var(--radius-block); padding: 32px 28px;
  box-shadow: var(--shadow); position: relative;
  display: flex; flex-direction: column;
}
/* Matched to the challenge cards: a bare 28px glyph, no tinted tile. The tile
   made these read as much larger than every other icon on the page, and it was
   rendering taller than wide anyway — the shared .icon rule adds a 16px bottom
   margin, which counted as height inside an inline-flex tile. */
.pillar-icon {
  display: inline-flex; align-self: flex-start;
  padding: 0; border-radius: 0; background: none; margin-bottom: 16px;
}
.pillar-icon .icon { width: 28px; height: 28px; margin-bottom: 0; }
/* Two lines reserved for the headline and a growing description, so every
   Read more lands on the same baseline. Headlines here run one line ("AI &
   Automation") to two ("Business Transformation"), and the descriptions two
   to four, which is what left the links stepped across the row. */
.pillar-card h3 { line-height: 1.3; min-height: calc(1.3em * 2); }
.pillar-card p { color: var(--text-muted); flex: 1; margin-bottom: 18px; }
.pillar-card .card-more { margin-top: auto; }

.foundation {
  margin-top: 56px; padding: 40px clamp(24px, 4vw, 48px); border-radius: var(--radius-panel);
  background: var(--surface); border: 1px solid var(--surface-border); box-shadow: var(--shadow);
  position: relative; overflow: hidden;
}
.foundation-bar-echo {
  position: absolute; left: 0; right: 0; top: 0; height: 5px;
  background: linear-gradient(90deg, var(--accent-soft), var(--accent), var(--accent-soft));
}
.foundation-grid { display: flex; flex-wrap: wrap; align-items: center; }
.foundation-copy { flex: 2 1 420px; }
.foundation-copy > p:not(.eyebrow) { color: var(--text-muted); }
.chip-row { display: flex; flex-wrap: wrap; margin: 16px -5px 0; }
.chip {
  font-family: var(--font-mono); font-size: .78rem; letter-spacing: .03em; padding: .5em 1em; margin: 4px 5px;
  border-radius: 999px; background: var(--accent-soft); color: var(--navy); border: 1px solid var(--surface-border);
}

/* ---------- AI Enablement ---------- */
.enable-grid { display: flex; flex-wrap: wrap; justify-content: center; margin: 40px -12px 0; }
.enable-card {
  flex: 1 1 260px; max-width: 340px; margin: 12px; padding: 26px 24px;
  background: var(--surface); border: 1px solid var(--surface-border); border-radius: var(--radius-block); box-shadow: var(--shadow);
}
.enable-card h3 { font-size: 1rem; margin-bottom: 8px; }
.enable-card p { color: var(--text-muted); font-size: .92rem; margin: 0; }

.step-list { margin-top: 22px; }
.step-item { display: flex; gap: 16px; margin-bottom: 20px; }
.step-item:last-child { margin-bottom: 0; }
.step-num {
  flex: none; width: 30px; height: 30px; border-radius: 50%; background: var(--accent-soft); color: var(--accent);
  display: flex; align-items: center; justify-content: center; font-family: var(--font-mono); font-weight: 600;
  font-size: .9rem;
}
.step-title { font-weight: 600; color: var(--navy); margin: 0 0 4px; font-size: .98rem; }
.step-desc { color: var(--text-muted); font-size: .92rem; margin: 0; }

/* The Sectors, Scale track and Deliver styles were removed on 2026-08-30 with
   the homepage sections they dressed. Verified dead first: those classes
   appear in no template and on no page, including /sectors/, /who-we-serve/
   and /approach/, which are ordinary WP pages with their own markup. */

/* ---------- News ---------- */
/* A real grid, not centred flex wrap. Equal columns mean equal card widths,
   which is what lets the clamped headline and teaser line up across every
   card — the previous flex fill produced a different width per row and so a
   different amount of text in each card. */
.news-grid, .post-grid {
  display: grid; gap: 24px; margin: 40px 0 0;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
}
/* Homepage carousel: two cards per view on desktop, one on mobile, scrolled
   by the arrows beneath. Built on scroll-snap rather than a transformed track
   so it still works by touch and keyboard if the JS never arrives. */
.news-carousel { max-width: 940px; margin: 40px auto 0; }
.news-carousel .news-track {
  display: grid; grid-auto-flow: column; grid-auto-columns: calc((100% - 24px) / 2);
  gap: 24px; margin: 0; overflow-x: auto; overscroll-behavior-x: contain;
  /*
   * scroll-behavior is deliberately NOT `smooth` here. It used to be, and it
   * cost the homepage its Largest Contentful Paint entirely — PageSpeed
   * reported NO_LCP, with Total Blocking Time erroring out behind it.
   *
   * Chromium stops collecting LCP candidates at the first scroll. A mandatory
   * scroll-snap container performs a programmatic scroll as it is laid out,
   * and with `scroll-behavior: smooth` that becomes an animated scroll firing
   * scroll events before any content has painted. LCP collection is therefore
   * terminated before a single candidate exists, so the page reports no LCP at
   * all — not a slow one, none.
   *
   * Bisected 2026-08-31: neutralising any one of scroll-snap-type,
   * scroll-snap-align or scroll-behavior restored LCP. This is the one that
   * costs nothing, because site.js already passes `behavior: 'smooth'` in its
   * scrollBy calls for the prev/next buttons — the CSS declaration was pure
   * duplication. Button clicks still animate; the load-time snap is instant.
   *
   * If you reinstate it, re-run PageSpeed and check LCP is still reported.
   */
  scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
  padding: 4px; margin: -4px;
}
.news-carousel .news-track::-webkit-scrollbar { display: none; }
.news-carousel .news-card { scroll-snap-align: start; }
.news-nav { display: flex; justify-content: center; gap: 14px; margin-top: 28px; }
.news-nav button {
  width: 44px; height: 44px; border-radius: 50%; display: inline-flex;
  align-items: center; justify-content: center; cursor: pointer;
  background: var(--surface); color: var(--accent);
  border: 1.5px solid var(--surface-border);
  transition: background .2s ease, border-color .2s ease, color .2s ease, opacity .2s ease;
}
.news-nav button:hover { background: var(--accent-soft); border-color: var(--accent); }
.news-nav button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.news-nav button svg { width: 18px; height: 18px; }
.news-nav button[disabled] { opacity: .35; cursor: default; }
.news-nav button[disabled]:hover { background: var(--surface); border-color: var(--surface-border); }
@media (max-width: 780px) {
  .news-carousel .news-track { grid-auto-columns: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .news-carousel .news-track { scroll-behavior: auto; }
}
.news-card {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--surface-border); border-radius: var(--radius-block);
  padding: 24px; box-shadow: var(--shadow); transition: transform .25s ease, box-shadow .25s ease;
  /* Containing block for the stretched .news-link overlay below. */
  position: relative;
}
.news-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-hover); }
.news-card:hover h3 { color: var(--accent); }
.news-date {
  font-family: var(--font-mono); font-size: .74rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 10px;
  /* Two lines reserved: adding the category made this wrap on the longer
     names, and one card wrapping while its neighbours did not pushed its
     headline out of line with the rest of the row. */
  line-height: 1.5; min-height: calc(1.5em * 2);
}
/* Headline and teaser are clamped to a fixed number of lines, and the space is
   reserved with min-height so a one-line headline still leaves the cards below
   it aligned. Titles here run from 47 to 96 characters; without this the amount
   of bold text per card varies wildly. */
.news-card h3 {
  font-size: 1.02rem; line-height: 1.35; margin-bottom: 10px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; min-height: calc(1.35em * 2);
}
.news-card p:not(.news-date) {
  color: var(--text-muted); font-size: .92rem; line-height: 1.55; flex: 1;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden; min-height: calc(1.55em * 3);
}
/* The whole card is the click target.

   The link has NO visible text — it is an invisible overlay covering the
   whole card, carrying only screen-reader text. There is deliberately no
   "Read more": it would be a second call to action for something already
   entirely clickable. Affordance comes from the hover state (the card lifts
   and the headline turns accent) and the pointer cursor.

   It is the <a> itself rather than a pseudo-element, so it takes no space in
   the card's flex flow. It resolves against .news-card (position:relative)
   rather than the <h3>, which is line-clamped with overflow:hidden and would
   clip it to the headline's own box.

   Side effect worth knowing: the overlay sits above the card's text, so text
   inside a card cannot be selected. That is the accepted trade for a card-
   sized target, and is how the challenge cards behave too. */
.news-link {
  position: absolute; inset: 0; border-radius: var(--radius-block);
  text-decoration: none;
}
.news-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ---------- Contact form ---------- */
.contact-form { max-width: 560px; margin: 36px auto 0; text-align: left; }
.form-row { display: flex; flex-wrap: wrap; margin: 0 -8px; }
.form-row .form-field { flex: 1 1 220px; margin: 0 8px 18px; }
.form-field { margin-bottom: 18px; }
.form-field label { display: block; font-size: .85rem; font-weight: 600; color: var(--navy); margin-bottom: 6px; }
.form-field input, .form-field textarea {
  width: 100%; padding: .8em .9em; border-radius: 10px; border: 1.5px solid var(--divider);
  background: var(--surface); color: var(--text); font-family: var(--font-body); font-size: .95rem;
  resize: vertical;
}
.form-field input:focus, .form-field textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
/* Honeypot — visually gone, still focusable-hidden from assistive tech. */
.form-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form-note { margin-top: 14px; font-size: .88rem; color: var(--text-muted); min-height: 1.2em; }
.form-note.error { color: #C0392B; }
:root[data-theme="dark"] .form-note.error { color: #FF8A7A; }
.contact-success { display: none; padding: 12px 0 4px; }
.contact-success.show { display: block; }
.contact-success p { color: var(--text-muted); }
.btn[aria-busy="true"] { opacity: .6; pointer-events: none; }

/* ---------- CTA / Footer ---------- */
.cta { padding: var(--section-pad) 0; text-align: center; }
.cta-inner { max-width: 620px; }
.cta p { color: var(--text-muted); font-size: 1.05rem; }
.footer { border-top: 1px solid var(--divider); padding: 40px 0; }
.footer-inner { text-align: center; color: var(--text-muted); font-size: .9rem; }
.footer-inner p { margin: 0 0 6px; }
.footer-brand {
  display: inline-flex; align-items: center; gap: 3px; font-family: var(--font-display); font-weight: 700;
  color: var(--navy); font-size: 1.1rem; margin-bottom: 10px;
}
.footer-brand .brand-mark { height: 19px; width: auto; }
.footer-copy { margin-top: 4px; opacity: .75; }
.footer-nav { margin-top: 10px; }
.footer-nav a { color: var(--text-muted); text-decoration: none; margin: 0 10px; }
.footer-nav a:hover { color: var(--accent); text-decoration: underline; }

/* News/post cards carrying their featured image. */
.news-card-media {
  margin: -24px -24px 18px; overflow: hidden; background: var(--bg-alt);
  border-radius: var(--radius-block) var(--radius-block) 0 0;
}
/* height:auto is load-bearing, not tidiness. WordPress emits width/height
   attributes on the img; with a definite height the browser ignores
   aspect-ratio entirely, and a medium_large 768x512 rendered at full 512px
   height — portrait, in a card meant to be landscape. */
.news-card-media img {
  display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover;
}

/* ===========================================================================
   3b. PHOTOGRAPHY
   Photographs are never recoloured — the only overlay anywhere is the hero
   scrim, and it exists purely so white type stays legible over an arbitrary
   image. Everything else is the picture as shot.
   =========================================================================== */

.page-hero { padding: clamp(18px, 3vw, 34px) 0 0; }
.page-hero-inner { max-width: 1180px; margin: 0 auto; padding: 0 clamp(20px, 4vw, 48px); }
.page-hero-media {
  position: relative; border-radius: var(--radius-panel); overflow: hidden;
  background: var(--bg-alt); box-shadow: var(--shadow);
}
.page-hero-media img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 21 / 9; object-fit: cover;
}
/* Fades to nothing across the top two thirds, so only the type area darkens. */
.page-hero-media::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(11,18,32,0) 34%, rgba(11,18,32,.55) 68%, rgba(11,18,32,.88) 100%);
}
.page-hero-text {
  position: absolute; z-index: 2; left: 0; right: 0; bottom: 0;
  padding: 0 clamp(20px, 3.6vw, 44px) clamp(20px, 3vw, 36px);
}
.page-hero-text .eyebrow { color: rgba(255,255,255,.82); margin-bottom: 10px; }
.page-hero-text h1 { color: #fff; margin: 0; text-shadow: 0 2px 18px rgba(8,16,31,.4); }

/* With a hero above it the body copy needs less top space. */
.article.has-hero { padding-top: var(--hero-gap); }
.section.has-hero { padding-top: var(--hero-gap); }

/* The contact layout carries a 32px top margin so it clears the <h1> on a
   heroless page. With a hero the <h1> moves into the hero, so that margin has
   nothing to clear and simply stacks on top of --hero-gap — which is why this
   page sat 76px below its hero while every other page sat 44px. */
.section.has-hero .contact-layout { margin-top: 0; }

/* Photograph inside long-form content, opening a section. It sits directly
   under its <h2>, so the top margin is tight and the breathing room goes
   below, before the prose. */
/* Sits directly under its <h2>, so the top stays tight and the breathing room
   goes below, before the prose resumes at the standard block interval. */
.entry-content .entry-figure { margin: .9em 0 var(--flow-block); }
.entry-figure img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: var(--radius-block); box-shadow: var(--shadow);
}

/* Full-width band used as a break between homepage sections. */
.photo-band { position: relative; overflow: hidden; background: var(--bg-alt); }
.photo-band img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 32 / 9; object-fit: cover;
}
.photo-band::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(11,18,32,0) 45%, rgba(11,18,32,.8) 100%);
}
.photo-band-label {
  position: absolute; z-index: 2; left: 0; right: 0; bottom: 0;
  margin: 0; padding: 0 clamp(20px, 4vw, 48px) clamp(16px, 2.4vw, 26px);
  max-width: 1180px; margin-inline: auto;
  font-family: var(--font-mono); font-size: .68rem; letter-spacing: .1em;
  text-transform: uppercase; color: rgba(255,255,255,.9);
}

@media (max-width: 700px) {
  .page-hero-media img { aspect-ratio: 4 / 3; }
  .photo-band img { aspect-ratio: 16 / 9; }
  .entry-figure img { aspect-ratio: 3 / 2; }
}

/* ---------- Section and card "read more" links ---------- */
.card-more {
  display: inline-block; margin-top: 16px; font-weight: 600;
  color: var(--accent); text-decoration: none; font-size: .92rem;
}
.card-more:hover { text-decoration: underline; }
.section-more { margin: 28px 0 0; }
.section-more .card-more { margin-top: 0; }

/* ---------- Contact page ---------- */
.contact-layout { display: flex; flex-wrap: wrap; margin: 32px -18px 0; align-items: flex-start; }
.contact-intro { flex: 1 1 320px; margin: 0 18px; }
.contact-form-wrap { flex: 1 1 380px; margin: 0 18px; }
.contact-form-wrap .contact-form { margin-top: 0; }
.contact-detail {
  margin-top: 28px; padding: 22px 24px; border-radius: var(--radius-block);
  background: var(--bg-alt); border: 1px solid var(--surface-border);
}
.contact-detail p { margin: 0 0 8px; color: var(--text-muted); font-size: .95rem; }
.contact-detail p:last-child { margin-bottom: 0; }
.contact-detail-label {
  font-family: var(--font-mono); font-size: .7rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--accent) !important; font-weight: 600;
}
.contact-detail-note { font-size: .85rem !important; opacity: .8; }

/* ---------- Reveal on scroll ---------- */
.js .reveal { opacity: 0; transform: translateY(18px); transition: opacity .7s ease, transform .7s ease; }
.reveal.is-visible { opacity: 1; transform: translateY(0); }

/* ===========================================================================
   4. ARTICLE / EDITOR CONTENT
   Styles the WordPress editor output for News posts and ordinary pages, so
   content written in Gutenberg inherits the same design language.
   =========================================================================== */

/* An article is a full-width band like a .section, so it takes the same
   padding. It previously ran 72px, which left article pages sitting further
   from the footer than every other page type. */
.article { padding: var(--section-pad) 0; }
/* A single post opens with the return link, which is a small muted line rather
   than a heading, so it needs less lead-in above it than a page whose <h1> is
   the first thing on screen. Scoped to body.single so pages keep the full
   section padding. */
body.single .article { padding-top: clamp(16px, 1.8vw, 22px); }
.article-inner { max-width: 760px; margin: 0 auto; padding: 0 clamp(20px, 4vw, 48px); }
.article-header { margin-bottom: 32px; }
.article-header h1 { margin-bottom: .35em; }
/* Return to the Insights index, at the TOP of an article.

   Named `article-return`, NOT `article-back`: `.article-back` is already the
   button block at the FOOT of the article (see below, near the table styles).
   Reusing that name inherited its `margin-top: 40px` here and leaked this
   block's inline-flex and mono typography onto those buttons.

   Deliberately muted rather than --accent: it is navigation and should not
   compete with the meta line directly beneath it, which is content. The arrow
   shifts left on hover — the same direction-of-travel cue the carousel uses. */
.article-return {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-mono); font-size: .72rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-muted); text-decoration: none;
  margin: 0 0 16px; transition: color .2s ease;
}
.article-return:hover { color: var(--accent); }
.article-return:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }
.article-return-arrow { display: inline-block; transition: transform .2s ease; }
.article-return:hover .article-return-arrow { transform: translateX(-3px); }
/* The same link repeated below the closing CTA, where it needs its own
   breathing room rather than the header's tight bottom margin. */
.article-return-foot { margin: 28px 0 0; }

.article-meta { font-family: var(--font-mono); font-size: .74rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--accent); margin: 0 0 14px; }

/* The category, when its archive has more than this article in it. Inherits
   the meta line's colour rather than restyling — it should read as part of the
   line, with the underline on hover as the only affordance. */
.article-cat { color: inherit; text-decoration: none; border-bottom: 1px solid transparent; transition: border-color .2s ease; }
.article-cat:hover { border-bottom-color: currentColor; }
.article-cat:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }
.article-featured { margin: 0 0 32px; }
.article-featured img { width: 100%; height: auto; border-radius: var(--radius-block); display: block; }

.entry-content { font-size: 1.02rem; }
.entry-content > * { margin-bottom: 1.15em; }
.entry-content h2 { font-size: clamp(1.4rem, 2.6vw, 1.8rem); margin: 1.8em 0 .5em; }
/* Heading hierarchy: h2 opens a section (--flow-section above), h3 a
   subsection (--flow-block above). Both sit ~14px above their own body copy,
   so the heading-to-text relationship reads the same at either level. */
.entry-content h3 { font-size: 1.15rem; margin: var(--flow-block) 0 .75em; }
.entry-content p { color: var(--text); }
.entry-content a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
/* Buttons must opt out of the prose link styling above. `.entry-content a` is
   (0,1,1) and beats `.btn-primary` at (0,1,0), which painted button text in
   the accent colour — i.e. blue text on a blue button, invisible. Any new
   button variant needs adding here too. */
.entry-content a.btn { text-decoration: none; }
.entry-content a.btn-primary { color: #fff; }
.entry-content a.btn-ghost { color: var(--navy); }
.entry-content a.btn-ghost:hover { color: var(--accent); }
.entry-content a.card-more { color: var(--accent); text-decoration: none; }
.entry-content a.card-more:hover { text-decoration: underline; }
.entry-content ul, .entry-content ol { margin: 0 0 1.15em; padding-left: 1.3em; }
.entry-content ul { list-style: disc; }
.entry-content ol { list-style: decimal; }
.entry-content li { margin-bottom: .5em; }
.entry-content blockquote {
  margin: 1.6em 0; padding: 4px 0 4px 22px; border-left: 4px solid var(--accent);
  color: var(--text-muted); font-style: italic;
}
/* An image is a container like any other, so it takes the container radius.
   This was 12px, which quietly overrode the 16px set on .entry-figure img —
   same specificity, declared later, so it won. Section photographs have been
   rendering 4px rounder than every block around them. */
.entry-content img { max-width: 100%; height: auto; border-radius: var(--radius-block); }
.entry-content figure { margin: 1.6em 0; }
.entry-content figcaption { font-size: .85rem; color: var(--text-muted); margin-top: .5em; text-align: center; }
.entry-content code {
  font-family: var(--font-mono); font-size: .88em; background: var(--bg-alt);
  border: 1px solid var(--surface-border); border-radius: 6px; padding: .12em .4em;
}
.entry-content pre {
  background: var(--bg-alt); border: 1px solid var(--surface-border); border-radius: 12px;
  padding: 18px 20px; overflow-x: auto;
}
.entry-content pre code { background: none; border: none; padding: 0; }
.entry-content hr { border: none; border-top: 1px solid var(--divider); margin: 2.2em 0; }

/* Tables scroll inside their own container rather than the page (checklist §5). */
.entry-content .table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; margin: 1.6em 0; }
.entry-content table { width: 100%; border-collapse: collapse; font-size: .93rem; }
.entry-content th, .entry-content td {
  border: 1px solid var(--surface-border); padding: 10px 12px; text-align: left;
}
.entry-content th { background: var(--bg-alt); color: var(--navy); font-weight: 600; }

.article-back { margin-top: 40px; }

/* WordPress core classes */
.screen-reader-text {
  border: 0; clip-path: inset(50%); height: 1px; margin: -1px; overflow: hidden;
  padding: 0; position: absolute; width: 1px; word-wrap: normal !important;
}
.screen-reader-text:focus {
  background: var(--surface); clip-path: none; color: var(--accent); display: block;
  font-size: .9rem; height: auto; left: 5px; line-height: normal; padding: 15px 23px 14px;
  text-decoration: none; top: 5px; width: auto; z-index: 100000;
}
.alignleft { float: left; margin: .4em 1.6em 1em 0; }
.alignright { float: right; margin: .4em 0 1em 1.6em; }
.aligncenter { display: block; margin-left: auto; margin-right: auto; }
.alignwide { max-width: 1000px; margin-left: auto; margin-right: auto; }
.alignfull { max-width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw); }
.wp-caption { max-width: 100%; }
.wp-caption-text { font-size: .85rem; color: var(--text-muted); text-align: center; }

/* Post list (blog index / archive) reuses the news card and its grid — the
   shared layout rule lives with the news styles above. */

/* ---------- Insights category filter ----------
   Chips link to real category archives, so this is navigation, not a widget:
   marked up as a nav/list and styled to look like the chips already used in
   the AI enablement block. */
.cat-filter { margin: 34px 0 0; }
.cat-filter-list { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; margin: 0; padding: 0; }
.cat-chip {
  display: inline-flex; align-items: baseline; gap: 7px; white-space: nowrap;
  font-family: var(--font-mono); font-size: .74rem; letter-spacing: .03em;
  padding: 8px 15px; border-radius: 99px; text-decoration: none;
  color: var(--text-muted); background: var(--surface);
  border: 1px solid var(--surface-border);
  transition: color .2s ease, border-color .2s ease, background .2s ease;
}
.cat-chip:hover { color: var(--accent); border-color: var(--accent); }
.cat-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cat-chip.is-active { background: var(--accent); border-color: var(--accent); color: #fff; }
/* The dark palette lifts --accent to #5B9BE0, where white text falls to
   2.9:1 — below AA. Dark text on the same fill gives 6.4:1.
   THE RULE: anything filled with var(--accent) takes #0B1220 text in dark
   mode. White is only safe on the light accent (#2E75B6, 4.84:1). If you add
   another accent-filled element, add it to the list below. */
:root[data-theme="dark"] .cat-chip.is-active,
:root[data-theme="dark"] .skip-link,
:root[data-theme="dark"] .btn-primary,
:root[data-theme="dark"] .pagination .page-numbers:hover,
:root[data-theme="dark"] .metric-head { color: #0B1220; }
.cat-chip-count { font-size: .68rem; opacity: .6; }
.cat-chip.is-active .cat-chip-count { opacity: .85; }
.news-date-sep { margin: 0 2px; opacity: .55; }

/* The category names run to 31 characters, so on a phone six of them wrap to
   four ragged rows. Scroll the row instead — one line, familiar pattern, and
   it needs no shortened labels or renamed categories to work. */
@media (max-width: 700px) {
  .cat-filter-list {
    flex-wrap: nowrap; overflow-x: auto; overscroll-behavior-x: contain;
    scrollbar-width: none; -ms-overflow-style: none; padding-bottom: 2px;
  }
  .cat-filter-list::-webkit-scrollbar { display: none; }
}
.pagination { margin-top: 48px; text-align: center; }
.pagination .page-numbers {
  display: inline-flex; align-items: center; justify-content: center; min-width: 38px; height: 38px;
  padding: 0 10px; margin: 0 4px; border-radius: 10px; border: 1px solid var(--surface-border);
  color: var(--text); text-decoration: none; font-size: .92rem;
}
.pagination .page-numbers.current,
.pagination .page-numbers:hover { background: var(--accent); border-color: var(--accent); color: #fff; }

/* ===========================================================================
   5. RESPONSIVE
   =========================================================================== */

@media (max-width: 1040px) {
  .nav-links {
    position: fixed; top: 64px; right: 0; left: 0; background: var(--bg); flex-direction: column; align-items: flex-start;
    padding: 24px clamp(20px, 4vw, 48px) 28px; border-bottom: 1px solid var(--divider); z-index: 90;
    transform: translateY(-8px); opacity: 0; pointer-events: none; transition: opacity .2s ease, transform .2s ease;
  }
  .nav-links a:not(.btn) { margin: 0 0 20px; display: block; }
  .nav-links.open { opacity: 1; transform: translateY(0); pointer-events: auto; }
  .nav-cta { display: none; }
  .nav-cta-mobile { display: inline-flex; margin-top: 6px; }
  .nav-toggle { width: 30px; }
  /* Push the theme toggle across so it sits beside the hamburger, not adrift
     in the middle of the bar once the desktop CTA is hidden. */
  .theme-toggle { margin-left: auto; margin-right: 12px; }

  /* Menu stacks, and the dropdown becomes an inline indented list rather than
     a floating panel — a hover panel is unusable on touch. */
  .nav-menu { flex-direction: column; align-items: flex-start; width: 100%; }
  .nav-menu > li { display: block; width: 100%; }
  .nav-menu > .menu-item-has-children > a::before { display: none; }
  .nav-menu > .menu-item-has-children > a { display: block; }
  .nav-menu .sub-menu {
    position: static; opacity: 1; visibility: visible; transform: none; box-shadow: none;
    border: none; background: transparent; padding: 2px 0 0 18px; margin: 10px 0 20px;
    min-width: 0;
  }
  .nav-menu .sub-menu a { padding: 8px 0; font-size: 1rem; white-space: normal; }
}
@media (max-width: 880px) {
  .hero-copy { flex-basis: 100%; margin-right: 0; }
  .hero-visual { order: -1; flex-basis: 100%; max-width: 340px; margin: 0 auto 8px; }
}
@media (max-width: 560px) {
  .stat { flex-basis: 40%; }
  .nav-links a:not(.btn) { font-size: 1.05rem; }
  /* Two inline buttons touch and render at different widths on mobile
     (checklist §5) — stack them full-width instead. */
  .hero-actions { display: block; margin-left: 0; margin-right: 0; }
  .hero-actions .btn { display: flex; width: 100%; margin: 0 0 12px; }
  .cta .btn { display: flex; width: 100%; }
}

/* ===========================================================================
   6. LONG-FORM ARTICLE COMPONENTS
   Used by the research series. Every colour resolves through the theme
   tokens, so these work in light and dark without a second set of rules.
   =========================================================================== */

:root {
  --sev-critical: #C0392B;
  --sev-high: #D6663B;
  --sev-medium: #C08A2E;
  --sev-low: #2E8B72;
}
:root[data-theme="dark"] {
  --sev-critical: #FF7A6B;
  --sev-high: #FF9E6B;
  --sev-medium: #E8C46B;
  --sev-low: #5FD1B0;
}

/* ---------- Series / scope strip ---------- */
/* Baseline, not centre. The label is an unpadded 18px line and the pills are
   24px once their padding is counted, so centring the boxes left the pill
   type sitting 6px above the label type — visible with mono uppercase, which
   has no descenders to disguise it. Aligning baselines lines the words up and
   lets the pills' padding sit around them. */
.geo-strip {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px;
  padding: 14px 18px; margin: 0 0 var(--flow-block); border-radius: var(--radius-block);
  background: var(--bg-alt); border: 1px solid var(--surface-border);
}
.geo-strip-label {
  font-family: var(--font-mono); font-size: .68rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-muted); margin: 0;
}
.geo-badge {
  font-family: var(--font-mono); font-size: .68rem; letter-spacing: .1em;
  text-transform: uppercase; padding: .35em .8em; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid var(--surface-border); white-space: nowrap;
}
/* Always its own row. With `flex: 1 1 200px` this sentence competed for
   whatever the label and pills left over — on a 626px strip that was 233px for
   60-odd characters, so it broke mid-phrase. How badly it wrapped depended on
   the label and pill text, which differs per article, so the strip was never
   the same shape twice. A full-width basis makes it one row of tags and one
   row of prose, on every article. */
.geo-scope {
  font-family: var(--font-mono); font-size: .68rem; letter-spacing: .04em;
  color: var(--text-muted); margin: 0; flex: 1 1 100%;
}

/* ---------- Article furniture ---------- */
.article-number {
  font-family: var(--font-display); font-size: 3.6rem; font-weight: 700; line-height: 1;
  color: var(--accent); opacity: .16; display: block; margin-bottom: -.1em;
}
.article-subtitle {
  font-size: 1.08rem; line-height: 1.6; color: var(--text-muted);
  border-top: 1px solid var(--divider); padding-top: 18px; margin-top: 18px;
}
.article-lead {
  font-size: 1.14rem; line-height: 1.7; color: var(--text);
  padding-left: 22px; border-left: var(--rule) solid var(--accent);
  margin: 0 0 var(--flow-block);
}

/* ---------- Pull quote ----------
   Someone else's words, with attribution. Same shell as .pull (below) on
   purpose — they are the same family — but this one carries a source line,
   which is the whole difference between quoting and asserting. */
.pullquote {
  margin: var(--flow-block) 0; padding: 26px 30px; border-radius: var(--radius-block);
  border-left: var(--rule) solid var(--accent); background: var(--bg-alt);
}
.pullquote-text {
  font-family: var(--font-display); font-size: 1.28rem; line-height: 1.5;
  color: var(--navy); margin: 0 0 10px;
}
.pullquote-attr {
  font-family: var(--font-mono); font-size: .7rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent); margin: 0;
}

/* ---------- Headline statistic ---------- */
.stat-block {
  margin: var(--flow-block) 0; padding: 34px 28px; text-align: center;
  border-radius: var(--radius-block);
  background: var(--surface); border: 1px solid var(--surface-border); box-shadow: var(--shadow);
}
.stat-block .stat-number {
  font-family: var(--font-display); font-size: clamp(2.8rem, 7vw, 4.2rem); font-weight: 700;
  line-height: 1; color: var(--accent); display: block; margin-bottom: 14px;
}
.stat-block .stat-text {
  font-size: .95rem; line-height: 1.6; color: var(--text-muted);
  max-width: 520px; margin: 0 auto;
}

/* ---------- Metric grid (revenue bands, stage timelines) ---------- */
.metric-grid {
  margin: var(--flow-block) 0; border-radius: var(--radius-block); overflow: hidden;
  border: 1px solid var(--surface-border); background: var(--surface);
}
.metric-head {
  font-family: var(--font-mono); font-size: .68rem; letter-spacing: .12em;
  text-transform: uppercase; padding: 13px 18px; margin: 0;
  background: var(--accent); color: #fff;
}
/* Flex rather than grid, deliberately. The 1px dividers are not borders: the row
   paints --surface-border as its background and the cells cover it, so ANY area a
   cell does not cover renders as a slab of divider colour. Grid leaves exactly
   that whenever the final band is partly filled — auto-fit only collapses tracks
   empty across every band, so 5 or 6 metrics at article width leaked 484px and
   323px respectively, and the fixed 2-column mobile rule leaked on every odd
   count. Flex grows the trailing items to fill the last row, which makes the
   uncovered state unreachable at any count and any width. Measured 0px dead at
   1-6 metrics on both mobile and desktop; no breakpoint override needed. */
.metric-row {
  display: flex; flex-wrap: wrap;
  gap: 1px; background: var(--surface-border);
}
.metric {
  flex: 1 1 150px;
  background: var(--surface); padding: 20px 16px; text-align: center; margin: 0;
}
.metric-key {
  font-family: var(--font-mono); font-size: .68rem; letter-spacing: .08em;
  color: var(--text-muted); margin: 0 0 6px; text-transform: uppercase;
}
.metric-value {
  font-family: var(--font-display); font-size: 1.5rem; font-weight: 700;
  color: var(--navy); margin: 0 0 4px; line-height: 1.1;
}
.metric-label {
  font-family: var(--font-mono); font-size: .66rem; color: var(--text-muted);
  margin: 0; letter-spacing: .03em;
}
/* Modifier for metric grids whose labels are sentences rather than units —
   mono microtype is unreadable at that length. */
.metric-grid.prose .metric-label {
  font-family: var(--font-body); font-size: .82rem; line-height: 1.5;
  letter-spacing: 0; text-transform: none;
}
.metric-note {
  font-family: var(--font-mono); font-size: .68rem; color: var(--text-muted);
  padding: 12px 18px; margin: 0; border-top: 1px solid var(--surface-border);
  line-height: 1.6;
}

/* ---------- Callout ----------
   Three jobs, three looks. They were previously one look, which meant a page
   could show "here is what to do" and "is this you?" in identical boxes.

     .callout            — what to do. An instruction or checklist. Accent.
     .callout.is-qualify — is this you? Symptoms the reader self-checks
                           against. Navy rule, so it reads as a diagnostic
                           rather than another instruction.
     .callout.is-note    — a caveat, disclaimer or reference detail. Quiet by
                           design: a legal note must not out-shout the argument
                           it qualifies.

   The bottom margin matters: this used to be `40px 0 0`, so a callout followed
   by a paragraph had a measured gap of zero and the two boxes touched. */
.callout {
  margin: var(--flow-block) 0; padding: 30px 32px; border-radius: var(--radius-block);
  border-left: var(--rule) solid var(--accent); background: var(--bg-alt);
}
.callout-title {
  font-family: var(--font-mono); font-size: .7rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--accent); margin: 0 0 18px; font-weight: 600;
}

.callout.is-qualify {
  background: var(--surface); border: 1px solid var(--surface-border);
  border-left: var(--rule) solid var(--navy); box-shadow: var(--shadow);
}
.callout.is-qualify .callout-title { color: var(--navy); }
.callout.is-qualify li::before { color: var(--navy); }

.callout.is-note {
  background: none; border-left: var(--rule) solid var(--divider);
  padding: 4px 0 4px 24px; border-radius: 0;
}
.callout.is-note .callout-title { color: var(--text-muted); margin-bottom: 10px; }
.callout.is-note p, .callout.is-note li { color: var(--text-muted); font-size: .9rem; }
.callout.is-note li::before { color: var(--text-muted); }
.entry-content .callout ul { list-style: none; margin: 0; padding: 0; }
.callout li {
  font-size: .95rem; line-height: 1.65; color: var(--text);
  padding-left: 22px; position: relative; margin-bottom: 13px;
}
.callout li:last-child { margin-bottom: 0; }
.callout li::before {
  content: "\203A"; position: absolute; left: 0; top: -1px;
  font-family: var(--font-mono); font-weight: 700; color: var(--accent);
}

/* ---------- Data tables ---------- */
.entry-content .data-table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.data-table caption {
  font-family: var(--font-mono); font-size: .68rem; letter-spacing: .08em;
  color: var(--text-muted); text-align: left; padding-bottom: 10px;
}
.entry-content .data-table th {
  background: var(--navy); color: var(--bg); padding: 11px 14px; text-align: left;
  font-family: var(--font-mono); font-size: .66rem; letter-spacing: .1em;
  text-transform: uppercase; font-weight: 600; vertical-align: bottom;
}
:root[data-theme="dark"] .entry-content .data-table th { background: var(--accent); color: #0B1220; }
.entry-content .data-table td {
  padding: 12px 14px; border-bottom: 1px solid var(--surface-border);
  vertical-align: top; line-height: 1.6; color: var(--text);
}
.entry-content .data-table tbody tr:last-child td { border-bottom: none; }
.entry-content .data-table td.row-key {
  font-family: var(--font-mono); font-size: .72rem; letter-spacing: .04em;
  color: var(--text-muted); background: var(--bg-alt); text-transform: uppercase;
}
.entry-content .data-table.striped tbody tr:nth-child(even) td { background: var(--bg-alt); }
.entry-content .data-table td.figure { font-family: var(--font-mono); color: var(--accent); font-weight: 600; }

/* ---------- Severity pills ---------- */
.risk-pill {
  display: inline-block; font-family: var(--font-mono); font-size: .64rem;
  letter-spacing: .1em; text-transform: uppercase; font-weight: 600;
  padding: .3em .7em; border-radius: 4px; color: #fff; white-space: nowrap;
}
.risk-pill.critical { background: var(--sev-critical); }
.risk-pill.high { background: var(--sev-high); }
.risk-pill.medium { background: var(--sev-medium); }
.risk-pill.low { background: var(--sev-low); }
:root[data-theme="dark"] .risk-pill { color: #0B1220; }

/* ---------- Inline source attribution ---------- */
.source-tag {
  display: inline-block; font-family: var(--font-mono); font-size: .6rem;
  letter-spacing: .1em; text-transform: uppercase; padding: .18em .55em;
  border-radius: 4px; vertical-align: middle; margin-left: 2px; white-space: nowrap;
  border: 1px solid var(--surface-border); background: var(--bg-alt); color: var(--text-muted);
}
.source-tag.uk { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
.source-tag.eu { color: var(--navy); border-color: var(--divider); }
:root[data-theme="dark"] .source-tag.eu { color: var(--text); }

/* ---------- Sources panel ---------- */
/* Sources, collapsed behind a disclosure (see diginom_collapse_sources).
   The label is deliberately the same mono/uppercase/muted treatment as
   .article-return, so the two quiet controls at the foot of an article read as
   a pair rather than as unrelated bits of furniture. */
/* The closing row: "All Insights" on the left, "Sources" on the right.

   When the sources open they take the full width of the row and drop to their
   own line, so a 600-character citation list is never squeezed into a
   half-width column. That means the summary moves left as it opens, which is
   the trade for keeping the expanded text readable. */
.article-foot {
  display: grid; align-items: baseline; margin-top: 16px;
}
/*
 * Both children occupy the SAME grid cell, deliberately overlapping.
 *
 * The return link sits at the start of it; the sources span the full width
 * with their summary pushed right by text-align. That way the summary keeps
 * its place on the right when the block opens — a flex row cannot do this,
 * because giving the sources full width on open drops them onto their own
 * line and drags the summary left with them.
 *
 * The details box therefore covers the return link. pointer-events: none on
 * the box lets clicks fall through to the link, and is restored on the
 * children so the summary still toggles and the citations stay selectable.
 */
.article-foot > .article-return-foot { grid-column: 1; grid-row: 1; justify-self: start; margin: 0; }
.article-foot > details.sources {
  grid-column: 1; grid-row: 1; margin: 0; padding: 0; border-top: 0;
  text-align: right; pointer-events: none;
}
.article-foot > details.sources > * { pointer-events: auto; }
.article-foot > details.sources > *:not(summary) { text-align: left; margin-top: 12px; }

/* Outside that row — any template that still renders sources in place. */
.sources { margin-top: 32px; padding-top: 26px; border-top: 2px solid var(--divider); }
.sources-label {
  font-family: var(--font-mono); font-size: .72rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-muted); margin: 0;
}
/* summary carries .sources-label, so this only hits the collapsed version. */
summary.sources-label {
  display: inline-flex; align-items: center; gap: 8px;
  cursor: pointer; list-style: none; transition: color .2s ease;
}
summary.sources-label::-webkit-details-marker { display: none; }
summary.sources-label:hover { color: var(--accent); }
summary.sources-label:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }
/* Chevron points down when closed, up when open. */
summary.sources-label::after {
  content: "\203A"; display: inline-block; font-size: 1.1em; line-height: 1;
  transform: rotate(90deg); transition: transform .2s ease;
}
details.sources[open] > summary.sources-label::after { transform: rotate(-90deg); }
/* Spacing under an open summary comes from the content's own margin-top in
   .article-foot, so nothing is added here. */
.sources p {
  font-family: var(--font-mono); font-size: .72rem; line-height: 1.85;
  color: var(--text-muted); margin: 0;
}

/* ---------- Section ornament ---------- */
/* The dinkus that closes an article.

   Margin is deliberately NOT --flow-section (52px) any more. Since every
   article gained a closing CTA, the ornament and the CTA are two "the piece
   is over" markers in a row, and a full section gap above each left 138px of
   near-empty space between the last paragraph and the box: 52 above the
   dinkus, 34 of dinkus, 52 above the CTA. They now read as one closing group.
   Used only on articles — no other template renders it. */
.ornament {
  text-align: center; margin: 28px 0 0; color: var(--divider);
  font-size: 1.3rem; letter-spacing: .7em;
  /* line-height 1 rather than inherited: the dots are tiny and the default
     line box wrapped them in ~13px of dead space top and bottom, which read
     as yet more gap above the closing row. */
  line-height: 1;
}

/* ---------- Standalone emphatic line (no attribution) ----------
   DigiNom asserting something, in our own voice. The absence of a source line
   is the signal: if it carries an attribution it is a .pullquote, if it does
   not it is ours to defend. One per page, never two. */
.entry-content .pull {
  font-family: var(--font-display); font-size: 1.2rem; line-height: 1.5;
  color: var(--navy); margin: var(--flow-block) 0; padding: 26px 30px;
  border-radius: var(--radius-block);
  border-left: var(--rule) solid var(--accent); background: var(--bg-alt);
}

/* ---------- Figure caption ----------
   A caption belongs to the figure above it, so it has to sit closer to that
   figure than to the paragraph below. The preceding block already carries a
   --flow-block bottom margin, so pull most of it back and restore a normal
   block interval underneath. Previously this was `-4px 0 0`, which measured
   32px above the figure it captioned and 0px above the next paragraph — the
   relationship inverted. */
.entry-content .fig-caption {
  font-family: var(--font-mono); font-size: .7rem; letter-spacing: .04em;
  line-height: 1.6; color: var(--text-muted);
  margin: calc(12px - var(--flow-block)) 0 var(--flow-block);
}

/* ---------- Framing pairs (vague ask vs measurable problem) ---------- */
.pairs { margin: var(--flow-block) 0; display: grid; gap: 14px; }
.pair {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  background: var(--surface-border); border: 1px solid var(--surface-border);
  border-radius: var(--radius-block); overflow: hidden;
}
.pair .ask, .pair .real {
  background: var(--surface); padding: 18px 20px; font-size: .95rem; line-height: 1.6;
}
.pair .ask { color: var(--text-muted); }
.pair .real { color: var(--text); box-shadow: inset 3px 0 0 var(--accent); }
.pair .ask::before, .pair .real::before {
  display: block; font-family: var(--font-mono); font-size: .62rem; letter-spacing: .12em;
  text-transform: uppercase; margin-bottom: 8px;
}
.pair .ask::before { content: "The ask"; color: var(--text-muted); }
.pair .real::before { content: "The problem"; color: var(--accent); }

/* ---------- Discipline viewpoints ---------- */
.lens { margin: var(--flow-tight) 0; padding: 2px 0 2px 20px; border-left: var(--rule) solid var(--divider); }
.lens .who {
  display: block; font-family: var(--font-mono); font-size: .68rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--accent); margin-bottom: 6px; font-weight: 600;
}
.entry-content .lens p { margin: 0; color: var(--text-muted); font-size: .97rem; }

/* ---------- Question gate ---------- */
.gate {
  margin: var(--flow-block) 0; padding: 32px; border-radius: var(--radius-block);
  background: var(--surface); border: 1px solid var(--surface-border); box-shadow: var(--shadow);
}
.entry-content .gate h2 { margin-top: 0; }
.gate .lead-muted { color: var(--text-muted); font-size: .95rem; margin-bottom: 22px; }
.entry-content .gate ol { list-style: none; counter-reset: gate; margin: 0; padding: 0; }
.gate li { counter-increment: gate; position: relative; padding-left: 46px; margin-bottom: 22px; }
.gate li:last-child { margin-bottom: 0; }
.gate li::before {
  content: counter(gate); position: absolute; left: 0; top: 0;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-weight: 600; font-size: .9rem;
}
.gate .qt { display: block; font-weight: 600; color: var(--navy); margin-bottom: 4px; }
.gate .qb { display: block; color: var(--text-muted); font-size: .95rem; line-height: 1.6; }

/* ---------- Closing call to action.
   Named .article-cta, not .cta: the homepage already owns .cta and its
   padding/centring would leak in here. ---------- */
.article-cta {
  /* Not --flow-section: the ornament above it already separates this from the
     article body, so a second full section gap just stacked whitespace. */
  margin: 24px 0 0; padding: 32px 28px; text-align: center;
  border-radius: var(--radius-block);
  background: var(--bg-alt); border: 1px solid var(--surface-border);
}
/* Not scoped to .entry-content: the closing CTA is rendered by single.php,
   outside the content, so every article ends the same way. Still requires an
   .article-cta ancestor, so a standalone .lead elsewhere is unaffected. */
.article-cta .lead {
  font-family: var(--font-display); font-size: 1.2rem; line-height: 1.45;
  color: var(--navy); margin: 0 0 20px;
}

@media (max-width: 560px) {
  /* .metric-row needs no override here — flex-basis wraps it to two per row at
     this width on its own, and fills any trailing row. */
  .article-number { font-size: 2.8rem; }
  .pullquote { padding: 22px 20px; }
  .callout { padding: 24px 20px; }
  .callout.is-note { padding: 4px 0 4px 18px; }
  .entry-content .pull { padding: 22px 20px; }
  .pair { grid-template-columns: 1fr; }
  .gate { padding: 24px 20px; }
  .article-cta .btn { display: flex; width: 100%; }
}
