/* Mizell Software — the one-page site.
 *
 * THIS IS A FILE, NOT A <style> BLOCK, and that is load-bearing. The server sends
 * `style-src 'self'` with no 'unsafe-inline'. Moving any of this into the document — a block or a
 * style attribute — makes it silently stop applying, and adding 'unsafe-inline' to get it back
 * weakens the header for the whole site. Same reasoning puts the form handler in public/form.js.
 *
 * EVERY TYPE SIZE COMES FROM THE SCALE IN fonts.css. Not one px value for type appears below: the
 * scale is --step--1 through --step-6 and a size outside it is a decision somebody made by eye at
 * 2am. tests/homepage.test.mjs fails on a font-size that is not a var(--step-*).
 *
 * ── THE DIRECTION, AND IT IS AN OWNER RULING RATHER THAN A PREFERENCE ─────────────────────────────
 *
 * DARK INK GROUND, FLAT, WITH COLOUR ARRIVING ONLY AS THIN GRADIENT ACCENTS. Picked by Master
 * Delaney on 2026-08-07 after five competitor sites were measured, from a mock called "Theme E —
 * Ink & Signal" that is on the design board. His words: *"i like the black theme as it looks like we
 * know tech, but if you see in the atlantic site they have some colour gradients for accents to
 * liven up the place it looks nice"* and *"for the design stick with the mizell knowledge base so
 * flat ink on paper is fine"*. The governing document is the gated knowledge base at
 * https://delaneymizell.com/delaney/software, sections `the-public-site` and `decision-log`.
 *
 * THIS FILE USED TO BE PALE CREAM AND IT SAID "ONE FLAT INK, ONE FLAT PAPER — NO GRADIENT ANYWHERE".
 * That was the right rule under the previous ruling and it is superseded, not forgotten. The half
 * that SURVIVES is the important half: **flat still means flat.** No mesh gradient as the ground, no
 * aurora, no animating hue field, no tinted band to break up the page. Dark ink instead of pale
 * paper is a colour swap; the gradient is an ACCENT — strips and edges — never the field behind the
 * words. A signage face over a disco ground is still a costume.
 *
 * THE GRADIENT APPEARS IN EXACTLY SIX PLACES AND THE LIST IS CLOSED. The masthead rule, the tick
 * above the hero kicker, the left edge of each receipt card, the hard figures inside them, one word
 * of the headline, and the fill on the button. **Adding a seventh is how this becomes a gradient
 * site**, which is the failure the flat-ink discipline exists to prevent.
 *
 * ── COLOUR, MEASURED RATHER THAN EYEBALLED ───────────────────────────────────────────────────────
 *
 * Computed with the WCAG 2.x relative-luminance formula against the ground each one actually lands
 * on, which on this page is the ink or the raised panel and never white:
 *
 *   chalk       #edeae3 on ink #0c0e10   16.10:1   body, headings, the wordmark    (needs 4.5:1)
 *   chalk       #edeae3 on panel #14171a 14.98:1   the same, inside a receipt card (needs 4.5:1)
 *   chalk-quiet #9aa0a4 on ink #0c0e10    7.31:1   meta lines, field labels, foot  (needs 4.5:1)
 *   chalk-quiet #9aa0a4 on panel #14171a  6.80:1   the same, inside a card         (needs 4.5:1)
 *   amber       #ffc247 on ink #0c0e10   12.03:1   every link on the page          (needs 4.5:1)
 *   alert       #ff9b85 on ink #0c0e10    9.47:1   failure messages, invalid boxes (needs 4.5:1)
 *   ink         #0c0e10 on amber #ffc247 12.03:1   the button label, warm end      (needs 4.5:1)
 *   ink         #0c0e10 on coral #f2603c  6.00:1   the button label, cool end      (needs 4.5:1)
 *   rule-strong #606a72 on ink #0c0e10    3.50:1   input borders                   (needs 3:1)
 *   rule-strong #606a72 on panel #14171a  3.26:1   the same, over a panel          (needs 3:1)
 *
 * TWO HAIRLINE TOKENS, AND THE SPLIT IS DELIBERATE. The old file had one at 3.33:1 and argued that
 * separating "decorative" from "meaningful" costs more than two shades of grey. On a near-black
 * ground that stops being true: a 3.5:1 line between every band reads as a stack of boxes and buries
 * the one accent the design has. So `--rule` (#262b30) draws the band separations, which carry no
 * information a heading does not already carry, and `--rule-strong` (#606a72) draws every input
 * border, which is the only thing telling a reader where the box is and therefore the thing 1.4.11
 * is about. If you are unsure which one a new element needs, it needs `--rule-strong`.
 *
 * WHY THE HEADLINE WORD AND THE BUTTON FILL USE THE WARM HALF ONLY (amber → coral, no teal), AND
 * THIS WAS MEASURED RATHER THAN GUESSED: the full three-stop run goes muddy mid-word on black, and
 * small dark label text over the teal end measured about 3:1, under the 4.5:1 it needs. The full
 * three stops are for rails, edges and hairlines, where nothing has to be read through them.
 * Anything new that puts text on or through a gradient gets measured against the stop it lands on.
 *
 * ── IMAGERY: DRAWN IS IN, PHOTOGRAPHIC FILLER IS OUT ─────────────────────────────────────────────
 *
 * Owner ruling, same day. The ban was never on ink, it was on lying. A stock or generated photograph
 * of a plumber, an office, a handshake or the Raleigh skyline implies work, clients and a company
 * that do not exist, and the receipts band is built precisely to be checkable. A DRAWN figure
 * implies nothing false. So the hero carries a hand-written SVG schematic — the whiteboard at four
 * o'clock, the phone, the four vans — with no library, no download and no external request, which is
 * also what the CSP (`img-src 'self'`) allows.
 *
 * AND HIS OWN REAL PHOTOGRAPHS ARRIVED, 2026-08-07 — ticket-1786135362528-yz6lai. Two of them, both
 * committed to this repo and EXIF-stripped: him in the intake band, him and Devon in the second
 * receipt. Their rules are under "The two photographs" below. They come in as <img> elements and NOT
 * as a `url()` in here, which is why there is still deliberately no `url(` anywhere in this file: a
 * CSS background cannot carry alt text, cannot offer a second file to a retina screen, and reserves
 * no box for itself while it loads. A rule waiting for a photograph is still banned; a rule styling
 * one that exists is not the same thing. */

