/* ============================================================================
   HiltLock, global stylesheet

   Replaces the Trampolyne AI system. The register change is the point: that
   site read as a consultancy (soft gradients, 22px radii, abstract hero art,
   54px/800 display type). This one reads as a technical product.

   Design mandate, HiltLock_Strategic_Plan.docx §4A:
     "Denser and more technical, monospace accents for findings and payloads,
      real artifacts instead of stock abstraction, tighter type,
      evidence-forward hierarchy. The reader should feel they are looking at
      the work, not at a brochure about the work."

   Structure:
     01 Fonts          06 Buttons          11 Tables
     02 Tokens         07 Artifact frame   12 Cards and grids
     03 Reset          08 Paper register   13 Forms
     04 Typography     09 Severity chips   14 Footer
     05 Layout, nav    10 Panels, tiles    15 Legacy compat, utilities
   ========================================================================== */

/* ==========================================================================
   01 FONTS, self-hosted latin subset
   Self-hosted rather than Google Fonts: removes a third-party connection on
   every page load, helps LCP, and avoids the DPDP/GDPR question about Google
   receiving visitor IPs. Synced by scripts/sync-brand-assets.js.
   ========================================================================== */
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/geist-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/fonts/geist-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/assets/fonts/geist-latin-600-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/geist-latin-700-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/geist-mono-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/assets/fonts/geist-mono-latin-500-normal.woff2") format("woff2");
}

/* ==========================================================================
   02 TOKENS
   Mirrors brand/tokens.css. Contrast ratios are computed, not estimated.
   ========================================================================== */
:root {
  /* Ground and surfaces. Neutral graphite, deliberately not navy: blue-black
     plus cyan is the default AI-startup palette, neutral black plus a warm
     signal reads as forensic instrumentation. */
  --ink-900: #08090b;
  --ink-850: #0c0e11;
  --ink-800: #111419;
  --ink-700: #171b21;
  --ink-600: #1f242c;

  /* Hairlines. Depth comes from borders and surface steps, not from shadow. */
  --line: #262c35;
  --line-strong: #333a45;
  --line-faint: #1a1e25;

  /* Text, ratios against --ink-900 */
  --text-hi: #f2f4f7;   /* 18.08:1 */
  --text-mid: #a9b1bd;  /*  9.21:1 */
  --text-lo: #7a8390;   /*  5.20:1 on ink-900, 4.81 on ink-800, 4.51 on ink-700.
                            Was #6e7784 at 4.40:1, which failed AA everywhere. */

  /* Ember. Interactive state and High severity: in a red-teaming brand the
     accent is the finding colour. Takes near-black text at 6.39:1 as a fill,
     which pure cyan cannot do (3.12:1 with white). */
  --ember-400: #ff7a47; /*  7.71:1 */
  --ember-500: #ff5a1f; /*  6.39:1, primary */
  --ember-600: #e14310; /*  pressed; the logo mark on paper */
  --ember-700: #c43a0c; /*  4.99:1 on paper, accent text on light grounds */
  --ember-tint: rgba(255, 90, 31, 0.12);
  --ember-edge: rgba(255, 90, 31, 0.32);

  /* Severity and state. Warm means found, cool means fixed. Never decorative. */
  --sev-critical: #ff2d55;
  --sev-high: #ff5a1f;
  --sev-medium: #f0a93b;
  --sev-low: #7c8896;
  --verify-500: #35d0a5;
  --info-500: #6ea8fe;
  --verify-tint: rgba(53, 208, 165, 0.12);
  --crit-tint: rgba(255, 45, 85, 0.12);

  /* Paper, the document register: report excerpts, PDF collateral, print. */
  --paper: #f7f8fa;
  --paper-sunk: #eceff3;
  --paper-line: #e3e7ec;
  --paper-text: #14171c;
  --paper-mid: #4a5260;

  /* Type */
  --font-sans: "Geist", "Inter Tight", "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", "JetBrains Mono", "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Geometry. 6px is the maximum radius in this system. */
  --r-sm: 3px;
  --r-md: 5px;
  --r-lg: 6px;
  --r-pill: 999px;

  /* One shadow token, for true overlays only. */
  --shadow-overlay: 0 12px 32px rgba(0, 0, 0, 0.55);

  --measure: 68ch;
  --container: 1180px;
  --nav-height: 60px;

  /* ---- Legacy aliases -------------------------------------------------
     assets/article.css, playbook.css and product-ui.css were written against
     the Trampolyne token names. Aliasing them here rebrands all 20 article
     pages from one place instead of editing each file. Note --accent-2 was
     purple; it now resolves to ember-400 so no purple survives anywhere.
     -------------------------------------------------------------------- */
  --accent: var(--ember-500);
  --accent-2: var(--ember-400);
  --border: var(--line);
  --border-soft: var(--line);
  --text-main: var(--text-hi);
  --text-sub: var(--text-mid);
  --radius-xl: var(--r-lg);
  --radius-lg: var(--r-lg);
  --radius-md: var(--r-md);
  --bg1: var(--ink-900);
  --bg2: var(--ink-900);
  --shadow-soft: none;
  --shadow-subtle: none;
}

