/* CyberWeb Services site.
   Derived from the mark: 96.5% black, 2.8% acid green (#8CC63F, hue 130),
   hard geometry, no curves. Engineered, not editorial.
   Green fails text contrast on light ground (2.05:1) and passes on black
   (10.26:1), so on light ground it is only ever a fill or a marker.
   Rationale in .impeccable.md. */

/* Self-hosted. No third-party request, no font-loading dependency on a CDN.
   Archivo carries both a weight and a width axis, which is what the expanded
   display sizes use. Both faces are SIL Open Font License; see the LICENSE
   files alongside.

   latin and latin-ext are separate files gated by unicode-range, so the
   extended set only downloads if the page actually contains those glyphs.
   Costs nothing until an accented character appears, and then it does not
   fall back mid-word. */

@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url("/static/fonts/archivo-latin-wdth-normal.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url("/static/fonts/archivo-latin-ext-wdth-normal.woff2") format("woff2-variations");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/public-sans-latin-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/public-sans-latin-ext-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --ground: oklch(0.988 0.003 130);
  --ground-alt: oklch(0.955 0.005 130);
  --ink: oklch(0.17 0.008 130);
  --ink-mid: oklch(0.38 0.008 130);
  --ink-muted: oklch(0.53 0.008 130);
  --rule: oklch(0.86 0.006 130);
  --rule-strong: oklch(0.17 0.008 130);
  --accent: oklch(0.76 0.174 130);
  --accent-deep: oklch(0.5 0.125 130);
  --black: oklch(0.14 0.008 130);
  --on-black: oklch(0.95 0.004 130);
  --on-black-muted: oklch(0.68 0.008 130);
  --on-black-rule: oklch(1 0 0 / 0.16);

  /* Form fields on the black section. Separate from --on-black-rule because a
     thing you can type into has to out-read a thing that only divides. */
  --field-ground: oklch(1 0 0 / 0.05);
  --field-ground-hover: oklch(1 0 0 / 0.08);
  --field-rule: oklch(1 0 0 / 0.36);

  /* What the .field rules actually read, resolved here for the light ground and
     overridden back to the three values above inside .contact.

     The three above are for the black section, as their comment says, and for a
     while they were the only field colours there were. /request-training/ and
     /become-a-trainer/ then put forms on plain light sections, where --on-black
     text over a 5% white wash renders white on white: labels, typed text, field
     surface and the form's top rule all gone. Neither page has a dark band to
     put them on, and adding one would be the first on either, against the light
     ground the whole site is built on.

     Light values reuse existing tokens. --ground-alt is the inset surface, so a
     field reads as a surface without a drawn box. The underline is --ink-muted
     rather than --rule, keeping the distinction the comment above draws: a thing
     you type into out-reads a thing that only divides. --accent-deep because
     green is never text on light ground at 2.05:1. */
  --field-ink: var(--ink);
  --field-surface: var(--ground-alt);
  --field-surface-hover: oklch(0.935 0.005 130);
  --field-line: var(--ink-muted);
  --field-line-hover: var(--rule-strong);
  --field-arrow: var(--ink-muted);
  --field-top-rule: var(--rule);
  --field-lead: var(--accent-deep);
  --field-focus: var(--accent-deep);

  --display: "Archivo", ui-sans-serif, system-ui, sans-serif;
  --body: "Public Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;

  --space-2xs: 0.25rem;
  --space-xs: 0.5rem;
  --space-sm: 0.75rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --space-xl: 2rem;
  --space-2xl: 3rem;
  --space-3xl: 4rem;
  --space-4xl: 6rem;

  --t-label: 0.6875rem;
  --t-sm: 0.875rem;
  --t-base: clamp(1rem, 0.96rem + 0.2vw, 1.0938rem);
  --t-md: clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem);
  --t-lg: clamp(1.6rem, 1.35rem + 1.2vw, 2.25rem);
  --t-xl: clamp(2.1rem, 1.6rem + 2.3vw, 3.1rem);
  --t-hero: clamp(2.6rem, 1.5rem + 5.2vw, 5.25rem);

  --measure: 33rem;
  --gutter: 15rem;
  --pad: 1.5rem;
}

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

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

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--body);
  font-size: var(--t-base);
  font-weight: 400;
  line-height: 1.66;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

::selection {
  background: var(--accent);
  color: var(--black);
}

a {
  color: inherit;
  text-decoration-color: var(--rule);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  transition: color 160ms cubic-bezier(0.22, 1, 0.36, 1);
}

a:hover {
  color: var(--ink);
  text-decoration-color: var(--accent);
}

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

/* ── Editorial grid ─────────────────────────────────────────── */

.spread {
  display: grid;
  grid-template-columns:
    minmax(var(--pad), 1fr)
    minmax(0, var(--measure))
    minmax(0, var(--gutter))
    minmax(var(--pad), 1fr);
  column-gap: var(--space-2xl);
}

