/* GENERATED by scripts/build-public-jobs-css.mjs — do not edit. */
:root {
  /* Canvas & surfaces — warm paper (riso indigo system) */
  --bg: #f6f2ea;
  --bg-tint: rgba(58, 74, 140, 0.05);
  --text: #232a4a;
  --text-soft: #47507a;
  /* Faint is still text, so it clears the 4.5:1 body floor on paper
     (4.9:1). The lighter #6b719c it replaced measured 4.21:1. */
  --text-faint: #5f6694;

  /* Action accent — burnt orange, primary buttons only */
  --accent: #b5500c;
  --accent-hover: #9c440a;
  --accent-light: rgba(181, 80, 12, 0.13);

  /* Structure — indigo drafting ink (labels, frame annotations) */
  --structure: #3a4a8c;

  /* Rule system — every line on the page is one of these two, at 1px.
     The sole exception is the 2px amber graduation tick (timeline). */
  --rule: rgba(58, 74, 140, 0.26); /* internal separation: rows, dividers */
  --rule-strong: rgba(58, 74, 140, 0.42); /* structural edges: plates, bands */

  /* Detail — amber, crop-marks/ticks/ghost-hover/tint bands/FAQ marker */
  --detail: #e0aa25;
  --detail-text: #a37310;

  /* Art ink — coral, the sunset heat. Overprint art ONLY: the hero/CTA
     compositions, divider roller bands, and the flood glow. Never text,
     buttons, links, borders, or any UI state — the trio above keeps
     running the interface. This is the only place the hex may appear;
     translucent uses go through color-mix. (DESIGN.md "The inks".) */
  --art-coral: #e85c3f;

  --font-display: "Besley", "Clarendon", Georgia, serif;
  --font-body: "Libre Franklin", -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "Fragment Mono", "SF Mono", "Fira Code", monospace;

  --radius: 2px;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);

  /* Widths — the same discipline as the inks: two, each with one job.
     --shell    the page container. Every section, plate and band aligns
                to it; nothing on the page is wider.
     --measure  the reading measure for any run of prose — ledes, section
                bodies, checklist and FAQ rows, timeline phases. 35rem is
                ~74 characters at the 17px body size, measured against
                the real average advance of Libre Franklin rather than
                the `ch` unit: this face's zero is 1.5x its average
                character, so the 68ch this site used to set was a
                105-character line.
     Two widths are deliberate exceptions, each commented where it is
     set: the testimonial's set-type width (centered display type reads
     on its own measure) and the candidate form's field width. A new
     width asks the same question a new color does — which of the two am
     I? — before it earns a third. */
  --shell: 1040px;
  --measure: 35rem;

  /* Motion knobs — the ink press (DESIGN.md "Motion"). Every duration,
     delay and easing the print sequence uses lives here, so the feel is
     tuned in one place without touching the mechanism. ink-press.js
     reads the same values for its coverage-build clocks. */
  --ink-hero-delay: 700ms; /* the hero prints after the h1 registers */
  --ink-register: 600ms; /* the h1 echo pulling into register */
  --ink-pass-coral: 2000ms; /* first pass: coverage build */
  --ink-pass-amber: 1800ms; /* second pass */
  --ink-pass-gap: 900ms; /* amber starts this long after coral */
  --ink-settle-delay: 700ms; /* into the amber pass, it starts settling */
  --ink-settle: 1100ms; /* out of register → in register */
  --ink-stamp: 950ms; /* a spot illustration landing */
  --ink-plate-gap: 220ms; /* the requisition's three plates land this far apart */
  --ink-breathe: 8s; /* one half-cycle of the ambient swell */
  --ink-drift: 40s; /* the flood's weather bleeds this slowly */
  --ink-wander: 30s; /* the flood's second plate leaves register and returns */
  /* A pass: slow start, soft finish, no overshoot. */
  --ease-ink: cubic-bezier(0.4, 0, 0.3, 1);
  /* A stamp: lands heavy, one small overshoot. */
  --ease-stamp: cubic-bezier(0.34, 1.45, 0.64, 1);
}


* {
  box-sizing: border-box;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.6;
  margin: 0;
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
  margin: 0 0 0.5em;
  text-wrap: balance;
}

h1 {
  font-size: clamp(2.1rem, 4.6vw, 3.1rem);
  letter-spacing: -0.01em;
  line-height: 1.12;
}

/* Mis-registration detail: a subtle amber offset echo (signature — two
   placements max, see .btn--primary above). Held to ≥768px — at the small
   end of the h1 clamp the echo muddies the Clarendon letterforms. */
@media (min-width: 768px) {
  h1 {
    text-shadow: 2px 2px 0 rgba(224, 170, 37, 0.35);
  }

  /* The press finding its register, once, as the page arrives — the
     amber plate lands wide and pulls into position. This is not a third
     mis-registration placement: it is THIS placement given an arrival,
     which is why the budget still reads two (DESIGN.md, "Concept").
     Only the echo moves; the letterforms are in their final position
     from the first frame, so nothing is waited on. Gated on .is-printing
     (ink-press.js) so the echo, the coral pass and the amber pass run on
     one clock; without the class the echo simply rests in register. */
  .is-printing h1 {
    animation: register-in var(--ink-register) var(--ease-out) both;
  }

  @media (prefers-reduced-motion: reduce) {
    .is-printing h1 {
      animation: none;
    }
  }
}

@keyframes register-in {
  from {
    text-shadow: 7px 7px 0 rgba(224, 170, 37, 0.35);
  }
}

h2 {
  font-size: clamp(1.55rem, 3vw, 2.05rem);
}

h3 {
  font-size: 1.1rem;
}

p {
  margin: 0 0 1em;
}

/* ── Links — one signature (DESIGN.md "Links") ──
   Content links are ink with a 1px amber underline (the detail ink
   annotating) and answer hover in the accent. Chrome (header, footer,
   breadcrumb) and row links opt out of the underline where their own
   pattern carries the affordance; buttons and the pocket card keep
   their own treatment entirely. */
a {
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--detail);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

a:not(.btn):not(.pocket-card):hover,
a:not(.btn):not(.pocket-card):active {
  color: var(--accent);
  text-decoration-color: currentColor;
}

/* On the flood the ink signature inverts: text inherits the knockout
   paper, the underline stays amber, hover answers in amber (the accent
   doesn't carry on indigo). Global because prose links render inside
   their own component scope. */
.section--flood a {
  color: inherit;
}

.section--flood a:not(.btn):hover {
  color: var(--detail);
  text-decoration-color: currentColor;
}

/* Interaction states — one consistent focus-visible indicator (indigo) for
   every interactive element: buttons, links, FAQ summary, form inputs. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
.form-field input:focus-visible,
.strip__consent input:focus-visible {
  outline: 2px solid var(--structure);
  outline-offset: 2px;
}

/* ── The hero plate ────────────────────────────────────────────────────
   The plate opening every page that is not the landing page: content
   pages (GtmesPageLayout), the resources index, and 404. It lives here
   rather than in each of those files because a component's scoped style
   cannot reach the .tech-frame / .graph-grid rendered inside its own
   children (the Astro caveat in DESIGN.md) — so each surface used to
   hand-copy the block, and the copies drifted: /resources/ kept a lede
   cap the layout had deliberately dropped, and every new surface started
   by copying whichever version it found first. One definition, three
   consumers. */
.page-hero {
  padding: 3rem 0 0;
  position: relative;
}

/* With a HUD, the band below supplies the hero's breathing room
   (.page-hud). Without one, the plate needs its own. */
.page-hero--no-hud {
  padding-bottom: 4rem;
}

.page-hero .graph-grid {
  z-index: 0;
}

.page-hero .tech-frame {
  margin: 0 auto;
  max-width: var(--shell);
  position: relative;
  z-index: 1;
}

.page-hero__content {
  padding: 3.5rem 3rem 3.25rem;
}

@media (max-width: 640px) {
  .page-hero__content {
    padding: 2.5rem 1.5rem 2.25rem;
  }
}

/* The one display width on the page: a long title breaks into two
   balanced lines instead of running the full plate. Not the reading
   measure — that is set in body characters, which at 3.1rem would be
   no cap at all. */
.page-hero h1 {
  margin: 0 0 1.25rem;
  max-width: 24ch;
}

/* The lede fills the plate rather than stopping at the reading measure:
   inside a bordered hero, prose ending two thirds across reads as an
   unfinished block rather than as a considered column. It is the one run
   of prose on the page that sits in a frame, so it takes the frame's
   width and the frame's padding on both sides. Body copy below still
   holds --measure. */
.page-hero .lede {
  color: var(--text-soft);
  font-size: 1.15rem;
  line-height: 1.65;
  margin: 0;
}

/* The breadcrumb rides the plate's top border in the frame's tag slot. */
.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

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

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

/* ── Browser surfaces ──────────────────────────────────────────────────
   The parts of the page the browser draws are still part of the print.
   Left at their defaults they ship someone else's design system onto
   warm paper: a blue selection, a black caret, a grey scrollbar. Each
   takes the ink whose job already covers it — no new hue, no new role. */

/* Selection is the highlighter pass: amber laid over the paper at the
   strength a mark needs, the ink still printing through it (10.2:1).
   This is amber's existing wash job — the ghost hover, the tint bands —
   at highlight strength; below ~30% it reads as a rendering artifact
   rather than as something a hand did. */
::selection {
  background: color-mix(in srgb, var(--detail) 32%, var(--bg));
  color: var(--text);
}

/* On the flood the surface is ink and the text is knocked out to paper,
   so the highlight inverts with it: amber over the structure ink, the
   knockout holding 5.3:1. */
.section--flood ::selection {
  background: color-mix(in srgb, var(--detail) 25%, var(--structure));
  color: var(--bg);
}

/* The caret is the one mark the visitor makes on this page, so it prints
   in the action ink rather than the browser's black. */
.form-field input {
  caret-color: var(--accent);
}

/* Placeholders are prompts, not content — the faint ink, at full alpha
   so the value is the token's and not the browser's dimming on top. */
::placeholder {
  color: var(--text-faint);
  opacity: 1;
}

/* A long page's scrollbar is its tallest single element, and grey is the
   one color the ink table does not contain. */
html {
  scrollbar-color: color-mix(in srgb, var(--structure) 38%, var(--bg)) var(--bg);
}

/* Pocket card — Joe's printed calling card, half-tucked into a pocket
   printed on the page. Two materials tell the layers apart: the card is
   clean paper with amber registration corners (a print artifact), the
   pocket is an indigo flat (tint + grain, the tinted-section surface)
   with its label set in the plate-coord grammar. Depth comes from
   overlap, not shadows. Hovering eases the card up out of the slot;
   clicking "pulls it out" to LinkedIn. One per page. */
.pocket-card {
  display: inline-block;
  margin-top: 1.25rem;
  position: relative;
  text-decoration: none;
  width: 300px;
}

.pocket-card__card {
  background: var(--bg);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  display: flex;
  gap: 0.9rem;
  margin: 0 18px;
  padding: 0.8rem 0.9rem 2.5rem;
  position: relative;
  /* Hand-placed, not machine-set: the card rests a shade off square and
     squares up as you take hold of it — the riso "human hand in a
     precise system" note, without touching the mis-registration budget. */
  transform: rotate(-1.4deg);
  transition:
    transform 0.4s var(--ease-out),
    background-color 0.4s var(--ease-out);
}

/* Hover lifts the card AND lights it in the amber ghost-wash the catalog
   rows and band cells use, so the card answers a pointer the way every
   other click target on the site does — the motion alone reads as
   decoration, the wash reads as "this is a link". Mixed to an opaque
   paper blend rather than layered as translucent amber: it transitions
   with the lift, where a gradient layer would snap. */