:root {
  /* THE GROUND IS CALLED INK AND THE TEXT IS CALLED CHALK, which is the vocabulary the knowledge
     base uses. Note this INVERTS what --ink meant in this file before 2026-08-07, when it was the
     dark text on pale paper — there is no --paper token any more, and a rule that still refers to
     one is a rule that was written against the old direction. */
  --ink: #0c0e10;
  --panel: #14171a;
  --chalk: #edeae3;
  --chalk-quiet: #9aa0a4;
  --rule: #262b30;
  --rule-strong: #606a72;
  --alert: #ff9b85;

  /* THE THREE STOPS, NAMED, BECAUSE THE DRAWN FIGURE NEEDS THEM ONE AT A TIME. Everything else on
     the page spends them through the two gradients below; the hero schematic strokes individual
     shapes, and a hex typed into an SVG attribute is exactly the drift this file exists to stop. */
  --amber: #ffc247;
  --coral: #f2603c;
  --teal: #25a5a0;

  /* Links are the amber end on its own — 12.03:1 on the ink. Named separately from --amber because
     "the link colour" and "the warm end of the brand gradient" are two ideas that happen to agree
     today, and a later pass changing one should not silently change the other. */
  --accent: var(--amber);

  /* THE ONE GRADIENT, IN ITS TWO LEGAL FORMS. Declared once here so that the six places it is
     allowed to appear cannot drift into six slightly different ramps. --grad-warm is the half that
     text is ever set on or through; --grad-full is for edges and rules, where nothing is read. */
  --grad-warm: linear-gradient(96deg, var(--amber), var(--coral));
  --grad-full: linear-gradient(96deg, var(--amber), var(--coral) 55%, var(--teal));

  /* THE SAME FULL RUN, TURNED DOWNWARDS, AND IT IS NOT A THIRD GRADIENT — same three stops, same
     order. It exists because a gradient does not rotate to fit the box it is put in: --grad-full
     handed to a 3px LEFT border via border-image gets sliced across the border box, so the left edge
     shows only the leftmost sliver of the ramp and renders as flat amber. That is what the receipt
     cards did on the first build, and it looks like a decision rather than a bug. Anything vertical
     — a card edge, the hero tick — takes this one. */
  --grad-down: linear-gradient(180deg, var(--amber), var(--coral) 55%, var(--teal));

  /* ────────────────────────────────────────────────────────────────────────────────────────────
     ALIGNMENT. THE OWNER'S RULING GOES HERE AND NOWHERE ELSE — ticket-1786067055076-lextp7.
     RULED: CENTRED, 2026-08-07, in his words "always centered aligned" — stated as a general
     preference rather than scoped to this page, so it is not re-openable here. This shipped `start`
     until that ruling and the fork is now closed; the token stays because every alignment decision
     on the page reads this ONE value (`text-align` takes it directly, and the flex columns take it
     as `align-items`, which is why it is the logical keyword `center` rather than a physical one).
     Two places deliberately opt out with their own `text-align: start` — the receipt cards and the
     form fields — because that is what the mock he approved does: a centred page axis with the
     inside of a card left-set. Those are the exception, not a precedent for a third.
     ──────────────────────────────────────────────────────────────────────────────────────────── */
  --align: center;

  /* SPACING, not type — the scale in fonts.css governs font sizes and these are the gaps between
     things. Same idea though: a short ratio-based list, so nothing lands on a number chosen by eye. */
  --space-xs: 0.4rem;
  --space-s: 0.75rem;
  --space-m: 1.5rem;
  --space-l: 3rem;
  --space-xl: 5.5rem;

  /* THE TAP TARGET, AND IT IS THE ONE RAW PIXEL VALUE IN THIS FILE THAT IS SUPPOSED TO BE ONE —
     ticket-1786091236984-msbilc. Everything else here is type (the scale in fonts.css) or space
     between things (the five above), and both of those scale with the screen. This is a finger. A
     finger is the same size on a 375px phone and a 1440px laptop, so a relative unit here would be
     the wrong answer rather than the tidier one. 44px is the figure the platform guidance has used
     for a decade and it clears WCAG 2.5.5's 44px comfortably; 2.5.8's floor of 24px is the one these
     links technically already met, because they sit isolated enough for the spacing exception. The
     buyer this page is written for is tapping in a van with a work glove half off. */
  --tap: 44px;

  /* The page runs 4–6 screens at 1280 rather than one. A one-screen landing page was an
     owner-rejected failure on the sibling product, and all five measured references ran 7–17. */
  --band-width: 46rem;
}

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

