/* subpage.css
 * Styles for pages built by the subpage system (website/subpages/scripts).
 * Loaded in addition to the main stylesheet. Consumes the v2.18 extended
 * palette — never hard-coded hex. Honors prefers-reduced-motion.
 */

/* Token overrides — define --navy and any other tokens used by subpage
 * styles that are not in the main stylesheet's :root. (The main
 * stylesheet defines --bg, --bg-alt, --bg-soft, --surface, --border, --gold,
 * --gold-fg, --blue, --red but not --navy or --burgundy. Subpage styles
 * use these for the design-variant bands and several other rules.)
 *
 * Note on --heading: the main stylesheet's --blue is dark in BOTH light
 * and dark mode (a deliberate palette choice), so we cannot use it
 * directly. We define --heading explicitly per theme:
 *   dark mode : light heading text (#f5f7fb) for contrast on dark bg
 *   light mode: dark heading text (#001f3f) for contrast on light bg
 *
 * Note on --band-dark: this is the "deep navy" used for the Questions
 * and Evidence section bands. --navy (#0a335c) is a brighter, more
 * saturated blue that was making the bands pop too much against the
 * page background. The main page's .section.alt uses #101b28 (very
 * close to the page bg #0c121a), so the subpage bands now match that
 * "barely lighter than the page" feel — present but not loud. */
html.subpage-layout-v2 {
  --navy: #0a335c;
  --burgundy: #721817;
  --band-dark: #152130;
  --heading: #f5f7fb;
  --text: #d4dce8;
  --text-soft: #d4dce8;
}
html.subpage-layout-v2[data-theme='light'] {
  --heading: #001f3f;
  --text: #2a3441;
  --text-soft: #4a5663;
}

/* =================================================================
 * Page layout — two-column on desktop, single-column on mobile.
 * The right column is the sticky on-this-page navigation.
 * ================================================================ */
html.subpage-layout-v2 .subpage-shell {
  /* v2: responsive max-width. The v1 shell uses max-width: 1180px
   * which is a hard cap — the shell stays at 1180px even when the
   * viewport is narrower (e.g. 1150px), causing horizontal overflow
   * and pushing the TOC off-screen. The v2 shell uses a CSS min()
   * function to cap at 1180px but shrink to fit when the viewport
   * is smaller. The padding is on each section (see the section
   * padding rule below), so the shell itself has no horizontal
   * padding and the max-width is just min(1180px, 100%).
   *
   * v2.1: bumped the upper cap to 1600px so the shell can grow with
   * the viewport on wide displays (e.g. 4K, or zoomed-out windows
   * on 1920px+ monitors). At 1600px the shell still respects a
   * reasonable reading width for prose sections — those are
   * constrained by their own .content.narrow { max-width: 64ch }
   * rule — and the wide-grid sections (cards, stats, compare,
   * evidence) get more room to spread out. Below 1600px viewport,
   * the shell still caps at 100% (the viewport width). */
  max-width: min(1600px, 100%);
  margin: 0 auto;
  padding: 0 0 4rem;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  position: relative;
  z-index: 1;
}

/* =================================================================
 * LumenLayers lighting — the underlay that sits behind every page.
 * Generated by website/subpage-configs/lumen/generate.py and rendered
 * as a fixed-position, viewport-sized layer. It does not scroll with
 * the page, so content moves over it (parallax effect).
 *
 * Each subpage sets a `data-lumen="<page>"` attribute on the
 * .lumen-lighting element; the SVG file is selected from that value.
 * No JS required. Adding a new page = add an SVG and one CSS rule.
 *
 * Per-page variants live at:
 *   /assets/svg/lumen/{page}.svg       (dark mode)
 *   /assets/svg/lumen/{page}-light.svg (light mode)
 *
 * The SVG itself uses mix-blend-mode: screen + opacity on its layers,
 * so the colours lighten the base background rather than obscuring it.
 * The body background still shows through where the SVG is transparent.
 * ================================================================ */
html.subpage-layout-v2 .lumen-lighting {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  mix-blend-mode: screen;
  transition: opacity var(--transition-theme, 0.2s ease);
  opacity: 1;
}