/* ==========================================================================
   03 RESET
   ========================================================================== */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-height) + 16px);
}

body {
  font-family: var(--font-sans);
  background: var(--ink-900);
  color: var(--text-hi);
  font-size: 15.5px;
  line-height: 1.62;
  min-height: 100vh;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img,
svg,
video {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}

/* Focus is always visible and always ember. Never remove it. */
:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--ink-900), 0 0 0 4px var(--ember-500);
  border-radius: var(--r-sm);
}

::selection {
  background: var(--ember-500);
  color: #08090b;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ==========================================================================
   04 TYPOGRAPHY
   Compressed from Trampolyne: display caps at 44px not 54px, weight ceiling
   700 not 800. A brochure breathes; an instrument packs.
   ========================================================================== */
h1 {
  font-size: clamp(30px, 4.2vw, 44px);
  line-height: 1.06;
  font-weight: 700;
  letter-spacing: -0.022em;
}

h2 {
  font-size: clamp(23px, 2.9vw, 31px);
  line-height: 1.14;
  font-weight: 600;
  letter-spacing: -0.018em;
}

h3 {
  font-size: clamp(17px, 1.9vw, 20px);
  line-height: 1.28;
  font-weight: 600;
  letter-spacing: -0.012em;
}

h4 {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.008em;
}

p {
  max-width: var(--measure);
  color: var(--text-mid);
}

.lede {
  font-size: 17px;
  color: var(--text-hi);
}

strong { color: var(--text-hi); font-weight: 600; }

/* Every metric, count and table figure. Numbers that shift width read as
   unserious. */
.tnum,
.tile .num,
td.num,
.stat .num {
  font-variant-numeric: tabular-nums;
}

code,
kbd,
samp {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: var(--ink-700);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 1px 5px;
  color: var(--text-hi);
}

/* The system's most characteristic device. Uppercase tracked mono labels are
   what make a page read as instrumentation. Never for sentences. */
.micro,
.kicker,
.eyebrow,
.section-tag {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.085em;
  color: var(--text-lo);
}

.micro .n,
.kicker .n { color: var(--ember-500); }

.mono { font-family: var(--font-mono); }

a.inline {
  color: var(--ember-500);
  border-bottom: 1px solid var(--ember-edge);
}
a.inline:hover { color: var(--ember-400); border-bottom-color: var(--ember-400); }

/* Prose lists. Ember tick rather than a bullet glyph. */
ul.ticks,
ol.ticks {
  list-style: none;
  max-width: var(--measure);
}
ul.ticks li,
ol.ticks li {
  position: relative;
  padding-left: 18px;
  color: var(--text-mid);
  margin-bottom: 8px;
}
ul.ticks li::before,
ol.ticks li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.62em;
  width: 5px;
  height: 1px;
  background: var(--ember-500);
}