.spread > * {
  grid-column: 2;
}

/* Headings and ledes run across the measure and the margin gutter. Body copy
   stays in the measure so the line length remains readable. Without this,
   display type wraps against a 33rem column while 15rem of gutter sits empty. */
.spread > h2,
.spread > .lede {
  grid-column: 2 / 4;
}

.annotated {
  display: contents;
}

.annotated > * {
  grid-column: 2;
}

.annotated > .note {
  grid-column: 3;
}

.note {
  grid-column: 3;
  font-size: var(--t-sm);
  line-height: 1.55;
  color: var(--ink-muted);
  align-self: start;
  padding-top: 0.35em;
  max-width: 22ch;
  border-top: 2px solid var(--ink);
}

.note strong {
  display: block;
  font-family: var(--display);
  font-stretch: 118%;
  font-weight: 600;
  font-size: var(--t-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  margin: var(--space-sm) 0 var(--space-2xs);
}

.bleed {
  grid-column: 1 / -1;
}

.wide {
  grid-column: 2 / 4;
}

/* ── The chevron, lifted from the spider's abdomen ──────────── */

.chev {
  display: inline-block;
  width: 0.85em;
  height: 0.95em;
  background: var(--accent);
  clip-path: polygon(0 0, 100% 0, 100% 52%, 50% 100%, 0 52%);
  flex: 0 0 auto;
}

.chev-mute {
  background: var(--rule);
}

.chev-up {
  transform: rotate(180deg);
}

/* ── Type ───────────────────────────────────────────────────── */

.label {
  font-family: var(--display);
  font-stretch: 118%;
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

h1,
h2,
h3 {
  font-family: var(--display);
  font-stretch: 125%;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.015em;
  text-wrap: balance;
  margin: 0;
}

h2 {
  font-size: var(--t-xl);
}

h3 {
  font-family: var(--display);
  font-stretch: 112%;
  font-size: var(--t-md);
  font-weight: 600;
  letter-spacing: -0.005em;
  line-height: 1.2;
}

p {
  margin: 0 0 var(--space-lg);
  text-wrap: pretty;
  max-width: 68ch;
}

.lede {
  font-size: var(--t-md);
  line-height: 1.42;
  max-width: 52ch;
  font-weight: 400;
  color: var(--ink-mid);
}

.muted {
  color: var(--ink-muted);
}

/* ── Masthead ───────────────────────────────────────────────── */

/* Light ground. The mark is black artwork with a green chevron; inverting it
   for a dark bar would destroy the green, which is the only color in it. */
.masthead {
  background: var(--ground);
  border-bottom: 3px solid var(--rule-strong);
  padding: var(--space-md) 0;
}

.masthead > .inner {
  grid-column: 2 / 4;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm) var(--space-xl);
}

.wordmark {
  display: flex;
  align-items: center;
  text-decoration: none;
}

.wordmark img {
  height: 42px;
  width: auto;
  display: block;
}

.masthead nav {
  display: flex;
  margin-left: auto;
  flex-wrap: wrap;
  gap: var(--space-xs) var(--space-md);
  font-family: var(--display);
  font-stretch: 112%;
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.masthead nav a {
  text-decoration: none;
  color: var(--ink-muted);
  padding-bottom: var(--space-2xs);
  border-bottom: 2px solid transparent;
}

.masthead nav a:hover,
.masthead nav a[aria-current="page"] {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

/* Set by ui/masthead-cta.js while the page is already showing whatever the
   header button offers. That is a training request on most pages and a
   consultation on /for-organizations/; the script works it out from the button's
   own href. Here the header is not sticky, so the row closes up. */
.masthead-cta[data-cta-hidden] {
  display: none;
}

/* ── Hero ───────────────────────────────────────────────────── */

.hero {
  padding: clamp(var(--space-3xl), 9vh, var(--space-4xl)) 0
    clamp(var(--space-2xl), 6vh, var(--space-3xl));
}

.hero .label {
  margin-bottom: var(--space-lg);
}

.hero h1 {
  grid-column: 2 / 4;
  font-size: var(--t-hero);
  font-stretch: 125%;
  letter-spacing: -0.03em;
  max-width: 14ch;
  text-transform: uppercase;
  /* A safety net, not something any headline relies on. The measure is in
     ch, but the face is uppercase at 125% stretch, so a glyph is wider than
     the "0" that ch is measured from, and a word of roughly twelve letters or
     more is wider than the line box and runs off the right edge at phone
     widths. A draft headline carrying "CYBERSECURITY" overflowed by 76px at
     400px; it was reworded, because a hard break reads badly at this size.
     Keep the headlines short and this never fires.

     break-word only breaks a word that would otherwise overflow, so it is
     inert wherever the longest word fits. Do not add hyphens: auto here. It
     splits any word that crosses the end of a line, not only one too long to
     fit, and it turned the /for-organizations/ headline into NO-BODY and
     DO-ING in a reviewer's browser. A browser without a hyphenation
     dictionary ignores it, so a headless render will not show the damage. */
  overflow-wrap: break-word;
}

.hero .deck {
  font-size: var(--t-md);
  line-height: 1.4;
  color: var(--ink-mid);
  margin-top: var(--space-lg);
  max-width: 48ch;
}

.hero .deck em {
  font-style: normal;
  color: var(--ink);
  font-weight: 600;
}

.hero-home h1 {
  font-size: clamp(2.15rem, 1.5rem + 3.4vw, 4.25rem);
  text-transform: none;
  letter-spacing: -0.022em;
  max-width: 26ch;
  line-height: 1.06;
}

.hero-home .deck {
  max-width: 48ch;
}

.actions-hero {
  margin-top: var(--space-xl);
}

/* ── The correction ─────────────────────────────────────────── */

.correction {
  border-top: 3px solid var(--rule-strong);
  border-bottom: 3px solid var(--rule-strong);
  padding: var(--space-3xl) 0;
}

.objective {
  grid-column: 2 / 4;
  display: grid;
  gap: var(--space-lg);
}

.objective p {
  margin: 0;
  font-family: var(--display);
  font-stretch: 112%;
  font-size: var(--t-lg);
  line-height: 1.16;
  font-weight: 600;
  letter-spacing: -0.015em;
  display: grid;
  grid-template-columns: 5.5rem 1fr;
  gap: var(--space-lg);
  align-items: baseline;
  max-width: none;
}

.objective .mark {
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.16em;
  color: var(--ink-muted);
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}

.objective .is .mark {
  color: var(--ink);
}

.struck {
  color: var(--ink-muted);
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--ink-muted);
}

.objective-tight {
  margin-bottom: var(--space-2xl);
}

.objective-tight p {
  font-size: var(--t-md);
}

/* ── Argument ───────────────────────────────────────────────── */

.argument {
  padding: var(--space-3xl) 0 var(--space-2xl);
}

.argument h2 {
  margin-bottom: var(--space-xl);
  max-width: 26ch;
}

.beat {
  font-family: var(--display);
  font-stretch: 112%;
  font-size: var(--t-md);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.01em;
  margin: var(--space-xl) 0;
}

.beat em {
  font-style: normal;
  border-bottom: 3px solid var(--accent);
}

blockquote {
  grid-column: 2 / 4;
  margin: var(--space-2xl) 0;
  padding: var(--space-xl);
  background: var(--black);
  color: var(--on-black);
}

blockquote p {
  font-family: var(--display);
  font-stretch: 112%;
  font-size: var(--t-lg);
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.018em;
  margin: 0 0 var(--space-md);
  max-width: none;
}

blockquote cite {
  font-style: normal;
  font-size: var(--t-sm);
  color: var(--on-black-muted);
  display: block;
  max-width: 48ch;
}

/* ── Numbered sequences ─────────────────────────────────────── */

.behaviors {
  padding: var(--space-3xl) 0;
}

.behaviors h2 {
  margin-bottom: var(--space-sm);
}

.behaviors .intro {
  margin-bottom: var(--space-2xl);
}

.steps {
  grid-column: 2 / 4;
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 3px solid var(--rule-strong);
}

.steps li {
  display: grid;
  grid-template-columns: 4rem 1fr;
  gap: var(--space-lg);
  padding: var(--space-lg) 0;
  border-bottom: 1px solid var(--rule);
  align-items: baseline;
}

.steps .num,
.metrics .num {
  font-family: var(--display);
  font-stretch: 125%;
  font-size: var(--t-md);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.steps h3 {
  margin-bottom: var(--space-2xs);
}

.steps p,
.metrics p {
  margin: 0;
  color: var(--ink-mid);
  font-size: var(--t-base);
  line-height: 1.52;
}

/* ── Moments ────────────────────────────────────────────────── */

.moments {
  background: var(--ground-alt);
  border-top: 3px solid var(--rule-strong);
  border-bottom: 3px solid var(--rule-strong);
  padding: var(--space-3xl) 0;
}

.moments h2 {
  margin-bottom: var(--space-lg);
}

.moment-list {
  grid-column: 2 / 4;
  list-style: none;
  margin: var(--space-xl) 0 0;
  padding: 0;
  counter-reset: moment;
  border-top: 3px solid var(--rule-strong);
}

.moment-list li {
  counter-increment: moment;
  border-bottom: 1px solid var(--rule);
  display: grid;
  grid-template-columns: 4rem 1fr;
  gap: var(--space-lg);
  align-items: baseline;
  padding: var(--space-lg) 0;
}

.moment-list li::before {
  content: counter(moment, decimal-leading-zero);
  font-family: var(--display);
  font-stretch: 125%;
  font-size: var(--t-md);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.moment-note {
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-muted);
  white-space: nowrap;
}

.moment-list .title {
  font-family: var(--display);
  font-stretch: 112%;
  font-size: var(--t-md);
  font-weight: 600;
  letter-spacing: -0.012em;
  line-height: 1.25;
}

/* Each moment carries one instance under it. The section claims these are
   ambiguous to professionals too, and six bare titles ask the reader to take
   that on faith. The settings are the ones the deployed site already names:
   a pastor's address, a giving platform, citizen records, a grant payment. */
.moment-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.moment-list .instance {
  font-size: var(--t-sm);
  line-height: 1.55;
  color: var(--ink-mid);
  max-width: 62ch;
  margin: 0;
}

/* ── Worked example and callout ─────────────────────────────── */

.worked {
  border-top: 3px solid var(--rule-strong);
  background: var(--ground-alt);
}

.worked h2 {
  margin-bottom: var(--space-xl);
  max-width: 26ch;
}

.callout {
  grid-column: 2 / 4;
  margin-top: var(--space-2xl);
  padding: var(--space-xl);
  background: var(--black);
  color: var(--on-black-muted);
}

.callout p {
  max-width: none;
}

.callout p:last-child {
  margin-bottom: 0;
}

.callout strong {
  color: var(--on-black);
  font-weight: 600;
}

.callout-label {
  font-family: var(--display);
  font-stretch: 118%;
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--space-md) !important;
}

.metrics-foot {
  grid-column: 2 / 4;
  margin-top: var(--space-xl);
  font-size: var(--t-sm);
  color: var(--on-black-muted);
  max-width: 52ch;
}

.leverage {
  border-top: 3px solid var(--rule-strong);
}

.referral {
  border-top: 3px solid var(--rule-strong);
  background: var(--ground-alt);
}

/* Banded so it reads as a different kind of work, not another product tier. */
.community {
  border-top: 3px solid var(--rule-strong);
  background: var(--ground-alt);
}

.community .fine strong {
  display: block;
  margin-bottom: var(--space-2xs);
}

.referral h2 {
  max-width: 26ch;
}

/* ── Inverted measurement block ─────────────────────────────── */

.measure-section {
  background: var(--black);
  color: var(--on-black);
  padding: var(--space-3xl) 0;
}

.measure-section .label {
  color: var(--accent);
}

.measure-section h2 {
  margin: var(--space-lg) 0 var(--space-xl);
  max-width: 24ch;
}

.measure-section p {
  color: var(--on-black-muted);
  line-height: 1.7;
}

.measure-section strong {
  color: var(--on-black);
  font-weight: 600;
}

/* The closing beat carries the proof callback and needs the full-strength ink,
   not the muted paragraph colour it would otherwise inherit. */
.measure-section .beat {
  color: var(--on-black);
}

/* Global a:hover goes to --ink, which is near-black and vanishes on this slab.
   Same answer as the contact section: on black, hover is the accent. */
.measure-section a:hover {
  color: var(--accent);
}

.metrics {
  grid-column: 2 / 4;
  list-style: none;
  margin: var(--space-2xl) 0 0;
  padding: 0;
  display: grid;
  gap: 0;
  border-top: 1px solid var(--on-black-rule);
}

.metrics li {
  display: grid;
  grid-template-columns: 4rem 1fr;
  gap: var(--space-lg);
  padding: var(--space-lg) 0;
  border-bottom: 1px solid var(--on-black-rule);
  align-items: baseline;
}

.metrics .num {
  color: var(--accent);
}

.metrics h3 {
  color: var(--on-black);
  margin-bottom: var(--space-2xs);
}

.metrics p {
  color: var(--on-black-muted);
}

/* ── Sections ───────────────────────────────────────────────── */

.section {
  padding: var(--space-3xl) 0;
}

/* Three tiers, assigned by weight. Everything sharing one value produced
   meaningless voids between unrelated sections. */
.section-major {
  padding: var(--space-4xl) 0;
}

.section-tight {
  padding: var(--space-2xl) 0;
}

.section h2 {
  margin-bottom: var(--space-lg);
}

.difference h2 {
  margin-bottom: var(--space-xl);
  max-width: 28ch;
}

/* ── Pipeline ladder ────────────────────────────────────────── */

.ladder {
  grid-column: 2 / 4;
  list-style: none;
  margin: var(--space-xl) 0 var(--space-xl);
  padding: 0;
  border-top: 3px solid var(--rule-strong);
}

.ladder li {
  display: grid;
  grid-template-columns: 4rem 1fr auto;
  gap: var(--space-lg);
  padding: var(--space-lg) 0;
  border-bottom: 1px solid var(--rule);
  align-items: baseline;
}

.ladder-num {
  font-family: var(--display);
  font-stretch: 125%;
  font-size: var(--t-md);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.ladder-body h3 {
  margin-bottom: var(--space-2xs);
}

.ladder-body p {
  margin: 0;
  color: var(--ink-mid);
  font-size: var(--t-base);
  line-height: 1.52;
}

.ladder-price {
  font-family: var(--display);
  font-stretch: 125%;
  font-size: var(--t-md);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.015em;
  text-align: right;
  white-space: nowrap;
}

.ladder-unit {
  display: block;
  font-stretch: 112%;
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-top: var(--space-2xs);
}

.ladder-foot {
  color: var(--ink-muted);
  font-size: var(--t-sm);
  line-height: 1.6;
}

.train-cell {
  color: var(--ink) !important;
  font-weight: 600;
}

.fine strong {
  color: var(--ink);
  font-weight: 600;
}

/* ── Training offers ────────────────────────────────────────── */

.offer-list {
  grid-column: 2 / 4;
  margin-top: var(--space-xl);
  border-top: 3px solid var(--rule-strong);
}

.offer {
  padding: var(--space-xl) 0;
  border-bottom: 1px solid var(--rule);
}

.offer h3 {
  margin-bottom: var(--space-sm);
}

.offer p {
  margin: 0 0 var(--space-sm);
  color: var(--ink-mid);
}

.offer-meta {
  font-size: var(--t-sm);
  color: var(--ink-muted) !important;
  margin-bottom: 0 !important;
}

/* ── Definition lists ───────────────────────────────────────── */

.svc-list,
.who-list,
.std-list {
  grid-column: 2 / 4;
  list-style: none;
  margin: var(--space-xl) 0 0;
  padding: 0;
  border-top: 3px solid var(--rule-strong);
}

.svc-list li,
.who-list li,
.std-list li {
  display: grid;
  /* Fixed, not fit-content. Shrink-to-fit tightens the gap for short labels but
     starts the description at a different x on every row, and a ragged second
     column costs more here than a wide gap does. */
  grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
  gap: var(--space-2xs) var(--space-xl);
  padding: var(--space-md) 0;
  border-bottom: 1px solid var(--rule);
  align-items: baseline;
}

.svc-name,
.who-name,
.std-name {
  font-family: var(--display);
  font-stretch: 112%;
  font-weight: 600;
  letter-spacing: -0.005em;
}

.svc-desc,
.who-desc,
.std-desc {
  color: var(--ink-mid);
  font-size: var(--t-base);
  line-height: 1.5;
}

/* ── Tables: plans, and the compliance standards ────────────── */

.plan-scroll,
.std-scroll {
  grid-column: 2 / 4;
  margin-top: var(--space-xl);
  overflow-x: auto;
}

/* The wrapper carries a top margin only, so the paragraph after the
   standards would otherwise land against the last row. */
.std-scroll + p {
  margin-top: var(--space-xl);
}

.plan-table,
.std-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-base);
  min-width: 40rem;
  table-layout: fixed;
}

/* On thead only. The row headers are first children too, and a width on them
   would survive into the stacked phone layout. */
.std-table thead th:nth-child(1) {
  width: 22%;
}
.std-table thead th:nth-child(2) {
  width: 34%;
}

/* Fixed widths. Auto layout starved the training column and "One workshop a
   year" broke across three lines next to an oversized description column. */
.plan-table th:nth-child(1) {
  width: 22%;
}
.plan-table th:nth-child(2) {
  width: 12%;
}
.plan-table th:nth-child(3) {
  width: 22%;
}

.plan-table caption {
  text-align: left;
}

.plan-table th,
.plan-table td,
.std-table th,
.std-table td {
  text-align: left;
  padding: var(--space-md) var(--space-lg) var(--space-md) 0;
  border-bottom: 1px solid var(--rule);
  vertical-align: baseline;
}

.plan-table thead th,
.std-table thead th {
  font-family: var(--display);
  font-stretch: 118%;
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-muted);
  border-bottom: 3px solid var(--rule-strong);
  padding-bottom: var(--space-sm);
}