html {
  background: var(--ink);
  /* The hero link and the header address both jump to anchors on this same page; without this the
     target lands flush against the viewport edge with its heading half off screen. */
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  /* There is no animation on this page at all — this is here because `scroll-behavior: smooth` IS
     motion, and it is the one piece of it that would otherwise slip past the preference. */
  html {
    scroll-behavior: auto;
  }
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--chalk);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: var(--leading-body);
  -webkit-text-size-adjust: 100%;

  /* A SHORT PAGE STILL ENDS AT THE BOTTOM OF THE WINDOW — ticket-1786112469951-mg6xp1.
     WRITTEN FOR ANY SHORT PAGE, NOT FOR THE ONE THAT FOUND IT. Measured on /contact at 1440x900:
     the footer's hairline landed at y=547 with 232px of empty ground beneath it, which does not read
     as broken — the ground is continuous — it reads as UNFINISHED, on the one page whose entire job
     is to stop a prospect concluding this company cannot keep a website up. The homepage never
     needed this because it is thousands of pixels tall at that width.

     `svh`, NOT `vh`. On a phone `vh` is the LARGE viewport — the height the window has only once the
     browser chrome has retracted — so a `vh` rule makes a short page taller than the screen it is on
     and puts a scrollbar on a page that fits. The 404 happens to fit exactly at 375 today, which is
     precisely the condition that would let the wrong unit look right until the copy changed by one
     line. A browser too old for `svh` drops this declaration and gets today's behaviour back, which
     is the correct thing to degrade to. */
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}

/* The region that takes the slack, so the footer is pushed rather than stretched. `main`, not the
   404 page's own band class: this is the first short page the site has had and it will not be the
   last, and a rule keyed on that page's markup has to be rediscovered by whoever writes the second.
   `flex-grow: 1` distributes FREE space and there is none on a tall page, so the homepage does not
   move; `flex-shrink: 0` is what stops a long page being squeezed to fit the window instead. */
main {
  flex: 1 0 auto;
}

/* ── Skip link ─────────────────────────────────────────────────────────────────────────────────
   Off screen until it is focused, then it is the first thing a keyboard reaches. Moved with a
   position offset rather than `display: none`, which would take it out of the focus order and make
   it decorative. Chalk ground and ink label — the inverse of the page, so it cannot be missed. */
.skip-link {
  position: absolute;
  top: var(--space-s);
  left: var(--space-s);
  transform: translateY(-400%);
  z-index: 2;
  padding: var(--space-xs) var(--space-s);
  background: var(--chalk);
  color: var(--ink);
  font-size: var(--step--1);
}

.skip-link:focus {
  transform: translateY(0);
}

/* ── Bands ─────────────────────────────────────────────────────────────────────────────────────
   Seven of them, separated by space and a hairline. Never by a second background colour: a tinted
   band is the "break the page up" reflex the flat discipline rules out. */