/* ==========================================================================
   05 LAYOUT AND NAV
   ========================================================================== */
.container {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 24px;
}

.section {
  padding: 88px 0;              /* was 120px+ */
  border-top: 1px solid var(--line-faint);
}
.section:first-of-type { border-top: none; }
.section.tight { padding: 56px 0; }
.section.band { background: var(--ink-850); }

.section-head { margin-bottom: 32px; }
.section-head h2 { margin-top: 10px; }
.section-head p { margin-top: 12px; }

/* The one texture: a 22px hairline point grid. No image asset. This replaces
   abstract hero illustration, which the plan retires. */
.grid-bg {
  background-image: radial-gradient(var(--line) 1px, transparent 1px);
  background-size: 22px 22px;
}

.rule {
  height: 1px;
  background: var(--line-faint);
  border: none;
}
.rule-ember {
  width: 56px;
  height: 2px;
  background: var(--ember-500);
  border: none;
}

/* ---- header / nav ---- */
header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(8, 9, 11, 0.9);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--line);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  height: var(--nav-height);
}

.nav-logo {
  display: flex;
  align-items: center;
  flex: none;
}
.nav-logo img { height: 22px; width: auto; }

.nav-links {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-left: auto;
}

.nav-links > a,
.nav-sections > summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 11px;
  border-radius: var(--r-md);
  font-size: 14px;
  font-weight: 500;
  color: var(--text-mid);
  cursor: pointer;
  list-style: none;
  white-space: nowrap;
}
.nav-links > a:hover,
.nav-sections > summary:hover {
  color: var(--text-hi);
  background: var(--ink-700);
}
.nav-links > a.active { color: var(--ember-500); }
.nav-sections > summary::-webkit-details-marker { display: none; }

.nav-sections { position: relative; }
.nav-sections > summary::after {
  content: "";
  width: 5px;
  height: 5px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
  opacity: 0.6;
}

.nav-submenu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  min-width: 268px;
  background: var(--ink-800);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-overlay);
  padding: 6px;
  z-index: 10;
}
.nav-submenu a {
  display: block;
  padding: 9px 11px;
  border-radius: var(--r-md);
  font-size: 14px;
  color: var(--text-mid);
}
.nav-submenu a:hover { background: var(--ink-700); color: var(--text-hi); }
.nav-submenu .sub {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-lo);
  margin-top: 2px;
}

.nav-cta {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
}

/* Contact lives in the CTA button on desktop, so the duplicate nav link only
   appears once the button is hidden. */
.mobile-only-link { display: none; }

.nav-toggle {
  display: none;
  width: 38px;
  height: 38px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  position: relative;
}
.nav-toggle span,
.nav-toggle span::before,
.nav-toggle span::after {
  position: absolute;
  left: 50%;
  width: 16px;
  height: 1.5px;
  background: var(--text-hi);
  transform: translateX(-50%);
  content: "";
}
.nav-toggle span { top: 50%; margin-top: -0.75px; }
.nav-toggle span::before { top: -5px; left: 0; transform: none; }
.nav-toggle span::after { top: 5px; left: 0; transform: none; }

@media (max-width: 1000px) {
  .nav-toggle { display: block; }
  .desktop-only { display: none !important; }
  .mobile-only-link { display: block; }
  .nav-links {
    display: none;
    position: absolute;
    top: var(--nav-height);
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    background: var(--ink-850);
    border-bottom: 1px solid var(--line);
    padding: 12px 24px 20px;
    max-height: calc(100vh - var(--nav-height));
    overflow-y: auto;
  }
  .nav-links.open { display: flex; }
  .nav-sections > summary { padding: 10px 11px; }
  .nav-submenu {
    position: static;
    box-shadow: none;
    border: none;
    background: transparent;
    padding: 2px 0 6px 11px;
    min-width: 0;
  }
}