.plan-table tbody th,
.std-table tbody th {
  font-family: var(--display);
  font-stretch: 112%;
  font-weight: 600;
}

.plan-table td {
  color: var(--ink-muted);
}

/* Sentences, not figures, so they read at body contrast like .std-desc. */
.std-table td {
  color: var(--ink-mid);
  line-height: 1.5;
}

.num-cell {
  font-family: var(--display);
  font-stretch: 125%;
  font-variant-numeric: tabular-nums;
  color: var(--ink) !important;
  font-weight: 700;
}

.is-popular th,
.is-popular td {
  background: var(--ground-alt);
}

/* Sits under the plan name, not beside it. Inline, it overflowed the fixed
   column width and collided with the price. */
.tag {
  display: block;
  width: fit-content;
  white-space: nowrap;
  font-family: var(--display);
  font-stretch: 118%;
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  background: var(--accent);
  color: var(--black);
  padding: 0.2em 0.5em;
  margin-top: var(--space-xs);
}

.fine {
  grid-column: 2 / 4;
  font-size: var(--t-sm);
  color: var(--ink-muted);
  margin-top: var(--space-lg);
}

/* ── Practitioner ───────────────────────────────────────────── */

.practitioner {
  border-top: 3px solid var(--rule-strong);
}

.practitioner .name {
  font-family: var(--display);
  font-stretch: 125%;
  font-size: var(--t-lg);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin: var(--space-lg) 0 var(--space-2xs);
}