.pocket-card:hover .pocket-card__card,
.pocket-card:focus-visible .pocket-card__card {
  background-color: color-mix(in srgb, var(--detail) 10%, var(--bg));
  transform: translateY(-12px) rotate(0deg);
}

.pocket-card:active .pocket-card__card {
  transform: translateY(-15px) rotate(0deg);
}

/* Registration corners — the card is a printed piece, so it carries the
   same amber crop-marks the plates do, at calling-card scale (two, not
   four: a cue, not a frame). */
.pocket-card__corner {
  border: 1px solid var(--detail);
  height: 7px;
  position: absolute;
  width: 7px;
}

.pocket-card__corner--tl {
  border-bottom: 0;
  border-right: 0;
  left: -1px;
  top: -1px;
}

.pocket-card__corner--tr {
  border-bottom: 0;
  border-left: 0;
  right: -1px;
  top: -1px;
}

.pocket-card__photo {
  border-radius: var(--radius);
  filter: grayscale(1);
  height: 48px;
  object-fit: cover;
  width: 48px;
}

.pocket-card__id {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  justify-content: center;
}

.pocket-card__name {
  color: var(--text);
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.15;
}

.pocket-card__role {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The pocket — an indigo printed flat the card slides behind. Same
   surface recipe as tinted sections (bg-tint + tint grain), so it reads
   as a different material than the paper card without any new ink. */
.pocket-card__pocket {
  /* Opaque paper base under the tint — the card must vanish behind the
     pocket, not ghost through it. */
  background-color: var(--bg);
  background-image:
    url("/riso/tint-grain.svg"),
    linear-gradient(var(--bg-tint), var(--bg-tint));
  background-repeat: repeat;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  bottom: 0;
  height: 30px;
  left: 0;
  position: absolute;
  right: 0;
  transition: background-color 0.4s var(--ease-out);
  z-index: 1;
}

/* The pocket answers too — same wash under its indigo tint, and the pull
   label goes accent. It is the part that names the destination, so it
   should not be the one part of the card that stays inert. */
.pocket-card:hover .pocket-card__pocket,
.pocket-card:focus-visible .pocket-card__pocket {
  background-color: color-mix(in srgb, var(--detail) 10%, var(--bg));
}

/* Pocket label in the plate-coord grammar: a small mono annotation
   sitting in the bottom-right corner, not a centered button caption. */
.pocket-card__pull {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  position: absolute;
  right: 10px;
  top: 50%;
  text-transform: uppercase;
  transform: translateY(-50%);
  transition: color 0.4s var(--ease-out);
}

.pocket-card:hover .pocket-card__pull,
.pocket-card:focus-visible .pocket-card__pull {
  color: var(--accent);
}

@media (prefers-reduced-motion: reduce) {
  .pocket-card__card,
  .pocket-card__pocket,
  .pocket-card__pull {
    transition: none;
  }
}

.shell {
  margin: 0 auto;
  width: min(var(--shell), calc(100% - 40px));
}

.eyebrow {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.12em;
  margin-bottom: 1rem;
  text-transform: uppercase;
}

.section {
  padding: 5rem 0;
}

/* Tight pairing after a SectionDivider — the divider already marks the
   seam, so the section right after it needs less lead-in air than a
   fresh section start. */
.section--tight-top {
  padding-top: 4rem;
}

@media (max-width: 640px) {
  .section--tight-top {
    padding-top: 3rem;
  }
}

/* Riso flat-tint pass: a light indigo ink wash carrying the same speckle
   the flood uses (assets/tint-grain.svg — the flood-grain tile printed in
   indigo instead of paper), so the light and dark flats read as one press. */
.section--tinted {
  background-color: var(--bg-tint);
  background-image: url("/riso/tint-grain.svg");
  background-repeat: repeat;
}

/* ── Ink flood — the riso solid flat: structure ink printed edge to edge,
   paper-grain speckle showing through, content knocked out to paper.
   The page's loudest surface; one flood per page (#archive-story). ── */
.section--flood {
  background-color: var(--structure);
  overflow: hidden;
  position: relative;
}

.section--flood::before {
  background-image: url("/riso/flood-grain.svg");
  background-repeat: repeat;
  content: "";
  inset: 0;
  opacity: 0.2;
  pointer-events: none;
  position: absolute;
}

/* Riso second pass on the flood: a grainy coral glow breathing behind
   the knocked-out quote, over a large-scale coral weather field that
   runs heavier toward the edges. Legibility gates the glow, not the
   reverse — if the knockout type ever muddies, the alpha here loses
   (44% center, tuned against WCAG large-text contrast on the worst-case
   backdrop). */
.section--flood::after {
  animation: weather-drift var(--ink-drift) ease-in-out infinite alternate;
  background-image: url("/riso/weather-coral.svg");
  /* A fine coral tooth — small tile-like mottle, evenly across the whole
     flood; no gradient focal point, the texture IS the second pass. It
     prints ONCE, stretched edge to edge — feTurbulence tiles never
     stitch cleanly in practice, and a visible repeat seam reads as a
     rendering bug, not a print. The asset is authored at 1600×900 so
     cover stays near 1:1 at real flood sizes. */
  background-repeat: no-repeat;
  background-size: cover;
  content: "";
  inset: -8%; /* pulled out so the drift never shows an edge */
  pointer-events: none;
  position: absolute;
}

.section--flood > .shell {
  position: relative;
  z-index: 1;
}

.section--flood .testimonial__quote p {
  color: var(--bg);
}

.section--flood .testimonial__who {
  color: rgba(246, 242, 234, 0.88);
}

/* Riso halftone pass: the screened-dot texture of a second print run.
   Rotates with the ink wash so adjacent sections never repeat a surface. */
.section--dotted {
  background-image: radial-gradient(
    rgba(58, 74, 140, 0.13) 1px,
    transparent 1.4px
  );
  background-size: 8px 8px;
}

/* Riso section washes — three structure-ink surface passes, user-tuned
   in the background studies (the values are deliberate calibration, not
   defaults to round off). Like the tint/dot passes they print around
   paper reserves (band cells, plates) and rotate so adjacent sections
   never repeat a surface. One consumer each:
   - mottle  → the offer (#search): the flat tint laid down unevenly
   - laid    → the framework: hairline pinstripes, laid-stock texture
   - speckle → the candidate strip: sparse ink flecks on the paper */
.section--wash-mottle {
  background-image: url("/riso/tint-mottle.svg");
  background-repeat: repeat;
}

.section--wash-laid {
  /* Pinstripes over the tint-blue flat: the laid texture alone reads as
     paper next to paper-based neighbors, so this wash keeps the tinted
     surface's gray-blue ground and prints the hairlines on top. */
  background-color: var(--bg-tint);
  background-image: repeating-linear-gradient(
    180deg,
    color-mix(in srgb, var(--structure) 5.5%, transparent) 0 1px,
    transparent 1px 7px
  );
}

.section--wash-speckle {
  background-image: url("/riso/speckle-ink.svg");
  background-repeat: repeat;
}

.section__lede {
  color: var(--text-soft);
  max-width: var(--measure);
  text-wrap: pretty;
}

/* ── Hanging heading — the site's one composition for prose-led sections,
   on the landing page and the content pages alike: the heading hangs in
   the left margin and the prose runs in the measure column beside it, so
   the section composes to the full shell instead of leaving a dead half
   beside a 35rem column. Content that is already full-shell — a band, the
   logo wall, the pricing plate, the deliverables — sits BELOW the grid,
   not inside it; that width change then reads as a deliberate contrast
   rather than a ragged edge. Sections built on display type (the flood
   quote, the closing statement) are not prose-led and keep their own
   composition. Stacks at 960px, the same breakpoint everywhere. ── */
.hang {
  display: grid;
  /* Row gap only bites in the stacked state (one column, heading over
     body) — the two-column state is a single row. */
  gap: 1.5rem;
}

@media (min-width: 960px) {
  .hang {
    align-items: start;
    column-gap: 4rem;
    grid-template-columns: 20rem minmax(0, var(--measure));
  }
}

.hang h2 {
  margin: 0;
}

/* The grid owns the spacing between the two columns' contents, so the
   first and last child give up the block margins they carry elsewhere
   (.checklist's lead-in, .faq's, a paragraph's trailing margin). */
.hang__body > :first-child {
  margin-top: 0;
}

.hang__body > :last-child {
  margin-bottom: 0;
}

/* ── GraphGrid — now a riso ink-grain field (edge-faded) ── */
/* Was pure-CSS graph paper; the drafting motif gives way to risograph
   print-studio texture — an feTurbulence grain tile mapped to indigo ink
   (see assets/riso-grain.svg), same class name/markup
   (components/astro/GraphGrid.astro), same edge-fade mask. */
.graph-grid {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: url("/riso/riso-grain.svg");
  background-repeat: repeat;
  -webkit-mask-image: linear-gradient(
    to bottom,
    transparent,
    #000 90px,
    #000 calc(100% - 90px),
    transparent
  );
  mask-image: linear-gradient(
    to bottom,
    transparent,
    #000 90px,
    #000 calc(100% - 90px),
    transparent
  );
}

/* ── TechFrame — hairline border + amber corner crop-marks + mono tag/coord ── */
/* Ported from src/marketing/styles/motif.css .tech-frame; --accent-primary →
   --detail, --canvas-bg → --bg, --font-mono-accent → --font-mono, tag/coord
   color → --structure (indigo drafting annotations). */
.tech-frame {
  position: relative;
  border: 1px solid var(--rule-strong);
  /* Plates are paper: section washes print around a plate, never through
     it (same knockout as .band > * cells). */
  background: var(--bg);
}
.tech-frame__corner {
  position: absolute;
  z-index: 2;
  width: 9px;
  height: 9px;
  border: 1px solid var(--detail);
}
.tech-frame__corner--tl {
  top: -1px;
  left: -1px;
  border-right: 0;
  border-bottom: 0;
}
.tech-frame__corner--tr {
  top: -1px;
  right: -1px;
  border-left: 0;
  border-bottom: 0;
}
.tech-frame__corner--bl {
  bottom: -1px;
  left: -1px;
  border-right: 0;
  border-top: 0;
}
.tech-frame__corner--br {
  bottom: -1px;
  right: -1px;
  border-left: 0;
  border-top: 0;
}
.tech-frame__tag,
.tech-frame__coord {
  position: absolute;
  z-index: 2;
  padding: 0 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--structure);
}
/* The label's paper knockout must stop at the plate edge: the half that
   protrudes outside stays transparent so section washes (tint/dots) show
   through; the inner half paints paper, which both matches the plate
   interior and erases the 1px frame line running behind the text. The
   7px stop is the -8px offset (measured from the padding box) minus the
   1px border the label must still cover. */
.tech-frame__tag {
  background: linear-gradient(to bottom, transparent 7px, var(--bg) 7px);
  top: -8px;
  left: 18px;
}
.tech-frame__coord {
  background: linear-gradient(to top, transparent 7px, var(--bg) 7px);
  bottom: -8px;
  right: 18px;
}

/* ── Band — the multi-item container: flush paper cells between strong
   top/bottom rules, hairline dividers via the gap-over-background trick.
   Used by the stats HUD and the offer deliverables (containment ladder,
   see DESIGN.md). ── */
.band {
  background: var(--rule);
  border-bottom: 1px solid var(--rule-strong);
  border-top: 1px solid var(--rule-strong);
  display: grid;
  gap: 1px;
  margin: 2.5rem 0 0;
}

.band > * {
  background: var(--bg);
  margin: 0;
}