/* ==========================================================================
   06 BUTTONS
   One primary per view. Ember fill with near-black text at 6.39:1.
   Never white text on ember, that is 3.12:1 and fails AA.
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.005em;
  padding: 10px 18px;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}

.btn-primary { background: var(--ember-500); color: #08090b; }
.btn-primary:hover { background: var(--ember-400); }
.btn-primary:active { background: var(--ember-600); }

.btn-secondary {
  background: var(--ink-700);
  color: var(--text-hi);
  border-color: var(--line-strong);
}
.btn-secondary:hover { background: var(--ink-600); border-color: var(--text-lo); }

.btn-ghost {
  background: transparent;
  color: var(--ember-500);
  border-color: var(--ember-edge);
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.btn-ghost:hover { background: var(--ember-tint); }

.btn-lg { padding: 13px 22px; font-size: 15px; }
.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-top: 24px;
}

/* ==========================================================================
   07 ARTIFACT FRAME
   The component that carries the repositioning. The plan asks for "real
   artifacts instead of stock abstraction", so the primary visual unit is a
   framed piece of evidence with a mono chrome bar, not an illustration.
   ========================================================================== */
.artifact {
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--ink-850);
}

.artifact-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--ink-700);
  border-bottom: 1px solid var(--line);
  padding: 8px 13px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.02em;
  color: var(--text-lo);
}
.artifact-bar .fname { color: var(--text-mid); }

.artifact-body {
  font-family: var(--font-mono);
  font-size: 12.5px;
  line-height: 1.72;
  padding: 15px 16px;
  overflow-x: auto;
  white-space: pre;
  color: var(--text-mid);
  -webkit-overflow-scrolling: touch;
}

.artifact-body .c-dim { color: var(--text-lo); }
.artifact-body .c-hi { color: var(--text-hi); }
.artifact-body .c-crit { color: var(--sev-critical); font-weight: 600; }
.artifact-body .c-ember { color: var(--ember-400); }
.artifact-body .c-ok { color: var(--verify-500); }
.artifact-body .c-info { color: var(--info-500); }

/* Redaction is a solid block, not a blur. It is a credibility signal: it says
   the artifact is real enough to need redacting. */
.artifact-body .redact,
.redact {
  background: var(--text-lo);
  color: transparent;
  border-radius: 2px;
  user-select: none;
}

/* ==========================================================================
   08 PAPER REGISTER
   Not a light mode for the site. The document register, so an artifact looks
   like a real deliverable rather than a web section.
   ========================================================================== */
.paper-doc {
  background: var(--paper);
  color: var(--paper-text);
  border: 1px solid var(--paper-line);
  border-radius: var(--r-lg);
  padding: 26px 28px;
}
.paper-doc .doc-kicker {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--paper-mid);
  padding-bottom: 10px;
  border-bottom: 1px solid var(--paper-line);
  margin-bottom: 16px;
}
.paper-doc h3,
.paper-doc h4 { color: var(--paper-text); }
.paper-doc p { color: var(--paper-mid); max-width: none; }
.paper-doc strong { color: var(--paper-text); }
.paper-doc .rule { background: var(--paper-line); margin: 16px 0; }
.paper-doc a.inline { color: var(--ember-700); border-bottom-color: var(--ember-700); }
.paper-doc code {
  background: var(--paper-sunk);
  border-color: var(--paper-line);
  color: var(--paper-text);
}

/* ==========================================================================
   09 SEVERITY CHIPS
   Pill radius is permitted here and nowhere else. The dot prefix keeps them
   legible when colour alone is not available to the reader.
   ========================================================================== */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  padding: 3px 9px 3px 7px;
  border-radius: var(--r-pill);
  white-space: nowrap;
  border: 1px solid;
}
.chip::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.chip-crit { color: var(--sev-critical); background: var(--crit-tint); border-color: rgba(255, 45, 85, 0.32); }
.chip-high { color: var(--sev-high); background: var(--ember-tint); border-color: var(--ember-edge); }
.chip-med  { color: var(--sev-medium); background: rgba(240, 169, 59, 0.12); border-color: rgba(240, 169, 59, 0.32); }
.chip-low  { color: var(--sev-low); background: rgba(124, 136, 150, 0.14); border-color: rgba(124, 136, 150, 0.32); }
.chip-ok   { color: var(--verify-500); background: var(--verify-tint); border-color: rgba(53, 208, 165, 0.32); }
.chip-info { color: var(--info-500); background: rgba(110, 168, 254, 0.12); border-color: rgba(110, 168, 254, 0.32); }

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