.practitioner .role {
  font-size: var(--t-sm);
  color: var(--ink-muted);
  margin-bottom: var(--space-lg);
}

/* ── Work / CTA ─────────────────────────────────────────────── */

.work {
  background: var(--ground-alt);
  border-top: 3px solid var(--rule-strong);
  border-bottom: 3px solid var(--rule-strong);
}

.actions {
  grid-column: 2 / 4;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm) var(--space-md);
  align-items: center;
  margin-top: var(--space-xl);
}

.btn {
  font-family: var(--display);
  font-stretch: 112%;
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  padding: var(--space-sm) var(--space-lg);
  border: 2px solid var(--ink);
  background: var(--ink);
  color: var(--ground);
  text-decoration: none;
  transition: background 160ms cubic-bezier(0.22, 1, 0.36, 1),
    color 160ms cubic-bezier(0.22, 1, 0.36, 1),
    border-color 160ms cubic-bezier(0.22, 1, 0.36, 1);
}

.btn:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--black);
}

.btn-ghost {
  background: transparent;
  color: var(--ink);
}

.btn-ghost:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--ground);
}

/* ── Contact ────────────────────────────────────────────────── */

.contact {
  background: var(--black);
  color: var(--on-black);

  /* Puts the field tokens back to the black-section values. Scoped here rather
     than on the form, because what decides these is the ground behind them. */
  --field-ink: var(--on-black);
  --field-surface: var(--field-ground);
  --field-surface-hover: var(--field-ground-hover);
  --field-line: var(--field-rule);
  --field-line-hover: var(--on-black);
  --field-arrow: var(--on-black-muted);
  --field-top-rule: var(--on-black-rule);
  --field-lead: var(--accent);
  --field-focus: var(--accent);
}