.band {
  padding: var(--space-xl) var(--space-m);
  border-top: 1px solid var(--rule);
}

.band--header,
.band--hero {
  border-top: 0;
}

.band--header {
  padding-top: var(--space-l);
  padding-bottom: var(--space-l);
}

.band--hero {
  padding-top: var(--space-xl);
}

.band--footer {
  padding-top: var(--space-l);
  padding-bottom: var(--space-l);
}

/* GRADIENT PLACE 1 OF 6 — THE MASTHEAD RULE. Full bleed, edge to edge, which is why it is its own
   element rather than a border on the header: the header band has horizontal padding, and a border
   on it would stop short of both edges and read as a box rather than as the line under a masthead.
   The full three stops, because nothing is read through it. */
.masthead-rule {
  height: 3px;
  background: var(--grad-full);
}

.wrap {
  display: flex;
  flex-direction: column;
  align-items: var(--align);
  max-width: var(--band-width);
  margin: 0 auto;
  text-align: var(--align);
}

.wrap--split {
  flex-direction: row;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-m);
  /* The header is a row and stays a row: the wordmark and the address are not a stack. Below the
     narrowest phone they wrap, which is what `flex-wrap` is for. */
  flex-wrap: wrap;
  text-align: start;
}

/* Prose never runs wider than the measure in fonts.css, whatever the band does. */
.wrap > p,
.wrap > .receipt > p,
.wrap > .work-row > p,
.wrap > dl,
.wrap > form,
.wrap > noscript {
  max-width: var(--measure);
}

/* ── Type ──────────────────────────────────────────────────────────────────────────────────────── */
h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: var(--tracking-display);
  text-wrap: balance;
}

h1 {
  margin: 0;
  font-size: var(--step-5);
  line-height: var(--leading-display);
  max-width: 20ch;
}

h2 {
  margin: 0 0 var(--space-m);
  font-size: var(--step-3);
  line-height: var(--leading-heading);
  max-width: 26ch;
}

h3 {
  margin: 0 0 var(--space-s);
  font-size: var(--step-1);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-tight);
  max-width: 34ch;
}

p {
  margin: 0 0 var(--space-m);
}

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

/* ── Links. Underlined, never colour-only: colour on its own is not a link affordance for a reader
   who cannot separate amber from chalk, and both of ours are light on the same ground. ─────────── */
a {
  color: var(--accent);
  text-underline-offset: 0.2em;
}

a:hover {
  text-decoration-thickness: 2px;
}

/* ── The links a thumb has to hit — ticket-1786091236984-msbilc ─────────────────────────────────
   MEASURED AT 375, BEFORE: every one of these came back 15.00px tall. Both receipt links and every
   hello@mizellsoftware.com on the site. The receipts are the second most important click on this
   page after the submit button — they are the proof, and the whole trust position is that a prospect
   can go and check the two live things — and the addresses are the way out of every failure branch
   the form has. AFTER: 44.00px, with the widths and the line positions unchanged.

   NOT A BUTTON, AND THAT IS THE POINT OF DOING IT THIS WAY. The reflex fix is a pill with a ground
   and a radius, which is the exact slop the design brief names and would break the page's argument —
   prose rows, not cards. There is no background, no border, no radius and no change of type size
   here: the link looks identical and the box around it got bigger.

   VERTICAL PADDING PLUS A CANCELLING NEGATIVE MARGIN. `(--tap - 1lh) / 2` grows the border box to
   exactly 44px whatever size the text is, and `(1lh - --tap) / 2` takes the same amount back off the
   margin box — so the MARGIN box stays exactly one line tall and the surrounding rhythm cannot move.
   Dropping the margin half is the likeliest thing a later pass does, and it shoves every line on the
   page apart. Measured against `1lh` rather than against the step these six happen to share, so a
   link set at another size still lands on 44 rather than on whatever that arithmetic produced.

   AND THE MAX-WIDTH IS NOT DECORATION. `inline-block` makes the link ATOMIC — it stops breaking
   across lines — and two of these addresses sit mid-sentence rather than isolated (the line beside
   the form and the footer colophon). Without a clamp, a container narrower than the address puts a
   horizontal scrollbar on a phone; with it, the box wraps inside itself the way the text used to.
   Checked at 375: the widest of them is 224.61px in a 327px column, so nothing wraps today — this is
   the guard for the day the copy or the container changes, not a fix for something visible now.

   The attribute selector is deliberate: it catches every address on the site, including the line
   form.js removes when it loads (visible only when the script never arrives, which is the one branch
   where the address is the ONLY way to reach him) and both on the 404 page, which reuses these
   classes and has no stylesheet of its own. */