/* ── TelemetryHUD — stat cells on the band pattern ── */
/* Ported from src/marketing/styles/motif.css .hud (live-dot variant skipped —
   the recruiting site has no "live" state to telemeter). Labels in
   --structure (indigo annotations); values in --detail-text (amber,
   text-contrast depth), set in Fragment Mono. */
.hud {
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}
.hud__cell {
  padding: 1rem 1.25rem;
}
.hud__label {
  display: block;
  margin-bottom: 0.4rem;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--structure);
}
.hud__value {
  display: block;
  font-family: var(--font-mono);
  font-size: 1.4rem;
  font-weight: 600;
  color: var(--detail-text);
}

/* ── SectionDivider — roller-gradient seam ── */
/* Two structure-ink bands fade from opposite ends with a dry-drum
   falloff and overlap mid-run — density variation in the page's own
   muted ink, not a new color moment. Paper speckle prints over the
   whole seam (ink coverage). Whisper strength: the seam is punctuation
   between sections; a divider that reads as a banner draws the eye
   it's supposed to release. */
.section-divider {
  display: flex;
  padding: 0;
  position: relative;
}

.section-divider__rule {
  border-bottom: 1px solid var(--rule-strong);
  border-top: 1px solid var(--rule-strong);
  height: 10px;
  overflow: hidden;
  position: relative;
  width: 100%;
}

.section-divider__rule::before,
.section-divider__rule::after {
  content: "";
  inset: 0;
  mix-blend-mode: multiply;
  position: absolute;
}

.section-divider__rule::before {
  background: color-mix(in srgb, var(--structure) 16%, transparent);
  -webkit-mask-image: linear-gradient(
    90deg,
    #000 12%,
    rgba(0, 0, 0, 0.35) 62%,
    transparent 94%
  );
  mask-image: linear-gradient(
    90deg,
    #000 12%,
    rgba(0, 0, 0, 0.35) 62%,
    transparent 94%
  );
}

.section-divider__rule::after {
  background: color-mix(in srgb, var(--structure) 10%, transparent);
  -webkit-mask-image: linear-gradient(
    270deg,
    #000 12%,
    rgba(0, 0, 0, 0.35) 62%,
    transparent 94%
  );
  mask-image: linear-gradient(
    270deg,
    #000 12%,
    rgba(0, 0, 0, 0.35) 62%,
    transparent 94%
  );
}

/* Ink coverage over the seam. */
.section-divider::after {
  background: url("/riso/speckle-paper.svg") repeat;
  content: "";
  inset: 1px 0;
  pointer-events: none;
  position: absolute;
}

/* ── Felt grain — one fibrous noise pass over the whole page, like ink on
   felt paper. Fixed, non-interactive, above content but nearly transparent. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 10;
  pointer-events: none;
  background: url("/riso/felt-noise.svg");
  background-repeat: repeat;
  mix-blend-mode: multiply;
}

/* Riso filter mount — zero-size SVG carrying the displacement filters;
   absolute so the empty element contributes no layout. */
.riso-filters {
  position: absolute;
}

/* ── Overprint art — translucent multiply plates of coral/amber/structure
   ink: the riso signature. Closed placement list (DESIGN.md "Overprint"):
   hero, section dividers, flood, final CTA. Ink-coverage rule: no art
   shape prints flat — every shape carries paper speckle and a roughened
   edge. The hero's art lives in the SECTION background, behind the
   opaque plate — it runs under the plate's edge (continuity: the print
   continues behind the document), so plate interiors stay clean paper
   with no exceptions. ── */
.overprint-art {
  display: none;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  position: absolute;
  z-index: 0;
}

@media (min-width: 768px) {
  .overprint-art {
    display: block;
  }
}

.overprint-art > span {
  mix-blend-mode: multiply;
  position: absolute;
}

/* Ink coverage: paper flecks over every shape's ink. */
.overprint-art > span::after {
  background: url("/riso/speckle-paper.svg") repeat;
  content: "";
  inset: 0;
  position: absolute;
}

/* Hero composition: one rhythmic pass of coral/amber stripes — a
   repeating unit with unequal bands (wide coral, narrow amber) so the
   rhythm reads printed rather than mechanical — with a dot grid KNOCKED
   OUT of the ink: the dots expose paper through the stripes, halftone-
   style; they never print as dots of their own. The pass prints in the
   hero's background, flush to the section's right edge, and runs about
   a third of the way in behind the opaque plate — cut by the plate's
   edge, it reads as a print continuing behind the document.

   One ink per layer, because a riso prints one color per pass (DESIGN.md
   "Motion"): the coral bands and the amber bands are two spans over the
   same 52px unit, so each can arrive on its own clock. */

/* The halftone hole — the dot knocked out of the ink. Registered so a
   pass can animate it: big holes (mostly paper) closing to the resting
   pinhole as the ink fills in through the screen. */
@property --hole {
  syntax: "<length>";
  inherits: false;
  initial-value: 1.3px;
}