.contact .label {
  color: var(--accent);
}

.contact .lede {
  color: var(--on-black-muted);
}

.contact-grid {
  grid-column: 2 / 4;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--space-xl);
  margin-top: var(--space-2xl);
}

.contact-item .label {
  display: block;
  margin-bottom: var(--space-xs);
}

.contact-big {
  font-family: var(--display);
  font-stretch: 112%;
  font-size: var(--t-md);
  font-weight: 600;
  letter-spacing: -0.012em;
  text-decoration: none;
  line-height: 1.2;
  display: inline-block;
  color: var(--on-black);
  /* The address has no space in it and is wider than its column at three
     across, so without this it runs over the booking link beside it. */
  overflow-wrap: anywhere;
}

.contact-big:hover {
  color: var(--accent);
}

.contact .fine {
  color: var(--on-black-muted);
}

/* The form sits under the three direct routes rather than replacing them. A
   reader who wants the phone number should not have to fill anything in. */
.contact-form {
  grid-column: 2 / 4;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--space-lg) var(--space-xl);
  margin-top: var(--space-3xl);
  padding-top: var(--space-2xl);
  border-top: 1px solid var(--field-top-rule);
}

.form-lead {
  grid-column: 1 / -1;
  color: var(--field-lead);
  margin: 0;
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.field-wide {
  grid-column: 1 / -1;
}

.field label {
  font-family: var(--display);
  font-stretch: 112%;
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--field-ink);
}