/* ==========================================================================
   10 PANELS AND EVIDENCE TILES
   ========================================================================== */
.panel {
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 20px 22px;
}
.panel-ember { background: var(--ember-tint); border-color: var(--ember-edge); }
.panel-crit  { background: var(--crit-tint); border-color: rgba(255, 45, 85, 0.3); }
.panel-ok    { background: var(--verify-tint); border-color: rgba(53, 208, 165, 0.3); }

.tile {
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-left: 2px solid var(--ember-500);
  border-radius: 0 var(--r-lg) var(--r-lg) 0;
  padding: 17px 19px;
}
.tile .num {
  font-family: var(--font-mono);
  font-size: 29px;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--text-hi);
  font-variant-numeric: tabular-nums;
}
.tile .lbl {
  font-family: var(--font-mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.085em;
  color: var(--text-lo);
  margin-top: 7px;
}

/* Published price. Both currencies always visible and static: no edge geo
   logic, no cache fragmentation, the same content for Googlebot, and no
   discoverable gap between what an Indian and an overseas buyer is quoted. */
.price {
  padding-top: 16px;
  border-top: 1px solid var(--line);
}
.price-main {
  display: block;
  font-family: var(--font-mono);
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text-hi);
  font-variant-numeric: tabular-nums;
}
.price-alt {
  display: block;
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--text-lo);
  margin-top: 5px;
  font-variant-numeric: tabular-nums;
}

blockquote.pull {
  border-left: 2px solid var(--ember-500);
  padding: 4px 0 4px 18px;
  color: var(--text-hi);
  font-size: 17px;
  max-width: var(--measure);
}
blockquote.pull cite {
  display: block;
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-style: normal;
  color: var(--text-lo);
  margin-top: 10px;
}

/* ==========================================================================
   11 TABLES
   ========================================================================== */
.table-wrap { overflow-x: auto; border-radius: var(--r-lg); border: 1px solid var(--line); }

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
th {
  text-align: left;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.085em;
  color: var(--text-lo);
  background: var(--ink-700);
  border-bottom: 1px solid var(--line);
  padding: 10px 14px;
  white-space: nowrap;
}
td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--line-faint);
  color: var(--text-mid);
  vertical-align: top;
}
tbody tr:last-child td { border-bottom: none; }
td.hi { color: var(--text-hi); font-weight: 500; }
td.was { color: var(--text-lo); }

/* ==========================================================================
   12 CARDS AND GRIDS
   ========================================================================== */
.grid { display: grid; gap: 16px; }

/* Grid and flex items default to min-width:auto, which means they refuse to
   shrink below their content's min-content width. An artifact frame contains
   `white-space: pre` payloads, so its min-content width is large, which
   inflated the whole column and pushed every sibling off-screen. This was the
   cause of a 133px document overflow on the homepage at 375px.
   The children still scroll their own content; they just no longer widen the
   layout to avoid it. */