.overprint-art__stripes {
  /* Declared as well as registered above (@property --hole): a browser
     without @property support still gets the resting halftone, just not
     the animated close (Important 2, final review). */
  --hole: 1.3px;
  bottom: 0;
  filter: url(#riso-ink);
  right: 0;
  top: 0;
  transform-origin: 30% 50%;
  /* Flush to the section's right edge, always; the 1036px cap only
     limits how far the pass reaches under the plate on ultrawide
     screens. */
  width: min(36%, 1036px);
  /* The dot grid as a mask: 7px pitch, a --hole radius of paper per
     cell. Mottled coverage comes from the filter; the left-end fade is
     the sibling .overprint-art__fade. No mask-composite, so Safari
     renders it the same. */
  -webkit-mask-image: radial-gradient(
    circle,
    transparent var(--hole),
    #000 calc(var(--hole) + 0.2px)
  );
  -webkit-mask-size: 7px 7px;
  mask-image: radial-gradient(
    circle,
    transparent var(--hole),
    #000 calc(var(--hole) + 0.2px)
  );
  mask-size: 7px 7px;
}

.overprint-art__stripes--coral {
  background: repeating-linear-gradient(
    90deg,
    color-mix(in srgb, var(--art-coral) 34%, transparent) 0 16px,
    transparent 16px 52px
  );
}

.overprint-art__stripes--amber {
  background: repeating-linear-gradient(
    90deg,
    transparent 0 28px,
    color-mix(in srgb, var(--detail) 38%, transparent) 28px 38px,
    transparent 38px 52px
  );
}

/* The stripes dissolve into paper at their left end (hidden behind the
   plate at most widths) and print solid out to the section's right
   edge. A paper-colored gradient rather than a mask so both ink layers
   share one fade; 48px wider than the ink because the roughened edge
   spills past the element box. A div, not a span: the span rules above
   would multiply it and speckle it. Shortened to 20% (from 42%, final
   review Minor): the plate caps at --shell (1040px, centered), so past
   ~2000px viewports the old 42% stop stayed opaque well past the
   plate's edge — a flat paper wash between the plate and the visible
   ink. 20% clears by the plate's edge on every width the plate can
   reach and still covers the roughened edge under it. */
.overprint-art__fade {
  background: linear-gradient(
    90deg,
    var(--bg) 0,
    var(--bg) 48px,
    transparent 20%
  );
  bottom: 0;
  pointer-events: none;
  position: absolute;
  right: 0;
  top: 0;
  width: calc(min(36%, 1036px) + 48px);
}

/* CTA composition: two hand-inked blots (heavier roughening at blob
   scale) off the top-right, plus the halftone screen fading in from the
   left — the dot texture's single sanctioned placement. */
.overprint-art--cta {
  inset: 0;
}

.overprint-art__blot {
  filter: url(#riso-roughen);
  /* Mottled ink coverage: an alpha-varying turbulence mask so the ink
     lays down unevenly across the whole shape (40–100%), the way a riso
     drum actually prints. (Set per shape, not on the base span: the base
     selector's class+element specificity would override the stripes'
     dotted mask — which is exactly the bug this comment is warding off.) */
  -webkit-mask-image: url("/riso/ink-coverage.svg");
  mask-image: url("/riso/ink-coverage.svg");
  transform-origin: center;
}

.overprint-art__blot--coral {
  aspect-ratio: 1.25;
  background: color-mix(in srgb, var(--art-coral) 32%, transparent);
  border-radius: 58% 42% 55% 45% / 48% 55% 45% 52%;
  right: -8%;
  top: -34%;
  rotate: -14deg;
  width: 38%;
}

.overprint-art__blot--amber {
  aspect-ratio: 1.2;
  background: color-mix(in srgb, var(--detail) 36%, transparent);
  border-radius: 45% 55% 48% 52% / 55% 44% 56% 45%;
  right: 14%;
  top: -16%;
  rotate: 9deg;
  width: 32%;
}

/* ── The ink press — every piece of art arrives as ink meeting paper,
   then breathes (DESIGN.md "Motion"). ink-press.js adds .is-printing to
   a [data-print] root once it is in view (the hero also waits for the
   webfonts) and starts each inked element's coverage build — its own
   clone of the #ink-dissolve filter — on the clock these delays
   describe. Without the class (no script, reduced motion, a thumbnail)
   the resting state is the fully printed page. Knobs: tokens.css. ── */

/* Armed by ink-press.js at load: art waits blank for its arrival, so
   nothing scrolls in printed and then un-prints. Only ever set by the
   script, so no-JS and reduced-motion pages keep the printed rest. */
.will-print:not(.is-printing) .overprint-art > span {
  --hole: 3.3px;
  opacity: 0.4;
}
.will-print:not(.is-printing) .spot-illustration__ink {
  opacity: 0;
}

/* A pass: the halftone closes and the ink saturates while the filter
   builds coverage from the near corner. */
@keyframes ink-pass {
  from {
    --hole: 3.3px;
    opacity: 0.4;
  }
  to {
    --hole: 1.3px;
    opacity: 1;
  }
}

/* The second pass lands out of register and settles in. Transient —
   nothing rests out of register, so the mis-registration budget stays
   at two. */
@keyframes ink-settle {
  from {
    transform: translate(3px, 2px);
  }
  to {
    transform: translate(0, 0);
  }
}

/* Landed ink swells 3% and back. Barely there; the page is never dead
   still. */
@keyframes ink-breathe {
  from {
    transform: scale(1);
  }
  to {
    transform: scale(1.03);
  }
}

/* The hero prints after the h1 has found its register; the close prints
   as soon as it is in view. Each composition sets the clock its layers
   inherit. */
.overprint-art--hero {
  --ink-start: var(--ink-hero-delay);
}

.overprint-art--cta {
  --ink-start: 0ms;
}

.is-printing .overprint-art__stripes--coral,
.is-printing .overprint-art__blot--coral {
  animation:
    ink-pass var(--ink-pass-coral) var(--ease-ink) var(--ink-start) both,
    ink-breathe var(--ink-breathe) ease-in-out
      calc(var(--ink-start) + var(--ink-pass-coral)) infinite alternate;
}

.is-printing .overprint-art__stripes--amber,
.is-printing .overprint-art__blot--amber {
  animation:
    ink-pass var(--ink-pass-amber) var(--ease-ink)
      calc(var(--ink-start) + var(--ink-pass-gap)) both,
    ink-settle var(--ink-settle) var(--ease-out)
      calc(var(--ink-start) + var(--ink-pass-gap) + var(--ink-settle-delay))
      both,
    ink-breathe var(--ink-breathe) ease-in-out
      calc(
        var(--ink-start) + var(--ink-pass-gap) + var(--ink-settle-delay) +
          var(--ink-settle)
      )
      infinite alternate;
}

/* The flood's weather bleeds, slowly. */
@keyframes weather-drift {
  from {
    transform: translate(0, 0) scale(1);
  }
  to {
    transform: translate(-6%, 5%) scale(1.08);
  }
}

@media (prefers-reduced-motion: reduce) {
  .is-printing .overprint-art > span,
  .spot-illustration.is-printing .spot-illustration__ink,
  .section--flood.is-printing .flood-register,
  .section--flood::after {
    animation: none;
  }
}

/* ── Spot illustrations — the fifth overprint placement, closed at
   three on the landing page (DESIGN.md "Concept"). Art, not a container:
   no box. They sit at the top of a section's heading column. ── */
.spot-illustration {
  margin-bottom: 1.25rem;
}

.spot-illustration svg {
  display: block;
  overflow: visible;
}

.spot-illustration .ink-coral {
  fill: color-mix(in srgb, var(--art-coral) 62%, transparent);
}

.spot-illustration .ink-indigo {
  fill: color-mix(in srgb, var(--structure) 62%, transparent);
}

.spot-illustration .ink-amber {
  fill: color-mix(in srgb, var(--detail) 72%, transparent);
}

/* Keylines print, they are not drawn: the paper shapes get the soft
   roughening (a hand-cut edge, no holes — a mottled sheet would let the
   plate behind show through), and the lines take the full ink coverage
   (rough edge, broken density) at overprint strength. A touch heavier
   than a vector hairline so the wobble reads as a keyline, not jitter. */
.spot-illustration .ink-paper {
  fill: var(--bg);
  filter: url(#riso-roughen-soft);
  stroke: color-mix(in srgb, var(--structure) 72%, transparent);
  stroke-width: 1.5;
}

.spot-illustration .ink-line {
  fill: none;
  filter: url(#riso-ink);
  mix-blend-mode: multiply;
  stroke: color-mix(in srgb, var(--structure) 78%, transparent);
  stroke-linecap: round;
  stroke-width: 1.7;
}

.spot-illustration .ink-line--rim {
  stroke-width: 3;
}

.spot-illustration .ink-line--handle {
  stroke-width: 7;
}

/* Inked groups overprint, like every art shape. */
.spot-illustration [filter] {
  mix-blend-mode: multiply;
}

.spot-illustration__ink {
  transform-box: fill-box;
  transform-origin: center;
}

/* The stamp: ink lands a touch heavy and off register, settles with one
   small overshoot, then breathes. */
@keyframes ink-stamp {
  0% {
    opacity: 0;
    transform: scale(1.07) translate(4px, 4px);
  }
  55% {
    opacity: 1;
  }
  100% {
    opacity: 1;
    transform: scale(1) translate(0, 0);
  }
}

.spot-illustration.is-printing .spot-illustration__ink {
  animation:
    ink-stamp var(--ink-stamp) var(--ease-stamp) var(--d, 0ms) both,
    ink-breathe var(--ink-breathe) ease-in-out
      calc(var(--d, 0ms) + var(--ink-stamp)) infinite alternate;
}

/* ── The flood's second plate — register wander (DESIGN.md "Motion").
   The coral weather printed a second time, and while the flood is being
   looked at that second plate wanders a few pixels around register, the
   way a two-color riso's second plate never quite sits still. It never
   RESTS out of register: with no script, or under reduced motion, it
   sits exactly on the first pass and reads as a denser weather — so the
   mis-registration budget stays at two. Transform only: one texture,
   rasterized once. Same gate as the overprint art: ≥768px. ── */
.flood-register {
  background-image: url("/riso/weather-coral.svg");
  background-repeat: no-repeat;
  background-size: cover;
  display: none;
  inset: -8%;
  opacity: 0.7;
  pointer-events: none;
  position: absolute;
}

@media (min-width: 768px) {
  .flood-register {
    display: block;
  }
}

/* Leaves register, wanders, returns — starting and ending on the first
   plate so the arrival is seamless. */
@keyframes weather-wander {
  0% {
    transform: translate(0, 0);
  }
  20% {
    transform: translate(6px, 4px);
  }
  45% {
    transform: translate(-5px, 6px);
  }
  70% {
    transform: translate(-6px, -4px);
  }
  90% {
    transform: translate(5px, -5px);
  }
  100% {
    transform: translate(0, 0);
  }
}

.is-printing .flood-register {
  animation: weather-wander var(--ink-wander) ease-in-out infinite;
}

/* ── Ambient motion rests while its root is off screen — ink-press.js
   toggles .is-offscreen on every print root. Each selector outranks the
   rule that starts the animation, since the animation shorthand resets
   play-state to running. ── */
.is-offscreen .overprint-art > span,
.spot-illustration.is-offscreen .spot-illustration__ink,
.section--flood.is-offscreen .flood-register {
  animation-play-state: paused;
}

/* ── Contour field — irregular topographic rings off one edge, mapping-the-
   market grammar. Applied sparingly (problem, why-us). ── */
.section--contour {
  overflow: hidden;
  position: relative;
}
.section--contour > .shell {
  position: relative;
  z-index: 1;
}
.section--contour::before {
  content: "";
  position: absolute;
  z-index: 0;
  pointer-events: none;
  width: min(680px, 78%);
  aspect-ratio: 1;
  right: -14%;
  top: 50%;
  transform: translateY(-50%);
  background: url("/riso/topo-rings.svg") center / contain no-repeat;
  -webkit-mask-image: radial-gradient(closest-side, #000 22%, transparent 96%);
  mask-image: radial-gradient(closest-side, #000 22%, transparent 96%);
}
.section--contour-left::before {
  left: -14%;
  right: auto;
}

/* ── Ambient wash — one soft gradient blob off a section corner. Composable
   with the tint/dot passes; applied sparingly (offer bottom-left, FAQ
   top-right via the --flip modifier so the two placements don't rhyme). ── */
.section--ambient {
  overflow: hidden;
  position: relative;
}
.section--ambient > .shell {
  position: relative;
  z-index: 1;
}
.section--ambient::before {
  content: "";
  position: absolute;
  width: 52%;
  aspect-ratio: 1.3;
  left: -14%;
  bottom: -24%;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(
    44% 48% at 52% 46%,
    rgba(224, 170, 37, 0.16),
    rgba(224, 170, 37, 0) 72%
  );
  border-radius: 52% 48% 60% 40% / 46% 58% 42% 54%;
  transform: rotate(11deg);
}
.section--ambient-flip::before {
  bottom: auto;
  left: auto;
  right: -12%;
  top: -22%;
  transform: rotate(-8deg);
}

/* ── Hero — grain field behind a centered TechFrame plate ── */
.hero {
  padding: 3rem 0 4rem;
  position: relative;
}
/* Display width mirrors content pages' documented 24ch (DESIGN.md
   "Widths") so a long headline breaks into balanced lines. */
.hero h1 {
  max-width: 24ch;
}
.hero .tech-frame {
  margin: 0 auto;
  max-width: var(--shell);
  position: relative;
  z-index: 1;
}
.hero__content {
  padding: 3.5rem 3rem 3.25rem;
  position: relative;
  z-index: 1;
}

@media (max-width: 640px) {
  .hero__content {
    padding: 2.5rem 1.5rem 2.25rem;
  }
}

.hero__sub {
  color: var(--text-soft);
  font-size: 1.2rem;
  margin: 1.25rem 0 2rem;
  max-width: var(--measure);
}

.hero__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

:where(.cal-modal-trigger) {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  font: inherit;
}

.btn {
  border-radius: var(--radius);
  display: inline-block;
  font-weight: 600;
  padding: 0.8rem 1.5rem;
  text-decoration: none;
}

/* Mis-registration detail: the amber plate printed slightly out of
   register; hover "snaps into registration" (signature — two placements
   max, see h1 below). */
.btn--primary {
  background: var(--accent);
  border: 1px solid var(--accent);
  box-shadow: 3px 3px 0 rgba(224, 170, 37, 0.85);
  color: #fff;
  transition:
    box-shadow 120ms var(--ease-out),
    transform 120ms var(--ease-out);
}

.btn--primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  box-shadow: 0 0 0 rgba(224, 170, 37, 0.85);
  transform: translate(2px, 2px);
}

/* Registration snaps further on press — the same move, one step deeper. */
.btn--primary:active {
  transform: translate(3px, 3px);
}

@media (prefers-reduced-motion: reduce) {
  .btn--primary {
    transition: none;
  }
}

.btn--ghost {
  border: 1px solid var(--rule-strong);
  color: var(--text);
  transition: border-color 150ms var(--ease-out);
}

.btn--ghost:hover {
  border-color: var(--detail);
  color: var(--accent);
}

/* Same treatment on :active so a tap (no hover on touch) still confirms. */
.btn--ghost:active {
  border-color: var(--detail);
  color: var(--accent);
}

@media (prefers-reduced-motion: reduce) {
  .btn--ghost {
    transition: none;
  }
}

/* Disabled state — the form submit button while a request is in flight. */
.btn[disabled] {
  box-shadow: none;
  cursor: default;
  opacity: 0.6;
  pointer-events: none;
}

#candidates .btn {
  cursor: pointer;
}

#candidates .btn[disabled] {
  cursor: not-allowed;
  pointer-events: auto;
}

/* Offer deliverables — band cells, not floating boxes: the same flush
   hairline grammar as the stats HUD. */
.deliverables {
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  list-style: none;
  padding: 0;
}

.deliverables li {
  padding: 1.5rem;
}

.deliverables__index {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 0.85rem;
  letter-spacing: 0.05em;
}

.deliverables p {
  color: var(--text-soft);
  margin: 0;
}

/* Why-us — two columns separated by a hairline rule centered in the gap
   (the HUD's divider grammar); stacks with a horizontal rule on mobile. */
.why {
  display: grid;
  gap: 2.5rem;
  grid-template-columns: 1fr;
  margin-top: 2.5rem;
}

.why > div + div {
  position: relative;
}

.why > div + div::before {
  background: var(--rule);
  content: "";
  height: 1px;
  inset: -1.25rem 0 auto 0;
  position: absolute;
}

@media (min-width: 768px) {
  .why {
    grid-template-columns: 1fr 1fr;
  }

  .why > div + div::before {
    height: auto;
    inset: 0 auto 0 -1.25rem;
    width: 1px;
  }
}

/* .strip carries no border-top: its tinted surface already marks the seam
   (one seam device per boundary). */

.strip form,
.strip .strip__success {
  margin-top: 1.5rem;
  /* Exception, deliberate: a field column, not a reading measure —
     inputs are sized to the answer they take, not to a line of prose. */
  max-width: 30rem;
}

/* The acknowledgement is the checklist box ticked. The page prints that
   box unticked all the way down the vetting list; here it is the one the
   visitor just checked, so the answer is drawn in their own vocabulary
   rather than announced in a heading alone. Amber's checklist-box job,
   in its checked state — no new ink, no new mark. */
.strip .strip__success {
  display: flex;
  gap: 0.9rem;
}

.strip__success h3 {
  margin-top: 0;
}

.strip__success-box {
  border: 1.5px solid var(--detail);
  border-radius: 1px;
  flex-shrink: 0;
  height: 15px;
  margin-top: 0.3em;
  position: relative;
  width: 15px;
}

/* The tick strokes itself in once, over ~180ms after the box lands: the
   mark being made, not a state that was always there. One authored
   moment, at the one interaction on this page that earns it. */
.strip__success-box::after {
  animation: tick-draw 260ms var(--ease-out) 120ms backwards;
  border-bottom: 1.5px solid var(--detail);
  border-right: 1.5px solid var(--detail);
  content: "";
  height: 8px;
  left: 4.5px;
  position: absolute;
  top: 0.5px;
  /* Rotated about its own centre, so the 4x8 L stays inside the 12px
     padding box; pivoting on a corner threw the long arm out past the
     box's top-right rule. */
  transform: rotate(45deg);
  width: 4px;
}

/* Clipped along the tick's own axis rather than grown from zero size:
   the geometry stays fixed while the stroke is revealed, so the mark
   lands exactly where the static version sits. */
@keyframes tick-draw {
  from {
    clip-path: inset(0 100% 0 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .strip__success-box::after {
    animation: none;
  }
}

.form-field {
  display: block;
  margin-bottom: 1rem;
}

.form-field span {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  margin-bottom: 0.35rem;
}

.form-field input {
  background: #fff;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  font: inherit;
  padding: 0.7rem 0.9rem;
  width: 100%;
}

.form-field input:focus {
  border-color: var(--accent);
}

/* Ties the offending field to its .form-error message for screen-reader
   and sighted users alike; reuses the same red already used for the text
   below, not a new hue. */
.form-field input[aria-invalid="true"] {
  border-color: #a33a2a;
}

.form-error {
  color: #a33a2a;
  font-size: 0.9rem;
  margin: 0.5rem 0 0;
}

/* The consent notice carries the legal weight of what the visitor agreed
   to, so it has to read as text rather than as browser chrome: the same
   0.85rem as .form-field span, secondary ink, and enough bottom margin that
   it stops butting against the submit button. Top-aligned to the box so a
   wrapped second line stays flush with the first. The tick is indigo — the
   structural ink — not amber: --accent is primary buttons ONLY
   (DESIGN.md, "The inks"). */
.strip__consent {
  accent-color: var(--structure);
  align-items: flex-start;
  color: var(--text-soft);
  display: flex;
  font-size: 0.85rem;
  gap: 0.55rem;
  line-height: 1.45;
  margin: 1rem 0 1.5rem;
}

.honeypot {
  left: -9999px;
  position: absolute;
}

/* ── Page chrome — the header bar and the footer. Neither is a container
   from the ladder: they are the page's own frame, drawn with the same 1px
   rule tokens, mono labels and no box. ── */
.site-header {
  background: var(--bg);
  border-bottom: 1px solid var(--rule);
}

/* Wraps rather than collapsing into a menu: the nav lists pillars only
   (content/nav.ts), so it stays short enough to print inline — one row on
   a laptop, two on a phone (wordmark + CTA, then the links). */
.site-header__bar {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.25rem;
  padding: 0.9rem 0;
  /* The containing block the wrapped-nav dropdown hangs from — see
     .nav-drop__panel in SiteHeader.astro. */
  position: relative;
}

.site-header__mark {
  color: var(--text);
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  text-decoration: none;
}

.site-header__nav {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  margin-left: auto;
}

.site-header__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-decoration: none;
  text-transform: uppercase;
}

.site-header__cta {
  font-size: 0.85rem;
  padding: 0.55rem 1.1rem;
}

@media (max-width: 640px) {
  .site-header__mark {
    order: 1;
  }

  .site-header__cta {
    font-size: 0.8rem;
    margin-left: auto;
    order: 2;
    padding: 0.5rem 0.9rem;
  }

  .site-header__nav {
    gap: 0.75rem;
    margin-left: 0;
    order: 3;
    width: 100%;
  }
}

/* Shared resources dropdown: Astro and backend-rendered jobs. */
/* Hover opens for a mouse, :focus-within opens for the keyboard, and
   a tap just follows the link to /resources/ — no JS, nothing to
   break without it. */
.nav-drop {
  align-items: center;
  display: flex;
  position: relative;
}

/* The trigger flexes so the smaller caret glyph can't drag its line
   box (and the whole item) below the sibling links' baseline. */
.nav-drop > .site-header__link {
  align-items: center;
  display: inline-flex;
  gap: 0.25rem;
}

.nav-drop__caret {
  font-size: 8px;
  line-height: 1;
}

.nav-drop__panel {
  background: var(--bg);
  border: 1px solid var(--rule-strong);
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  min-width: 10rem;
  opacity: 0;
  padding: 0.9rem 1rem;
  pointer-events: none;
  position: absolute;
  /* Anchored to the trigger's RIGHT edge, so the panel grows inward
     rather than toward the viewport. Centring it (the old rule) aimed
     its growth at the right edge instead: the trigger is the last nav
     item before the CTA, so the panel overran the viewport by up to
     54px — and because a CLOSED panel still counts toward scroll
     width, every page scrolled sideways on a phone with nothing
     visible to explain it. */
  right: 0;
  top: calc(100% + 0.5rem);
  visibility: hidden;
  z-index: 20;
}

/* Below the header's wrap point the nav drops to its own row and the
   trigger's position stops being predictable — it sits at the row's
   left edge at 320px and 190px further right at 375px. Anchoring to
   it therefore overflows one side or the other whichever edge we
   pick, so the panel stops hanging off the trigger and spans the
   header bar instead: it cannot pass an edge it is measured from. */
@media (max-width: 640px) {
  .nav-drop {
    position: static;
  }

  .nav-drop__panel {
    left: 0;
    right: 0;
  }
}

/* A hoverless bridge so the pointer can cross the gap between the
   link and the panel without closing it. */
.nav-drop::after {
  content: "";
  height: 0.6rem;
  inset: 100% 0 auto;
  position: absolute;
}

.nav-drop:hover .nav-drop__panel,
.nav-drop:focus-within .nav-drop__panel {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
}

.nav-drop__item--all {
  border-top: 1px solid var(--rule);
  padding-top: 0.75rem;
}

/* The dropdown is the cluster list, so a row names a cluster and says
   how deep it runs — the same count the index shelf prints. Mono for
   the count: it is an annotation, which is the mono face's job. */
.nav-drop__item {
  align-items: baseline;
  display: flex;
  gap: 1.5rem;
  justify-content: space-between;
}

.nav-drop__count {
  color: var(--text-soft);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.site-footer {
  border-top: 1px solid var(--rule);
  color: var(--text-soft);
  font-size: 0.9rem;
  padding: 3rem 0 2.5rem;
}

.site-footer a {
  color: inherit;
}

.site-footer__cols {
  display: grid;
  gap: 2rem;
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .site-footer__cols {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.site-footer__label {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  margin: 0 0 0.9rem;
  text-transform: uppercase;
}

.site-footer__col ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.site-footer__col li {
  border-top: 1px solid var(--rule);
}

.site-footer__col li:last-child {
  border-bottom: 1px solid var(--rule);
}

.site-footer__col a {
  display: block;
  padding: 0.6rem 0;
  text-decoration: none;
}

.site-footer__practice {
  margin: 2.5rem 0 0;
}

/* ── Page list — the ledger one page uses to point at several others: a
   pillar's hub list of its cluster members, and the landing page's route
   into the framework. Hairline rows, title in the display face. ── */
.page-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* The wash stops at the rules: a ledger row reserves its own paper, the
   way plate interiors and band cells do, so a section's dot or tint pass
   prints around the rows rather than behind the type. */
.page-list li {
  background-color: var(--bg);
  border-top: 1px solid var(--rule);
  padding: 1rem;
  position: relative;
}

.page-list li:last-child {
  border-bottom: 1px solid var(--rule);
}

/* Every row except the current page's is a link row, so the whole row is
   the target: the title's hit area stretches over it (one tab stop, the
   title as the accessible name) and the row answers on hover with the
   pointer and the same amber wash, printed over its paper. The current
   page's row is deliberately inert — it carries no click affordance, so
   it is excluded here rather than answering a hover it can't act on. */
.page-list li:not(:has(.page-list__here)):hover {
  background-image: linear-gradient(
    rgba(224, 170, 37, 0.1),
    rgba(224, 170, 37, 0.1)
  );
  cursor: pointer;
}

/* Row links: the row is the target and answers with the wash; the
   title carries the amber underline as the standing click signal. */
.page-list a {
  color: var(--text);
  font-family: var(--font-display);
  font-size: 1.1rem;
}

.page-list a::after {
  content: "";
  inset: 0;
  position: absolute;
}

.page-list a:hover {
  color: var(--accent);
}

.page-list p {
  color: var(--text-soft);
  font-size: 0.9rem;
  margin: 0.35rem 0 0;
  max-width: var(--measure);
}

/* The pillar's row says so, in the same words and the same mono
   annotation voice the index shelf uses for its lead guide. Scoped as
   `.page-list .page-list__start` (0,2,0) because it sits inside a
   `.page-list li` row and the row's own `.page-list p` rule (0,1,1) would
   otherwise win the cascade and overwrite these declarations. */
.page-list .page-list__start {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  margin: 0 0 0.35rem;
  text-transform: uppercase;
}

/* You-are-here borrows the catalog's selected-row vocabulary exactly:
   the structure tint at selection strength, no new ink and no new edge.
   It is a span, not an anchor — a link to the page you are reading is a
   promise the system does not keep. */
.page-list li:has(.page-list__here) {
  background-color: rgba(58, 74, 140, 0.08);
}

.page-list__here {
  color: var(--text);
  display: block;
  font-family: var(--font-display);
  font-size: 1.1rem;
}

/* ── Catalog — a Band variant for a set too long to print open: nine
   ledger rows on the left against one specification panel on the right,
   selection swapping the panel. Same edges as a Band (strong outer rule,
   hairline row dividers, paper cells); the only additions are the two
   states a selection needs, both washes of inks that already own them —
   amber for hover (the ghost button's hover ink) and the structure tint
   at selection strength for the active row. ── */
.catalog {
  border: 1px solid var(--rule-strong);
  display: grid;
  grid-template-columns: 1fr;
  margin-top: 2.5rem;
}

@media (min-width: 860px) {
  .catalog {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
  }
}

.catalog__list {
  border-bottom: 1px solid var(--rule-strong);
  list-style: none;
  margin: 0;
  padding: 0;
}

@media (min-width: 860px) {
  .catalog__list {
    border-bottom: 0;
    border-right: 1px solid var(--rule-strong);
  }
}

.catalog__list li + li .catalog__row {
  border-top: 1px solid var(--rule);
}

.catalog__row {
  align-items: baseline;
  color: inherit;
  display: grid;
  gap: 0.2rem 0.9rem;
  grid-template-columns: 1.6rem auto minmax(7rem, 1fr);
  padding: 0.78rem 1.1rem;
  text-decoration: none;
  transition: background 120ms var(--ease-out);
}

.catalog__row:hover {
  background: rgba(224, 170, 37, 0.1);
}

@media (prefers-reduced-motion: reduce) {
  .catalog__row {
    transition: none;
  }
}

.catalog__index {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 0.7rem;
}

.catalog__name {
  font-family: var(--font-display);
  font-size: 0.98rem;
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--detail);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

/* The row anchor inherits the base hover; only the name answers. */
.catalog__row:hover {
  color: inherit;
}

.catalog__row:hover .catalog__name {
  color: var(--accent);
  text-decoration-color: currentColor;
}

.catalog__scan {
  color: var(--text-soft);
  font-size: 0.88rem;
  line-height: 1.45;
  min-width: 0;
  white-space: normal;
}

/* Narrow rows stack the scan line under the name instead of sharing the
   row with the index column. */
@media (max-width: 859px) {
  .catalog__row {
    grid-template-columns: 1.6rem minmax(0, 1fr);
  }

  .catalog__name,
  .catalog__scan {
    grid-column: 2;
  }
}

/* The selected row: the tint pass at selection strength, its index in
   amber, and the accent marker pointing at the panel it prints. */
.catalog__row[aria-current] {
  background: rgba(58, 74, 140, 0.08);
}

.catalog__row[aria-current] .catalog__index {
  color: var(--detail-text);
}

.catalog__row[aria-current] .catalog__name::after {
  color: var(--accent);
  content: " ▸";
}

.catalog__panel {
  padding: 1.8rem 1.5rem;
}

/* Selecting a row swaps the specification beside it, and the swap used
   to be a hard cut — the panel simply became a different panel, which
   reads as a flicker rather than as an answer to the click. The new
   spec prints instead, in the timeline's vocabulary: ink landing, a few
   pixels of settle. It runs only on selection, never on load — before
   the script runs every panel is already visible, so panel 0 never
   changes display and never animates. */
@media (prefers-reduced-motion: no-preference) {
  .catalog__panel:not([hidden]) {
    animation: catalog-print 200ms var(--ease-out);
  }
}

/* Stillness was asked for, but the swap still has to be legible as a
   swap — the movement goes, the ink still lands. */
@media (prefers-reduced-motion: reduce) {
  .catalog__panel:not([hidden]) {
    animation: catalog-ink 140ms var(--ease-out);
  }
}

@keyframes catalog-print {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
}

@keyframes catalog-ink {
  from {
    opacity: 0;
  }
}

@media (min-width: 860px) {
  .catalog__spec {
    align-self: start;
    position: sticky;
    top: 1.5rem;
  }

  .catalog__panel {
    padding: 1.8rem 2rem;
  }
}

.catalog__spec-label {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  margin: 0 0 0.5rem;
  text-transform: uppercase;
}

.catalog__panel h3 {
  font-size: 1.45rem;
  margin: 0 0 0.7rem;
}

.catalog__panel p:not(.catalog__spec-label) {
  margin: 0 0 0.75rem;
}

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

/* Only once the script has run does the panel column show one at a time;
   without JS every panel stays printed and every row is an anchor to its
   own. */
.catalog__panel + .catalog__panel {
  border-top: 1px solid var(--rule);
}

/* ── Question list — a register too long for the catalog ledger.
   Same grammar as the catalog (mono index, display title, scan line, amber
   hover, structure tint on the open row); the difference is that it runs
   full width and opens in place rather than printing into a side panel.
   No new hue and no new edge weight — the two rules and the three inks. */
.qlist {
  margin-top: 2.5rem;
}

.qlist__filters-label {
  color: var(--text-faint);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  margin: 0 0 0.7rem;
  text-transform: uppercase;
}

.qlist__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.qlist__chip {
  background: none;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  color: var(--text-soft);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  padding: 0.36rem 0.68rem;
  transition:
    background 120ms var(--ease-out),
    border-color 120ms var(--ease-out),
    color 120ms var(--ease-out);
}

.qlist__chip:hover {
  background: var(--accent-light);
  border-color: var(--rule-strong);
  color: var(--text);
}

.qlist__chip[aria-pressed="true"] {
  background: var(--structure);
  border-color: var(--structure);
  color: var(--bg);
}

.qlist__chip-n {
  font-variant-numeric: tabular-nums;
  margin-left: 0.35rem;
  opacity: 0.62;
}

.qlist__state {
  border-bottom: 1px solid var(--rule-strong);
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
  margin: 1.3rem 0 0;
  padding-bottom: 0.5rem;
  text-transform: uppercase;
}

/* Without the script the filter bar is hidden, so the register needs its
   own top edge — the state line is not there to draw one. */
.qlist__filters[hidden] + .qlist__rows {
  border-top: 1px solid var(--rule-strong);
}

.qlist__rows {
  border-bottom: 1px solid var(--rule-strong);
  list-style: none;
  margin: 0;
  padding: 0;
}

.qlist__item + .qlist__item {
  border-top: 1px solid var(--rule);
}

.qlist__item[hidden] {
  display: none;
}

/* The scan line sits UNDER the question rather than beside it. Beside it,
   a question long enough to wrap squeezes the scan to a few words and an
   ellipsis on nearly every row — and a truncated essence is worse than no
   essence (the same call the catalog row makes at narrow widths, taken
   here at every width because these questions are sentences, not names). */
.qlist__row {
  cursor: pointer;
  display: grid;
  gap: 0.15rem 1rem;
  grid-template-columns: 2.1rem minmax(0, 1fr) 1.1rem;
  list-style: none;
  padding: 0.8rem 1.1rem 0.85rem;
  transition: background 120ms var(--ease-out);
}

.qlist__row::-webkit-details-marker {
  display: none;
}

/* Hover is the closed row's invitation. An open row has already answered
   it and wears the selection tint instead — letting hover repaint just its
   header would split the open block into two colours. */
.qlist__details:not([open]) .qlist__row:hover {
  background: var(--accent-light);
}

.qlist__index {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-variant-numeric: tabular-nums;
  /* The index sits on the question's first baseline, not the row's top. */
  padding-top: 0.2rem;
}

/* No underline. The amber underline is this system's standing signal for a
   LINK — something that takes the reader elsewhere (DESIGN.md, "Row
   links"). A question takes them nowhere; it opens underneath them.
   Carrying the link treatment here promised a navigation that never
   happened, so the row states its affordance with the marker below and
   with hover, and keeps the underline for things that really do leave. */
.qlist__q {
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.45;
  transition: color 120ms var(--ease-out);
}

.qlist__row:hover .qlist__q {
  color: var(--accent);
}

/* The disclosure tick: a drafting mark that turns a quarter-turn down when
   the row opens. It is the only moving part, and it moves once. */
/* Drawn, not typed: two 1px strokes meeting at a right angle, on the same
   hairline the rest of the page is ruled with. A glyph would carry a
   typeface's own metrics and weight, and would pivot around its em box
   rather than its own corner when the row opens. */
.qlist__marker {
  align-self: center;
  grid-column: 3;
  grid-row: 1 / -1;
  height: 0.44rem;
  justify-self: end;
  position: relative;
  transform: rotate(45deg);
  transition: transform 200ms var(--ease-out);
  width: 0.44rem;
}

.qlist__marker::before,
.qlist__marker::after {
  background: var(--structure);
  content: "";
  position: absolute;
  transition: background 120ms var(--ease-out);
}

/* The two strokes of the corner: one across the top, one down the right. */
.qlist__marker::before {
  height: 1px;
  left: 0;
  top: 0;
  width: 100%;
}

.qlist__marker::after {
  bottom: 0;
  height: 100%;
  right: 0;
  width: 1px;
}

.qlist__row:hover .qlist__marker::before,
.qlist__row:hover .qlist__marker::after {
  background: var(--accent);
}

.qlist__details[open] .qlist__marker {
  transform: rotate(135deg);
}

.qlist__scan {
  color: var(--text-faint);
  font-size: 0.84rem;
  grid-column: 2;
  line-height: 1.45;
  max-width: var(--measure);
}

/* The open row takes the catalog's selection treatment: structure tint,
   amber index, accent marker — the same two states, said the same way. */
.qlist__details[open] {
  background: rgba(58, 74, 140, 0.08);
}

.qlist__details[open] .qlist__index {
  color: var(--detail-text);
}

/* The open state is carried by the tint, the amber index and the turned
   marker. A second glyph on the question itself would say it a fourth
   time. */

/* The body arrives rather than appearing. One short move, and only for
   readers who have not asked for stillness. */
@media (prefers-reduced-motion: no-preference) {
  .qlist__details[open] .qlist__detail {
    animation: qlist-reveal 180ms var(--ease-out);
  }
}

@keyframes qlist-reveal {
  from {
    opacity: 0;
    transform: translateY(-3px);
  }
}

/* The body is a second surface for closing the row, so it says so with the
   pointer. A text cursor here reads as "nothing to click" and the
   affordance goes undiscovered. */
.qlist__detail {
  border-top: 1px solid var(--rule);
  cursor: pointer;
  /* Left and right match. The left inset hangs the body under the question
     rather than the index, and the rules inside it are only square with
     the row when the right inset answers it. */
  padding: 1.15rem 4.2rem 1.4rem;
}

@media (max-width: 719px) {
  .qlist__detail {
    padding-left: 1.1rem;
    padding-right: 1.1rem;
  }
}

/* Both labels take structure ink. Amber already means "this is the one
   selected" on the open row's index; spending it again on WEAK would give
   one ink two jobs and read as a severity the palette does not own. The
   two cells are told apart by the rule between them and by the words. */
.qlist__label {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  margin: 0 0 0.45rem;
  text-transform: uppercase;
}

.qlist__block {
  margin: 0;
}

/* Follow-ups are the instrument, so they get the panel's opening position
   and its full measure. */
.qlist__follow {
  color: var(--text-soft);
  list-style: none;
  margin: 0;
  max-width: var(--measure);
  padding: 0;
}

.qlist__follow li {
  padding-left: 1.35rem;
  position: relative;
}

.qlist__follow li + li {
  margin-top: 0.4rem;
}

/* A leader dash on the same hairline as every other line on the page,
   sitting on the first line's baseline — a drafting mark, not a bullet. */
.qlist__follow li::before {
  background: var(--rule-strong);
  content: "";
  height: 1px;
  left: 0;
  position: absolute;
  top: 0.72em;
  width: 0.75rem;
}

.qlist__signal {
  color: var(--text-soft);
  margin: 0;
  max-width: var(--measure);
}

/* Strong and weak are read against each other — the pair is the rubric —
   so they sit side by side wherever there is room, as two cells of one
   spec block: a rule across the top of both, and a rule between them. */
.qlist__pair {
  border-top: 1px solid var(--rule);
  display: grid;
  gap: 1.15rem;
  margin-top: 1.4rem;
  padding-top: 1.1rem;
  position: relative;
}

@media (min-width: 820px) {
  .qlist__pair {
    column-gap: 4rem;
    grid-template-columns: 1fr 1fr;
  }

  /* The divider is drawn at the pair's true midpoint rather than hung off
     the weak cell's edge. Two equal `1fr` tracks either side of one gap
     put 50% exactly in the gap's centre, so both cells get the same
     measure — the previous version padded the rule off the weak cell and
     took that padding out of its width, leaving weak narrower than
     strong for no reason a reader could see. */
  .qlist__pair::before {
    background: var(--rule);
    bottom: 0;
    content: "";
    left: 50%;
    position: absolute;
    top: 0;
    width: 1px;
  }
}

.qlist__empty {
  color: var(--text-soft);
  padding: 1.6rem 1.1rem;
}

/* ── Band cells — the deliverables grammar (mono index, display title,
   soft body) carrying an enumerated set: the taxonomy's domains and
   approaches, and the landing page's framework links. No new box; .band
   supplies the rules and the paper knockout. Column counts are set per
   band, never auto-fit — an unoccupied grid cell prints as a block of
   band background. ── */
.band-cells {
  grid-template-columns: 1fr;
  list-style: none;
  padding: 0;
}

@media (min-width: 640px) {
  .band-cells--two {
    grid-template-columns: 1fr 1fr;
  }
}

@media (min-width: 860px) {
  .band-cells--three {
    grid-template-columns: repeat(3, 1fr);
  }
}

.band-cells li {
  padding: 1.5rem;
}

.band-cells__index {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 0.85rem;
  letter-spacing: 0.05em;
  margin: 0 0 0.35rem;
}

/* Cell titles fill the cell rather than balancing. The global h1/h2/h3
   rule sets `text-wrap: balance`, which is right for a page headline
   sitting alone in a wide plate and wrong here: a cell is already narrow,
   so balancing pulls a two-line title well short of the right edge and
   leaves a column of dead space beside it. `pretty` still prevents an
   orphaned last word. */
.band-cells h3 {
  margin: 0 0 0.6rem;
  text-wrap: pretty;
}

.band-cells h3 a {
  color: var(--text);
}

.band-cells h3 a:hover {
  color: var(--accent);
}

/* A cell whose title is a link is a link card: the title's hit area
   stretches over the whole cell, so the click target matches what the
   cell looks like — and the cell says so on hover, with the same amber
   wash the catalog rows use. Cells with no link (the taxonomy's
   approaches) are untouched. */
.band-cells li:has(.band-cells__link) {
  position: relative;
}

.band-cells li:has(.band-cells__link):hover {
  /* Amber printed OVER the cell's paper, not instead of it — a bare rgba
     would let a washed section's tint show through and read grey (the
     pocket card's recipe). */
  background-color: var(--bg);
  background-image: linear-gradient(
    rgba(224, 170, 37, 0.1),
    rgba(224, 170, 37, 0.1)
  );
  cursor: pointer;
}

.band-cells__link::after {
  content: "";
  inset: 0;
  position: absolute;
}

.band-cells li p:not(.band-cells__index) {
  color: var(--text-soft);
  margin: 0 0 0.75rem;
}

.band-cells li p:last-child {
  margin-bottom: 0;
}

/* v2 sections */

/* Checklist — hairline-separated rows, Fragment Mono index leading each item.
   No border-left accent stripes (design ban). */
.checklist {
  list-style: none;
  margin: 2rem 0 0;
  max-width: var(--measure);
  padding: 0;
}

.checklist li {
  border-top: 1px solid var(--rule);
  color: var(--text-soft);
  display: flex;
  gap: 1rem;
  padding: 0.9rem 0;
}

.checklist li:last-child {
  border-bottom: 1px solid var(--rule);
}

/* Print-style checkbox leading each row — the reader ticks boxes; amber
   detail ink. Decorative, not interactive (aria-hidden). */
.checklist__box {
  border: 1.5px solid var(--detail);
  border-radius: 1px;
  flex-shrink: 0;
  height: 15px;
  margin-top: 0.3em;
  width: 15px;
}

.checklist__closer {
  font-family: var(--font-display);
  font-size: 1.2rem;
  margin-top: 2rem;
  max-width: var(--measure);
}

/* Pricing — a spec-sheet panel wrapped in a TechFrame; the frame is the sole
   enclosure. Terms are hairline-separated rows, first row ink-primary. */
.pricing-frame {
  margin-top: 2.5rem;
}

.pricing {
  padding: 2.25rem 2rem 2rem;
}

.pricing__terms {
  list-style: none;
  margin: 0 0 1.75rem;
  padding: 0;
}

.pricing__terms li {
  border-bottom: 1px solid var(--rule);
  color: var(--text-soft);
  padding: 0.85rem 0;
}

.pricing__terms li:first-child {
  color: var(--text);
  font-weight: 600;
}

/* Timeline — the 30-day ruler: the spine graduates into a measuring
   instrument (1px hairline + minor tick comb), amber major ticks marking
   each phase start. The tail fades out past the last phase — the 90-day
   guarantee runs beyond the measured window. One spine per page. */
.timeline {
  list-style: none;
  margin: 2.5rem 0 0;
  padding: 0;
  position: relative;
}

.timeline::before {
  background:
    repeating-linear-gradient(
        to bottom,
        var(--rule) 0 1px,
        transparent 1px 10px
      )
      0 0 / 7px 100% no-repeat,
    linear-gradient(var(--rule-strong), var(--rule-strong)) 0 0 / 1px 100%
      no-repeat;
  content: "";
  inset: 0 auto 0 0;
  -webkit-mask-image: linear-gradient(#000 72%, transparent 98%);
  mask-image: linear-gradient(#000 72%, transparent 98%);
  pointer-events: none;
  position: absolute;
  width: 7px;
}

.timeline__phase {
  margin: 0;
  padding: 0 0 1.75rem 1.5rem;
  position: relative;
}

/* Major graduation: an amber dash reaching from the spine toward the
   phase label. */
.timeline__phase::before {
  background: var(--detail);
  content: "";
  height: 2px;
  left: 0;
  position: absolute;
  top: 0.5rem;
  width: 14px;
}

/* Print-in: each phase presses onto the page as it scrolls into view.
   Scroll-driven (no JS), gated so unsupported browsers and reduced-motion
   users get the fully visible static list. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .timeline__phase {
      animation: timeline-print linear both;
      animation-range: entry 0% entry 45%;
      animation-timeline: view();
    }
  }
}

@keyframes timeline-print {
  from {
    opacity: 0.1;
    transform: translateY(10px);
  }
}

.timeline__phase h3 {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  margin-bottom: 0.4rem;
  text-transform: uppercase;
}

.timeline__phase p {
  color: var(--text-soft);
  margin: 0;
  max-width: var(--measure);
}

/* Logo wall — bare client logos printed straight on the paper, no boxes:
   a single file of featured marks distributed across the full measure,
   reading as one line of type. Each mark is a CSS mask filled with soft
   ink, so mixed-color source assets all print in the same indigo. */
.logos {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 1.75rem 2.5rem;
  justify-content: space-between;
  list-style: none;
  margin: 2.75rem 0 0;
  padding: 0;
}

@media (max-width: 720px) {
  .logos {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    justify-items: start;
  }
}

.logos__logo {
  background: var(--text-soft);
  display: block;
  -webkit-mask: var(--mark) center / contain no-repeat;
  mask: var(--mark) center / contain no-repeat;
}

/* The total line: a full-width hairline rule (ledger grammar) sums the
   entries above it — the payoff lands in serif ink on the left, and the
   rest of the client list rides the same line as a mono annotation. */
.logos__total {
  align-items: baseline;
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2.5rem;
  justify-content: space-between;
  margin-top: 2.75rem;
  padding-top: 1.25rem;
}

.logos__closer {
  color: var(--text);
  font-family: var(--font-display);
  font-size: 1.3rem;
  margin: 0;
  text-wrap: balance;
}

.logos__also {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  margin: 0;
  text-transform: uppercase;
}

/* Testimonial — a set pull quote printed straight on the paper, no box
   (same discipline as the logo wall). Besley carries the quote; the only
   ornament is one amber detail mark: an oversized opening quote glyph.
   Attribution is a structural annotation (mono, indigo) plus the same
   ink-masked Archive mark the wall uses. */
.testimonial {
  padding-top: 3.5rem;
}

/* Exception, deliberate: centered display type on the flood reads on
   its own measure — wider than the body measure at a larger size, and
   centered rather than ranged left, because it is set as a quote. */
.testimonial__figure {
  margin: 0 auto;
  max-width: 44rem;
  text-align: center;
}

.testimonial__quote {
  margin: 0;
}

.testimonial__quote::before {
  color: var(--detail);
  content: "\201C";
  display: block;
  font-family: var(--font-display);
  font-size: 4.5rem;
  line-height: 0.72;
  margin-bottom: 0.75rem;
}

.testimonial__quote p {
  color: var(--text);
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 2.2vw, 1.45rem);
  line-height: 1.55;
  margin: 0 0 1em;
  text-wrap: pretty;
}

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

.testimonial__attribution {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  justify-content: center;
  margin-top: 2rem;
}

/* Grayscale keeps the photo inside the three-ink discipline — it prints
   as a halftone element, not a full-color intrusion on the paper. */
.testimonial__photo {
  border-radius: 50%;
  filter: grayscale(1);
  height: 48px;
  object-fit: cover;
  width: 48px;
}

.testimonial__who {
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Below the hero the logo wall runs as a proof argument on one axis:
   claim, one-line setup, a single file of marks, then the ruled total
   line (serif payoff left, "also" annotation right). */
.logos-strip {
  padding: 3.25rem 0 3.75rem;
}

.logos-strip h2 {
  font-size: 1.55rem;
  margin-bottom: 0.5rem;
}

/* FAQ — serif question, Fragment Mono "+" indicator that rotates on open. */
.faq {
  margin-top: 2rem;
  max-width: var(--measure);
}

.faq__item {
  border-bottom: 1px solid var(--rule);
  padding: 1rem 0;
}

.faq__item summary {
  align-items: center;
  cursor: pointer;
  display: flex;
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 600;
  list-style: none;
  min-height: 44px;
  padding-right: 2rem;
  position: relative;
}

.faq__item summary::-webkit-details-marker {
  display: none;
}

.faq__item summary::after {
  color: var(--detail-text);
  content: "+";
  font-family: var(--font-mono);
  font-size: 1.1rem;
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  transition: transform 150ms var(--ease-out);
}

.faq__item[open] summary::after {
  transform: translateY(-50%) rotate(45deg);
}

@media (prefers-reduced-motion: reduce) {
  .faq__item summary::after {
    transition: none;
  }
}

/* No max-width: the .faq container already holds the measure. */
.faq__item p {
  color: var(--text-soft);
  margin: 0.75rem 0 0;
  text-wrap: pretty;
}

.final-cta {
  padding: 6rem 0;
  position: relative;
  text-align: left;
}

@media (max-width: 640px) {
  .final-cta {
    padding: 4.5rem 0;
  }
}

/* Halftone screen — single placement (DESIGN.md). Coarser dots than the
   .section--dotted wallpaper, washed to just above the wallpaper's ink
   strength so, like any wash, it may run under the display type at
   narrow widths without shouting. */
@media (min-width: 768px) {
  .final-cta::before {
    background-image: radial-gradient(
      color-mix(in srgb, var(--structure) 18%, transparent) 1.4px,
      transparent 1.6px
    );
    background-size: 9px 9px;
    content: "";
    inset: 0 auto 0 0;
    -webkit-mask-image: linear-gradient(105deg, #000 5%, transparent 50%);
    mask-image: linear-gradient(105deg, #000 5%, transparent 50%);
    pointer-events: none;
    position: absolute;
    width: 40%;
  }
}

.final-cta .shell {
  position: relative;
  z-index: 1;
}

/* Jobs-specific composition only. Fonts, paper, print textures, plates,
 * navigation, buttons, links and footer come from the real site.css. */
.public-jobs :is(button, input, select) {
  font-family: inherit;
  line-height: inherit;
}
.public-jobs button {
  cursor: pointer;
}
.public-jobs :is(input, select):focus-visible {
  outline: 2px solid var(--structure);
  outline-offset: 2px;
}
.public-jobs :is(input, select) {
  color: var(--text);
  accent-color: var(--structure);
}
.public-jobs .site-header__link[aria-current] {
  color: var(--accent);
}
.jobs-sr-only,
.jobs-skip:not(:focus) {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.jobs-skip:focus {
  position: fixed;
  z-index: 30;
  top: 12px;
  left: 12px;
  padding: 12px;
  background: var(--bg);
}
.jobs-hero {
  padding-bottom: 3rem;
}
.jobs-hero .page-hero__content {
  padding: 2.75rem 3rem;
}
.jobs-hero .lede {
  max-width: var(--measure);
}
.jobs-hero h1 {
  overflow-wrap: anywhere;
}
/* A light printed field separates browsing from the introduction and close.
 * The rows and controls reserve clean paper; texture lives around them. */
.jobs-browse-surface {
  padding: 2.5rem 0 3rem;
}
.jobs-browse {
  scroll-margin-top: 1rem;
  display: grid;
  grid-template-columns: 208px minmax(0, 1fr);
  gap: 2rem;
}
.jobs-browse[aria-busy="true"] {
  cursor: progress;
}
.jobs-filters {
  align-self: start;
  border-top: 1px solid var(--rule-strong);
}
.jobs-filters summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--structure);
  cursor: pointer;
  list-style: none;
}
.jobs-filters summary::-webkit-details-marker {
  display: none;
}
.jobs-filters fieldset {
  border: 0;
  margin: 0;
  padding: 0;
}
.jobs-clear {
  display: inline-block;
  font-size: 0.8rem;
  padding: 0.25rem 0;
}
.jobs-field {
  display: block;
  font-size: 0.85rem;
  font-weight: 500;
  margin-top: 1.5rem;
}
.jobs-field select {
  display: block;
  width: 100%;
  min-height: 44px;
  margin-top: 0.5rem;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  padding: 0.65rem 0.35rem;
  background: var(--bg);
  font-size: 0.8rem;
}
.jobs-toggle {
  display: flex;
  align-items: start;
  gap: 0.6rem;
  font-size: 0.85rem;
  padding: 0.6rem 0;
  margin-top: 0.5rem;
}
.jobs-toggle input {
  margin: 0.2rem 0 0;
  width: 17px;
  height: 17px;
  flex: none;
}
.jobs-filter-note {
  margin: 1rem 0;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
  font-size: 0.8rem;
  color: var(--text-soft);
}
.jobs-filter-submit {
  width: 100%;
  min-height: 44px;
  background: var(--bg);
  font-size: 0.85rem;
}
.jobs-search {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.5rem 0.5rem 1rem;
  border: 1px solid var(--rule-strong);
  background: var(--bg);
}
.jobs-search svg {
  width: 20px;
  height: 20px;
  flex: none;
  fill: none;
  stroke: var(--structure);
  stroke-width: 1.5;
}
.jobs-search input {
  min-width: 0;
  flex: 1;
  border: 0;
  background: transparent;
  padding: 0.5rem 0;
  font-size: 1rem;
}
.jobs-search button {
  min-height: 44px;
  padding: 0.65rem 1.1rem;
  font-size: 0.85rem;
  background: var(--bg);
}
.jobs-result-meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.75rem 1.5rem;
  align-items: center;
  margin: 1.5rem 0 1rem;
  color: var(--text-soft);
  font-size: 0.85rem;
}
.jobs-result-meta strong {
  color: var(--text);
  font-weight: 600;
}
.jobs-sort {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.75rem;
}
.jobs-sort select {
  min-height: 44px;
  max-width: 180px;
  border: 0;
  border-bottom: 1px solid var(--rule);
  background: var(--bg);
  padding: 0.5rem 0;
}
.jobs-list {
  border-top: 1px solid var(--rule-strong);
  border-bottom: 1px solid var(--rule-strong);
}
.jobs-row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 168px;
  gap: 1.5rem;
  padding: 1.5rem 0.75rem;
  border-bottom: 1px solid var(--rule);
  background: var(--bg);
}
.jobs-row:last-child {
  border-bottom: 0;
}
.jobs-row:hover,
.jobs-row:focus-within {
  background: color-mix(in srgb, var(--detail) 8%, var(--bg));
}
.jobs-company {
  margin: 0 0 0.35rem;
  color: var(--structure);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  overflow-wrap: anywhere;
}
.jobs-row h2 {
  margin: 0;
  font: 600 1.15rem/1.45 var(--font-body);
  letter-spacing: -0.01em;
  text-wrap: initial;
  overflow-wrap: anywhere;
}
/* The title is the link and the row is its target, as on the resources index.
 * Metadata remains ordinary text; no nested controls or duplicate tab stops. */
.jobs-row h2 a::after {
  content: "";
  position: absolute;
  inset: 0;
}
.jobs-row:hover h2 a {
  color: var(--accent);
  text-decoration-color: currentColor;
}
.jobs-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 0.8rem;
  margin-top: 0.65rem;
  font-size: 0.8rem;
  color: var(--text-soft);
  overflow-wrap: anywhere;
}
.jobs-meta span + span::before {
  content: "·";
  color: var(--structure);
  margin-right: 0.8rem;
}
.jobs-summary {
  margin: 0.85rem 0 0;
  max-width: var(--measure);
  font-size: 0.9rem;
  color: var(--text-soft);
  overflow-wrap: anywhere;
}
.jobs-row-right {
  display: flex;
  flex-direction: column;
  align-items: end;
  text-align: right;
  gap: 0.65rem;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.jobs-pay {
  list-style: none;
  margin: 0;
  padding: 0;
  font-weight: 500;
}
.jobs-pay li + li {
  margin-top: 0.6rem;
}
.jobs-row .jobs-pay {
  font-size: 0.85rem;
}
.jobs-missing {
  font-size: 0.85rem;
  font-weight: 400;
  color: var(--text-soft);
}
.jobs-pagination {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  margin-top: 1.5rem;
  font-size: 0.8rem;
  color: var(--text-soft);
  font-variant-numeric: tabular-nums;
}
.jobs-pagination nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}
.jobs-pagination a {
  display: inline-block;
  padding: 0.65rem 0.5rem;
}
.jobs-under-list {
  /* Scale the body measure with this smaller factual type. */
  max-width: calc(var(--measure) * 0.8);
  margin: 1rem 0 0;
  font-size: 0.8rem;
  color: var(--text-soft);
}
.jobs-cta-section {
  padding: 4rem 0;
  color: var(--bg);
}
/* The close borrows the site's indigo flood and grain. Keep its weather
 * still so the hero remains this browsing surface's one moving moment. */
.jobs-cta-section::after {
  animation: none;
}
.jobs-cta-section h2 {
  margin-bottom: 2rem;
}
.jobs-cta-section :is(a, button):focus-visible {
  outline-color: var(--bg);
}
.jobs-split-cta {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 3rem;
}
.jobs-split-cta h3 {
  font-size: 1.65rem;
}
.jobs-split-cta p {
  font-size: 0.95rem;
  color: var(--bg);
  max-width: var(--measure);
  margin: 0 0 1.5rem;
}
.jobs-primary {
  display: inline-flex;
  gap: 1rem;
  align-items: center;
  justify-content: space-between;
  font-size: 0.9rem;
}
.jobs-newsletter {
  display: block;
  width: fit-content;
  margin-top: 1.25rem;
  font-size: 0.85rem;
}
.jobs-detail-head .jobs-company {
  margin-bottom: 0.75rem;
}
.jobs-detail-head .jobs-meta {
  margin-top: 1.25rem;
  font-size: 0.9rem;
}
.jobs-detail-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  grid-template-areas: "intro facts" "copy facts";
  column-gap: 3rem;
  row-gap: 0;
  padding-block: 1rem 3rem;
}
.jobs-detail-copy {
  grid-area: copy;
  max-width: var(--measure);
  overflow-wrap: anywhere;
}
.jobs-detail-copy h2 {
  font-size: 1.65rem;
  margin: 2.5rem 0 1rem;
}
.jobs-detail-copy p {
  color: var(--text-soft);
  line-height: 1.75;
}
.jobs-detail-copy ul:not(.jobs-pay) {
  padding-left: 1.25rem;
  line-height: 1.75;
}
.jobs-detail-copy li {
  padding: 0.3rem 0;
}
.jobs-detail-copy li::marker {
  color: var(--structure);
}
.jobs-detail-copy .jobs-source-note {
  max-width: calc(var(--measure) * 0.8);
  font-size: 0.8rem;
  margin: 2rem 0 0;
  border-top: 1px solid var(--rule);
  padding-top: 1.25rem;
}
/* Reuse the browsing field as a quiet surround for the facts plate. */
.jobs-detail-rail {
  grid-area: facts;
  width: 100%;
  padding: 0.75rem;
  align-self: start;
}
.jobs-detail-aside {
  padding: 1.25rem;
  overflow-wrap: anywhere;
}
.jobs-detail-aside h2 {
  font-size: 1.4rem;
}
.jobs-source-link {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.85rem;
}
.jobs-ledger {
  margin: 1rem 0 1.5rem;
}
.jobs-ledger > div {
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--rule);
}
.jobs-ledger dt {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--structure);
}
.jobs-ledger dd {
  margin: 0.35rem 0 0;
  font-size: 0.85rem;
}
/* The summary and actions lead in DOM and visual order on every screen. */
.jobs-detail-intro {
  grid-area: intro;
  max-width: var(--measure);
}
.jobs-detail-intro > p {
  margin: 0 0 1.25rem;
  color: var(--text-soft);
  line-height: 1.75;
}
.jobs-pending {
  margin: 0.75rem 0 0;
  font-size: 0.85rem;
  color: var(--text-soft);
}
/* Functional frame labels need a larger target than decorative annotations. */
.public-jobs .tech-frame__tag:has(a) {
  top: -22px;
  max-width: calc(100% - 2rem);
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  background: linear-gradient(to bottom, transparent 21px, var(--bg) 21px);
}
.public-jobs .breadcrumb {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.public-jobs .tech-frame__tag a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.jobs-disclosure-mark {
  width: 8px;
  height: 8px;
  flex: none;
  margin-right: 0.5rem;
  border-right: 1px solid var(--structure);
  border-bottom: 1px solid var(--structure);
  transform: rotate(-45deg);
}
.jobs-filters[open] .jobs-disclosure-mark {
  transform: rotate(45deg);
}
.jobs-state {
  padding: 3rem;
  display: flex;
  flex-direction: column;
  align-items: start;
  justify-content: center;
}
.jobs-results .jobs-state {
  border-block: 1px solid var(--rule-strong);
  background: var(--bg);
  min-height: 320px;
  padding: 2rem 1.5rem;
}
.jobs-state :is(h1, h2) {
  overflow-wrap: anywhere;
}
.jobs-state p {
  max-width: var(--measure);
  margin: 0.75rem 0 1.25rem;
  color: var(--text-soft);
}
.jobs-state form {
  margin: 1rem 0;
  max-width: 100%;
}
.jobs-state .cf-turnstile {
  min-height: 140px;
  margin-bottom: 1.25rem;
}
.jobs-error {
  margin-block: 3rem 4rem;
}
@media (max-width: 1000px) {
  .jobs-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
  }
  .jobs-row-right {
    align-items: start;
    flex-direction: row;
    flex-wrap: wrap;
    text-align: left;
  }
  .jobs-detail-layout {
    grid-template-columns: minmax(0, 1fr) 290px;
    gap: 2rem;
  }
}
@media (max-width: 740px) {
  .jobs-hero {
    padding-top: 2rem;
    padding-bottom: 1.5rem;
  }
  .jobs-hero .page-hero__content {
    padding: 1.5rem 1.25rem;
  }
  .jobs-hero .lede {
    font-size: 1rem;
    margin-top: 0.75rem;
  }
  .jobs-browse-surface {
    padding: 1.5rem 0 2rem;
  }
  .jobs-browse {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    padding-top: 0;
  }
  .jobs-filters {
    width: 100%;
    border-bottom: 1px solid var(--rule-strong);
  }
  .jobs-filters summary {
    min-height: 48px;
  }
  .jobs-filters fieldset {
    padding-bottom: 1.25rem;
  }
  .jobs-field select,
  .jobs-sort select {
    font-size: 1rem;
  }
  .jobs-search {
    gap: 0.5rem;
    padding-left: 0.75rem;
  }
  .jobs-search button {
    padding-inline: 0.75rem;
  }
  .jobs-result-meta {
    margin-top: 1rem;
  }
  .jobs-row {
    padding: 1.5rem 0.5rem;
  }
  .jobs-detail-layout {
    display: flex;
    flex-direction: column;
    gap: 0;
    padding-top: 0;
  }
  .jobs-detail-rail {
    margin-top: 2rem;
  }
  .jobs-detail-aside {
    width: 100%;
  }
  .jobs-cta-section {
    padding: 3rem 0;
  }
  .jobs-split-cta {
    grid-template-columns: minmax(0, 1fr);
    gap: 2rem;
  }
  .jobs-split-cta > div + div {
    border-top: 1px solid color-mix(in srgb, var(--bg) 30%, transparent);
    padding-top: 2rem;
  }
  .jobs-state {
    padding: 2rem 1.25rem;
  }
  .jobs-state form {
    width: 100%;
  }
}