.receipt-link a,
a[href^='mailto:'] {
  display: inline-block;
  max-width: 100%;
  overflow-wrap: break-word;
  padding-block: calc((var(--tap) - 1lh) / 2);
  margin-block: calc((1lh - var(--tap)) / 2);
}

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

/* ── Band 0, header ────────────────────────────────────────────────────────────────────────────── */
.wordmark {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--step-1);
  letter-spacing: var(--tracking-tight);
}

.header-contact {
  margin: 0;
  color: var(--chalk-quiet);
  font-size: var(--step--1);
}

/* ── Band 1, hero ──────────────────────────────────────────────────────────────────────────────── */

/* GRADIENT PLACE 2 OF 6 — THE TICK ABOVE THE KICKER. A 40px vertical strip and nothing else: it is
   the smallest possible mark saying the page has a spine, and it is what stops a centred column of
   type reading as a document with no design in it. Full three stops, top to bottom, nothing read
   through it. `role="presentation"` in the markup keeps it out of the accessibility tree. */
.hero-tick {
  width: 2px;
  height: var(--space-l);
  margin-bottom: var(--space-m);
  background: var(--grad-down);
}

/* The line above the headline. Mono and letterspaced because it is a label rather than a sentence —
   it is the one place on the page that states, flatly, what kind of company this is. */
.hero-kicker {
  margin: 0 0 var(--space-m);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--chalk-quiet);
}

.hero-kicker strong {
  color: var(--accent);
  font-weight: 400;
}

/* GRADIENT PLACE 3 OF 6 — ONE WORD OF THE HEADLINE. The WARM HALF, because this is text: the full
   run goes muddy across a word on black. The fallback matters more than the effect — a browser
   without `background-clip: text` that got `color: transparent` anyway would render the page's most
   important word as a hole, so the flat amber is declared first and unconditionally and the clip is
   layered on inside @supports. Amber alone measures 12.03:1 on the ink, so the fallback is not a
   degraded state, it is a quieter version of the same idea. */
.headline-signal {
  color: var(--accent);
}