.grid > *,
.btn-row > *,
.artifact,
.artifact-bar > * {
  min-width: 0;
}
@media (min-width: 720px) {
  .grid.two { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 900px) {
  .grid.three { grid-template-columns: repeat(3, 1fr); }
  .grid.four { grid-template-columns: repeat(4, 1fr); }
  .grid.split { grid-template-columns: 1.05fr 0.95fr; gap: 40px; align-items: center; }
}

.card {
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 22px;
}
.card:hover { border-color: var(--line-strong); }
.card h3 { margin-bottom: 8px; }
.card p { font-size: 14.5px; max-width: none; }
a.card { display: block; }
a.card:hover { border-color: var(--ember-edge); }

.card .step {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.085em;
  color: var(--ember-500);
  margin-bottom: 12px;
}

/* ==========================================================================
   13 FORMS
   ========================================================================== */
label {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.085em;
  color: var(--text-lo);
  margin-bottom: 7px;
}

input[type="text"],
input[type="email"],
input[type="tel"],
select,
textarea {
  width: 100%;
  font-family: var(--font-sans);
  font-size: 15px;
  color: var(--text-hi);
  background: var(--ink-600);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  padding: 10px 12px;
}
input::placeholder,
textarea::placeholder { color: var(--text-lo); }
input:focus,
select:focus,
textarea:focus { border-color: var(--ember-500); }
textarea { min-height: 130px; resize: vertical; }

.field { margin-bottom: 18px; }
.field-help { font-size: 13px; color: var(--text-lo); margin-top: 6px; }

.form-note {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-mid);
  margin-top: 14px;
  line-height: 1.55;
}

/* Pedigree logo row. Desaturated by default so it reads as provenance rather
   than as a customer-logo wall, which would be a different (and unearned)
   claim. */
.logo-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 28px 40px;
}
.logo-row img {
  height: 22px;
  width: auto;
  filter: grayscale(1) brightness(1.7);
  opacity: 0.62;
}

/* Success modal for the contact form.
   main.js toggles inline display:flex/none and puts .modal-open on <body>, so
   the base state must be display:none and the flex centring lives here. */
.modal {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 200;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(8, 9, 11, 0.78);
  backdrop-filter: blur(4px);
}

.modal-content {
  background: var(--ink-800);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-overlay);
  padding: 28px 30px;
  max-width: 440px;
  width: 100%;
}

body.modal-open { overflow: hidden; }

/* ==========================================================================
   14 FOOTER
   ========================================================================== */
footer {
  border-top: 1px solid var(--line);
  background: var(--ink-850);
  padding: 56px 0 40px;
  margin-top: 0;
}

.footer-grid {
  display: grid;
  gap: 32px;
  margin-bottom: 40px;
}
@media (min-width: 760px) {
  .footer-grid { grid-template-columns: 1.4fr 1fr 1fr 1fr; }
}

.footer-brand img { height: 20px; width: auto; margin-bottom: 14px; }
.footer-brand p { font-size: 14px; max-width: 34ch; }

.footer-col h5 {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.085em;
  color: var(--text-lo);
  margin-bottom: 12px;
}
.footer-col a {
  display: block;
  font-size: 14px;
  color: var(--text-mid);
  padding: 4px 0;
}
.footer-col a:hover { color: var(--ember-500); }

.footer-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  justify-content: space-between;
  align-items: center;
  padding-top: 22px;
  border-top: 1px solid var(--line-faint);
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-lo);
}

/* ==========================================================================
   15 LEGACY COMPAT AND UTILITIES
   Class names kept alive so the existing article and playbook pages keep
   working while they are rewritten. Gradients are neutralised rather than
   removed, so old markup degrades to solid ember instead of breaking.
   ========================================================================== */
.gradient-text {
  background: none;
  -webkit-background-clip: initial;
  background-clip: initial;
  -webkit-text-fill-color: currentColor;
  color: var(--ember-500);
}

.section-divider { height: 1px; background: var(--line-faint); border: none; }

.content-width { max-width: var(--measure); }

.callout {
  background: var(--ember-tint);
  border: 1px solid var(--ember-edge);
  border-radius: var(--r-lg);
  padding: 18px 20px;
}

.stat .num {
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--text-hi);
}