/* Per-page dark-mode SVGs */
html.subpage-layout-v2 .lumen-lighting[data-lumen="cybersecurity"] { background-image: url("/assets/svg/lumen/cybersecurity.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="digital-identity"] { background-image: url("/assets/svg/lumen/digital-identity.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="enterprise-architecture"] { background-image: url("/assets/svg/lumen/enterprise-architecture.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="applied-ai"] { background-image: url("/assets/svg/lumen/applied-ai.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="software-engineering"] { background-image: url("/assets/svg/lumen/software-engineering.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="advisory-assessments"] { background-image: url("/assets/svg/lumen/advisory-assessments.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="methodology"] { background-image: url("/assets/svg/lumen/methodology.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="deliverables"] { background-image: url("/assets/svg/lumen/deliverables.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="zero-trust-architecture"] { background-image: url("/assets/svg/lumen/zero-trust-architecture.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="iam-patterns"] { background-image: url("/assets/svg/lumen/iam-patterns.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="threat-modeling"] { background-image: url("/assets/svg/lumen/threat-modeling.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="mlops"] { background-image: url("/assets/svg/lumen/mlops.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="platform-engineering"] { background-image: url("/assets/svg/lumen/platform-engineering.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="api-ecosystems"] { background-image: url("/assets/svg/lumen/api-ecosystems.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="capability-driven-planning"] { background-image: url("/assets/svg/lumen/capability-driven-planning.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="decentralized-identity"] { background-image: url("/assets/svg/lumen/decentralized-identity.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="security-governance"] { background-image: url("/assets/svg/lumen/security-governance.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="application-security"] { background-image: url("/assets/svg/lumen/application-security.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="intelligent-automation"] { background-image: url("/assets/svg/lumen/intelligent-automation.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="data-lineage-and-integration"] { background-image: url("/assets/svg/lumen/data-lineage-and-integration.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="resilience"] { background-image: url("/assets/svg/lumen/resilience.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="high-compliance-delivery"] { background-image: url("/assets/svg/lumen/high-compliance-delivery.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="privacy-engineering"] { background-image: url("/assets/svg/lumen/privacy-engineering.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="privacy-policy"] { background-image: url("/assets/svg/lumen/privacy-policy.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="product"] { background-image: url("/assets/svg/lumen/product.svg"); }
html.subpage-layout-v2 .lumen-lighting[data-lumen="standards-manager"] { background-image: url("/assets/svg/lumen/standards-manager.svg"); }

/* Per-page light-mode SVGs (override the dark image) */
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="cybersecurity"] { background-image: url("/assets/svg/lumen/cybersecurity-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="digital-identity"] { background-image: url("/assets/svg/lumen/digital-identity-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="enterprise-architecture"] { background-image: url("/assets/svg/lumen/enterprise-architecture-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="applied-ai"] { background-image: url("/assets/svg/lumen/applied-ai-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="software-engineering"] { background-image: url("/assets/svg/lumen/software-engineering-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="advisory-assessments"] { background-image: url("/assets/svg/lumen/advisory-assessments-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="methodology"] { background-image: url("/assets/svg/lumen/methodology-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="deliverables"] { background-image: url("/assets/svg/lumen/deliverables-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="zero-trust-architecture"] { background-image: url("/assets/svg/lumen/zero-trust-architecture-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="iam-patterns"] { background-image: url("/assets/svg/lumen/iam-patterns-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="threat-modeling"] { background-image: url("/assets/svg/lumen/threat-modeling-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="mlops"] { background-image: url("/assets/svg/lumen/mlops-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="platform-engineering"] { background-image: url("/assets/svg/lumen/platform-engineering-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="api-ecosystems"] { background-image: url("/assets/svg/lumen/api-ecosystems-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="capability-driven-planning"] { background-image: url("/assets/svg/lumen/capability-driven-planning-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="decentralized-identity"] { background-image: url("/assets/svg/lumen/decentralized-identity-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="security-governance"] { background-image: url("/assets/svg/lumen/security-governance-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="application-security"] { background-image: url("/assets/svg/lumen/application-security-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="intelligent-automation"] { background-image: url("/assets/svg/lumen/intelligent-automation-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="data-lineage-and-integration"] { background-image: url("/assets/svg/lumen/data-lineage-and-integration-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="resilience"] { background-image: url("/assets/svg/lumen/resilience-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="high-compliance-delivery"] { background-image: url("/assets/svg/lumen/high-compliance-delivery-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="privacy-engineering"] { background-image: url("/assets/svg/lumen/privacy-engineering-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="privacy-policy"] { background-image: url("/assets/svg/lumen/privacy-policy-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="product"] { background-image: url("/assets/svg/lumen/product-light.svg"); }
html.subpage-layout-v2[data-theme='light'] .lumen-lighting[data-lumen="standards-manager"] { background-image: url("/assets/svg/lumen/standards-manager-light.svg"); }
@media (min-width: 1100px) {
html.subpage-layout-v2 .subpage-shell {
    /* v2: single-column grid. Main is full-width (up to the shell's
     * max-width). The TOC is a fixed sidebar positioned to the right
     * of the main content. This lets sections be full-bleed (the
     * main column spans the full shell width, not 912px). */
    grid-template-columns: 1fr;
    gap: 0;
  }
  html.subpage-layout-v2 .subpage-toc {
    display: block;
    position: fixed;
    top: 120px;
    /* v2: TOC right edge is aligned with the shell's right edge.
     * The shell is 1180px max, centered. The space to the right of
     * the shell is (100vw - 1180px) / 2. We want the TOC's right
     * edge to be at the shell's right edge, so right: (100vw - 1180px) / 2.
     * On viewports < 1180px, the shell is 100% of the viewport, so
     * the space is 0. The max() ensures the TOC doesn't go off-screen
     * on very narrow viewports (the @media query already hides the
     * TOC below 1100px, so this is just a safety net). */
    right: max(1.5rem, calc((100vw - 1180px) / 2));
    width: 220px;
    max-height: calc(100vh - 140px);
    overflow-y: auto;
    z-index: 10;
    /* The TOC can be dragged to a custom position. When the user
     * drags, JS sets `style.transform` to the new offset. We keep
     * `right` for the resting position so the TOC defaults to the
     * shell's right edge on first load, but `transform` overrides
     * `right` while a saved position exists. */
    transform: translate(0, 0);
  }
  /* When the TOC has a custom saved position (JS-added class), the
   * transform takes precedence over right. We leave right in place
   * so on viewports that don't have sessionStorage (e.g. private
   * browsing), the TOC falls back to its right-edge default. */
  html.subpage-layout-v2 .subpage-toc.is-positioned {
    right: auto;
    left: var(--toc-left, auto);
    top: var(--toc-top, 120px);
    transform: none;
  }
}

/* =================================================================
 * On-this-page navigation (sticky on desktop).
 * Hidden on mobile — a TOC there would push real content off-screen.
 * ================================================================ */
html.subpage-layout-v2 .subpage-toc {
  display: none;
}
@media (min-width: 1100px) {
html.subpage-layout-v2 .subpage-toc {
    display: flex;
    flex-direction: column;
    /* v2: the TOC is a fixed sidebar (not a grid column). The
     * position and dimensions are set in the earlier @media block
     * (line 157). This block only sets the visual styling. */
    padding: .75rem 1rem .75rem 1.25rem;
    /* Subtle separator from main content */
    border-left: 1px solid var(--borderSubtle);
    /* Subtle backing so the TOC reads as a discrete panel on both
     * light and dark themes. The background is mostly transparent
     * so the page colour shows through, but with enough contrast
     * for the chip state (when the sidebar collapses to a small
     * element) to be clearly visible against any page background. */
    background: var(--surface);
    border: 1px solid var(--borderSubtle);
    border-left: 1px solid var(--borderSubtle);
    border-radius: var(--radius);
    /* Whole-TOC drag handle (cursor: grab on the panel). Links
     * inside the TOC override this to the default cursor. */
    cursor: grab;
    /* Disable text selection while dragging. */
    user-select: none;
    -webkit-user-select: none;
    /* Smooth transition for the minimize/restore animation. Only
     * enabled after the inline toc-hydrate script (right after the
     * <aside> in shell.tt) has applied the saved position + minimized
     * state and added .is-ready. Before that, the TOC is visibility:
     * hidden (see the second .subpage-toc rule below the @media
     * block) so the user doesn't see the initial state-computation
     * transition (e.g. a saved "minimized" state animating down from
     * the full expanded size on first paint). See
     * references/draggable-minimizable-toc-pattern.md "FOUC fix"
     * for the full rationale. */
    transition: width 200ms ease, height 200ms ease, padding 200ms ease, border-color 150ms ease, box-shadow 200ms ease;
    /* The TOC is hidden by default until the toc-hydrate inline
     * script applies saved state + adds .is-ready. This prevents the
     * first-paint flash of the unstyled default position/state, which
     * would briefly show the TOC at the right-anchor in expanded
     * form before JS-applied saved state repositions + minimizes it. */
    visibility: hidden;
  }
  html.subpage-layout-v2 .subpage-toc.is-ready {
    visibility: visible;
  }
  /* Fallback for JS-disabled visitors: the inline toc-hydrate
   * script that would normally reveal the TOC never runs, so the
   * default visibility:hidden rule above would leave them without
   * any TOC. Override visibility: visible for users without JS via
   * the @media block so the TOC shows at its right-anchor default
   * position (no saved state to apply, but at least they get a
   * working TOC). The <noscript> element in shell.tt adds the .no-js
   * class to <html> when JS is disabled; this rule activates on
   * that class. */
  html.subpage-layout-v2.no-js .subpage-toc {
    visibility: visible;
  }
  /* Drop shadow: light theme only (dark theme panels already separate
   * well from the background via the dark surface colour). Medium
   * elevation: 6px y-offset, 18px blur, two-layer for a defined edge
   * + soft falloff. Mirrors the elevation feel of `.card:hover`
   * without going as far as `--shadow-card-hi`. */
  html.subpage-layout-v2[data-theme='light'] .subpage-toc {
    box-shadow:
      0 1px 2px rgba(13, 47, 87, 0.08),
      0 6px 18px rgba(13, 47, 87, 0.12);
  }
  /* Dark mode: skip the drop shadow, but use a lighter outline
   * instead so the panel still separates from the page. The
   * default --borderSubtle (#263646) is very close to the
   * panel's --surface, so it nearly disappears. #34465b is
   * one shade darker than the #3d4f64 we tried first, but
   * still ~25 units lighter than --borderSubtle so it reads
   * as a deliberate edge. The full `border` shorthand is
   * used (rather than longhand border-color + border-width)
   * because the translucent-backing block further down re-
   * sets `border-left-color: transparent` and a previous
   * attempt with longhand overrides ended up computing as
   * `0px none` due to the cascade — the explicit shorthand
   * plus an explicit `border-left-color` re-assertion makes
   * all 4 sides reliably render. */
  html.subpage-layout-v2[data-theme='dark'] .subpage-toc,
  html.subpage-layout-v2[data-theme='dark'] .subpage-toc-chip {
    border: 1px solid #34465b;
    border-left-color: #34465b;
  }
  html.subpage-layout-v2 .subpage-toc.is-dragging { cursor: grabbing; }
  /* Repositioning transition: when the window resizes or zooms
   * and the TOC is now off-screen, subpage.js adds this class
   * for the duration of the slide-back animation. We use a
   * dedicated transition on left/top (separate from the base
   * transition which covers width/height/padding) so the
   * repositioning feels smooth without making the minimize/
   * drag interactions laggy. The class is stripped on
   * transitionend so subsequent drags are still instant. */
  html.subpage-layout-v2 .subpage-toc.is-repositioning {
    transition: left 220ms ease-out, top 220ms ease-out;
  }
  /* Reduced-motion: kill the repositioning transition (the
   * narrower selector above has higher specificity than the
   * general .subpage-toc { transition: none } rule a few
   * lines down, so we need a matching specificity override
   * to honor the reduced-motion preference). The position
   * still gets clamped instantly by JS — it just doesn't
   * animate to the new spot. */
  @media (prefers-reduced-motion: reduce) {
    html.subpage-layout-v2 .subpage-toc.is-repositioning { transition: none; }
  }
  html.subpage-layout-v2 .subpage-toc a,
  html.subpage-layout-v2 .subpage-toc button { cursor: default; }
  html.subpage-layout-v2 .subpage-toc a { cursor: pointer; }
  /* Reduced-motion: kill the transition. The minimize/restore and
   * drag still work, but they snap rather than animate. */
  @media (prefers-reduced-motion: reduce) {
    html.subpage-layout-v2 .subpage-toc { transition: none; }
  }
  html.subpage-layout-v2 .subpage-toc-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    margin: 0 0 .85rem;
  }
  html.subpage-layout-v2 .subpage-toc h2 {
    font-size: .72rem;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--text-soft);
    margin: 0;
    font-weight: 600;
    flex: 1 1 auto;
  }
  /* Minimize/restore button. Stays subtle (no border, no shadow) so
   * it doesn't compete with the page content. The +/− glyph changes
   * to reflect the next state. */
  html.subpage-layout-v2 .subpage-toc-toggle {
    flex: 0 0 auto;
    background: transparent;
    border: 1px solid var(--borderSubtle);
    border-radius: 4px;
    padding: 0;
    width: 24px;
    height: 24px;
    line-height: 1;
    font-size: 1rem;
    color: var(--text-soft);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 150ms ease, border-color 150ms ease, background 150ms ease;
  }
  html.subpage-layout-v2 .subpage-toc-toggle:hover {
    color: var(--text);
    border-color: var(--border);
    background: var(--surface);
  }
  html.subpage-layout-v2 .subpage-toc-toggle:focus-visible {
    outline: 2px solid var(--gold);
    outline-offset: 2px;
  }
  /* Body collapses to 0 height when minimized. We use max-height +
   * opacity + margin to keep the transition smooth. */
  html.subpage-layout-v2 .subpage-toc-body {
    max-height: 1000px;
    opacity: 1;
    overflow: hidden;
    transition: max-height 200ms ease, opacity 200ms ease, margin 200ms ease;
  }
  html.subpage-layout-v2 .subpage-toc.is-minimized .subpage-toc-body {
    max-height: 0;
    opacity: 0;
    margin-top: 0;
  }
  /* Chip: the minimized form of the TOC. Small enough to be out of
   * the way (~120px wide, ~32px tall) but big enough to show the
   * current section name clearly. The chip is hidden by default; the
   * JS shows it when is-minimized is set. */
  html.subpage-layout-v2 .subpage-toc-chip {
    display: none;
  }
  html.subpage-layout-v2 .subpage-toc.is-minimized .subpage-toc-chip {
    display: flex;
    align-items: center;
    gap: .35rem;
    padding: .35rem .65rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--text-soft);
    font-size: .78rem;
    line-height: 1.2;
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  html.subpage-layout-v2 .subpage-toc-chip::before {
    content: "§";
    color: var(--gold);
    font-weight: 600;
    font-size: .85rem;
  }
  /* When minimized, the TOC becomes a small pill (~32px tall). The
   * full panel shadow would look disproportionate on it, so tighten
   * the y-offset and blur for the chip state. Same theme-gating
   * (light only) applies. */
  html.subpage-layout-v2[data-theme='light'] .subpage-toc.is-minimized {
    box-shadow:
      0 1px 2px rgba(13, 47, 87, 0.08),
      0 3px 8px rgba(13, 47, 87, 0.10);
  }
  html.subpage-layout-v2 .subpage-toc-chip-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
html.subpage-layout-v2 .subpage-toc ol {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    gap: .35rem;
    counter-reset: toc;
  }
html.subpage-layout-v2 .subpage-toc a {
    display: block;
    color: var(--text-soft);
    text-decoration: none;
    font-size: .9rem;
    line-height: 1.4;
    padding: .25rem 0;
    border-left: 2px solid transparent;
    padding-left: .75rem;
    margin-left: -.75rem;
    transition: color 150ms ease, border-color 150ms ease;
  }
html.subpage-layout-v2 .subpage-toc a:hover { color: var(--text); }
html.subpage-layout-v2 .subpage-toc a[aria-current="true"] {
    color: var(--heading-accent);
    border-left-color: var(--gold);
    font-weight: 600;
  }
  /* 'Top of page' link: prefix with an up arrow so it's visually
   * distinct from the section links below it. The arrow is
   * rendered via ::before so the link text remains plain. */
  html.subpage-layout-v2 .subpage-toc a[data-toc-top]::before {
    content: "↑";
    display: inline-block;
    margin-right: .35rem;
    color: var(--gold);
    font-weight: 600;
  }
html.subpage-layout-v2 .subpage-toc .toc-meta {
    margin-top: 1.5rem;
    padding-top: 1rem;
    border-top: 1px solid var(--borderSubtle);
    font-size: .78rem;
    color: var(--text-soft);
    line-height: 1.5;
  }
html.subpage-layout-v2 .subpage-toc .toc-meta strong { color: var(--text); font-weight: 600; }
}

/* =================================================================
 * Section eyebrow — small `§ 0X ·` index label above section title.
 * ================================================================ */
html.subpage-layout-v2 .section-eyebrow {
  margin: 0 0 .35rem;
  font-family: var(--font-body);
  font-size: .72rem;
  letter-spacing: var(--tracking-eyebrow-wide);
  text-transform: uppercase;
  /* Use --gold-fg, not --gold: the eyebrow is foreground text on a light
   * background, and the bright brand gold fails AA there. --gold-fg is
   * the darkened gold that passes 5.8:1+ on light surfaces. */
  color: var(--gold-fg);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Section intro paragraph (used inside section-intro wrapper as a separate
 * element from the eyebrow). */
html.subpage-layout-v2 .section-intro-text {
  margin: 0 0 1.5rem;
  font-size: 1.02rem;
  line-height: 1.6;
  color: var(--text-soft);
  max-width: 60ch;
}

/* =================================================================
 * Faint gradient hairline between major sections — visual divider that
 * reads as structural rather than decorative.
 * ================================================================ */
html.subpage-layout-v2 .section + .section {
  position: relative;
}
html.subpage-layout-v2 .section + .section::before {
  content: "";
  display: block;
  position: absolute;
  top: 0; left: 50%;
  transform: translateX(-50%);
  width: min(140px, 25%);
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    var(--noetroniq-amber-800) 30%,
    var(--noetroniq-amber-800) 70%,
    transparent 100%);
}

html.subpage-layout-v2[data-theme='light'] .section + .section::before {
  background: linear-gradient(90deg,
    transparent 0%,
    var(--border) 30%,
    var(--border) 70%,
    transparent 100%);
}

/* =================================================================
 * Hero — full-bleed editorial hero. Photograph is the entire hero
 * background; headline + tagline + chips overlay at the bottom-left
 * with a dark scrim for legibility. Pattern follows the editorial
 * article style (Linear, Stripe blog, Cloudflare blog).
 * ================================================================ */
.subpage-hero {
  position: relative;
  left: 0;
  right: 0;
  /* v2: full-bleed hero via viewport-centered margin. The hero is
   * position: relative, so it sits at the top of <main> in flow
   * (taking its own vertical space), and uses the classic full-bleed
   * trick: margin-left: calc(50% - 50vw) + width: 100vw to span the
   * viewport regardless of the main column width. Switching from
   * position: absolute to relative was needed so the mobile TOC
   * (placed after the hero in DOM order) renders below it instead of
   * overlapping the absolute-positioned hero's bottom edge.
   *   - 50% = 50% of the containing block (the shell, 1180px max)
   *   - 50vw = 50% of the viewport width
   * The difference is negative when the shell is narrower than the
   * viewport, pushing the hero's left edge to viewport-x=0. Combined
   * with width: 100vw, the hero spans the full viewport regardless
   * of the main column's width (the main column is 912px on desktop
   * because the TOC takes 220px and the gap is 48px). */
  margin-left: calc(50% - 50vw);
  width: 100vw;
  min-height: clamp(360px, 56vh, 560px);
  margin-bottom: 0;
  overflow: hidden;
  isolation: isolate;
  display: flex;
  /* v2: center the text plate both horizontally and vertically
   * in the hero band. Previously the plate was at the bottom-left
   * (align-items: flex-end, default justify-content: flex-start);
   * the user wants it centered. */
  align-items: center;
  justify-content: center;
  z-index: 1;
}
/* The hero is in normal flow (position: relative) at the top of
 * <main>. The mobile TOC is placed after the hero in DOM order, so
 * it naturally renders below the hero's actual height with no
 * padding-top reservation needed. */
html.subpage-layout-v2 main {
  padding-top: 0;
}
/* Layer 1: full-bleed hero background. The hero-bg breaks out of
 * the hero element (864px main column) to fill the viewport. The
 * -200% offset extends 1728px on each side, covering viewports
 * up to ~4K. The body's overflow-x: clip prevents horizontal
 * scroll without affecting vertical scroll. */
html.subpage-layout-v2 .subpage-hero-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  z-index: 0;
  /* 0.85 opacity lets the LumenLayers lighting show through the hero
   * gradient. The hero gradient is full-bleed and would otherwise
   * completely cover the per-page lighting. At 0.85 the gradient
   * stays visually dominant (text and contrast unchanged) but the
   * LumenLayers tints the hero with its own colors. */
  opacity: 0.85;
}
/* Layer 2 (removed 2026-07-13): was a soft blue photo darkening layer
 * that gently toned down bright regions of the hero photograph for text
 * legibility. The hero is now a gradient (no photograph), so this layer
 * was redundant with the .subpage-hero-content translucent text
 * backing. It also created a visible edge against the full-bleed
 * gradient (the blue tint at the top and bottom of the hero was
 * noticeable where the gradient met the page). User requested removal
 * or full transparency; we removed it entirely. */
/* Layer 3: glow vignette. Extends full-bleed using the same -200%
 * breakout as .subpage-hero-bg (Layer 1) so the glow covers the
 * same area as the gradient — no visible edge where the glow ends
 * and the full-bleed gradient continues. The radial gradient uses a
 * large ellipse (300% × 300%) and a very gradual falloff
 * (transparent at 80% of radius) so the transition is imperceptible.
 * The glow color is set per-variant via --hero-glow (defined on the
 * .subpage-hero element via the data-hero-variant rules below) so
 * each page can have its own glow tint. The glow is a "lifted" version
 * of the dominant gradient color — for navy pages it's a lighter
 * blue/navy, for gold pages it's gold, for red/burgundy pages it's
 * a lighter burgundy or rose. The opacity is kept low (~10%) so the
 * glow is a subtle tonal variation, not a visible highlight that
 * would create an edge. */
html.subpage-layout-v2 .subpage-hero::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background:
    radial-gradient(ellipse 300% 300% at 85% 15%,
      color-mix(in srgb, var(--hero-glow, var(--noetroniq-gold-500)) 10%, transparent) 0%,
      transparent 80%);
  pointer-events: none;
  z-index: 1;
}

/* Per-variant glow color. These set --hero-glow on the hero element,
 * which the ::after rule above reads via var(--hero-glow). The default
 * (gold) is the historical brand accent. Variants get a color from
 * the same family as their gradient so the glow feels related to the
 * base color (blue glow on blue gradient, red glow on red gradient).
 * Using the extended palette gives more stops to work with for the
 * "lifted" glow color. */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="cybersecurity"] { --hero-glow: var(--noetroniq-blue-300); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="digital-identity"] { --hero-glow: var(--noetroniq-teal-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="enterprise-architecture"] { --hero-glow: var(--noetroniq-blue-300); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="applied-ai"] { --hero-glow: var(--noetroniq-magenta-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="software-engineering"] { --hero-glow: var(--noetroniq-cyan-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="advisory-assessments"] { --hero-glow: var(--noetroniq-brown-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="methodology"] { --hero-glow: var(--noetroniq-green-300); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="deliverables"] { --hero-glow: var(--noetroniq-amber-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="zero-trust-architecture"] { --hero-glow: var(--noetroniq-blue-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="iam-patterns"] { --hero-glow: var(--noetroniq-teal-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="threat-modeling"] { --hero-glow: var(--noetroniq-burgundy-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="mlops"] { --hero-glow: var(--noetroniq-orange-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="platform-engineering"] { --hero-glow: var(--noetroniq-blue-300); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="api-ecosystems"] { --hero-glow: var(--noetroniq-cyan-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="capability-driven-planning"] { --hero-glow: var(--noetroniq-gold-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="decentralized-identity"] { --hero-glow: var(--noetroniq-teal-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="security-governance"] { --hero-glow: var(--noetroniq-indigo-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="application-security"] { --hero-glow: var(--noetroniq-indigo-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="intelligent-automation"] { --hero-glow: var(--noetroniq-orange-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="data-lineage-and-integration"] { --hero-glow: var(--noetroniq-gold-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="resilience"] { --hero-glow: var(--noetroniq-blue-300); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="high-compliance-delivery"] { --hero-glow: var(--noetroniq-slate-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="privacy-engineering"] { --hero-glow: var(--noetroniq-purple-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="privacy-policy"] { --hero-glow: var(--noetroniq-magenta-200); }
html.subpage-layout-v2 .subpage-hero[data-hero-variant="product"] { --hero-glow: var(--noetroniq-purple-200); }
html.subpage-layout-v2 .subpage-hero-content {
  position: relative;
  z-index: 2;
  width: 100%;
  /* v2: the hero centers its text plate (justify-content: center on
   * the hero's flex container). The plate is sized to the text content
   * (max-width: 720px) and uses margin: 0 auto so it sits centered
   * horizontally. The previous v1 max-width: 1180px was a safety
   * cap for when the main column was 912px; in v2 the main column
   * is 1180px so the cap was hit and the plate extended too far right. */
  max-width: 720px;
  margin: 0 auto;
  padding: 2.5rem 2rem 2.25rem;
  color: #f5f7fb;
  /* Translucent black underlay — guaranteed legibility on any photo.
   * Wraps the text content with a known black-at-65%-opacity panel so
   * the white H1 and tagline always sit on a known dark surface. The
   * rectangle is sized to the text (not a fixed bottom band), so it
   * moves with the content and the photo stays visible above and to
   * the right. A small left-bleed keeps the panel from feeling like a
   * floating card; it reads as a "text plate" over the photo.
   * 32px corners — modern, deliberately rounded, not pill-y. Reads as
   * a panel rather than a card or a button. */
  background: linear-gradient(90deg,
    rgba(0, 0, 0, .72) 0%,
    rgba(0, 0, 0, .68) 70%,
    rgba(0, 0, 0, .55) 100%);
  border-radius: 32px;
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero-content {
  color: var(--noetroniq-grey-900);
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--noetroniq-ivory-50) 80%, transparent) 0%,
    color-mix(in srgb, var(--noetroniq-ivory-50) 76%, transparent) 70%,
    color-mix(in srgb, var(--noetroniq-ivory-50) 68%, transparent) 100%);
  border-radius: 32px;
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero h1 { color: var(--noetroniq-grey-950); text-shadow: none; }
html.subpage-layout-v2[data-theme='light'] .subpage-hero .tagline { color: var(--noetroniq-grey-900); text-shadow: none; }
html.subpage-layout-v2[data-theme='light'] .subpage-hero .hero-eyebrow { text-shadow: none; }
html.subpage-layout-v2[data-theme='light'] .subpage-hero .hero-chips li {
  color: var(--noetroniq-grey-900);
  background: color-mix(in srgb, var(--noetroniq-grey-900) 6%, transparent);
  border-color: color-mix(in srgb, var(--noetroniq-grey-900) 22%, transparent);
}
html.subpage-layout-v2 .subpage-hero .hero-eyebrow {
  display: inline-block;
  font-size: .72rem;
  letter-spacing: var(--tracking-eyebrow-wide);
  text-transform: uppercase;
  color: var(--gold);
  margin: 0 0 .85rem;
  font-weight: 600;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .75), 0 0 8px rgba(0, 0, 0, .55);
}
html.subpage-layout-v2 .subpage-hero h1 {
  font-family: var(--font-heading);
  font-size: clamp(2.4rem, 5.5vw, 3.8rem);
  font-weight: 600;
  margin: 0 0 1rem;
  max-width: 22ch;
  line-height: 1.1;
  color: #fff;
  text-wrap: balance;
  /* Multi-stop dark halo: a wide soft glow for the general background
   * brightness, a medium glow for the medium-brightness regions, and a
   * tight 1px hard shadow for edge sharpness on the brightest photo
   * regions (high-key photos like the software-engineering keyboard
   * shot). Three layers because the photograph's brightness varies
   * across the headline width — one shadow can't cover all of it. */
  text-shadow:
    0 0 22px rgba(0, 0, 0, .8),
    0 2px 14px rgba(0, 0, 0, .85),
    0 1px 2px rgba(0, 0, 0, .95);
}
html.subpage-layout-v2 .subpage-hero .tagline {
  font-size: clamp(1.05rem, 1.4vw, 1.25rem);
  line-height: 1.55;
  color: #fff;
  margin: 0 0 1.5rem;
  max-width: 56ch;
  /* Tagline is body weight at a smaller size, so it loses to the photo
   * the most. The previous 95%-white with 5% transparency let the photo
   * bleed through; full opacity + a stronger 3-stop shadow gives the
   * edge contrast that body text needs on a high-key photo. */
  text-shadow:
    0 0 18px rgba(0, 0, 0, .85),
    0 1px 12px rgba(0, 0, 0, .85),
    0 1px 2px rgba(0, 0, 0, .95);
}
html.subpage-layout-v2 .subpage-hero .hero-chips {
  display: inline-flex;
  flex-wrap: wrap;
  gap: .5rem .75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
html.subpage-layout-v2 .subpage-hero .hero-chips li {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .3rem .7rem;
  background: color-mix(in srgb, #fff 8%, transparent);
  border: 1px solid color-mix(in srgb, #fff 22%, transparent);
  border-radius: 999px;
  font-size: .78rem;
  color: #fff;
  backdrop-filter: blur(6px);
}
html.subpage-layout-v2 .subpage-hero .hero-chips li strong {
  color: #fff;
  font-weight: 600;
}

/* Photographic placeholder (used when no heroPhoto is set). Renders a
 * topic-tinted gradient based on the section's data-hero-variant.
 * The gradient is set by the .subpage-hero-bg rule below; this element
 * is a no-op marker that the renderer emits to indicate "no real photo."
 *
 * The wordmark watermark and placeholder caption are intentionally not
 * emitted by the renderer for the new variant-based heroes — the
 * gradients are now intentional design (not "page not finished" filler). */
html.subpage-layout-v2 .subpage-hero-photo-placeholder { display: none; }

/* Hero variant gradients. Each topic group has its own gradient so the
 * hero signals what the page is about at a glance. Defined in CSS so a
 * tweak to one variant propagates to every page in that group without
 * re-rendering.
 *
 * The .subpage-hero-bg rule applies the variant gradient; the photo
 * rule above (with background-image inline) takes precedence when a
 * real heroPhoto is set, so the variant is the temporary default.
 *
 * 2026-07-12 (rev): switched from 22 too-similar dark-blue gradients
 * to 22 gradients that use the full noetroniq palette (blue + red +
 * gold + navy) with bold color presence. The previous version used
 * subtle color-mix() with 25-40% red/gold into a dominant blue, which
 * made most heroes look the same dark blue at a glance. This version
 * uses the red and gold tokens directly (no mix, or a 50% mix) so
 * the differences between pages are visible.
 *
 * Light and dark mode versions are tuned independently — the dark
 * version uses the dark-palette values, the light version uses the
 * light-palette values plus surface-mix where appropriate. */

/* ----- cybersecurity (cool, vigilant — deepest navy, top-down) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="cybersecurity"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-navy-700) 0%, var(--noetroniq-navy-1000) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="cybersecurity"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-navy-100) 0%, var(--noetroniq-navy-200) 100%);
}

/* ----- digital-identity (warm key — brass escutcheons, navy → gold diagonal) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="digital-identity"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-teal-700) 0%, var(--noetroniq-navy-925) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="digital-identity"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-teal-300) 0%, var(--noetroniq-navy-200) 100%);
}

/* ----- enterprise-architecture (architectural — sunlit blueprints, deep blue) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="enterprise-architecture"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-blue-900) 0%, var(--noetroniq-navy-1000) 100%);
}

/* The source photo has the two human figures in the lower
 * portion of the frame (silhouettes against a light sky).
 * The default `object-position: center` places them in the
 * middle-bottom of the hero, where their bodies get cut off
 * by the hero's bottom edge. Using `object-position: center
 * bottom` keeps the figures at the bottom of the hero but
 * shifts the crop so the figures sit higher up — their
 * bodies are visible above the hero's bottom edge. */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="enterprise-architecture"] .hero-photo {
  object-position: center bottom;
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="enterprise-architecture"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-blue-200) 0%, var(--noetroniq-navy-300) 100%);
}

/* ----- applied-ai (calibration — brass dials, warm-cool radial, magenta) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="applied-ai"] .subpage-hero-bg {
  background: radial-gradient(circle at 30% 40%, var(--noetroniq-navy-900) 0%, var(--noetroniq-magenta-800) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="applied-ai"] .subpage-hero-bg {
  background: radial-gradient(circle at 30% 40%, var(--noetroniq-magenta-100) 0%, var(--noetroniq-navy-200) 100%);
}

/* ----- software-engineering (precision — mechanical pencils, cyan to navy) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="software-engineering"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-cyan-800) 0%, var(--noetroniq-navy-900) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="software-engineering"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-cyan-100) 0%, var(--noetroniq-navy-200) 100%);
}

/* ----- advisory-assessments (premium — reading lamp, warm navy → gold) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="advisory-assessments"] .subpage-hero-bg {
  background: linear-gradient(45deg, var(--noetroniq-brown-600) 0%, var(--noetroniq-navy-900) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="advisory-assessments"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-brown-100) 0%, var(--noetroniq-navy-50) 100%);
}

/* ----- methodology (process — forest, steady iteration, green → deep green) -----
 * The hero gradient uses the noetroniq extended green family. Dark mode is
 * bold — a deep forest wash that suggests the steady, considered work of
 * an engagement moving through phases. Light mode is airy — pale sage,
 * the same green family lifted to the airy end of the spectrum. */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="methodology"] .subpage-hero-bg {
  background: linear-gradient(160deg, var(--noetroniq-green-700) 0%, var(--noetroniq-green-900) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="methodology"] .subpage-hero-bg {
  background: linear-gradient(160deg, var(--noetroniq-green-100) 0%, var(--noetroniq-green-200) 100%);
}

/* ----- deliverables (artefacts — parchment, finished work, deep brown → cream) -----
 * The hero gradient uses the noetroniq extended brown/ivory family. Dark mode
 * is bold — deep warm brown like the wood of a finished shelf, the kind you
 * see in the libraries where completed work is catalogued. Light mode is airy
 * — pale ivory/parchment, the page the work has been written on. The lighter
 * stops deliberately sit at the ivory end (not the tan end) to distinguish
 * deliverables from advisory-assessments, which uses the tan/warm-brown stops. */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="deliverables"] .subpage-hero-bg {
  background: linear-gradient(45deg, var(--noetroniq-brown-800) 0%, var(--noetroniq-brown-950) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="deliverables"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-ivory-100) 0%, var(--noetroniq-beige-200) 100%);
}

/* ----- zero-trust-architecture (deep trust — solid, cool, darkest navy) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="zero-trust-architecture"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-navy-975) 0%, var(--noetroniq-navy-900) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="zero-trust-architecture"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-navy-100) 0%, var(--noetroniq-navy-300) 100%);
}

/* ----- iam-patterns (illuminated — LED lit, teal to navy diagonal) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="iam-patterns"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-teal-600) 0%, var(--noetroniq-navy-900) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="iam-patterns"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-teal-50) 0%, var(--noetroniq-navy-100) 100%);
}

/* `object-position: center bottom` shifts the crop to the top
 * so the image's bottom edge aligns with the hero's bottom edge. */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="iam-patterns"] .hero-photo {
  object-position: center bottom;
}

/* ----- threat-modeling (strategic — chess, horizontal navy → burgundy) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="threat-modeling"] .subpage-hero-bg {
  background: linear-gradient(90deg, var(--noetroniq-burgundy-600) 0%, var(--noetroniq-navy-900) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="threat-modeling"] .subpage-hero-bg {
  background: linear-gradient(90deg, var(--noetroniq-burgundy-100) 0%, var(--noetroniq-navy-100) 100%);
}

/* ----- mlops (industrial action — satellite, orange → navy radial) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="mlops"] .subpage-hero-bg {
  background: radial-gradient(circle at 70% 30%, var(--noetroniq-orange-925) 0%, var(--noetroniq-navy-950) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="mlops"] .subpage-hero-bg {
  background: radial-gradient(circle at 70% 30%, var(--noetroniq-orange-100) 0%, var(--noetroniq-navy-200) 100%);
}

/* ----- platform-engineering (stack — rail yard, vertical blue to navy) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="platform-engineering"] .subpage-hero-bg {
  background: linear-gradient(195deg, var(--noetroniq-blue-900) 0%, var(--noetroniq-navy-1000) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="platform-engineering"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-blue-300) 0%, var(--noetroniq-navy-300) 100%);
}

/* ----- api-ecosystems (dense — rack equipment, cyan flow) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="api-ecosystems"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-cyan-900) 0%, var(--noetroniq-cyan-800) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="api-ecosystems"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-cyan-200) 0%, var(--noetroniq-cyan-100) 100%);
}

/* ----- capability-driven-planning (warm-organized — wood table, navy → gold) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="capability-driven-planning"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-gold-900) 0%, var(--noetroniq-navy-950) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="capability-driven-planning"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-gold-300) 0%, var(--noetroniq-navy-200) 100%);
}

/* ----- decentralized-identity (verifiable — passport stamp, teal → blue rising) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="decentralized-identity"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-teal-800) 0%, var(--noetroniq-blue-700) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="decentralized-identity"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-teal-100) 0%, var(--noetroniq-blue-50) 100%);
}

/* ----- security-governance (rigorous — leather ledgers, warm navy → gold vertical) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="security-governance"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-indigo-800) 0%, var(--noetroniq-navy-900) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="security-governance"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-indigo-100) 0%, var(--noetroniq-navy-100) 100%);
}

/* ----- application-security (vault — metal, indigo gradient) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="application-security"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-indigo-900) 0%, var(--noetroniq-indigo-800) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="application-security"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-indigo-100) 0%, var(--noetroniq-indigo-50) 100%);
}

/* ----- intelligent-automation (assembly line — action, horizontal orange → burgundy) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="intelligent-automation"] .subpage-hero-bg {
  background: linear-gradient(90deg, var(--noetroniq-orange-925) 0%, var(--noetroniq-burgundy-800) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="intelligent-automation"] .subpage-hero-bg {
  background: linear-gradient(90deg, var(--noetroniq-orange-200) 0%, var(--noetroniq-burgundy-100) 100%);
}

/* The silhouette sits in the lower portion of the source frame.
 * `object-position: center bottom` shifts the crop to the top so
 * the image's bottom edge aligns with the hero's bottom edge,
 * keeping the silhouette in the lower half of the hero. */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="intelligent-automation"] .hero-photo {
  object-position: center bottom;
}

/* ----- data-lineage-and-integration (multi-color — tiled printouts, 3-stop) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="data-lineage-and-integration"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-blue-900) 0%, var(--noetroniq-gold-900) 50%, var(--noetroniq-burgundy-900) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="data-lineage-and-integration"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-blue-100) 0%, var(--noetroniq-gold-200) 50%, var(--noetroniq-burgundy-200) 100%);
}

/* The default `object-position: center` vertically centers
 * the image, cropping equal amounts from the top and
 * bottom. For data-lineage, the user wants the image's
 * bottom edge aligned with the hero's bottom edge —
 * `object-position: center bottom` shifts the crop to the
 * top, keeping the bottom anchored. */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="data-lineage-and-integration"] .hero-photo {
  object-position: center bottom;
}

/* ----- resilience (stone — load-bearing, deepest navy, bottom-up lift) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="resilience"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-navy-900) 0%, var(--noetroniq-navy-700) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="resilience"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-navy-50) 0%, var(--noetroniq-navy-200) 100%);
}

/* `object-position: center bottom` shifts the crop to the top
 * so the image's bottom edge aligns with the hero's bottom edge. */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="resilience"] .hero-photo {
  object-position: center bottom;
}

/* ----- high-compliance-delivery (formal — audit folder, warm navy → brown) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="high-compliance-delivery"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-slate-800) 0%, var(--noetroniq-navy-900) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="high-compliance-delivery"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-slate-200) 0%, var(--noetroniq-navy-200) 100%);
}

/* ----- privacy-engineering (private — library door, brass, vertical navy → gold) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="privacy-engineering"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-purple-800) 0%, var(--noetroniq-navy-900) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="privacy-engineering"] .subpage-hero-bg {
  background: linear-gradient(180deg, var(--noetroniq-purple-200) 0%, var(--noetroniq-navy-200) 100%);
}

/* `object-position: center top` shifts the crop to the bottom
 * so the image's top edge aligns with the hero's top edge. */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="privacy-engineering"] .hero-photo {
  object-position: center top;
}

/* ----- privacy-policy (cool-neutral — formal, navy → blue diagonal) ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="privacy-policy"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-magenta-800) 0%, var(--noetroniq-navy-900) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="privacy-policy"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-magenta-200) 0%, var(--noetroniq-navy-100) 100%);
}

/* ----- product (purple — structured / formal / precise, reads as 'standards author') ----- */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="product"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-indigo-900) 0%, var(--noetroniq-navy-975) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="product"] .subpage-hero-bg {
  background: linear-gradient(135deg, var(--noetroniq-indigo-100) 0%, var(--noetroniq-purple-100) 100%);
}
html.subpage-layout-v2 .subpage-hero-photo-placeholder .placeholder-caption {
  position: absolute;
  bottom: 1.5rem;
  left: 1.5rem;
  font-size: .72rem;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: color-mix(in srgb, #fff 65%, transparent);
}

/* =================================================================
 * Section anchor offset (so deep links land below the sticky header).
 * ================================================================ */
.subpage-section[id],
html.subpage-layout-v2 section[id] {
  scroll-margin-top: 5rem;
}

/* =================================================================
 * Section horizontal padding (v2 only).
 *
 * In v1 the .subpage-shell carried padding: 0 1.5rem 4rem and every
 * section inherited the 1.5rem horizontal gutter as a side effect. In
 * v2 the padding is on the section itself, so the layout is robust to
 * changes in the shell structure (e.g. if the shell is removed, each
 * section still has its gutter from the viewport edge).
 *
 * The hero is excluded: it is full-bleed (100vw via the centering
 * trick in .subpage-hero) and carries its own internal padding via
 * .subpage-hero-content. Adding 1.5rem here would make the hero
 * overflow the viewport by 3rem.
 *
 * The CTA section is also excluded: it has its own internal padding
 * (4rem 2rem 3.5rem) which already provides a wider gutter than the
 * default 1.5rem. Overriding it here would shrink the CTA's gutter.
 * ================================================================ */
html.subpage-layout-v2 .section:not(.subpage-hero):not(.cta-prominent) {
  padding-left: 1.5rem;
  padding-right: 1.5rem;
}

/* =================================================================
 * Section title + intro — refined typography.
 * ================================================================ */
html.subpage-layout-v2 .section h2 {
  font-family: var(--font-heading);
  font-size: clamp(1.5rem, 2.4vw, 1.95rem);
  font-weight: 600;
  margin: 0 0 .35rem;
  color: var(--heading);
  letter-spacing: var(--heading-spacing-h2);
}
html.subpage-layout-v2 .section h2 + .section-intro {
  margin-top: .35rem;
  margin-bottom: 1.5rem;
}
html.subpage-layout-v2 .section .section-intro {
  font-size: 1.02rem;
  line-height: 1.6;
  color: var(--text-soft);
  max-width: 60ch;
}
html.subpage-layout-v2 .section .content {
  /* v2: centered, shrink-to-fit container. The .content block lives
   * inside a 1180px-max-width .section; without centering, it sits
   * flush-left in the section and looks stranded. `width: fit-content`
   * makes the container as wide as its content needs (the stats grid
   * settles to ~1100px, the narrow prose settles to ~64ch), and
   * `max-width: min(1180px, 100%)` caps it at the shell's max-width
   * (and shrinks to the viewport when narrower). `margin: 0 auto`
   * centers the block in the section. Internal text is left-aligned
   * (no `text-align: center`), so the look is "centered, left-justified,
   * adaptive" — narrow when content is narrow, full-bleed when content
   * is wide. */
  width: fit-content;
  max-width: min(1180px, 100%);
  margin: 0 auto;
}
/* Wide-split body containers: the .content block that follows a
 * .content.narrow header in a section using the wide-split pattern
 * (stats / cards / compare / evidence). These have a GRID as their
 * body, and the grid's intrinsic width (from auto-fit / 1fr columns)
 * is content-driven, not viewport-driven. The base .section .content
 * rule above uses `width: fit-content` which shrinks the container
 * to the grid's intrinsic width — meaning the grid only fills the
 * space it needs, not the space the section has. For wide-split
 * sections, we want the body to use the full shell width and let
 * the inner grid distribute that width across its columns. This
 * rule is a sibling selector: it matches a .content block that is
 * a direct child of a section that ALSO has a .content.narrow
 * child, and is itself NOT .narrow. The mistakes (anti-patterns)
 * section is also a wide-split section, but its grid is a
 * 1-column list of prose items, so it's handled below with a
 * specific override. */
html.subpage-layout-v2 .section:has(> .content.narrow) > .content:not(.narrow) {
  width: 100%;
  max-width: 100%;  /* override the base rule's 1180px cap so the body uses
                     * the full section width, which grows with the shell
                     * to 1600px on wide viewports */
}
/* The mistakes (anti-patterns) section is a wide-split section
 * (it has a .content.narrow header) but its body is a 1-column
 * list of prose-style .anti-pattern items. The general
 * wide-split body rule above would make it 1180px wide, which
 * is too wide for a single column of prose. Cap it at 900px
 * to keep the prose lines at a reasonable reading length.
 * Selector specificity is matched to (and slightly higher than)
 * the general rule above so the override wins. */
html.subpage-layout-v2 .anti-patterns-section:has(> .content.narrow) > .content:not(.narrow) {
  max-width: 900px;
}
/* The compare section is a wide-split section but its body is
 * a 2-column side-by-side comparison where the user wants the
 * columns to be readable as prose, not stretched full-bleed.
 * Cap at 1180px (the v1 design intent) so the columns are a
 * comfortable reading width. The cards and evidence sections
 * keep the full-width behavior (their grids can flex). */
html.subpage-layout-v2 .compare-section:has(> .content.narrow) > .content:not(.narrow) {
  max-width: 1180px;
}
/* The stats section is a wide-split section. The user wants the
 * stats cards to be a comfortable size (not stretched full-bleed
 * across the 1600px shell), but the section should still grow
 * horizontally as more stats are added (i.e., should not be
 * pinned to a narrow column). Use width: fit-content so the
 * section sizes to its content's intrinsic width, capped at
 * 1180px (the v1 design intent). At 4 stats the section settles
 * to ~1100-1200px, giving each card ~270px — a comfortable
 * stat-card width. If more stats are added, the section grows
 * naturally up to the 1180px cap. */
html.subpage-layout-v2 .stats-section:has(> .content.narrow) > .content:not(.narrow) {
  width: fit-content;
  max-width: min(1180px, 100%);
}
/* The evidence section has the same issue as stats: stretched
 * full-bleed, the citation cards look 'lost in space' because
 * they're each ~870px wide on a 1600px viewport. The user wants
 * the same fit-content + 1180px cap as stats, so the cards are
 * a comfortable size and the section still grows with content. */
html.subpage-layout-v2 .evidence-section:has(> .content.narrow) > .content:not(.narrow) {
  width: fit-content;
  max-width: min(1180px, 100%);
}
html.subpage-layout-v2 .section .content.narrow {
  /* Narrow prose columns (pullquotes, intro paragraphs, FAQ bodies).
   * `width: fit-content` lets the column shrink to the longest line of
   * text rather than being stretched to 64ch. The `max-width: 64ch`
   * cap is preserved for prose sections where 64ch is the design
   * "good reading line length" (v1 design intent). For wide-grid
   * sections using the plain .content class, the 1180px cap applies. */
  width: fit-content;
  max-width: 64ch;
  margin: 0 auto;
}
html.subpage-layout-v2 .section .content.narrow p {
  line-height: 1.7;
  margin: 0 0 1rem;
}

/* =================================================================
 * Pull-quote — the orienting sentence at the top of the context prose.
 * ================================================================ */
html.subpage-layout-v2 .subpage-pullquote {
  margin: 0 auto 2rem;
  max-width: 56ch;
  padding: 1.5rem 2rem 1.25rem;
  background:
    linear-gradient(135deg,
      color-mix(in srgb, var(--surfaceInset) 95%, transparent),
      color-mix(in srgb, var(--surface) 80%, transparent));
  border-left: 3px solid var(--gold);
  border-radius: 0 var(--radius) var(--radius) 0;
  position: relative;
  font-size: 1.14rem;
  line-height: 1.55;
  color: var(--text);
  font-style: italic;
  box-shadow: 0 1px 0 color-mix(in srgb, var(--gold) 12%, transparent);
}
html.subpage-layout-v2 .subpage-pullquote::before {
  content: "\201C";
  position: absolute;
  left: .35rem;
  top: -.15rem;
  font-family: var(--font-heading);
  font-size: 2.8rem;
  color: var(--gold);
  line-height: 1;
  font-style: normal;
  opacity: .55;
  pointer-events: none;
}
html.subpage-layout-v2 .subpage-pullquote p {
  margin: 0;
  position: relative;
}
html.subpage-layout-v2 .subpage-pullquote p::after {
  /* closing quote — sized smaller and gold-on-tinted, balances the open */
  content: "\201D";
  display: inline-block;
  margin-left: .15rem;
  font-family: var(--font-heading);
  font-style: normal;
  font-size: 1.4rem;
  color: var(--gold);
  line-height: 0;
  vertical-align: -0.15em;
  opacity: .75;
}

/* =================================================================
 * Phase tracker — vertical rail with numbered steps on desktop.
 * ================================================================ */
html.subpage-layout-v2 .methodology-section {
  position: relative;
  padding: 3rem 1.5rem;
  margin: 2.5rem 0;
  /* "blueprint" backdrop — subtle navy→surface tint that reads as a
   * distinct work surface, not just another text section */
  background:
    linear-gradient(135deg,
      color-mix(in srgb, var(--navy) 8%, var(--surfaceInset)) 0%,
      var(--surfaceInset) 60%,
      color-mix(in srgb, var(--burgundy) 4%, var(--surfaceInset)) 100%);
  border-top: 1px solid color-mix(in srgb, var(--borderSubtle) 70%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--borderSubtle) 70%, transparent);
  border-radius: var(--radius-lg);
}
html.subpage-layout-v2 .methodology-section .section-intro {
  max-width: 64ch;
  margin: 0 auto 1rem;
  padding: 0 .5rem;
}
html.subpage-layout-v2 .phase-tracker {
  display: none;
}
@media (min-width: 900px) {
html.subpage-layout-v2 .phase-tracker {
    display: grid;
    grid-template-columns: 4rem minmax(0, 1fr);
    gap: 0 1.5rem;
    margin-top: 1.5rem;
  }
html.subpage-layout-v2 .phase-tracker-rail {
    position: relative;
    grid-column: 1;
    grid-row: 1 / -1;
    border-right: 1px solid var(--borderSubtle);
  }
html.subpage-layout-v2 .phase-tracker-rail::before {
    /* Active progress fill — height set by JS based on the current step. */
    content: "";
    position: absolute;
    top: 0; right: -1px;
    width: 2px;
    height: var(--phase-progress, 0%);
    background: var(--gold);
    transition: height 360ms cubic-bezier(.22, .61, .36, 1);
  }
html.subpage-layout-v2 .phase-track-list {
    grid-column: 2;
    grid-row: 1;
    display: grid;
    gap: 2rem;
  }
html.subpage-layout-v2 .phase-step {
    position: relative;
    padding-left: 0;
  }
html.subpage-layout-v2 .phase-step-marker {
    position: absolute;
    left: -3rem;
    top: -.05rem;
    width: 2rem;
    height: 2rem;
    display: grid;
    place-items: center;
    background: var(--surface);
    border: 1px solid var(--borderSubtle);
    border-radius: 50%;
    color: var(--text-soft);
    font-size: .8rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    transition: background 220ms ease, color 220ms ease, border-color 220ms ease, transform 220ms ease;
  }
html.subpage-layout-v2 .phase-step[data-current="true"] .phase-step-marker {
    background: var(--gold);
    border-color: var(--gold);
    color: var(--text-on-gold, #1a1a1a);
    transform: scale(1.08);
  }
html.subpage-layout-v2 .phase-step h3 {
    margin: 0 0 .5rem;
    color: var(--heading);
    font-size: 1.18rem;
    font-weight: 600;
  }
html.subpage-layout-v2 .phase-step[data-current="true"] h3 {
    color: var(--heading-accent);
  }
html.subpage-layout-v2 .phase-step p { margin: 0; line-height: 1.65; color: var(--text-soft); }
html.subpage-layout-v2 .phase-step[data-current="true"] p { color: var(--text); }
}

/* =================================================================
 * Q&A — questions section. Each item is a card with the question as
 * the title and the answer body below. Slugified anchors for FAQPage.
 * ================================================================ */
html.subpage-layout-v2 .qa-list { display: grid; gap: 1.25rem; margin-top: 1.5rem; }
html.subpage-layout-v2 .qa-item {
  background: var(--surfaceInset);
  border: 1px solid var(--borderSubtle);
  border-radius: var(--radius);
  padding: 0;
  transition: border-color 180ms ease, transform 180ms ease;
  /* Deep links (#<slug>) need to clear the sticky header. The
   * 5rem offset matches the section[id] rule. */
  scroll-margin-top: 5rem;
}
html.subpage-layout-v2 .qa-item:hover { border-color: var(--border); }
html.subpage-layout-v2 .qa-item.is-expanded { border-color: var(--border); }
html.subpage-layout-v2 .qa-question {
  display: flex;
  align-items: center;
  gap: .85rem;
  width: 100%;
  background: transparent;
  border: 0;
  padding: 1.25rem 1.5rem;
  margin: 0;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  border-radius: var(--radius);
}
html.subpage-layout-v2 .qa-question:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: -2px;
}
html.subpage-layout-v2 .qa-item h3 {
  margin: 0;
  font-size: 1.08rem;
  font-weight: 600;
  color: var(--heading-accent);
  line-height: 1.35;
  flex: 1 1 auto;
}
html.subpage-layout-v2 .qa-item h3 a {
  color: inherit;
  text-decoration: none;
}
html.subpage-layout-v2 .qa-item h3 a::before {
  content: "Q.";
  display: inline-block;
  margin-right: .55rem;
  color: var(--gold);
  font-weight: 600;
  font-size: 1.15rem;
  font-family: var(--font-body);
  letter-spacing: -.04em;
}
html.subpage-layout-v2 .qa-chevron {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-soft);
  font-size: 1.1rem;
  font-weight: 600;
  line-height: 1;
  border: 1px solid var(--borderSubtle);
  border-radius: 999px;
  transition: transform 180ms ease, color 180ms ease, border-color 180ms ease;
}
html.subpage-layout-v2 .qa-item.is-expanded .qa-chevron {
  transform: rotate(45deg);
  color: var(--text);
  border-color: var(--border);
}
/* The body wrap is the collapsible region. When the parent
 * .qa-item has is-collapsed (or no is-expanded class), the body
 * is hidden via max-height + opacity. */
html.subpage-layout-v2 .qa-answer-wrap {
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 220ms ease, opacity 220ms ease, padding 220ms ease;
  padding: 0 1.5rem;
}
html.subpage-layout-v2 .qa-item.is-expanded .qa-answer-wrap {
  max-height: 4000px;
  opacity: 1;
  padding: 0 1.5rem 1.25rem;
}
@media (prefers-reduced-motion: reduce) {
  html.subpage-layout-v2 .qa-answer-wrap { transition: none; }
  html.subpage-layout-v2 .qa-chevron { transition: none; }
}
html.subpage-layout-v2 .qa-answer { color: var(--text); }
html.subpage-layout-v2 .qa-answer p { margin: 0 0 .65rem; line-height: 1.65; }
html.subpage-layout-v2 .qa-answer p:last-child { margin-bottom: 0; }
html.subpage-layout-v2 .qa-answer ul, html.subpage-layout-v2 .qa-answer ol { margin: 0 0 .65rem 1.25rem; }
html.subpage-layout-v2 .qa-answer code { background: var(--surface); padding: .05rem .35rem; border-radius: var(--radius-sm); font-size: .9em; }
html.subpage-layout-v2 .qa-answer strong { color: var(--text); font-weight: 600; }

/* =================================================================
 * Anti-patterns — numbered cards with gold left border.
 * ================================================================ */
html.subpage-layout-v2 .anti-patterns-grid {
  display: grid;
  gap: .85rem;
  margin-top: 1.5rem;
}
html.subpage-layout-v2 .anti-pattern {
  /* The anti-pattern is now a collapsible card. The header
   * (number + name) is the button; the body (the 'why'
   * explanation) is the collapsible region. */
  position: relative;
  overflow: hidden;
  padding: 0;
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--gold) 8%, var(--surfaceInset)) 0%,
      var(--surfaceInset) 30%,
      var(--surfaceInset) 100%);
  border: 1px solid var(--borderSubtle);
  border-left: 3px solid transparent;
  border-image: linear-gradient(180deg,
    var(--gold) 0%,
    color-mix(in srgb, var(--gold) 65%, transparent) 60%,
    color-mix(in srgb, var(--gold) 30%, transparent) 100%) 1;
  border-radius: 0 var(--radius) var(--radius) 0;
  transition: transform 180ms ease, border-color 180ms ease;
  scroll-margin-top: 5rem;
  /* Spotlight (cursor-following highlight) variables. The ::after
   * is a masked radial gradient: the bright color is clipped to
   * the hatch pattern (defined in the existing ::before rule
   * below) so the spotlight only brightens the hatch lines
   * themselves, not the empty space between them. */
  /* "Reflective" hatch: the hatch lines are treated as a polished
   * material that catches the cursor's light dramatically. See
   * .qa-item for the rationale on the high alpha value. */
  --ap-mx: 50%;
  --ap-my: 50%;
  --ap-bright: rgba(245, 247, 251, 0.95);
  --ap-bright-mid: rgba(245, 247, 251, 0.45);
  --ap-bright-faint: rgba(245, 247, 251, 0.18);
}
html.subpage-layout-v2[data-theme='light'] .anti-pattern {
  --ap-bright: rgba(13, 47, 87, 0.95);
  --ap-bright-mid: rgba(13, 47, 87, 0.55);
  --ap-bright-faint: rgba(13, 47, 87, 0.25);
}
html.subpage-layout-v2 .anti-pattern::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  transition: .35s opacity;
  mix-blend-mode: screen;
  background: radial-gradient(
    circle at var(--ap-mx) var(--ap-my),
    var(--ap-bright) 0%,
    var(--ap-bright-mid) 22%,
    var(--ap-bright-faint) 40%,
    rgba(0, 0, 0, 0) 56%
  );
  /* Mask: clip the radial gradient to the hatch pattern. The
   * existing ::before rule (further down in the file) sets the
   * dim hatch background-image on this same element; we use a
   * full-alpha MASK version of the same hatch SVG here so the
   * bright color can fully paint the hatch lines (not be capped
   * at 0.20 alpha by the dim hatch SVG). */
  -webkit-mask-image: url("../svg/patterns/antipattern-hatch-mask.svg");
  mask-image: url("../svg/patterns/antipattern-hatch-mask.svg");
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: 160px 90px;
  mask-size: 160px 90px;
}
html.subpage-layout-v2[data-theme='light'] .anti-pattern::after {
  -webkit-mask-image: url("../svg/patterns/antipattern-hatch-light-mask.svg");
  mask-image: url("../svg/patterns/antipattern-hatch-light-mask.svg");
  mix-blend-mode: multiply;
}
html.subpage-layout-v2 .anti-pattern:hover::after,
html.subpage-layout-v2 .anti-pattern:focus-within::after,
html.subpage-layout-v2 .anti-pattern.prox-glow::after { opacity: 1; }
html.subpage-layout-v2 .anti-pattern > * { position: relative; z-index: 1; }
html.subpage-layout-v2 .anti-pattern:hover { border-color: var(--border); }
html.subpage-layout-v2 .anti-pattern.is-expanded { border-color: var(--border); }
html.subpage-layout-v2 .anti-pattern-header {
  display: grid;
  grid-template-columns: 2.5rem 1fr auto;
  align-items: center;
  gap: .25rem 1rem;
  width: 100%;
  background: transparent;
  border: 0;
  padding: 1.1rem 1.25rem 1.1rem .5rem;
  margin: 0;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
html.subpage-layout-v2 .anti-pattern-header:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: -2px;
}
html.subpage-layout-v2 .anti-pattern-number {
  font-family: var(--font-heading);
  font-size: 1.4rem;
  font-weight: 600;
  /* Use --gold-fg, not --gold: foreground text on a light background.
   * The bright --gold fails AA at this size. */
  color: var(--gold-fg);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  padding-top: .15rem;
}
html.subpage-layout-v2 .anti-pattern-name {
  font-weight: 600;
  color: var(--heading);
  font-size: 1rem;
  line-height: 1.4;
  margin: 0;
}
html.subpage-layout-v2 .anti-pattern-chevron {
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-soft);
  font-size: 1.1rem;
  font-weight: 600;
  line-height: 1;
  border: 1px solid var(--borderSubtle);
  border-radius: 999px;
  transition: transform 180ms ease, color 180ms ease, border-color 180ms ease;
}
html.subpage-layout-v2 .anti-pattern.is-expanded .anti-pattern-chevron {
  transform: rotate(45deg);
  color: var(--text);
  border-color: var(--border);
}
html.subpage-layout-v2 .anti-pattern-body-wrap {
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 220ms ease, opacity 220ms ease, padding 220ms ease;
  padding: 0 1.25rem 0 3.5rem;
}
html.subpage-layout-v2 .anti-pattern.is-expanded .anti-pattern-body-wrap {
  max-height: 4000px;
  opacity: 1;
  padding: 0 1.25rem 1.1rem 3.5rem;
}
@media (prefers-reduced-motion: reduce) {
  html.subpage-layout-v2 .anti-pattern-body-wrap { transition: none; }
  html.subpage-layout-v2 .anti-pattern-chevron { transition: none; }
}
html.subpage-layout-v2 .anti-pattern-why {
  color: var(--text-soft);
  font-size: .94rem;
  line-height: 1.55;
  margin: 0;
}

/* =================================================================
 * Evidence — citation cards.
 * ================================================================ */
html.subpage-layout-v2 .evidence-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: 1.5rem;
}
html.subpage-layout-v2 .evidence-card {
  flex: 1 1 100%;  /* 1-col default (mobile); overridden to 2-col below */
  max-width: 100%;
  min-width: 0;
  position: relative;
  overflow: hidden;
  padding: 1.1rem 1.25rem;
  background: var(--surface);
  border: 1px solid var(--borderSubtle);
  border-radius: var(--radius);
  display: grid;
  gap: .35rem;
  transition: transform 180ms ease, border-color 180ms ease;
  /* Spotlight (cursor-following highlight) variables. The ::before
   * is a radial gradient that brightens the area under the cursor
   * on hover. Mirrors the .card spotlight from styles.css but with
   * tuned colors that work on the lighter --surface background. */
  --ev-mx: 50%;
  --ev-my: 50%;
  --ev-highlight-color: rgba(255, 255, 255, 0.10);
}
html.subpage-layout-v2[data-theme='light'] .evidence-card {
  --ev-highlight-color: rgba(13, 47, 87, 0.14);
}
/* Mobile-first: 1-col default above; promote to 2-col at 721px+.
 * The override MUST come AFTER the base rule (equal specificity;
 * later rule wins in CSS cascade). The prior `@media (max-width: 720px)`
 * pattern was a desktop-first override on top of a 2-col default. */
@media (min-width: 721px) {
  html.subpage-layout-v2 .evidence-card { flex: 1 1 calc((100% - 1rem) / 2); }
}
html.subpage-layout-v2 .evidence-card::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  transition: .4s opacity, .6s background;
  background: radial-gradient(circle at var(--ev-mx) var(--ev-my),
    var(--ev-highlight-color) 0%,
    rgba(255, 255, 255, 0.04) 30%,
    rgba(255, 255, 255, 0) 60%);
}
html.subpage-layout-v2[data-theme='light'] .evidence-card::before {
  background: radial-gradient(circle at var(--ev-mx) var(--ev-my),
    var(--ev-highlight-color) 0%,
    rgba(13, 47, 87, 0.05) 40%,
    rgba(13, 47, 87, 0) 70%);
}
html.subpage-layout-v2 .evidence-card:hover::before,
html.subpage-layout-v2 .evidence-card:focus-within::before,
html.subpage-layout-v2 .evidence-card.prox-glow::before { opacity: 1; }
html.subpage-layout-v2 .evidence-card > *:not(.card-arrow) { position: relative; z-index: 1; }

/* Clickable evidence card — the entire card becomes a single link target
 * via an absolutely-positioned overlay. Mirrors the homepage .card-link
 * pattern. The visible <a> in the title remains for inline reading and
 * becomes the accessible label (aria-label is set in renderEvidence). */
html.subpage-layout-v2 .evidence-card.is-clickable {
  cursor: pointer;
}
html.subpage-layout-v2 .evidence-card.is-clickable:hover,
html.subpage-layout-v2 .evidence-card.is-clickable:focus-within {
  border-color: var(--border);
}
html.subpage-layout-v2 .evidence-card.is-clickable .evidence-card-link {
  position: absolute;
  inset: 0;
  z-index: 2;
  text-indent: -9999px;
  overflow: hidden;
  color: transparent;
  text-decoration: none;
  cursor: pointer;
  border-radius: inherit;
}
html.subpage-layout-v2 .evidence-card.is-clickable .evidence-card-link:focus-visible {
  outline: var(--focus-ring);
  outline-offset: -2px;
  border-radius: var(--radius-lg);
}
/* The title <a> inside a clickable card is decorative (the overlay is the
 * click target). Hide the underline on hover so it doesn't double-look
 * like a link. */
html.subpage-layout-v2 .evidence-card.is-clickable .evidence-card-title a:hover {
  text-decoration: none;
}
/* On wider viewports, allow 5 evidence cards to fit in a single
 * row (mirroring the .cards pattern from styles.css). At
 * 1180px body width, 5 cards = (1180 - 4*16) / 5 = 223px each,
 * which is narrow but usable for citation cards. The 1500px
 * viewport breakpoint matches the cards section's. */
@media (min-width: 1500px) {
html.subpage-layout-v2 .evidence-card { flex: 1 1 calc((100% - 4rem) / 5); }  /* 5-col */
}
html.subpage-layout-v2 .evidence-card:hover {
  transform: translateY(-2px);
  border-color: var(--border);
}
html.subpage-layout-v2 .evidence-card-title {
  font-weight: 600;
  color: var(--heading);
  font-size: 1rem;
  line-height: 1.35;
}
html.subpage-layout-v2 .evidence-card-title a {
  color: var(--heading-accent);
  text-decoration: none;
}
html.subpage-layout-v2 .evidence-card-title a:hover { text-decoration: underline; }
html.subpage-layout-v2 .evidence-card-source {
  color: var(--text-soft);
  font-size: .82rem;
  font-style: italic;
}
html.subpage-layout-v2 .evidence-card-note {
  color: var(--text-soft);
  font-size: .9rem;
  line-height: 1.5;
  margin: 0;
}

/* =================================================================
 * Read-next — categorized cross-links, with colored kind badges.
 * ================================================================ */
html.subpage-layout-v2 .readnext-list {
  list-style: none;
  padding: 0;
  margin: 1.5rem 0 0;
  display: grid;
  gap: .65rem;
}
html.subpage-layout-v2 .readnext-item {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .65rem 1rem;
  align-items: baseline;
  padding: .85rem 0;
  border-bottom: 1px solid var(--borderSubtle);
  /* Position context for the .readnext-link overlay (when is-clickable)
   * and the .card-arrow indicator. Mirrors the .card / .evidence-card
   * pattern: the <li> is the click target via an absolutely-positioned
   * overlay, the arrow sits at the bottom-right corner of the row. */
  position: relative;
}
html.subpage-layout-v2 .readnext-item:last-child { border-bottom: 0; }
/* Clickable readnext row — the whole <li> becomes a single link target
 * via an absolutely-positioned .readnext-link overlay. Mirrors the
 * .card-link and .evidence-card-link patterns. The visible <a> in the
 * <div> stays for inline reading and gets an accessible label. The
 * .card-arrow (defined globally in styles.css) provides the bottom-right
 * affordance; the hover/focus-within ramp to opacity 1 + 2px nudge
 * happens there too. */
html.subpage-layout-v2 .readnext-item.is-clickable { cursor: pointer; }
html.subpage-layout-v2 .readnext-item .readnext-link {
  position: absolute;
  inset: 0;
  z-index: 2;
  text-indent: -9999px;
  overflow: hidden;
  color: transparent;
  text-decoration: none;
}
html.subpage-layout-v2 .readnext-item .readnext-link:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 0;
}
html.subpage-layout-v2 .readnext-kind {
  display: inline-block;
  font-size: .68rem;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-weight: 600;
  padding: .2rem .55rem;
  border-radius: 999px;
  white-space: nowrap;
}
html.subpage-layout-v2 .readnext-kind[data-kind="Service"]    { background: color-mix(in srgb, var(--burgundy) 14%, var(--surface)); color: var(--burgundy); border: 1px solid color-mix(in srgb, var(--burgundy) 28%, transparent); }
html.subpage-layout-v2 .readnext-kind[data-kind="Product"]    { background: color-mix(in srgb, var(--red)     14%, var(--surface)); color: var(--red);     border: 1px solid color-mix(in srgb, var(--red)     28%, transparent); }
html.subpage-layout-v2 .readnext-kind[data-kind="Expertise"]  { background: color-mix(in srgb, var(--blue)    14%, var(--surface)); color: var(--blue);    border: 1px solid color-mix(in srgb, var(--blue)    28%, transparent); }
html.subpage-layout-v2 .readnext-kind[data-kind="Main page"]  { background: color-mix(in srgb, var(--navy)    14%, var(--surface)); color: var(--navy);    border: 1px solid color-mix(in srgb, var(--navy)    28%, transparent); }
html.subpage-layout-v2 .readnext-kind[data-kind="Contact"]    { background: color-mix(in srgb, var(--gold)    14%, var(--surface)); color: var(--gold-fg); border: 1px solid color-mix(in srgb, var(--gold)    35%, transparent); }
html.subpage-layout-v2 .readnext-kind[data-kind="Reference"]  { background: color-mix(in srgb, var(--blue-d2) 14%, var(--surface)); color: var(--blue-d2); border: 1px solid color-mix(in srgb, var(--blue-d2) 28%, transparent); }
html.subpage-layout-v2 .readnext-kind[data-kind="Email"]      { background: color-mix(in srgb, var(--gold)    14%, var(--surface)); color: var(--gold-fg); border: 1px solid color-mix(in srgb, var(--gold)    35%, transparent); }
html.subpage-layout-v2 .readnext-kind[data-kind="Home"]       { background: color-mix(in srgb, var(--navy)    14%, var(--surface)); color: var(--navy);    border: 1px solid color-mix(in srgb, var(--navy)    28%, transparent); }
/* In dark mode, --burgundy, --navy, --blue are all dark colors, so
 * the readnext-kind text (which uses them) is dark-on-dark. Lighten
 * the text by mixing with white. */
html.subpage-layout-v2:not([data-theme='light']) .readnext-kind[data-kind="Service"]    { color: color-mix(in srgb, var(--burgundy) 55%, #fff); }
html.subpage-layout-v2:not([data-theme='light']) .readnext-kind[data-kind="Product"]    { color: color-mix(in srgb, var(--red)      55%, #fff); }
html.subpage-layout-v2:not([data-theme='light']) .readnext-kind[data-kind="Expertise"]  { color: color-mix(in srgb, var(--blue)     55%, #fff); }
html.subpage-layout-v2:not([data-theme='light']) .readnext-kind[data-kind="Main page"]  { color: color-mix(in srgb, var(--navy)     55%, #fff); }
html.subpage-layout-v2:not([data-theme='light']) .readnext-kind[data-kind="Reference"]  { color: color-mix(in srgb, var(--blue-d2)  55%, #fff); }
html.subpage-layout-v2 .readnext-item a {
  color: var(--heading-accent);
  text-decoration: none;
  font-weight: 600;
  font-size: 1rem;
}
html.subpage-layout-v2 .readnext-item a:hover { text-decoration: underline; }
html.subpage-layout-v2 .readnext-note {
  grid-column: 2;
  color: var(--text-soft);
  font-size: .9rem;
  line-height: 1.5;
}

/* =================================================================
 * Stats — large numbers in a row. Used as a visual rhythm break and
 * to ground the page in concrete data. (BCG / McKinsey article style.)
 * ================================================================ */
html.subpage-layout-v2 .stats-section {
  padding: 2rem 1.5rem 2.5rem;
}
/* The .stats-section .content rule previously set max-width: 1100px
 * which stranded the stats section flush-left in the 1180px shell
 * and conflicted with the new centered, shrink-to-fit .content rule
 * (see above). The stats content now inherits the shell-capping
 * behavior from .section .content. The intrinsic width of the 4-card
 * grid is ~1100-1200px, so the centered stats block will visually
 * span the same range without the hard cap. */
html.subpage-layout-v2 .stats-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  margin-top: 1.5rem;
}
@media (min-width: 640px) {
html.subpage-layout-v2 .stats-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 960px) {
html.subpage-layout-v2 .stats-grid { grid-template-columns: repeat(4, 1fr); }
}
html.subpage-layout-v2 .stat-item {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  padding: 1.25rem 1.25rem 1.1rem;
  background: var(--surfaceInset);
  border-top: 2px solid var(--gold);
  border-radius: 0 var(--radius) var(--radius) 0;
}
html.subpage-layout-v2 .stat-value {
  font-family: var(--font-heading);
  font-size: clamp(2.2rem, 4vw, 3rem);
  font-weight: 600;
  line-height: 1;
  color: var(--heading);
  letter-spacing: -.5px;
}
html.subpage-layout-v2 .stat-label {
  font-size: .92rem;
  line-height: 1.45;
  color: var(--text-soft);
}
html.subpage-layout-v2 .stat-sub {
  font-size: .72rem;
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: .35rem;
}

/* =================================================================
 * Compare — side-by-side "Do this / Not that" or "Common approach /
 * What we do" comparison. Negative column on the left (red-tinted hairline),
 * positive column on the right (gold hairline).
 * ================================================================ */
html.subpage-layout-v2 .compare-section .compare-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  margin-top: 1.75rem;
}
@media (min-width: 720px) {
html.subpage-layout-v2 .compare-section .compare-grid { grid-template-columns: 1fr 1fr; gap: 1.5rem; }
}
html.subpage-layout-v2 .compare-col {
  padding: 1.5rem 1.5rem 1.4rem;
  background: var(--surfaceInset);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  gap: .8rem;
}
html.subpage-layout-v2 .compare-col h3 {
  margin: 0 0 .25rem;
  font-family: var(--font-heading);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--heading);
  display: flex;
  align-items: center;
  gap: .5rem;
}
html.subpage-layout-v2 .compare-col h3::before {
  display: inline-grid;
  place-items: center;
  width: 1.4rem;
  height: 1.4rem;
  font-size: .9rem;
  font-weight: 700;
  border-radius: 50%;
  flex: 0 0 auto;
}
html.subpage-layout-v2 .compare-col-not { border-left: 3px solid color-mix(in srgb, var(--burgundy) 70%, transparent); }
html.subpage-layout-v2 .compare-col-not h3::before { content: "✕"; background: var(--burgundy); color: #fff; }
html.subpage-layout-v2 .compare-col-do { border-left: 3px solid var(--gold); }
html.subpage-layout-v2 .compare-col-do h3::before { content: "✓"; background: var(--gold); color: var(--navy); }
html.subpage-layout-v2 .compare-col p {
  margin: 0;
  font-size: .95rem;
  line-height: 1.55;
  color: var(--text-soft);
}
html.subpage-layout-v2 .compare-col ul {
  margin: 0;
  padding: 0 0 0 1.1rem;
  list-style: disc;
  color: var(--text-soft);
  font-size: .9rem;
  line-height: 1.55;
}
html.subpage-layout-v2 .compare-col ul li + li { margin-top: .35rem; }

/* =================================================================
 * Big quote — full-width pull-quote from a named source.
 * ================================================================ */
html.subpage-layout-v2 .quote-section {
  padding: 3rem 1.5rem;
}
html.subpage-layout-v2 .quote-section .content { max-width: 900px; }
html.subpage-layout-v2 .big-quote {
  margin: 0;
  padding: 0 0 0 2rem;
  border-left: 3px solid var(--gold);
  font-family: var(--font-heading);
  font-size: clamp(1.4rem, 2.4vw, 1.85rem);
  line-height: 1.4;
  color: var(--heading);
  font-weight: 500;
  text-wrap: balance;
}
html.subpage-layout-v2 .big-quote p { margin: 0; }
html.subpage-layout-v2 .big-quote p::before { content: "\201C"; color: var(--gold); margin-right: .15rem; }
html.subpage-layout-v2 .big-quote p::after { content: "\201D"; color: var(--gold); margin-left: .15rem; }
html.subpage-layout-v2 .big-quote footer {
  margin-top: 1.25rem;
  font-family: var(--font-body);
  font-size: .92rem;
  font-weight: 400;
  font-style: normal;
  color: var(--text-soft);
  letter-spacing: .3px;
}
html.subpage-layout-v2 .big-quote cite::before { content: "— "; color: var(--text-muted); }

/* =================================================================
 * CTA — prominent closing action.
 * ================================================================ */
html.subpage-layout-v2 .section.cta-prominent {
  position: relative;
  margin-top: 3.5rem;
  padding: 4rem 2rem 3.5rem;
  background:
    /* Layered: navy→burgundy diagonal, with a gold radial vignette from the
     * top-right to draw the eye to the headline. */
    radial-gradient(ellipse 60% 80% at 80% 0%,
      color-mix(in srgb, var(--gold) 22%, transparent) 0%,
      transparent 60%),
    linear-gradient(135deg,
      color-mix(in srgb, var(--navy) 18%, var(--surface)) 0%,
      var(--surface) 50%,
      color-mix(in srgb, var(--burgundy) 18%, var(--surface)) 100%);
  border: 1px solid color-mix(in srgb, var(--gold) 25%, var(--borderSubtle));
  border-radius: var(--radius-lg);
  text-align: center;
  overflow: hidden;
  isolation: isolate;
}
html.subpage-layout-v2 .section.cta-prominent::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("/assets/img/svg/noetroniq-name-reversed.svg");
  background-repeat: no-repeat;
  background-position: center 92%;
  background-size: min(360px, 50%) auto;
  opacity: .06;
  pointer-events: none;
  z-index: 0;
}
html.subpage-layout-v2 .section.cta-prominent > * { position: relative; z-index: 1; }
html.subpage-layout-v2 .section.cta-prominent h2 {
  font-family: var(--font-heading);
  font-size: clamp(1.6rem, 3vw, 2.2rem);
  margin: 0 0 .85rem;
  color: var(--heading);
}
html.subpage-layout-v2 .section.cta-prominent p {
  max-width: 56ch;
  margin: 0 auto 1.75rem;
  color: var(--text-soft);
  line-height: 1.6;
  font-size: 1.05rem;
}
html.subpage-layout-v2 .section.cta-prominent .btn-cta {
  display: inline-block;
  padding: .85rem 1.75rem;
  background: var(--gold);
  color: var(--text-on-gold, #1a1a1a);
  font-weight: 600;
  font-size: 1rem;
  border-radius: var(--radius);
  text-decoration: none;
  letter-spacing: .01em;
  transition: transform 180ms ease, box-shadow 180ms ease;
  box-shadow: 0 4px 12px color-mix(in srgb, var(--gold) 25%, transparent);
}
html.subpage-layout-v2 .section.cta-prominent .btn-cta:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 18px color-mix(in srgb, var(--gold) 35%, transparent);
}
html.subpage-layout-v2 .section.cta-prominent .btn-cta:focus-visible {
  outline: var(--focus-ring-lg);
  outline-offset: 3px;
}

/* =================================================================
 * Header theme-toggle slot (small icon next to breadcrumb).
 * ================================================================ */
html.subpage-layout-v2 .subpage-header-actions {
  display: inline-flex;
  align-items: center;
  gap: .65rem;
  margin-left: auto;
}
html.subpage-layout-v2 .subpage-theme-toggle {
  appearance: none;
  background: transparent;
  border: 1px solid var(--borderSubtle);
  color: var(--text-soft);
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 180ms ease, color 180ms ease, border-color 180ms ease, transform 220ms cubic-bezier(.22, .61, .36, 1);
  font-size: 1rem;
}
html.subpage-layout-v2 .subpage-theme-toggle:hover {
  background: var(--surface);
  color: var(--text);
  border-color: var(--border);
}
html.subpage-layout-v2 .subpage-theme-toggle:focus-visible {
  outline: var(--focus-ring-lg);
  outline-offset: 2px;
}
html.subpage-layout-v2 .subpage-theme-toggle .icon {
  display: block;
  transition: transform 220ms cubic-bezier(.22, .61, .36, 1);
}
html.subpage-layout-v2 .subpage-theme-toggle[aria-pressed="true"] .icon { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
html.subpage-layout-v2 .subpage-theme-toggle, html.subpage-layout-v2 .subpage-theme-toggle .icon { transition: none; }
}

/* =================================================================
 * Subpage breadcrumb — give it more breathing room and the theme
 * toggle a place to live.
 * ================================================================ */
html.subpage-layout-v2 .subpage-breadcrumb {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .65rem;
  padding: 1rem 1.5rem;
  border-bottom: 1px solid var(--borderSubtle);
  background: color-mix(in srgb, var(--surface) 80%, transparent);
}
html.subpage-layout-v2 .subpage-breadcrumb ol {
  list-style: none;
  padding: 0; margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .35rem .5rem;
  font-size: .9rem;
  color: var(--text-soft);
}
html.subpage-layout-v2 .subpage-breadcrumb li {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
}
html.subpage-layout-v2 .subpage-breadcrumb li + li::before {
  content: "/";
  color: var(--border);
}
html.subpage-layout-v2 .subpage-breadcrumb a {
  color: var(--text-soft);
  text-decoration: none;
}
html.subpage-layout-v2 .subpage-breadcrumb a:hover { color: var(--heading-accent); }
html.subpage-layout-v2 .subpage-breadcrumb [aria-current="page"] {
  color: var(--heading);
  font-weight: 600;
}

/* =================================================================
 * Fade-up on view entry — IntersectionObserver adds .is-visible.
 * ================================================================ */
html.subpage-layout-v2 .fade-up {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 480ms ease, transform 480ms cubic-bezier(.22, .61, .36, 1);
  will-change: opacity, transform;
}
html.subpage-layout-v2 .fade-up.is-visible {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
html.subpage-layout-v2 .fade-up { opacity: 1; transform: none; transition: none; }
}

/* =================================================================
 * Subtle SVG pattern overlays on section backgrounds.
 *
 * Three patterns layered at 3-6% opacity via ::before pseudo-elements:
 *   1. .section.alt     — tiny dot field (works in both modes)
 *   2. .band-dark       — diagonal lines on the deep navy band
 *   3. .quote-section   — paper grain for editorial feel
 *
 * All patterns are inline SVG data URIs (no extra HTTP requests).
 * Pattern color is theme-aware: white at low opacity on dark
 * backgrounds, dark grey at low opacity on light backgrounds.
 * Patterns are pointer-events: none and z-index: 0 so they sit
 * behind content. Content elements within these sections should
 * have z-index: 1 or position: relative to stack above.
 * ================================================================ */

/* Pattern 1: .section.alt — tiny dot field, 24px spacing, 2.5px dots.
 * The SVG uses a circle at 12,12 inside a 24x24 tile. The pattern
 * color is set via the SVG's circle fill; we use two themed copies
 * (dark mode: white; light mode: dark grey) by swapping the data URI. */
html.subpage-layout-v2 .subpage-shell .section.alt {
  position: relative;
  overflow: hidden;
  /* v2: make the section full-bleed by extending it past the shell.
   * The shell is 1180px max, centered. The section is inside the shell
   * (so its parent is the shell, not the viewport). The trick:
   *   - margin-left: calc(50% - 50vw) pulls the left edge to viewport-x=0
   *     (50% = 50% of the shell = 590px, 50vw = 960px, diff = -370px)
   *   - margin-right: same on the right
   *   - width is auto (fills the space from margin-left to margin-right)
   *   - padding-left/right: 1.5rem restores the section's internal gutter
   * The section's content stays in the main column (constrained by the
   * padding), but the section's box (and its ::before background) spans
   * the full viewport. */
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  padding-left: 1.5rem;
  padding-right: 1.5rem;
}
html.subpage-layout-v2 .subpage-shell .section.alt::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
  pointer-events: none;
  background-image: url("../svg/patterns/sectionalt-grid.svg");
  background-repeat: repeat;
  background-size: 480px 270px; /* 30% of 1600x900 tile */
}
html.subpage-layout-v2[data-theme='light'] .subpage-shell .section.alt::before {
  background-image: url("../svg/patterns/sectionalt-grid-light.svg");
  background-size: 480px 270px; /* 30% of 1600x900 tile */
}
/* Section content stacks above the pattern overlay */
html.subpage-layout-v2 .subpage-shell .section.alt > * {
  position: relative;
  z-index: 1;
}

/* Pattern 2 was originally designed for `.band-dark` but that class is
 * never used. The diagonal-line design is now applied to the full-bleed
 * `::after` of `.questions-section` and `.evidence-section` (the dark
 * bands). See the "Section bands" block below. */



/* Pattern 3: .quote-section — paper grain via SVG noise filter.
 * The SVG uses feTurbulence to generate a low-frequency noise field
 * inside a 200x200 tile, then feColorMatrix to map it to white at
 * 3% opacity. In light mode, the noise is dark grey at 4% opacity. */
html.subpage-layout-v2 .subpage-shell .quote-section {
  position: relative;
  overflow: hidden;
}
html.subpage-layout-v2 .subpage-shell .quote-section::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  transform: none;
  z-index: 0;
  pointer-events: none;
  background-image: url("../svg/patterns/quote-organic.svg");
  background-repeat: repeat;
  background-size: 800px 450px; /* 50% of 1600x900 tile */
}
html.subpage-layout-v2[data-theme='light'] .subpage-shell .quote-section::before {
  background-image: url("../svg/patterns/quote-organic-light.svg");
  background-size: 800px 450px; /* 50% of 1600x900 tile */
}
html.subpage-layout-v2 .subpage-shell .quote-section > * {
  position: relative;
  z-index: 1;
}

/* Pattern 4: .methodology-section — blueprint grid (dual-scale: 20px
 * major + 5px minor). The existing .methodology-section background is
 * a navy→surfaceInset gradient already named "blueprint backdrop" —
 * this pattern makes that metaphor literal with real engineering-paper
 * geometry. Major grid at 4% opacity, minor grid at 1.5% — the major
 * anchors the blueprint reading, the minor adds fine texture.
 * To remove: delete this entire block (parent + ::before rules). */
html.subpage-layout-v2 .subpage-shell .methodology-section {
  position: relative;
  overflow: hidden;
}
html.subpage-layout-v2 .subpage-shell .methodology-section::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  width: 100%;
  height: 100%;
  transform: none;
  z-index: 0;
  pointer-events: none;
  background-image: url("../svg/patterns/methodology-blueprint.svg");
  background-repeat: repeat;
  background-size: 800px 450px; /* 50% of 1600x900 tile */
}
html.subpage-layout-v2[data-theme='light'] .subpage-shell .methodology-section::before {
  background-image: url("../svg/patterns/methodology-blueprint-light.svg");
  background-size: 800px 450px; /* 50% of 1600x900 tile */
}
html.subpage-layout-v2 .subpage-shell .methodology-section > * {
  position: relative;
  z-index: 1;
}

/* Pattern 5: .anti-pattern — diagonal hatch (18px tile, 1px lines at
 * 45°). Reinforces the "warning / things to avoid" concept with a
 * subtle tape-like texture. Uses a linearGradient (gold 8% → gold 2%)
 * so the hatch fades from top-left to bottom-right, giving it visual
 * depth without changing overall opacity.
 * To remove: delete this entire block (parent + ::before rules). */
html.subpage-layout-v2 .subpage-shell .anti-pattern {
  position: relative;
  overflow: hidden;
}
html.subpage-layout-v2 .subpage-shell .anti-pattern::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  width: 100%;
  height: 100%;
  transform: none;
  z-index: 0;
  pointer-events: none;
  background-image: url("../svg/patterns/antipattern-hatch.svg");
  background-repeat: repeat;
  background-size: 160px 90px; /* 10% of 1600x900 tile */
}
html.subpage-layout-v2[data-theme='light'] .subpage-shell .anti-pattern::before {
  background-image: url("../svg/patterns/antipattern-hatch-light.svg");
  background-size: 160px 90px; /* 10% of 1600x900 tile */
}
html.subpage-layout-v2 .subpage-shell .anti-pattern > * {
  position: relative;
  z-index: 1;
}

/* Pattern 6: .compare-col — fine dot field (16px spacing, 1.2px dots).
 * Differentiates the do/not-do columns from the surrounding surface
 * without competing with the colored left border. Uses a radialGradient
 * that's denser in the center of each tile and sparser at the edges,
 * creating a subtle "spotlight" effect that draws the eye inward.
 * To remove: delete this entire block (parent + ::before rules). */
html.subpage-layout-v2 .subpage-shell .compare-col {
  position: relative;
  overflow: hidden;
}
html.subpage-layout-v2 .subpage-shell .compare-col::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  width: 100%;
  height: 100%;
  transform: none;
  z-index: 0;
  pointer-events: none;
  background-image: url("../svg/patterns/compare-dots.svg");
  background-repeat: repeat;
  background-size: 240px 135px; /* 15% of 1600x900 tile */
}
html.subpage-layout-v2[data-theme='light'] .subpage-shell .compare-col::before {
  background-image: url("../svg/patterns/compare-dots-light.svg");
  background-size: 240px 135px; /* 15% of 1600x900 tile */
}
html.subpage-layout-v2 .subpage-shell .compare-col > * {
  position: relative;
  z-index: 1;
}

/* Pattern 7: .qa-item — fine dot field (12px spacing, 1px dots).
 * The Q&A section is a large surface on every service page. The cards
 * are already visually distinct (border, padding), but a subtle dot
 * field adds depth without competing with the question/answer text.
 * 5% opacity dark / 3% light — very subtle, reads as texture.
 * To remove: delete this entire block (parent + ::before rules). */
html.subpage-layout-v2 .subpage-shell .qa-item {
  position: relative;
  overflow: hidden;
}
html.subpage-layout-v2 .subpage-shell .qa-item::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  width: 100%;
  height: 100%;
  transform: none;
  z-index: 0;
  pointer-events: none;
  background-image: url("../svg/patterns/qaitem-dots.svg");
  background-repeat: repeat;
  background-size: 160px 90px; /* 10% of 1600x900 tile */
}
html.subpage-layout-v2[data-theme='light'] .subpage-shell .qa-item::before {
  background-image: url("../svg/patterns/qaitem-dots-light.svg");
  background-size: 160px 90px; /* 10% of 1600x900 tile */
}
html.subpage-layout-v2 .subpage-shell .qa-item > * {
  position: relative;
  z-index: 1;
}
/* Spotlight (cursor-following highlight) on Q&A items. The ::before
 * above carries the dim dot pattern (always visible, ~0.20 fill).
 * The ::after is a MASKED radial gradient: the bright color is
 * clipped to the dot shapes by the same SVG used in ::before, so
 * the spotlight only brightens the dots themselves (not the empty
 * space between them). When the cursor is over a card, the dots
 * in the spotlight area appear at full color, while dots outside
 * stay at the dim base opacity. The result: subtle dot pattern
 * always present + dramatic bright dots under the cursor. */
html.subpage-layout-v2 .qa-item {
  --qa-mx: 50%;
  --qa-my: 50%;
  /* "Reflective" pattern: the dots are treated as a polished
   * material that catches the cursor's light dramatically. Higher
   * alpha than the .card spotlight (which is 0.10 dark / 0.30 light)
   * because the mask only paints the dot shapes — the surrounding
   * empty space is unaffected. We can push the alpha much higher
   * without making the card "too bright" overall. */
  --qa-bright: rgba(245, 247, 251, 0.95);
  --qa-bright-mid: rgba(245, 247, 251, 0.45);
  --qa-bright-faint: rgba(245, 247, 251, 0.18);
}
html.subpage-layout-v2[data-theme='light'] .qa-item {
  --qa-bright: rgba(13, 47, 87, 0.95);
  --qa-bright-mid: rgba(13, 47, 87, 0.55);
  --qa-bright-faint: rgba(13, 47, 87, 0.25);
}
html.subpage-layout-v2 .qa-item::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  transition: .35s opacity;
  /* In dark mode, the dots are light (#f5f7fa) and the card is
   * dark. A "screen" blend makes the spotlight add to the light
   * dots, brightening them dramatically (reflective feel). In
   * light mode (set below), the dots are dark and the card is
   * light; a "multiply" blend makes the dark spotlight multiply
   * with the dark dots, darkening them. Both are "reflective"
   * but follow the existing .card convention. */
  mix-blend-mode: screen;
  /* Radial gradient: bright at the cursor, fading to transparent.
   * The falloff stops mirror the .card spotlight from styles.css
   * (0% / 22% / 40% / 56%) so the "spotlight size" feels
   * consistent across the page. The high peak alpha (0.95) makes
   * the dots in the spotlight area look "lit" — the reflective
   * material is catching the light at full intensity. */
  background: radial-gradient(
    circle at var(--qa-mx) var(--qa-my),
    var(--qa-bright) 0%,
    var(--qa-bright-mid) 22%,
    var(--qa-bright-faint) 40%,
    rgba(0, 0, 0, 0) 56%
  );
  /* Mask: clip the radial gradient to only show where the dot
   * pattern is opaque. We use a SEPARATE mask SVG (qaitem-dots-mask.svg)
   * that has the same dot positions but at full fill-opacity (1.0).
   * The dim qaitem-dots.svg is used in ::before for the always-
   * visible base pattern. Using a full-alpha mask means the
   * spotlight can fully brighten the dots, rather than being
   * capped at 0.20 alpha (the dim SVG's fill-opacity). */
  -webkit-mask-image: url("../svg/patterns/qaitem-dots-mask.svg");
  mask-image: url("../svg/patterns/qaitem-dots-mask.svg");
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-size: 160px 90px;
  mask-size: 160px 90px;
}
html.subpage-layout-v2[data-theme='light'] .qa-item::after {
  -webkit-mask-image: url("../svg/patterns/qaitem-dots-light-mask.svg");
  mask-image: url("../svg/patterns/qaitem-dots-light-mask.svg");
  mix-blend-mode: multiply;
}
html.subpage-layout-v2 .qa-item:hover::after,
html.subpage-layout-v2 .qa-item:focus-within::after,
html.subpage-layout-v2 .qa-item.prox-glow::after { opacity: 1; }

/* =================================================================
 * Print — strip theme chrome and TOC.
 * ================================================================ */
@media print {
html.subpage-layout-v2 .subpage-toc, html.subpage-layout-v2 .subpage-theme-toggle, html.subpage-layout-v2 .subpage-header-actions { display: none !important; }
html.subpage-layout-v2 .subpage-hero { background: none; padding: 1rem 0; }
}

/* =====================================================================
 * Section bands — full-bleed background bands that extend to the
 * viewport edges, breaking out of the .subpage-shell (max-width:1180px)
 * and the main column (864px on desktop).
 *
 * Implementation: each banded section gets position:relative and a
 * ::after pseudo-element positioned with left:-100%; right:-100%. The
 * ::after extends by the section's own width on each side — more than
 * enough to cover any viewport width regardless of where the section
 * is positioned in the grid.
 *
 * Background colors are on the ::after so the section's content sits
 * above them (z-index:1 on > * and z-index:0 on the section itself).
 *
 * This brings the subpage visual rhythm closer to the main page's
 * .section.alt pattern (alternating dark/light bands) without making
 * the subpage feel like a marketing page.
 * ================================================================ */

.questions-section, .evidence-section, .readnext-section,
html.subpage-layout-v2 .anti-patterns-section, html.subpage-layout-v2 .compare-section, html.subpage-layout-v2 .stats-section {
  position: relative;
  z-index: 0;
  /* v2: make the section full-bleed by extending it past the shell
   * (same trick as .section.alt in step 14). The previous v1
   * approach used a `::after` breakout (left: -200%; right: -200%)
   * to make the `::after` extend past the section. In v2 the
   * section itself is full-bleed, and the `::after` is positioned
   * with inset: 0 to fill the section naturally. This avoids the
   * 5900px body width that the breakout was causing. */
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  padding-left: 1.5rem;
  padding-right: 1.5rem;
}
.questions-section > *, .evidence-section > *, .readnext-section > *,
html.subpage-layout-v2 .anti-patterns-section > *, html.subpage-layout-v2 .compare-section > *, html.subpage-layout-v2 .stats-section > * {
  position: relative;
  z-index: 1;
}
.questions-section::after,
.evidence-section::after,
.readnext-section::after,
.anti-patterns-section::after,
.compare-section::after,
html.subpage-layout-v2 .stats-section::after {
  content: "";
  position: absolute;
  /* v2: the section is full-bleed (margin-left/right: calc(50% - 50vw)),
   * so the ::after uses inset: 0 to fill the section naturally. The
   * previous v1 breakout (left: -200%; right: -200%) was causing the
   * body to be 5760px wide, which conflicted with the html
   * overflow-x: clip. */
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

/* TOC translucent backing — needed because dark bands scroll behind
 * the floating TOC. Active only at >= 1100px (when the TOC is shown). */
@media (min-width: 1100px) {
html.subpage-layout-v2 .subpage-toc {
    background: color-mix(in srgb, var(--bg) 88%, transparent);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-left-color: transparent;
    border-radius: var(--radius);
    padding: 0.85rem 0.85rem 0.85rem 1.1rem;
    margin-left: -1.1rem;
  }
html.subpage-layout-v2[data-theme='light'] .subpage-toc {
    background: color-mix(in srgb, var(--bg) 92%, transparent);
  }
}

/* Dark bands: questions + evidence = deep navy gradient.
 * Uses --band-dark (not --navy) so the band is barely lighter than
 * the page background (#0c121a) — present but not loud. The
 * gradient is very subtle (4% range) so the band has a consistent
 * tone regardless of section height. */
/* Questions-section background — applied to the ::after (which is
 * already full-bleed via inset: 0 -200%) so the band runs edge-to-edge
 * across the viewport. The ::after carries both the pattern (first
 * layer) and the band gradient (second layer). */
.subpage-shell .questions-section,
html.subpage-layout-v2 .subpage-shell .evidence-section {
  position: relative;
  /* overflow: visible lets the ::after { left/right: -200% } breakout escape
   * the section's box. */
  overflow: visible;
}
/* .alt-wrapped questions-section pages (services + privacy-policy, 7 of 22
 * subpages) have an opaque .section.alt base background, a dot-pattern
 * ::before, and overflow:hidden. The compound selector below raises
 * specificity to (0,4,0) — beating .subpage-shell .section.alt::before
 * (0,3,0 + one pseudo-class = 0,4,0, tied) and .subpage-shell .section.alt
 * (0,3,0). On a tie, source order wins, and this rule appears later in
 * the file. So the rule works by specificity *and* source order. */
html.subpage-layout-v2 .subpage-shell .section.alt.questions-section {
  background: transparent;
  overflow: visible;
}
html.subpage-layout-v2 .subpage-shell .section.alt.questions-section::before {
  display: none; /* suppress the generic .section.alt dot pattern so the
                    section's own ::after pattern (waves) shows through
                    cleanly. evidence-section is not currently wrapped in
                    .alt on any page; re-add this rule if that changes. */
}
html.subpage-layout-v2 .questions-section::after {
  background:
    url("../svg/patterns/questions-waves.svg") repeat,
    linear-gradient(180deg,
      color-mix(in srgb, var(--band-dark) 35%, transparent) 0%,
      color-mix(in srgb, var(--band-dark) 32%, var(--bg)) 100%);
  background-size: 800px 450px, auto; /* 50% of 1600x900 tile */
}
html.subpage-layout-v2 .evidence-section::after {
  background:
    url("../svg/patterns/evidence-circuits.svg") repeat,
    linear-gradient(180deg,
      color-mix(in srgb, var(--band-dark) 35%, transparent) 0%,
      color-mix(in srgb, var(--band-dark) 32%, var(--bg)) 100%);
  background-size: 400px 225px, auto; /* 25% of 1600x900 tile */
}
html.subpage-layout-v2[data-theme='light'] .questions-section::after {
  background:
    url("../svg/patterns/questions-waves-light.svg") repeat,
    linear-gradient(180deg,
      color-mix(in srgb, var(--navy) 4%, var(--surface)) 0%,
      color-mix(in srgb, var(--navy) 3%, var(--bg-alt)) 100%);
  background-size: 800px 450px, auto;
}
html.subpage-layout-v2[data-theme='light'] .evidence-section::after {
  background:
    url("../svg/patterns/evidence-circuits-light.svg") repeat,
    linear-gradient(180deg,
      color-mix(in srgb, var(--navy) 4%, var(--surface)) 0%,
      color-mix(in srgb, var(--navy) 3%, var(--bg-alt)) 100%);
  background-size: 400px 225px, auto;
}
/* Readnext = light surface band with SubtlePatterns dot grid.
 * Order: SVG FIRST (on top), gradient SECOND (behind) so the dots
 * are visible. The gradient provides the band color tint.
 * Subtle: ~5% dot opacity, very small dots — reads as texture. */
html.subpage-layout-v2 .readnext-section::after {
  background:
    url("../svg/patterns/readnext-dots.svg") repeat,
    linear-gradient(180deg,
      color-mix(in srgb, var(--surface) 100%, transparent) 0%,
      color-mix(in srgb, var(--bg-alt) 100%, transparent) 100%);
  background-size: 400px 225px, auto; /* 25% of 1600x900 tile */
}
html.subpage-layout-v2[data-theme='light'] .readnext-section::after {
  background:
    url("../svg/patterns/readnext-dots-light.svg") repeat,
    linear-gradient(180deg,
      color-mix(in srgb, var(--surface) 100%, transparent) 0%,
      color-mix(in srgb, var(--bg-alt) 100%, transparent) 100%);
  background-size: 400px 225px, auto;
}

/* Inverse text colors for the dark sections (questions + evidence) */
.questions-section .section-eyebrow,
html.subpage-layout-v2 .evidence-section .section-eyebrow { color: #d4af37; }
.questions-section h2,
html.subpage-layout-v2 .evidence-section h2 { color: #f5f7fb; }
.questions-section p,
.questions-section .qa-item,
.evidence-section p,
html.subpage-layout-v2 .evidence-section .evidence-item { color: #d4dce8; }
.questions-section .qa-item h3 a,
html.subpage-layout-v2 .evidence-section .evidence-title { color: #f5f7fb; }
:root[data-theme='light'] .questions-section .section-eyebrow,
html.subpage-layout-v2[data-theme='light'] .evidence-section .section-eyebrow { color: var(--gold-fg); }
:root[data-theme='light'] .questions-section h2,
html.subpage-layout-v2[data-theme='light'] .evidence-section h2 { color: var(--heading); }
:root[data-theme='light'] .questions-section p,
:root[data-theme='light'] .questions-section .qa-item,
:root[data-theme='light'] .evidence-section p,
html.subpage-layout-v2[data-theme='light'] .evidence-section .evidence-item { color: var(--text); }
:root[data-theme='light'] .questions-section .qa-item h3 a,
html.subpage-layout-v2[data-theme='light'] .evidence-section .evidence-title { color: var(--heading); }


/* =====================================================
 * Product-page styles
 * =====================================================
 * The product hero, screenshots gallery, and capabilities list are
 * distinct from the editorial hero / expertise grid / cards layouts
 * because product pages are sales material, not reference material.
 * The hero carries a PRODUCT tag, a "What is it" oneLiner, small
 * facts (version, license, deployment), and optionally a leading
 * screenshot. The screenshots and capabilities sections are 2-up
 * grids on desktop that stack on mobile. */

/* ---- Product hero ---- */
html.subpage-layout-v2 .subpage-hero.product-hero .subpage-hero-content.product-hero-content {
  /* Override the editorial hero content width to leave room for the
   * leading screenshot (when one is present). */
  max-width: 100%;
  padding: 2.75rem 2rem 2.5rem;
}
html.subpage-layout-v2 .product-hero-tag {
  /* The PRODUCT tag is a small label, not a section eyebrow. */
  display: inline-block;
  font-size: .72rem;
  letter-spacing: 2.4px;
  text-transform: uppercase;
  color: var(--noetroniq-gold-500);
  background: color-mix(in srgb, var(--noetroniq-gold-500) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--noetroniq-gold-500) 35%, transparent);
  border-radius: 4px;
  padding: .35rem .75rem;
  margin: 0 0 1rem;
  font-weight: 600;
}
html.subpage-layout-v2[data-theme='light'] .product-hero-tag {
  color: var(--noetroniq-gold-700);
  background: color-mix(in srgb, var(--noetroniq-gold-500) 10%, transparent);
  border-color: color-mix(in srgb, var(--noetroniq-gold-700) 30%, transparent);
}
html.subpage-layout-v2 .product-hero-oneliner {
  /* "What is it" — a short paragraph that frames the product. */
  max-width: 64ch;
  margin: 1rem 0 0;
  font-size: 1.05rem;
  line-height: 1.5;
  color: color-mix(in srgb, #fff 88%, transparent);
}
html.subpage-layout-v2[data-theme='light'] .product-hero-oneliner {
  color: color-mix(in srgb, var(--noetroniq-grey-900) 80%, transparent);
}
html.subpage-layout-v2 .product-hero-facts {
  /* Small key-value grid (Version, License, Deployment, etc.) */
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem 2.5rem;
  margin: 1.75rem 0 0;
  padding: 0;
}
html.subpage-layout-v2 .product-hero-fact {
  display: flex;
  flex-direction: column;
  gap: .15rem;
}
html.subpage-layout-v2 .product-hero-fact dt {
  font-size: .68rem;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: color-mix(in srgb, #fff 55%, transparent);
  margin: 0;
}
html.subpage-layout-v2 .product-hero-fact dd {
  font-size: .98rem;
  font-weight: 500;
  color: #fff;
  margin: 0;
}
html.subpage-layout-v2[data-theme='light'] .product-hero-fact dt {
  color: color-mix(in srgb, var(--noetroniq-grey-900) 55%, transparent);
}
html.subpage-layout-v2[data-theme='light'] .product-hero-fact dd {
  color: var(--noetroniq-grey-900);
}
html.subpage-layout-v2 .product-hero-screenshot {
  position: relative;
  margin: 1.5rem auto 0;
  max-width: 1180px;
  padding: 0 2rem;
  z-index: 2;
}
.product-hero-screenshot picture,
html.subpage-layout-v2 .product-hero-screenshot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 12px;
  box-shadow: 0 18px 40px -16px rgba(0, 0, 0, .55), 0 4px 12px -2px rgba(0, 0, 0, .25);
  border: 1px solid color-mix(in srgb, #fff 8%, transparent);
}
html.subpage-layout-v2[data-theme='light'] .product-hero-screenshot img {
  box-shadow: 0 18px 40px -16px rgba(15, 23, 42, .35), 0 4px 12px -2px rgba(15, 23, 42, .12);
  border: 1px solid color-mix(in srgb, var(--noetroniq-grey-900) 10%, transparent);
}

/* ---- Screenshots gallery ---- */
html.subpage-layout-v2 .screenshots-section .content {
  max-width: 1180px;
}
html.subpage-layout-v2 .product-screenshots-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem;
  margin: 1.5rem 0 0;
}
@media (min-width: 720px) {
html.subpage-layout-v2 .product-screenshots-grid {
    grid-template-columns: 1fr 1fr;
  }
}
html.subpage-layout-v2 .product-screenshot-item {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: .85rem;
}
.product-screenshot-item picture,
html.subpage-layout-v2 .product-screenshot-item img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 10px;
  box-shadow: 0 12px 28px -10px rgba(0, 0, 0, .45), 0 2px 6px -1px rgba(0, 0, 0, .18);
  border: 1px solid color-mix(in srgb, #fff 8%, transparent);
}
html.subpage-layout-v2[data-theme='light'] .product-screenshot-item img {
  box-shadow: 0 12px 28px -10px rgba(15, 23, 42, .25), 0 2px 6px -1px rgba(15, 23, 42, .10);
  border: 1px solid color-mix(in srgb, var(--noetroniq-grey-900) 10%, transparent);
}
html.subpage-layout-v2 .product-screenshot-item figcaption {
  font-size: .92rem;
  line-height: 1.45;
  color: var(--text);
}
html.subpage-layout-v2 .product-screenshot-item figcaption strong {
  color: var(--heading);
  font-weight: 600;
}
html.subpage-layout-v2 .product-screenshot-caption {
  color: color-mix(in srgb, var(--text) 80%, transparent);
}

/* ---- Capabilities list ---- */
html.subpage-layout-v2 .capabilities-section .content {
  max-width: 1180px;
}
html.subpage-layout-v2 .capabilities-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem;
  margin: 1.5rem 0 0;
}
@media (min-width: 900px) {
html.subpage-layout-v2 .capabilities-grid {
    grid-template-columns: 1fr 1fr;
  }
}
html.subpage-layout-v2 .capability-item {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  padding: 1.5rem;
  background: color-mix(in srgb, var(--surface) 96%, transparent);
  border: 1px solid color-mix(in srgb, var(--noetroniq-grey-900) 8%, transparent);
  border-radius: 14px;
}
html.subpage-layout-v2[data-theme='light'] .capability-item {
  background: color-mix(in srgb, #fff 88%, transparent);
  border-color: color-mix(in srgb, var(--noetroniq-grey-900) 10%, transparent);
}
@media (min-width: 720px) {
html.subpage-layout-v2 .capability-item.has-screenshot {
    grid-template-columns: 1fr 1fr;
    align-items: start;
  }
}
html.subpage-layout-v2 .capability-body h3 {
  font-size: 1.2rem;
  font-weight: 600;
  margin: 0 0 .5rem;
  color: var(--heading);
}
html.subpage-layout-v2 .capability-summary {
  font-size: .98rem;
  line-height: 1.5;
  margin: 0 0 1rem;
  color: var(--text);
}
html.subpage-layout-v2 .capability-bullets {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .4rem;
}
html.subpage-layout-v2 .capability-bullets li {
  font-size: .92rem;
  line-height: 1.5;
  padding-left: 1.25rem;
  position: relative;
  color: var(--text);
}
html.subpage-layout-v2 .capability-bullets li::before {
  content: "›";
  position: absolute;
  left: 0;
  top: 0;
  color: var(--noetroniq-gold-500);
  font-weight: 600;
}
.capability-screenshot picture,
html.subpage-layout-v2 .capability-screenshot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 8px;
  border: 1px solid color-mix(in srgb, #fff 8%, transparent);
  box-shadow: 0 8px 20px -8px rgba(0, 0, 0, .35);
}
html.subpage-layout-v2[data-theme='light'] .capability-screenshot img {
  border-color: color-mix(in srgb, var(--noetroniq-grey-900) 10%, transparent);
  box-shadow: 0 8px 20px -8px rgba(15, 23, 42, .15);
}


/* =====================================================
 * Subpage hero photo
 * =====================================================
 * Any subpage can opt in to a photographic hero. The renderHero()
 * step in scripts/lib/render.mjs emits a
 * <img class="hero-photo" data-src-dark data-src-light>
 * alongside the .subpage-hero-bg gradient, IF AND ONLY IF the
 * page's frontmatter declares heroPhoto / heroPhotoDark /
 * heroPhotoLight. Pages without those fields render the plain
 * gradient hero — no broken-image icons, no empty img tags.
 *
 * main.js's applyHeroPhoto() swaps the src on theme toggle so
 * the same image can work as both a dark-mode and light-mode
 * backdrop. The blend modes + low opacity let the variant
 * gradient show through (~50% of the visible color comes from
 * the gradient, not the photo).
 *
 * How to opt in (in a subpage's markdown frontmatter):
 *
 *   - type: hero
 *     id: overview
 *     heroVariant: cybersecurity
 *     title: Cybersecurity
 *     tagline: ...
 *     heroPhotoDark: /assets/img/photos/<slug>-hero.jpg
 *     heroPhotoLight: /assets/img/photos/<slug>-hero.jpg
 *     heroPhotoAlt: One-sentence description of the image.
 *
 * The same image can be used for both themes (recommended for
 * tonal/abstract photos) — just set both fields to the same
 * path. The CSS blend modes make the same image work in both
 * themes: screen (dark, light wisps add highlights) and
 * multiply (light, dark areas create a fabric texture).
 *
 * Graceful degradation: if a heroPhoto URL is set but the file
 * is missing, main.js's onerror handler hides the img and the
 * page shows just the variant gradient. The variant gradient
 * is always present, so the hero never collapses to a blank
 * box.
 *
 * Full-bleed math: the .subpage-hero is inside the .subpage-shell
 * 2-column grid (main 864px + TOC 220px), left-aligned in the
 * shell content area (1180px - 48px padding = 1132px). The main
 * column's center is (1132 - 864) / 2 = 134px to the LEFT of the
 * viewport's center. To make the photo span the full viewport
 * we shift the breakout by +134px (constant across viewport
 * widths) and set `width: 100vw`. The .subpage-hero parent has
 * `overflow: visible` so the photo breaks out cleanly.
 */

/* Photo positioning: full-bleed, matching the .subpage-hero-bg
 * gradient's width.
 *
 * The .subpage-hero is inside the .subpage-shell, which is a
 * 2-column grid: main (864px) on the left + TOC (220px) on the
 * right. The grid is `864px 220px`, left-aligned in the shell
 * content area (1180px - 48px padding = 1132px). So the main
 * column's center is at (shell_content_left + 864/2) = 134px
 * to the LEFT of the viewport's center.
 *
 * To make the photo full-bleed (start at viewport-x=0, end at
 * viewport-x=100vw), we shift the breakout's left by +134px
 * and the right by -134px. This is the offset between the
 * main column's center and the viewport's center, and is
 * CONSTANT regardless of viewport width.
 *
 * The image inside the breakout is centered with `margin:
 * auto`. With the breakout shifted by 134px, the breakout's
 * center is at the viewport's center, and so is the image's
 * center.
 *
 * The .subpage-hero parent has `overflow: visible` so the photo
 * can break out cleanly. */
html.subpage-layout-v2 .subpage-hero .hero-photo {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  /* v2: the hero is full-bleed (no main-column offset). The photo
   * uses inset: 0 to fill the hero naturally. The previous v1
   * rule used a breakout trick with `left: calc(-200% + 134px)`
   * to compensate for the 134px main-column offset; that offset
   * is gone in v2, so the photo is now positioned with simple
   * inset: 0. */
  width: 100%;
  max-width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  z-index: 0;
  pointer-events: none;
}

/* Phase 4 (Task 4.2): when the hero photo uses <picture> for
 * mobile + desktop sources, the wrapper takes the same absolute
 * positioning as the inner <img>. The inner img inherits its
 * position from .hero-photo (above) since both classes are kept on
 * the <img>; the wrapper is invisible (no background, no border)
 * and exists only to make the browser pick the right source.
 */
html.subpage-layout-v2 .subpage-hero .hero-photo-picture {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}
html.subpage-layout-v2 .subpage-hero .hero-photo-picture > img.hero-photo {
  /* The inner img's absolute positioning is relative to the
   * nearest positioned ancestor. The .hero-photo-picture wrapper
   * is now that ancestor, so the inset: 0 above fills the wrapper
   * (which itself fills the hero). No additional rules needed. */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The hero-bg is also at z=0. The .hero-photo on top of it; the
 * blend mode in the variant-specific rule below controls how the
 * two interact. */
html.subpage-layout-v2 .subpage-hero .subpage-hero-bg {
  z-index: 0;
}

/* A hero-photo that failed to load (e.g. file missing, 404).
 * main.js sets `display: none` inline as the primary fallback;
 * this rule is a safety net so the broken-image icon is never
 * shown, even if a future code change removes the inline style. */
html.subpage-layout-v2 .subpage-hero .hero-photo.hero-photo-missing {
  display: none !important;
}

/* Default photo treatment: NORMAL blend in dark mode (the photo
 * sits on top of the gradient at ~50% opacity, so the gradient's
 * vibrant colors dominate and the photo provides texture). SCREEN
 * blend was tried first but it washes out dark photos — `screen`
 * only lightens, so dark areas of the photo become transparent and
 * the photo disappears into the dark gradient. NORMAL blend
 * preserves the photo's full tonal range.
 *
 * The 0.50 opacity keeps the gradient dominant: with normal blend,
 * visible_color = photo × 0.50 + gradient × 0.50, so the page's
 * hero gradient (blue-900 → gold-900 → burgundy-900 for
 * data-lineage, etc.) keeps its character while the photo
 * provides a subtle texture overlay.
 *
 * MULTIPLY blend in light mode (dark areas of the photo darken
 * the light page, creating a fabric texture) — kept at ~48% opacity
 * so the gradient clearly shows through.
 *
 * The transition is animated so theme toggles feel like the photo
 * is "rediscovering" itself rather than snapping. */
html.subpage-layout-v2 .subpage-hero .hero-photo {
  opacity: 0.50;
  mix-blend-mode: normal;
  transition: opacity .8s ease, filter .8s ease, mix-blend-mode 0s;
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero .hero-photo {
  opacity: 0.48;
  mix-blend-mode: multiply;
  filter: contrast(1.05) saturate(1.05);
}

/* ----- Master hero photo (greyscale source, CSS-tinted per theme) -----
 *
 * A master photo is a single greyscale asset that's rendered
 * differently in dark vs light mode via CSS filter: and
 * mix-blend-mode:. This is the parallel implementation alongside
 * the dark/light JPEG pair — it produces a near-identical visual
 * result with one asset instead of two.
 *
 * The filter chain colourises the greyscale source. Both themes
 * use a sepia + hue-rotate + saturate pipeline; the per-theme
 * difference is in the hue rotation amount and the blend mode.
 * Opacity is set per-render (style="opacity: 0.86" by default
 * via heroMasterOpacity frontmatter).
 *
 *   dark:  hue-rotate(190deg) saturate(2.4) brightness(0.95)
 *          mix-blend-mode: screen
 *          (cybersecurity variant — blue-tinted screen-blend over
 *           navy gradient; circuit traces glow against the dark)
 *
 *   light: hue-rotate(190deg) saturate(2.4) brightness(1.05)
 *          mix-blend-mode: multiply  opacity ~ 0.48
 *          (same hue but more brightness, multiply blend on light
 *           page; circuit traces darken the ivory backing)
 *
 * These values were tuned against cybersecurity-hero-dark.jpg and
 * cybersecurity-hero-light.jpg as targets. Other variants may need
 * a per-variant hue-rotate (set on the .subpage-hero[data-hero-variant]
 * element below). */
html.subpage-layout-v2 .subpage-hero .hero-photo-master {
  filter: sepia(0.15) hue-rotate(var(--hero-hue, 190deg)) saturate(1.5) brightness(0.78);
  mix-blend-mode: screen;
  transition: opacity .8s ease, filter .8s ease, mix-blend-mode 0s;
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero .hero-photo-master {
  filter: sepia(0.15) hue-rotate(var(--hero-hue, 190deg)) saturate(1.3) brightness(1.18) contrast(1.15);
  mix-blend-mode: multiply;
  opacity: 0.62 !important;
}
/* Per-variant filter tuning.
 *
 * The base filter chain is shared (.hero-photo-master above), but each
 * variant has a different photo "brightness" — the dark-mode original
 * varies from "very dark" (cybersecurity, navy) to "medium dark" (mlops,
 * which has bright orange circuit traces). A single `brightness()`
 * value can't cover them all. Per-variant overrides here.
 *
 * Each value was tuned to bring the new master+filter render within
 * ~3-5 mean diff of the original dark/light JPEG pair, in the
 * region where the difference is largest (the photo's bright areas).
 *
 * Both themes get a per-variant override because the hue + brightness
 * needs are different for each. */
html.subpage-layout-v2 .subpage-hero[data-hero-variant="cybersecurity"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(190deg) saturate(1.2) brightness(0.78);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="cybersecurity"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(190deg) saturate(1.3) brightness(1.18) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="digital-identity"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(178deg) saturate(1.7) brightness(0.55);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="digital-identity"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(165deg) saturate(1.2) brightness(1.16) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="enterprise-architecture"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(200deg) saturate(1.4) brightness(0.74);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="enterprise-architecture"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(200deg) saturate(1.5) brightness(1.10) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="applied-ai"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(305deg) saturate(1.8) brightness(0.62);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="applied-ai"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(305deg) saturate(1.7) brightness(1.04) contrast(1.10);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="software-engineering"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(180deg) saturate(1.4) brightness(0.72);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="software-engineering"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(180deg) saturate(1.55) brightness(1.10) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="advisory-assessments"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(40deg) saturate(1.8) brightness(0.55);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="advisory-assessments"] .hero-photo-master {
  filter: sepia(0.5) hue-rotate(45deg) saturate(1.35) brightness(1.04) contrast(1.10);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="zero-trust-architecture"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(210deg) saturate(1.4) brightness(0.78);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="zero-trust-architecture"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(210deg) saturate(1.0) brightness(1.18) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="iam-patterns"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(185deg) saturate(1.3) brightness(0.58);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="iam-patterns"] .hero-photo-master {
  filter: sepia(1.0) hue-rotate(175deg) saturate(2.2) brightness(1.10) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="threat-modeling"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(350deg) saturate(1.7) brightness(0.62);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="threat-modeling"] .hero-photo-master {
  filter: sepia(0.5) hue-rotate(350deg) saturate(2.0) brightness(1.04) contrast(1.10);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="mlops"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(18deg) saturate(1.8) brightness(0.65);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="mlops"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(25deg) saturate(1.65) brightness(1.04) contrast(1.10);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="platform-engineering"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(200deg) saturate(1.3) brightness(0.65);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="platform-engineering"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(200deg) saturate(1.35) brightness(1.10) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="api-ecosystems"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(180deg) saturate(1.4) brightness(0.74);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="api-ecosystems"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(180deg) saturate(1.55) brightness(1.10) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="capability-driven-planning"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(55deg) saturate(1.8) brightness(0.60);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="capability-driven-planning"] .hero-photo-master {
  filter: sepia(0.5) hue-rotate(55deg) saturate(2.0) brightness(1.05) contrast(1.12);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="decentralized-identity"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(180deg) saturate(1.3) brightness(0.60);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="decentralized-identity"] .hero-photo-master {
  filter: sepia(1.5) hue-rotate(170deg) saturate(1.4) brightness(1.17) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="security-governance"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(230deg) saturate(1.2) brightness(0.70);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="security-governance"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(230deg) saturate(1.3) brightness(1.16) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="application-security"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(230deg) saturate(1.2) brightness(0.74);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="application-security"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(230deg) saturate(1.5) brightness(1.10) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="intelligent-automation"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(20deg) saturate(1.2) brightness(0.66);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="intelligent-automation"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(30deg) saturate(1.55) brightness(1.05) contrast(1.12);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="data-lineage-and-integration"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(45deg) saturate(1.4) brightness(0.68);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="data-lineage-and-integration"] .hero-photo-master {
  filter: sepia(0.5) hue-rotate(45deg) saturate(2.0) brightness(1.05) contrast(1.12);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="resilience"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(200deg) saturate(1.0) brightness(0.78);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="resilience"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(200deg) saturate(1.3) brightness(1.18) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="high-compliance-delivery"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(215deg) saturate(1.7) brightness(0.74);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="high-compliance-delivery"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(215deg) saturate(1.35) brightness(1.10) contrast(1.15);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="privacy-engineering"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(285deg) saturate(1.8) brightness(0.62);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="privacy-engineering"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(270deg) saturate(1.65) brightness(1.04) contrast(1.10);
}
html.subpage-layout-v2 .subpage-hero[data-hero-variant="privacy-policy"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(305deg) saturate(1.5) brightness(0.62);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="privacy-policy"] .hero-photo-master {
  filter: sepia(0.15) hue-rotate(305deg) saturate(1.4) brightness(1.10) contrast(1.10);
}

/* Text plate scrim when a photo is present. The default
 * .subpage-hero-content has no scrim (the gradient alone gives
 * the H1 enough contrast). When a photo is layered underneath,
 * bright areas of the photo can wash out the white text in dark
 * mode. Darken the scrim to keep the headline readable. Light
 * mode doesn't have this issue (multiply blend only darkens,
 * never lightens), but the scrim still helps with separation.
 *
 * Applied via :has() so it activates only when a .hero-photo is
 * present, without needing a separate class on the hero. */
html.subpage-layout-v2 .subpage-hero:has(.hero-photo) .subpage-hero-content {
  background: linear-gradient(90deg,
    color-mix(in srgb, #000 92%, transparent) 0%,
    color-mix(in srgb, #000 86%, transparent) 55%,
    color-mix(in srgb, #000 50%, transparent) 100%);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero:has(.hero-photo) .subpage-hero-content {
  background: linear-gradient(90deg,
    color-mix(in srgb, #fff 88%, transparent) 0%,
    color-mix(in srgb, #fff 82%, transparent) 55%,
    color-mix(in srgb, #fff 45%, transparent) 100%);
  color: var(--noetroniq-grey-900);
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero:has(.hero-photo) .subpage-hero-content h1 {
  color: var(--noetroniq-grey-900);
  text-shadow: none;
}
html.subpage-layout-v2[data-theme='light'] .subpage-hero:has(.hero-photo) .subpage-hero-content .tagline {
  color: color-mix(in srgb, var(--noetroniq-grey-900) 95%, transparent);
  text-shadow: none;
}

/* =================================================================
 * Per-page hero scrim reductions (light mode only)
 *
 * The default light-mode scrim is a left-to-right white gradient
 * (88% / 82% / 45%) designed to keep the text plate readable while
 * letting the photo show through on the right. On pages where the
 * source image is intrinsically pale or has low contrast, the 45%
 * white tail still washes out the photo's color. For those pages
 * we keep the text-plate (0% and 55% stops) at the original opacity
 * for legibility, and only relax the right-hand 100% stop so the
 * photo's natural saturation can come through.
 *
 * Per-page, not global: the user asked to tune the scrim per page
 * rather than change it globally, since pages with vivid photos
 * still benefit from the original 45% stop.
 * ================================================================ */

/* Pages whose light-mode hero looked washed out (mean_sat < 8% in
 * the photo region under the original 45% white tail). Right-side
 * scrim reduced from 45% to ~25%. Text-plate stops unchanged. */
:root[data-theme='light'] .subpage-hero[data-hero-variant="advisory-assessments"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="applied-ai"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="enterprise-architecture"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="software-engineering"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="api-ecosystems"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="application-security"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="capability-driven-planning"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="data-lineage-and-integration"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="high-compliance-delivery"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="iam-patterns"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="intelligent-automation"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="mlops"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="platform-engineering"]:has(.hero-photo) .subpage-hero-content,
:root[data-theme='light'] .subpage-hero[data-hero-variant="privacy-engineering"]:has(.hero-photo) .subpage-hero-content,
html.subpage-layout-v2[data-theme='light'] .subpage-hero[data-hero-variant="threat-modeling"]:has(.hero-photo) .subpage-hero-content {
  background: linear-gradient(90deg,
    color-mix(in srgb, #fff 88%, transparent) 0%,
    color-mix(in srgb, #fff 82%, transparent) 55%,
    color-mix(in srgb, #fff 25%, transparent) 100%);
}


/* sec B.9 film grain disabled 2026-07-20. SVG assets retained in /svg/patterns/ for future re-enablement. */

/* =================================================================
 * Mobile UX v1.0 — touch-target floor for subpage controls.
 * See the same block in styles.css for the rationale. Scoped to
 * touch devices so the desktop-pixel gate stays green.
 *   --noetroniq-target-min = 44px (styles.css :root)
 * Standards §3: "All touch targets are at least 44 × 44 CSS pixels."
 * ================================================================ */
@media (hover: none), (pointer: coarse) {
  /* Suppress the default WebKit/Chromium tap-highlight rectangle
   * across the entire subpage surface. The browser default is
   * rgba(51, 181, 229, 0.4) — a sky-blue rectangle painted behind
   * every element being touched. The site's :focus-visible outline
   * (2px gold --focus-ring) already satisfies WCAG 2.4.7 Focus
   * Visible, so the legacy tap-highlight is redundant and clashes
   * with the dark navy / gold visual language. The same rule lives
   * in styles.css for the homepage chrome; duplicating it here
   * makes the suppression unconditional across every page. */
  *, *::before, *::after {
    -webkit-tap-highlight-color: transparent;
    tap-highlight-color: transparent;
  }
  /* On mobile, the page header now carries a .theme-toggle-header
   * button in the header's top-right slot (always visible, AAA
   * compliant). With that toggle reachable on every page, the
   * breadcrumb's .subpage-theme-toggle and the compact footer's
     * .theme-toggle-inline become redundant — having three toggles
     * on one screen is visual noise. Hide both on touch.
   * The buttons remain in the DOM (and keep their JS wiring) so
   * existing click handlers still work if a stale class triggers
   * them, but they're not rendered. */
  html.subpage-layout-v2 .subpage-theme-toggle,
  html.subpage-layout-v2 .subpage-header-actions,
  html.subpage-layout-v2 .theme-toggle-inline { display: none !important; }
  html.subpage-layout-v2 .subpage-toc-toggle {
    width: var(--noetroniq-target-min);
    height: var(--noetroniq-target-min);
  }
  html.subpage-layout-v2 .subpage-theme-toggle {
    width: var(--noetroniq-target-min);
    height: var(--noetroniq-target-min);
  }
  html.subpage-layout-v2 .section.cta-prominent .btn-cta {
    min-height: var(--noetroniq-target-min);
    display: inline-flex;
    align-items: center;
  }
  /* Inline anchor links whose desktop rendering is `display: inline`
   * (breadcrumb, readnext, qa-question) — without `inline-flex` the
   * min-height is computed but the box stays at the text's content
   * height. Same fix as the styles.css block.
   *
   * The `.subpage-breadcrumb a` rule also adds `min-width` so a
   * single-word item like "Home" reaches 44×44 on touch. Inline
   * body text links inside `<p>` prose are NOT included — they are
   * WCAG 2.5.8 AA-compliant at their natural line-height and
   * applying 44px to them would balloon the prose line-height. The
   * noetroniq design system permits this exception inline-text
   * links (Reconciliation rule 2 footnote). */
  html.subpage-layout-v2 .subpage-breadcrumb a,
  html.subpage-layout-v2 .readnext-item a,
  html.subpage-layout-v2 .qa-item h3 a {
    min-height: var(--noetroniq-target-min);
    display: inline-flex;
    align-items: center;
  }
  html.subpage-layout-v2 .subpage-breadcrumb a {
    min-width: var(--noetroniq-target-min);
    justify-content: flex-start;
    padding-inline: .35rem;
  }
}

/* =====================================================================
   /more/ page (Phase 2 / Task 2.5a).
   Standards §5: 'Every list item receives a 44x44 CSS pixel tap
   target.' The destination list is the page; the layout below
   applies the touch-target floor to every link in the list.
   On desktop the list renders at natural sizes (the touch rules are
   gated on `(hover: none), (pointer: coarse)` so mouse-driven
   desktop still sees the original spacing). */
html.subpage-layout-v2 .more-list {
  list-style: none;
  padding: 0;
  margin: 1.5rem 0 2rem;
  display: grid;
  gap: .65rem;
}
html.subpage-layout-v2 .more-list li { margin: 0; }
html.subpage-layout-v2 .more-list a {
  display: inline-flex;
  align-items: center;
  min-height: var(--noetroniq-target-min);
  padding: .55rem .85rem;
  border-radius: var(--radius-sm, 4px);
  text-decoration: none;
  color: var(--text);
  border: 1px solid var(--borderSubtle);
  background: var(--surface);
}
html.subpage-layout-v2 .more-list a:hover,
html.subpage-layout-v2 .more-list a:focus-visible {
  border-color: var(--gold, #d4af37);
  color: var(--gold, #d4af37);
}

/* =====================================================================
   Mobile hero sizing (Phase 5 / touch-scoped polish).
   On iPhone 11 (414x715), the desktop hero resolves to ~400px tall —
   56% of the viewport. The hero content (h1 + 4-line tagline + chips)
   actually exceeds min-height, so the hero ends up 374px on a phone,
   pushing all page content below the fold. The user has to scroll
   past the hero before they see the actual subpage content.

   The touch-scoped rules below make the hero more compact on phones:
     - min-height: clamp(220px, 30vh, 320px) instead of the desktop
       360-560px. The hero can still grow to fit content.
     - .subpage-hero-content padding shrinks from 2.5rem/2.25rem to
       1.25rem vertical (saves ~36px).
     - .tagline font-size: from clamp(1.05rem, 1.4vw, 1.25rem) to
       clamp(.92rem, 1vw, 1.05rem), and max-width shrinks from 56ch
       to 38ch. Net: the tagline wraps to 2 lines instead of 4,
       saving ~52px on a typical cybersecurity-style page.
     - .hero-chips gap shrinks from .5rem .75rem to .3rem .5rem so
       the chip row doesn't dominate.

   Desktop is unchanged (gate 52/52 PASS at the noise floor).
   Verified by Playwright on iPhone 11: hero shrinks from ~374px to
   ~250px on a typical page, putting the first paragraph above the
   fold. */
@media (hover: none), (pointer: coarse) {
  html.subpage-layout-v2 .subpage-hero {
    min-height: clamp(220px, 30vh, 320px);
  }
  /* main no longer needs padding-top reservation: with the hero now
   * position: relative (in flow at the top of <main>), the mobile TOC
   * (placed after the hero in DOM order) renders naturally below the
   * hero's actual height with no extra reservation needed. */
  html.subpage-layout-v2 .subpage-hero-content {
    padding: 1.25rem 1rem 1.1rem;
  }
  html.subpage-layout-v2 .subpage-hero .tagline {
    font-size: clamp(.92rem, 1vw, 1.05rem);
    line-height: 1.45;
    max-width: 38ch;
    margin: 0 0 .85rem;
  }
  html.subpage-layout-v2 .subpage-hero .hero-chips {
    gap: .3rem .5rem;
  }
}

/* =====================================================================
   Scrollspy top app bar (Phase 5 / Task 5.4).
   Opt-in via the URL query string `scrollspy=on`. When active,
   subpage.js removes the `hidden` attribute on .page-section-indicator
   and updates the label inside [data-section-label] as the user scrolls.

   Hidden by default and on viewports >= 1100px (the desktop layout
   already has the .subpage-toc sticky sidebar for context; the
   scrollspy is a mobile-only convenience). On touch + desktop-preview,
   the bar becomes a sticky strip at the top of the viewport, 44px tall
   (touch-target floor).

   Sits at z-index 50 — above the sticky header but below the offline
   indicator (z-index 200, Phase 3 / Task 3.3) and the bottom tab bar
   (z-index 100, Phase 2 / Task 2.3). The order in the stack:
     offline indicator (200) > bottom tab bar (100) > scrollspy (50) >
     main content.

   The label uses a single-line ellipsis; if the section title is long,
   only the first ~30 characters show. The label is also exposed via
   aria-live="polite" so screen readers announce the section change.
   The component is keyboard- and pointer-friendly; it doesn't capture
   focus, just sits there as a passive indicator. */
.page-section-indicator {
  position: sticky;
  top: 0;
  z-index: 50;
  height: 44px;
  display: flex;
  align-items: center;
  padding: 0 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--border-subtle);
  color: var(--heading);
  font-size: .9rem;
  font-weight: 600;
  letter-spacing: .01em;
  box-shadow: 0 1px 0 rgba(0, 0, 0, .04);
}
.page-section-indicator[hidden] { display: none; }
.page-section-indicator-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
@media (min-width: 1100px) {
  .page-section-indicator { display: none !important; }
}


/* =====================================================================
   Mobile "On this page" link (Phase 5 / Task 5.6 — architecture
   exception E1 in the plan). The shell template emits
   <details class="on-this-page-mobile"> at the top of <main> on every
   subpage that has at least one section anchor (i.e. most service
   and expertise pages). The <details>/<summary> primitives give
   tap-to-expand behaviour for free, with no JS. Native + accessible.

   Visibility rules:
     - Default (desktop, viewport >= 768px): display: none. The
       desktop sidebar (.subpage-toc) is the primary TOC surface.
     - Mobile (viewport < 768px) and ?mobile=on preview: visible.
       Hides on desktop, shows on touch — same gating pattern as the
       bottom tab bar and offline indicator (touch media query +
       desktop preview attribute).

   Touch-target floor (Phase 1 / Task 1.2): the summary is 44px tall
   so it's a comfortable tap target on phones. The list items inside
   are 40px tall — slightly under the 44px floor because they're
   in-document anchors, not primary navigation. The list item height
   matches the project's `<li>` baseline (used by the .more-list
   destinations list and the desktop TOC), so we keep it consistent.

   Color tokens: surface, border-subtle, text-soft are all already
   theme-aware (light + dark); no per-theme overrides needed. */

.on-this-page-mobile {
  display: none;
}
@media (max-width: 767px), (hover: none), (pointer: coarse) {
  html.subpage-layout-v2 .on-this-page-mobile {
    display: block;
    margin: 1rem 1rem 0;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius, 8px);
    background: var(--surface, #fff);
    overflow: hidden;
    /* Sticky positioning: TOC floats under the site-header (which is
     * sticky; top:0; z-index:50; ~99px tall on touch after the mobile
     * nav scroll refactor — branding row + horizontal-scroll nav row).
     * The TOC sits at top: 100px initially in its natural position
     * (right below the hero), then sticks at top: 100px once the user
     * scrolls past. z-index 49 stays below the header (50) so the
     * header's blurred backdrop remains visually layered on top of the
     * TOC's top edge.
     *
     * NAV MORPH (Phase B / toc-merged): when the TOC would visually
     * bump against the header bottom, it merges into the header as
     * its second row. The header collapses (site-nav row fades out,
     * saving ~44px), and the TOC's sticky offset drops to the new
     * collapsed-header height. The card styling (border, radius,
     * surface background, side margins) is dropped so the TOC reads
     * as part of the header rather than a separate widget below it. */
    position: sticky;
    top: 100px;
    z-index: 49;
    transition: top 280ms cubic-bezier(.4,0,.2,1),
                background 280ms ease,
                border-color 280ms ease,
                margin 280ms cubic-bezier(.4,0,.2,1),
                border-radius 280ms ease;
  }
  /* Merged state — TOC is the header's second row. The card
   * chrome disappears, side margins collapse to 0, and the sticky
   * top overlaps the header by 1px (top: 54px on a 54.67px
   * header) to guarantee no transparent gap at the seam.
   *
   * The widget uses one of the deepest navy / slate stops from
   * the extended palette (navy-925 / slate-300) so it sits
   * clearly darker than the header in both themes — the user
   * asked for the widget to be "darker than the header in both
   * light and dark mode" without losing the airy light-mode feel.
   * navy-925 is essentially black-navy, slate-300 is a soft
   * mid-gray-blue that's distinct from white without being heavy. */
  html.toc-merged.subpage-layout-v2 .on-this-page-mobile {
    top: 54px;
    margin: 0;
    border-color: transparent;
    border-radius: 0;
  }
  html.toc-merged.subpage-layout-v2 .on-this-page-mobile {
    background: var(--noetroniq-navy-925, #00080c);
    box-shadow: 0 4px 14px -2px rgba(0, 0, 0, 0.55);
    border-bottom: 0;
  }
  :root[data-theme='light'] html.toc-merged.subpage-layout-v2 .on-this-page-mobile,
  html.toc-merged[data-theme='light'].subpage-layout-v2 .on-this-page-mobile {
    background: var(--noetroniq-slate-300, #d5dbe4);
    box-shadow: 0 4px 14px -2px rgba(0, 0, 0, 0.18);
  }
  /* Drop shadow (theme-tuned) further separates the widget from
    * the header in both themes. The header's `border-bottom: 1px
    * solid #072640` (dark) / `var(--border)` (light) is hidden when
    * merged — that hairline was the source of the "thin translucent
    * line at the bottom of the header" the user reported. Without
    * it, the widget sits flush against the header with no seam. */
   /* Merged state — leaner. Earlier iterations tried 32, 36, 44.
    * Going further to 28px brings the widget closer to a true
    * "compact header chrome" element rather than a content widget.
    * The label sits comfortably in this band — 0.8rem text (~13px
    * font) with a 7-8px visual gap above and below. Padding stays
    * zero vertical so flexbox centers the title+chevron perfectly. */
   html.toc-merged.subpage-layout-v2 .on-this-page-mobile > summary {
     min-height: 28px;
     font-size: .8rem;
     padding: 0 1.25rem;
     color: #f5f7fa;
   }
  /* Hide the header's border-bottom AND box-shadow when merged —
   * both are the source of the visible seam at the header/widget
   * boundary. The header's box-shadow extends below the header
   * (offset-y: 4px in both themes; spread: -8 to -10px) and casts
   * a soft dark band on whatever sits below — when the widget
   * sits flush against the header, that shadow shows up as a
   * darker stripe right at the seam. The widget's own drop
   * shadow replaces it as the visual separator, with cleaner
   * alignment (the shadow lifts the widget off the header
   * without drawing an actual line at the boundary).
   *
   * Specificity: the dark-mode header rule is `.site-header { ... }`
   * with one class. The light-mode header rule is
   * `:root[data-theme='light'] .site-header { ... }` with an attr
   * selector + class. We match the light-mode selector shape here so
   * our override wins for both themes. */
  html.toc-merged .site-header,
  html.toc-merged[data-theme='light'] .site-header,
  :root[data-theme='light'] html.toc-merged .site-header {
    border-bottom-color: transparent;
    box-shadow: none;
  }
  /* Belt-and-braces: the light-mode scrolled state also has its own
   * box-shadow rule (`0 4px 16px -8px rgba(0,0,0,.18)`) — make sure
   * it's also killed when merged. */
  :root[data-theme='light'] html.toc-merged .site-header.scrolled,
  html.toc-merged[data-theme='light'] .site-header.scrolled {
    box-shadow: none;
  }
  /* Merged state — even thinner. Earlier we tried 44px, then 36px.
   * Going further to 32px brings the widget closer to a true
   * "compact header chrome" element rather than a content widget.
   * The font also shrinks further (0.8rem) to keep the visual
   * weight proportionate to the band height. The summary gets an
   * extra bottom padding (12px) so the widget's solid background
   * extends a few pixels below the text — a "tray" of opaque
   * background that prevents scrolled content from appearing
   * flush with the section title in dark mode (where both widget
   * and content are dark, a sharp transition reads as a seam
   * rather than a boundary). */
  html.toc-merged.subpage-layout-v2 .on-this-page-mobile > summary::after {
    color: rgba(245,247,250,.7);
  }
  /* LIGHT MODE: the widget is now a light slate band, so the text
   * reverts to dark — matches the user's "light and airy" feedback
   * (no light text on a light surface; airy means light text-on-dark
   * doesn't apply here). */
  :root[data-theme='light'] html.toc-merged.subpage-layout-v2 .on-this-page-mobile > summary,
  html.toc-merged[data-theme='light'].subpage-layout-v2 .on-this-page-mobile > summary {
    color: var(--noetroniq-slate-950, #1b2733);
  }
  :root[data-theme='light'] html.toc-merged.subpage-layout-v2 .on-this-page-mobile > summary::after,
  html.toc-merged[data-theme='light'].subpage-layout-v2 .on-this-page-mobile > summary::after {
    color: rgba(27, 39, 51, 0.55);
  }
  /* Current-section title ellipsis: when the summary label shows
   * the user's current section name (longer than "On this page"),
   * the line is single-row with text-overflow ellipsis so the
   * widget stays a flat pill instead of wrapping to two lines. */
  html.subpage-layout-v2 .on-this-page-mobile-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 1 1 auto;
  }
  /* Merged-state expanded list: sits below the now-darker band,
   * uses the page surface so the list reads as content rather
   * than another header row. Top hairline marks the seam.
   * Light mode: the lighter widget uses the existing border-subtle
   * hairline so the seam reads naturally on a pale surface. */
  html.toc-merged.subpage-layout-v2 .on-this-page-mobile-list {
    border-top: 1px solid rgba(255,255,255,.08);
  }
  :root[data-theme='light'] html.toc-merged.subpage-layout-v2 .on-this-page-mobile-list,
  html.toc-merged[data-theme='light'].subpage-layout-v2 .on-this-page-mobile-list {
    border-top: 1px solid var(--noetroniq-slate-300, #d5dbe4);
  }
  /* The ?mobile=on preview switch on a desktop viewport should also
   * surface this — same data-mobile-preview attribute the bottom-tab-
   * bar uses. */
  html.subpage-layout-v2[data-mobile-preview='on'] .on-this-page-mobile {
    display: block;
  }
}
html.subpage-layout-v2 .on-this-page-mobile > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: 0 1rem;
  min-height: var(--noetroniq-target-min, 44px);
  cursor: pointer;
  list-style: none;
  user-select: none;
  color: var(--heading, #1a1a1a);
  font-size: .95rem;
  font-weight: 600;
  -webkit-tap-highlight-color: transparent;
}
html.subpage-layout-v2 .on-this-page-mobile > summary::-webkit-details-marker { display: none; }
html.subpage-layout-v2 .on-this-page-mobile > summary::marker { display: none; content: ''; }
html.subpage-layout-v2 .on-this-page-mobile > summary::after {
  content: '\2304';  /* small down arrow */
  font-size: .8rem;
  color: var(--text-soft, #666);
  transition: transform 180ms ease;
}
html.subpage-layout-v2 .on-this-page-mobile[open] > summary::after {
  transform: rotate(180deg);
}
html.subpage-layout-v2 .on-this-page-mobile-list {
  list-style: none;
  padding: 0 1rem .75rem;
  margin: 0;
  border-top: 1px solid var(--border-subtle);
}
html.subpage-layout-v2 .on-this-page-mobile-list li {
  margin: 0;
  border-bottom: 1px solid var(--border-subtle);
}
html.subpage-layout-v2 .on-this-page-mobile-list li:last-child {
  border-bottom: 0;
}
html.subpage-layout-v2 .on-this-page-mobile-list a {
  display: flex;
  align-items: center;
  min-height: 40px;
  padding: .35rem .25rem;
  color: var(--text, #222);
  text-decoration: none;
  font-size: .92rem;
  line-height: 1.4;
}
html.subpage-layout-v2 .on-this-page-mobile-list a:hover,
html.subpage-layout-v2 .on-this-page-mobile-list a:focus-visible {
  color: var(--heading-accent, #b8881e);
}
@media (min-width: 1100px) {
  /* Belt-and-suspenders: even if the touch media query happens to
   * match (e.g. some laptop trackpads report pointer: coarse), the
   * wide viewport definitively hides the mobile TOC. */
  html.subpage-layout-v2 .on-this-page-mobile { display: none; }
}
/* Reduced motion: kill the summary arrow rotation. */
@media (prefers-reduced-motion: reduce) {
  html.subpage-layout-v2 .on-this-page-mobile > summary::after { transition: none; }
}