/* Still an underline rather than an outlined box, but a transparent field on
   this ground was invisible: nothing showed where to type and the message box
   read as a hole in the page. The wash gives each field a surface without
   drawing a rectangle, and the rule out-reads the decorative rules on the same
   section so an input edge does not look like one.

   Every colour here is a --field-* token, because the same form appears on the
   black section and on the light ground and only the ground decides. Set for
   light in :root, overridden in .contact. */
.field input,
.field select,
.field textarea {
  font-family: var(--body);
  font-size: var(--t-base);
  line-height: 1.5;
  color: var(--field-ink);
  background-color: var(--field-surface);
  border: 0;
  border-bottom: 2px solid var(--field-line);
  padding: var(--space-xs) var(--space-sm);
  transition:
    border-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
    background-color 160ms cubic-bezier(0.22, 1, 0.36, 1);
}

.field input:hover,
.field select:hover,
.field textarea:hover {
  background-color: var(--field-surface-hover);
  border-bottom-color: var(--field-line-hover);
}

.field textarea {
  resize: vertical;
  min-height: 7rem;
}

/* The arrow is drawn here because a native dark select on a dark ground is
   rendered by the platform and comes out light on most of them. */
.field select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--field-arrow) 50%),
    linear-gradient(135deg, var(--field-arrow) 50%, transparent 50%);
  background-position: right 0.75rem center, right 0.4rem center;
  background-size: 0.35rem 0.35rem, 0.35rem 0.35rem;
  background-repeat: no-repeat;
  padding-right: var(--space-lg);
}