@supports ((background-clip: text) or (-webkit-background-clip: text)) {
  .headline-signal {
    background: var(--grad-warm);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

.hero-body {
  margin-top: var(--space-m);
  font-size: var(--step-1);
  letter-spacing: var(--tracking-tight);
}

.hero-action {
  margin-top: var(--space-l);
}

/* GRADIENT PLACE 4 OF 6 — THE FILL ON THE BUTTON, and there is one button on this page in two
   places: the hero's and the form's submit. They are the same control doing the same job, so they
   share the rule rather than each getting one — two differently-styled primary actions is how a page
   stops having a primary action.

   IT IS A THING YOU CLICK WITH A NOUN IN IT, NOT A VERB IN A PILL. "The $750 audit", with the terms
   beside it in the mono face, rather than "Get started". No radius: square is the discipline the
   rest of the page runs on, and a pill would be the first thing to make this look like everybody
   else's landing page. The WARM half again — ink on amber is 12.03:1 and ink on coral is 6.00:1, so
   the label clears 4.5:1 across the whole run, which the teal end does not.

   THE CLASS IS `.hero-link` AND IT KEEPS THAT NAME. It is the class the 404 page reuses for its one
   way home (server/not-found-page.mjs has no stylesheet of its own and
   tests/not-found-page.test.mjs proves every class it uses is declared here), and
   tests/intake-escape-hatches.test.mjs matches on the exact attribute `class="hero-link"` to prove
   the hero still points at the audit band. Renaming it to something that reads more like a button
   breaks both of those in places nobody would look. */
.hero-link,
button[type='submit'] {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: var(--space-s);
  padding: var(--space-s) var(--space-m);
  border: 0;
  border-radius: 0;
  background: var(--grad-warm);
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--step-0);
  letter-spacing: var(--tracking-tight);
  text-decoration: none;
  cursor: pointer;
}

.hero-link {
  font-size: var(--step-1);
}

.hero-link:hover,
button[type='submit']:hover {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* The terms riding along inside the button. Mono, because they are facts rather than a slogan, and
   still ink so they inherit the same measured contrast as the label. */
.hero-link-terms {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 400;
  letter-spacing: 0;
}

/* The quiet way out, under the button. Not a second CTA: it is one sentence with an address in it,
   and the rule is one CTA, never two. */
.hero-alt {
  margin-top: var(--space-m);
  color: var(--chalk-quiet);
  font-size: var(--step--1);
}

/* ── The drawn hero figure ─────────────────────────────────────────────────────────────────────
   DRAWN, NOT PHOTOGRAPHED, and that distinction is the whole imagery policy on this site: the ban
   was never on ink, it was on lying. A stock photograph of a plumbing office implies a client that
   does not exist; a line drawing of the job implies nothing false.

   IT IS ONE COMPOSITION, NOT THREE PARTS IN A ROW, AND THAT IS THE FIX FOR THE PHONE. The approved
   mock lays the whiteboard, the phone and the four vans out horizontally, and at 390 wide that mock
   scales the whole strip down until the mono labels inside it are grey noise — the one piece of
   imagery on the page stops communicating at the width most of this audience is on. Recorded on the
   board as a known gap in the mock rather than a change of direction. The answer here is a figure
   whose aspect ratio is close to square, so its rendered width barely changes between 1440 and 375
   (440px against 327px) and the labels stay legible at both without a single breakpoint. Do not
   "restore" the wide strip.

   The width is capped in rem so it cannot grow into the band and swamp the headline above it. */
.hero-figure {
  margin: var(--space-xl) 0 0;
}

.hero-figure svg {
  display: block;
  width: 100%;
  max-width: 27.5rem;
  height: auto;
  margin: 0 auto;
}

/* THE FIGURE'S COLOURS LIVE HERE, NOT IN THE SVG. Every shape in the drawing carries a class and
   takes its stroke from a token, so the schematic cannot drift away from the palette the rest of the
   page runs on — a hex typed into a `stroke=` attribute is invisible to every check in this repo.
   Type SIZE inside the drawing is the deliberate exception and it stays as an attribute in the
   markup: those are viewBox units that scale with the figure, not document pixels, so the type scale
   in fonts.css is the wrong instrument for them and a var(--step-*) here would be a bug. */
.hero-figure .fig-teal {
  stroke: var(--teal);
}

.hero-figure .fig-amber {
  stroke: var(--amber);
}

.hero-figure .fig-coral {
  stroke: var(--coral);
}

.hero-figure text {
  fill: var(--chalk-quiet);
  font-family: var(--font-mono);
  letter-spacing: 0.06em;
}

.hero-figure .fig-label {
  fill: var(--chalk);
}

.hero-figure figcaption {
  margin-top: var(--space-m);
  color: var(--chalk-quiet);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ── The two photographs ───────────────────────────────────────────────────────────────────────
   REAL PHOTOGRAPHS OF REAL PEOPLE, WHICH IS WHY THEY ARE ALLOWED AT ALL — ticket-1786135362528-yz6lai.
   The rule on this site is LYING versus INK, not photographic versus drawn: a stock portrait, a
   generated face or a picture of a job that did not happen is out however useful it looks, and these
   two files are his own, committed to this repo and stripped of their EXIF. Both are used once —
   `.portrait` is him, in the intake band, beside the sentence claiming a person reads the form;
   `.credential` is him and Devon in the second receipt, whose deposits that product holds. Until
   2026-08-07 this page rendered ZERO images while both files sat on the server answering 200, which
   left the one claim the whole positioning rests on as the only one with nothing behind it.

   FLAT, SQUARE, ONE HAIRLINE. No radius, no ring, no glow, no drop shadow, no blob mask and no
   duotone: that treatment is the template look the rest of this page is built to avoid, and on a
   page whose entire visual discipline is thin edges it would instantly be the loudest thing on it.
   The hairline is --rule, the same line that separates the bands, and it earns its place because a
   dark photograph on a near-black ground otherwise has no edge at all.

   NO GRADIENT HERE, DELIBERATELY. The accent list is closed at six and a photograph is not one of
   them — a gradient edge or a gradient wash on an image would be the seventh, which is the exact
   step that turns this into a gradient site.

   `height: auto` IS LOAD-BEARING AND IS NOT TIDY-UP. The markup carries real width and height
   attributes so the browser can reserve the box before the file arrives; the page measures zero
   cumulative layout shift and an unsized image is the usual way to lose that. With `width: 100%` and
   no `height: auto`, the height ATTRIBUTE wins and every photograph renders squashed to 525px tall.
   The two are a pair and tests/page-geometry.test.mjs is what keeps them together.

   THE 24rem CAP IS ALSO A NUMBER IN THE MARKUP. Each image's `sizes` attribute names this same
   width, which is what lets the browser pick the 700 on a 1x screen and the 1400 on a 2x one. Move
   the cap here and the `sizes` there becomes a lie, and one of the two committed files becomes dead
   weight — tests/homepage.test.mjs compares the two. */
.portrait,
.credential {
  width: 100%;
  max-width: 24rem;
  margin: 0 0 var(--space-m);
}

/* More room under the portrait than under the credential: what follows it is the form itself, and
   the three boxes need to read as a separate act from the face above them. */
.portrait {
  margin-bottom: var(--space-l);
}

.portrait img,
.credential img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rule);
}

/* Set like every other quiet line on the page — the body face at the small step, in chalk-quiet.
   The caption is what names the person for a reader who can see the photograph; the alt text is what
   names them for a reader who cannot, and the two say different things on purpose. */
.portrait figcaption,
.credential figcaption {
  margin-top: var(--space-s);
  color: var(--chalk-quiet);
  font-size: var(--step--1);
}

/* ── Band 2, receipts ──────────────────────────────────────────────────────────────────────────
   GRADIENT PLACE 5 OF 6 — THE LEFT EDGE OF EACH CARD. Full three stops, running down the edge,
   nothing read through it. This is the one place on the page a panel ground is used, and it is used
   because these two rows are the centre of the argument: they are the things a prospect can go and
   check. `border-inline-start` rather than `border-left` so the edge follows the writing direction.

   NOT A CARD GRID. Two full-width rows, stacked, prose inside — never a 2-up of screenshots and
   never a logo wall. The panel and the edge are what mark them as the evidence; the moment they sit
   side by side they become a features section. */
.receipt {
  margin-bottom: var(--space-l);
  padding: var(--space-m) var(--space-m) var(--space-m) var(--space-l);
  width: 100%;
  max-width: var(--measure);
  background: var(--panel);
  border-inline-start: 3px solid transparent;
  border-image: var(--grad-down) 1;
  /* The page axis is centred; the inside of a card is left-set, which is what the approved mock
     does. Prose in a box reads worse centred and he was shown it this way. */
  text-align: start;
}

.receipt-meta {
  color: var(--chalk-quiet);
  margin-bottom: var(--space-xs);
}

/* GRADIENT PLACE 6 OF 6 — THE HARD FIGURES. `data-numeric` in fonts.css already sets the mono family
   and tabular figures; this is what makes the number sit up in the sentence as the thing being
   claimed. WARM HALF, same measured reason as the headline word, same unconditional amber fallback
   underneath the @supports — a number rendered as a hole is worse than a number rendered flat. */
.figure,
.price-figure {
  color: var(--accent);
  font-weight: 700;
}

@supports ((background-clip: text) or (-webkit-background-clip: text)) {
  .figure,
  .price-figure {
    background: var(--grad-warm);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

.receipt-link {
  font-size: var(--step--1);
}

.receipt-honesty {
  padding-top: var(--space-m);
  border-top: 1px solid var(--rule);
  max-width: var(--measure);
}

/* ── Band 3, what I actually do ────────────────────────────────────────────────────────────────
   THREE UNEQUAL ROWS, and the inequality is the argument. Three cards of the same size imply that
   discovery, build and care are parallel and interchangeable; they are not, they are a dependency
   chain, and the first is where nearly all of the value is. The rows get narrower and quieter as
   they go, so the shape of the section says that before the words do. */
.work-row {
  margin-bottom: var(--space-l);
}

.work-row--first {
  max-width: var(--measure);
}

.work-row--second {
  max-width: 56ch;
}

.work-row--third {
  max-width: 44ch;
  color: var(--chalk-quiet);
}

.work-row--third h3 {
  color: var(--chalk);
}

/* ── Band 4, the audit ─────────────────────────────────────────────────────────────────────────── */
.price {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: var(--align);
  gap: var(--space-s);
  margin-bottom: var(--space-l);
}

.price-figure {
  font-size: var(--step-4);
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
}

.price-note {
  color: var(--chalk-quiet);
  font-size: var(--step--1);
}

.terms {
  margin: 0;
  max-width: var(--measure);
}

.terms dt {
  margin-bottom: var(--space-xs);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--step-0);
  letter-spacing: var(--tracking-tight);
}

.terms dd {
  margin: 0 0 var(--space-m);
}

.terms dd:last-child {
  margin-bottom: 0;
}

/* ── Band 5, what it costs after that ──────────────────────────────────────────────────────────── */
.ladder {
  padding-top: var(--space-m);
  border-top: 1px solid var(--rule);
}

/* ── The two sentences that carry a reader to the form ───────────────────────────────────────────
   One closes band 4, one closes band 5 — ticket-1786102545722-7py4ig. Body size, body colour, body
   face: it is prose with a link in it and it has to read as the next thing he says, not as a control
   somebody bolted onto the end of the section. There is deliberately NO rule here (that would be a
   third hairline in the pricing band alone), no ground, no border, no padding and no width of its
   own — space above it is the entire treatment.

   THE THINGS THIS MUST NEVER BECOME are named because the reflex is strong: a sticky bar, a button
   bar, a card. `position: fixed` and `position: sticky` appear nowhere in this file and
   tests/intake-escape-hatches.test.mjs is what keeps it that way. */
.onward {
  margin-top: var(--space-l);
  margin-bottom: 0;
}

/* ── Band 6, intake ────────────────────────────────────────────────────────────────────────────── */
.intake-lede {
  color: var(--chalk-quiet);
  margin-bottom: var(--space-l);
}

.intake {
  width: 100%;
  max-width: var(--measure);
}

.field {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-xs);
  margin-bottom: var(--space-m);
  text-align: start;
}

.field label {
  color: var(--chalk-quiet);
  font-size: var(--step--1);
}

/* The panel ground rather than the page ground, so a box is visibly a box before its border is read
   at all — on a near-black page an unfilled input outlined in a hairline is easy to miss entirely. */
.field input,
.field textarea {
  width: 100%;
  padding: var(--space-s);
  border: 1px solid var(--rule-strong);
  border-radius: 0;
  background: var(--panel);
  color: var(--chalk);
  font-family: var(--font-body);
  /* Inputs do not inherit the document's font size, and anything under 16px makes iOS Safari zoom
     the whole page on focus — which reads as the layout breaking when a field is tapped. */
  font-size: var(--step-0);
  line-height: var(--leading-body);
}

.field textarea {
  resize: vertical;
}

.field input:focus-visible,
.field textarea:focus-visible {
  border-color: var(--chalk);
}

/* ── The invalid state, AND IT IS NOT COLOUR ALONE ──────────────────────────────────────────────
   1.4.1 is the rule and a red border is the classic way to break it: a reader who cannot separate
   these two hues sees an unchanged box. So the box also gains a THICK LEFT RULE — a change in
   shape, visible with no colour perception at all — and the sentence saying what is wrong sits
   directly underneath it. Three signals: shape, colour, words.

   Driven by [aria-invalid='true'] rather than a class, so the visible state and the state a screen
   reader announces cannot come apart — there is only one attribute, and setting it does both. */
.field input[aria-invalid='true'],
.field textarea[aria-invalid='true'] {
  border-color: var(--alert);
  border-left-width: 4px;
}

/* The message for one box, beside that box. 9.47:1 on the ink. */
.field-error {
  margin: 0;
  color: var(--alert);
  font-size: var(--step--1);
}

.submit-row {
  margin-bottom: var(--space-m);
}

button[type='submit'][disabled] {
  /* Not a faded ghost: a disabled control still has to be legible, because the reason it is
     disabled is explained right underneath it and has to be readable too. The gradient comes off
     entirely — the one lit thing on the page is the thing you can press, so a dead control keeping
     the fill would be the most misleading state available.

     AND THE SHAPE HAS TO SAY IT, WHICH IS THE HALF THAT WAS MISSING — ticket-1786091236695-w7ugp3.
     A panel ground with a quiet label and a hairline is what an ordinary outlined button looks like
     on this page, so a visitor whose script never arrived read a dead control as a pressable one,
     typed all three boxes and pressed it. A dashed rule is not a button anybody has ever pressed,
     and it is legible with no colour perception at all — the same argument as the thick left rule on
     an invalid box. Not opacity and not a faded label: the sentence saying WHY it is disabled sits
     directly underneath, and dimming the control to prove a point costs the reader that sentence. */
  background: var(--panel);
  color: var(--chalk-quiet);
  border: 1px solid var(--rule-strong);
  border-style: dashed;
  cursor: not-allowed;
}

button[type='submit'][disabled]:hover {
  text-decoration: none;
}

.feedback {
  margin-bottom: 0;
  /* Empty until the form says something. `role="status"` on an element with no text announces
     nothing, which is the correct resting state. */
  max-width: var(--measure);
}

.feedback--error {
  color: var(--alert);
}

.feedback--sent {
  padding-top: var(--space-s);
  border-top: 1px solid var(--rule);
}

/* The three quiet notes around the form. `.intake-fallback` is the one form.js removes when it
   arrives, so it is only ever on screen next to a button that cannot be pressed — it is set like the
   other two rather than as an alarm, because it is a way out, not a warning. */
.noscript-note,
.intake-fallback,
.intake-alt {
  margin-top: var(--space-m);
  color: var(--chalk-quiet);
  font-size: var(--step--1);
  max-width: var(--measure);
}

/* ── Band 7, footer ────────────────────────────────────────────────────────────────────────────── */
.colophon {
  margin: 0;
  color: var(--chalk-quiet);
  font-size: var(--step--1);
}