/* Utilities */
.center { text-align: center; }
.center p { margin-left: auto; margin-right: auto; }
.nowrap { white-space: nowrap; }
.mt-0 { margin-top: 0; }
.mt-2 { margin-top: 8px; }
.mt-3 { margin-top: 12px; }
.mt-4 { margin-top: 16px; }
.mt-5 { margin-top: 24px; }
.mt-6 { margin-top: 32px; }
.mt-7 { margin-top: 48px; }
.mb-4 { margin-bottom: 16px; }
.mb-5 { margin-bottom: 24px; }
.mb-6 { margin-bottom: 32px; }
.dim { color: var(--text-mid); }
.dimmer { color: var(--text-lo); }
.hi { color: var(--text-hi); }
.ember { color: var(--ember-500); }
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Skip link, keyboard users land here first */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--ember-500);
  color: #08090b;
  padding: 10px 16px;
  font-weight: 600;
  z-index: 200;
}
.skip:focus { left: 8px; top: 8px; }

/* ==========================================================================
   PRINT
   Findings and playbooks get printed and forwarded. Send them to the paper
   register rather than burning ink on a graphite ground.
   ========================================================================== */
@media print {
  body { background: #fff; color: #000; font-size: 11pt; }
  header, footer, .nav, .btn-row, .skip { display: none !important; }
  .section { padding: 12pt 0; border: none; }
  .panel, .card, .artifact, .tile {
    border: 1px solid #ccc;
    background: #fff;
    color: #000;
  }
  .artifact-body { color: #000; white-space: pre-wrap; }
  a { color: #000; text-decoration: underline; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; }
}

/* ==========================================================================
   16 RESPONSIVE
   Added after a real-browser audit (scripts/audit-responsive.js) found actual
   overflow at 375, 390 and 412px. The stylesheet previously had no mobile
   refinement beyond the nav breakpoint.
   ========================================================================== */

/* Long unbreakable strings (hashes, record names, URLs) in inline code were
   able to push their container wider than the viewport. */
code {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* The artifact bar puts a filename and a status on one row. A long filename
   should truncate rather than widen the frame. */
.artifact-bar .fname {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The paper document kicker is the same two-up pattern. */
.paper-doc .doc-kicker {
  flex-wrap: wrap;
}

@media (min-width: 520px) {
  /* Four stat tiles stacked one-per-row eats most of a phone screen. */
  .grid.four { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 719px) {
  /* Section rhythm is tuned for desktop. On a phone it reads as dead space. */
  .section { padding: 56px 0; }
  .section.tight { padding: 40px 0; }
  .section-head { margin-bottom: 24px; }
  .container { padding: 0 18px; }

  /* Keep payload lines readable without forcing a horizontal scroll for every
     artifact. They still scroll when genuinely wider. */
  .artifact-body { font-size: 11.5px; padding: 13px 13px; }
  .tile .num { font-size: 25px; }
  .price-main { font-size: 19px; }

  /* Full-width CTAs are easier to hit and stop odd two-up wrapping. */
  .btn-row .btn { width: 100%; }
  .btn-row { gap: 8px; }
}

@media (max-width: 419px) {
  .artifact-body { font-size: 10.5px; }
  .grid.four { grid-template-columns: 1fr; }
}

/* Tables in the article and playbook library have no scroll wrapper in their
   markup, and some are far wider than a phone: the widest overflowed by 422px.
   Naming individual table classes missed several, so this applies to every
   table and then opts out the ones already inside .table-wrap, which scrolls
   via the wrapper instead. Narrow widths only, so desktop layout is untouched.

   display:block is what makes the element a scroll container. The row and cell
   display values are untouched, so it still renders as a table. */
@media (max-width: 900px) {
  table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .table-wrap table {
    display: table;
    overflow-x: visible;
  }
}

/* Chips are nowrap by design so a severity label never breaks mid-word, but a
   long one ("Clause 5.10 Agents & Privileged Access") overflowed a 320px
   screen. Allow wrapping only where there is genuinely no room. */
@media (max-width: 520px) {
  .chip {
    white-space: normal;
    max-width: 100%;
  }
}