.field select option {
  color: var(--ink);
  background: var(--ground);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-bottom-color: var(--field-focus);
}

.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible {
  outline: 2px solid var(--field-focus);
  outline-offset: 4px;
}

.form-send {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-md) var(--space-lg);
}

.form-send .btn {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--black);
  cursor: pointer;
}

.form-send .btn:hover {
  background: var(--on-black);
  border-color: var(--on-black);
}

.form-send .fine {
  flex: 1 1 18rem;
  margin: 0;
}

/* Off screen rather than display:none, because a bot filling the form reads
   the markup and skips what is not rendered. */
.decoy {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ── Mission signature ──────────────────────────────────────── */

/* The company's own line, and the only thing on /approach/ that is not part
   of the argument. It closes the page because everything above it is what the
   line means.

   No top rule. This follows the black measurement slab, and that edge already
   divides harder than a 3px rule would. Set at the same size, width, and
   weight as .practitioner .name, so the two identity statements on the site,
   the person and the company, carry the same weight. */

.mission {
  padding: var(--space-3xl) 0;
}

/* Sized with h2 rather than under it. This is the argument's closing
   statement, not a caption on the way to the call to action.

   The break is explicit. `text-wrap: balance` splits the line after "for",
   which strands a preposition and leaves the shorter half on top. The comma is
   the natural caesura, and the /approach/ hero already breaks its h1 the same
   way. */
.mission .statement {
  grid-column: 2 / 4;
  font-family: var(--display);
  font-stretch: 125%;
  font-size: var(--t-xl);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.015em;
  margin: var(--space-lg) 0 var(--space-xl);
}

.mission .gloss {
  font-size: var(--t-base);
  line-height: 1.6;
  color: var(--ink-mid);
  max-width: 44ch;
  margin: 0;
}

/* ── Footer ─────────────────────────────────────────────────── */

footer {
  background: var(--black);
  color: var(--on-black-muted);
  border-top: 1px solid var(--on-black-rule);
  padding: var(--space-2xl) 0 var(--space-3xl);
  font-size: var(--t-sm);
}

footer .inner {
  grid-column: 2 / 4;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--space-xl);
  align-items: start;
}

.foot-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

footer a {
  text-decoration: none;
  color: var(--on-black-muted);
}

footer a:hover {
  color: var(--accent);
}

.foot-strong {
  font-family: var(--display);
  font-stretch: 118%;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: var(--t-label);
  color: var(--on-black);
}

/* Sits under the wordmark as the company descriptor, the slot the live site
   uses for it. Stays muted: it is a signature, not a claim being made here. */
.foot-mission {
  margin-bottom: var(--space-sm);
  max-width: 20ch;
}

/* ── Sticky masthead and back to top ────────────────────────── */

/* Desktop only. On mobile the nav becomes a two-column grid and a stuck header
   would eat a third of the screen; the back-to-top control covers that case. */
@media (min-width: 62.01rem) {
  .masthead {
    position: sticky;
    top: 0;
    z-index: 10;
  }

  /* visibility is in the list so the fade runs both ways. Left out, it flips
     at once and the button vanishes mid-fade on the way out. */
  .masthead-cta {
    transition: opacity 160ms cubic-bezier(0.22, 1, 0.36, 1),
      visibility 160ms cubic-bezier(0.22, 1, 0.36, 1);
  }

  /* Stuck to the top at this width, so the button keeps its slot instead of
     letting the nav slide sideways every time it comes and goes. */
  .masthead-cta[data-cta-hidden] {
    display: revert;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
  }
}

/* Sits at section boundaries instead of hovering over the page. Right-aligned
   to the same 1128 edge every ruled block now ends at, so it reads as part of
   the structure rather than as an overlay. No JavaScript. */
.uptop {
  grid-column: 2 / 4;
  justify-self: end;
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  margin-top: var(--space-xl);
  font-family: var(--display);
  font-stretch: 118%;
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-muted);
  text-decoration: none;
}

.uptop .chev {
  width: 10px;
  height: 11px;
  background: var(--ink-muted);
}

.uptop:hover {
  color: var(--ink);
}

.uptop:hover .chev {
  background: var(--accent);
}

.btn-sm {
  padding: var(--space-xs) var(--space-md);
  border-width: 1px;
}

html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

/* Anchors must clear the stuck masthead rather than landing under it. */
:target {
  scroll-margin-top: 6rem;
}

/* ── Utility ────────────────────────────────────────────────── */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ── Load motion ────────────────────────────────────────────── */

@media (prefers-reduced-motion: no-preference) {
  .rise {
    animation: rise 700ms cubic-bezier(0.16, 1, 0.3, 1) backwards;
  }

  .rise-1 {
    animation-delay: 40ms;
  }
  .rise-2 {
    animation-delay: 120ms;
  }
  .rise-3 {
    animation-delay: 220ms;
  }
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(0.6rem);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ── Narrow viewports ───────────────────────────────────────── */

@media (max-width: 62rem) {
  :root {
    --gutter: 0rem;
  }

  body {
    line-height: 1.58;
  }

  /* A deliberate two-column grid with real touch targets, rather than six
     links wrapping wherever flex happens to break them. */
  .masthead nav {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0;
    width: 100%;
    border-top: 1px solid var(--rule);
    margin-top: var(--space-sm);
  }

  .masthead nav a {
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--rule);
  }

  .masthead > .inner {
    align-items: flex-start;
  }

  .actions .btn {
    width: 100%;
    text-align: center;
  }

  .masthead-cta {
    width: 100%;
    text-align: center;
    margin-top: var(--space-sm);
  }

  .masthead nav {
    margin-left: 0;
  }

  .ladder-price {
    font-size: var(--t-md);
    color: var(--ink);
  }

  .spread {
    column-gap: 0;
  }

  /* Must match the specificity of `.annotated > .note` (0,2,0). A bare `.note`
     here loses to it, and the note stays in a zero-width gutter column: text
     breaks one character per line against the right edge. */
  .note,
  .annotated > .note {
    grid-column: 2;
    max-width: none;
    padding: var(--space-sm) 0 var(--space-lg);
    margin-bottom: var(--space-lg);
  }

  .objective p {
    grid-template-columns: 1fr;
    gap: var(--space-xs);
  }

  /* The forced break is a desktop nicety. At this width the line wraps on its
     own and the explicit break only makes it ragged. */
  .mission .statement br {
    display: none;
  }

  .steps li,
  .metrics li,
  .moment-list li {
    grid-template-columns: 2.75rem 1fr;
  }

  .ladder li {
    grid-template-columns: 2.75rem 1fr;
    gap: var(--space-sm) var(--space-lg);
  }

  .ladder-price {
    grid-column: 2;
    text-align: left;
  }

  .ladder-unit {
    display: inline;
    margin-left: var(--space-xs);
  }

  .moment-note {
    grid-column: 2;
  }

  .callout {
    padding: var(--space-lg);
  }

  .svc-list li,
  .who-list li,
  .std-list li {
    grid-template-columns: 1fr;
    gap: var(--space-xs);
    padding: var(--space-lg) 0;
  }

  /* The table becomes one labelled record per plan. Horizontal scrolling put
     "Behind it" offscreen with no affordance, so a phone reader saw $250 buying
     two workshops and nothing else. The standards table does the same. */
  .plan-scroll,
  .std-scroll {
    overflow-x: visible;
  }

  .plan-table,
  .std-table {
    min-width: 0;
    table-layout: auto;
  }

  .plan-table,
  .plan-table tbody,
  .plan-table tr,
  .plan-table th,
  .plan-table td,
  .std-table,
  .std-table tbody,
  .std-table tr,
  .std-table th,
  .std-table td {
    display: block;
    width: auto;
  }

  .plan-table thead,
  .std-table thead {
    display: none;
  }

  .plan-table tr,
  .std-table tr {
    border-top: 3px solid var(--rule-strong);
    padding: var(--space-lg) 0;
  }

  /* Kept at desktop size. A plan name is one word; "CJIS Security Policy
     v6.1, AT-2" at display size breaks into three lines on a phone. */
  .std-table tbody th {
    padding: 0;
    border: 0;
  }

  .plan-table tbody th {
    font-family: var(--display);
    font-stretch: 125%;
    font-size: var(--t-lg);
    font-weight: 700;
    letter-spacing: -0.02em;
    padding: 0;
    border: 0;
  }

  .plan-table td,
  .std-table td {
    padding: var(--space-sm) 0 0;
    border: 0;
    color: var(--ink-mid);
  }

  .plan-table td::before,
  .std-table td::before {
    content: attr(data-label);
    display: block;
    font-family: var(--display);
    font-stretch: 118%;
    font-size: var(--t-label);
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--ink-muted);
    margin-bottom: var(--space-2xs);
  }

  .plan-table .num-cell {
    font-size: var(--t-lg);
  }

  .is-popular th,
  .is-popular td {
    background: none;
  }

  .is-popular {
    background: var(--ground-alt);
    padding-inline: var(--space-lg);
  }
}

/* ── Smallest phones ────────────────────────────────────────── */

/* --t-hero rises too slowly to keep a long word inside a narrow column. A
   ten-letter word in a headline overflows the right edge on every phone width
   up to about 450px; short-word headlines only escaped it by luck. This
   steepens the curve below that. The bounds are set so the size matches
   --t-hero at 448px and nothing jumps at the breakpoint. */
@media (max-width: 28rem) {
  .hero h1 {
    font-size: clamp(1.8rem, 12.5vw - 0.55rem, 2.95rem);
  }
}
