/* Leadmakker · public site (ADR-059, restructured by ADR-091). Three static
   pages, no JS, no cookies, no external requests. Own stylesheet on purpose —
   the owner dashboard's sheet lives in src/web/html.ts and sets a theme
   cookie; this surface must set nothing.

   TWO SHEETS, ONE SYSTEM (ADR-110). The dashboard now takes its palette, its
   type and its flat material FROM HERE: neutrals, the brand ground, the four
   product signals, the two typefaces, the 6px radius. This file is the source
   of truth for all of it, so a value changed here has a twin in html.ts and
   they must move together. The sheets stay separate because the promises are:
   this one sets no cookie and asks for nothing off-origin.

   Design intent, so a later edit does not drift:
   - The front page names the reader's problem and sells one thing: a door.
     Four promises, one button, a phone number. Everything the earlier version
     put on the front page (the full agreement, the price, the practicalities)
     now lives on /sadan-virker-det.html, so the first screen can be read in
     twenty seconds by someone standing in a van.
   - Quiet, not futuristic (owner decision 2026-08-04). Warm paper, hairlines,
     white space and two real typefaces do the work. Still deliberately absent
     from the earlier "field terminal" register: uppercase letter-spaced
     monospace labels, indicator lamps, drop shadows and the load animation.
     The dashboard used to keep that register; as of ADR-110 it does not
     either, and this list is now what BOTH surfaces are without. What the
     dashboard still has and this page has no use for: monospace tabular
     figures (it has columns to align), and 44px tap targets on the task path.
   - A brand ground, and it carries the page's ENDS, never its middle
     (ADR-094). Header and footer on all three pages, plus the front page's
     opening block; everything read at length stays on paper. This reverses
     the part of the 2026-08-04 decision that listed coloured header bands and
     the dark fascia as removed — the page read as black-and-white and had no
     image at all, which is not what "quiet" was meant to buy.
   - Colour still only ever means something, and the ground is no exception:
     green is go/approve, which is the one button this product exists to
     produce. Amber is "this lands on you", red is stop, violet is the
     propose-times action. Those are the product's own signals (DESIGN.md) and
     appear only where they encode one. Links are ink plus an underline, not a
     fifth hue.
   - Serif for headings, sans for everything else. No third typeface.
     One deliberate extension of that line: the serif also sets <em>. We ship
     no italic file, so emphasis was being drawn by shearing the roman, and a
     fake oblique is in practice the third typeface this rule exists to
     refuse. Using a face we already load costs nothing and keeps the count at
     two — see the note on the `em, i` rule for the measurements.

   Fonts are SELF-HOSTED, and that is the whole point: a fonts.googleapis.com
   link would be a third-party request on every visit and would break ADR-059's
   promise (and re-open the cookie-banner question). Provenance and licence:
   site/fonts/OFL.txt — SIL OFL 1.1 for both. Literata v40 (static, weight
   600, TypeTogether for Google) and Public Sans v21 (variable 400–700,
   USWDS, after Libre Franklin), latin subset only, which covers æ ø å.
   ~49 kB together, and the pair they replaced was ~50 (ADR-153).

   Replacing a font means moving three things at once, and a test
   (src/site/landing-site.test.ts) checks all three: the @font-face blocks
   below, `font-src 'self'` in the CSP — which lives in BOTH Caddyfile and
   scripts/serve-site.mjs and must match — and site/fonts/OFL.txt. */

@font-face {
  font-family: "Literata";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/fonts/literata-600-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/fonts/public-sans-400-700-latin.woff2") format("woff2");
}

:root {
  color-scheme: light dark;
  /* Warm paper rather than the dashboard's cool graphite: this surface is
     read indoors on a phone by someone deciding whether to trust us, not
     outdoors between jobs. */
  --bg: #f7f6f3;
  --surface: #ffffff;
  --sunk: #f2f0ec;
  --ink: #1c1b19;
  --ink-2: #5d5b55;      /* secondary text, ≥4.5:1 on both surfaces */
  --line: #e4e1da;
  /* Two steps darker than the #cdc9c0 this file used to carry (ADR-110). It is
     the boundary of every quiet control in the owner UI — buttons, day chips,
     inputs — where the border is the only thing saying "control", and the
     lighter value measured 1.64:1 against a white card where the previous
     owner-UI hairline managed 1.78. Here it does less work (it edges the
     illustrative card's Ret button and the sign-in field), but the two files
     hold one value per token. Twin in src/web/html.ts. */
  --line-2: #c4bfb6;
  /* The one edge every quiet control shares. It is deliberately darker than
     the structural hairline: this must remain visible against both paper and
     a white card in daylight. Twin in src/web/html.ts. */
  --control-line: #85807a;
  /* Brand ground. The product is one green button — Godkend — so green is not
     a decoration picked off a wheel; it is the act the whole thing exists to
     produce, promoted to an identity. It carries the two ends of the page
     (header and footer on every page, plus the front page's opening block)
     and NOTHING that is read at length, so the long prose stays on paper.
     Measured against #0d4a2b: cream 9.2:1, muted 6.6:1. */
  --brand: #0d4a2b;
  --brand-ink: #f4f2ec;
  --brand-ink-2: #c8d2c6;
  /* Used by ONE thing: the border of `.signin`, the owner's door in the header.
     That makes it a control boundary, not a decorative hairline — WCAG 1.4.11
     asks 3:1 of it, and at the .18 it carried it measured 1.6:1 against the
     ground. At that value the border is not visible: the button read as a link
     with padding sitting next to two other links.
     The alpha is picked for MARGIN, not for the minimum that scrapes past:
     .44 lands on 3.08 and the night ground's first passing step lands on
     3.03, and a guarantee held to the third decimal is not held at all —
     compositing the same rgba to whole channels, which is what a screen
     actually shows, already moves it by .01. .46 here and .40 at night both
     measure ~3.2:1 either way, and land the two themes on the same perceived
     weight. A test asserts the ratio, so the pair cannot drift apart, but
     move BOTH by hand if the ground moves. */
  --brand-line: rgba(244, 242, 236, .46);
  --brand-fill: rgba(244, 242, 236, .09);
  /* The same green dark enough to be structural INK on paper (7.5:1): list
     marks and the numerals of the ten points, nothing that carries meaning. */
  --brand-2: #0d5c33;
  /* Material, not signal (ADR-211): the plate behind an icon and the band
     behind one section. Site-only, like --measure: NOT twins of anything in
     html.ts, and never given a meaning. Measured by day: --brand-2 on the
     plate 6.8:1, ink on sand 13.8:1, ink-2 on sand 5.5:1. */
  --brand-soft: #e1eee6;
  --sand: #ebe6db;
  /* The one-time ring on the card's Godkend at the end of its film (the
     motion block at the foot of this file): the go colour at half alpha,
     never text. */
  --go-ring: rgba(15, 122, 65, .55);
  /* Product signals (DESIGN.md). Only used where they mean something. */
  --go: #0f7a41;   --go-ink: #ffffff;
  --info: #1d5fd0;
  /* The card's action badge, and the ONE signal pair this file needs that the
     owner UI did not have a token for until ADR-192. Twins in html.ts, held by
     the twin test, and declared here for the same reason the --act trio was
     deleted: this pair HAS a user on this page. The owner UI's five other
     badge pairs are still deliberately absent — this card wears one badge, and
     a token named after a signal and used nowhere is the ready-made wrong
     answer that trio turned out to be.
     Day value is the hex this rule carried written out, unchanged. */
  --plan: #6a34c9; --plan-ink: #ffffff;
  /* The owner UI's stop red, not the #b4302a this file used to carry. One value
     per meaning across both surfaces (ADR-110), and this is the one the product
     itself paints — it is DESIGN.md's signal and the colour the badge on an
     acute escalation is drawn in. 5.6:1 on white, so the card's "Afvis" line
     keeps its margin. The night value was already identical. */
  --stop: #c0342b; --stop-soft: #fbeceb; --stop-line: #eeb4af;
  /* The owner UI's warn tints, not the slightly softer pair this file used to
     carry (ADR-110). One value per meaning across both surfaces, and where the
     two disagreed the STRONGER one wins: a reskin must not make a boundary
     fainter than it already was. Twins live in src/web/html.ts.
     TWO of the three are twins. The ink is NOT, and it used to share the
     app's name while meaning the opposite thing (R259's sibling, R260): here it
     is ink on the PALE tint (.status, the policy page), while html.ts' own
     --warn-ink is ink on the FILLED amber (.approve.takeover). The values are
     therefore each other's opposites, #6f4310 against #ffffff, and the twin
     test compares --warn-soft and --warn-line only. Measured 2026-08-17: a
     future reskin that "aligned" the two would have put white on #fbf0e4 at
     1.12:1, i.e. invisible text in the box that says what is not lawyer
     approved, and no test would have gone red. Hence the name it carries now
     — a token that cannot be mistaken for a twin. */
  --warn-soft: #fbf0e4; --warn-line: #ecc79a; --warn-ink-soft: #6f4310;
  /* There is deliberately no --act trio here. It used to be declared in both
     palettes and used in exactly nought places, and a dead token that names a
     signal is worse than no token: `var(--act)` was a plausible-looking wrong
     answer sitting ready to hand, and the twin test in src/web/html.test.ts
     never compared the three either, so they were not holding the two surfaces
     together.
     ADR-192, 2026-09-03: the second half of this note used to say the badge
     must NOT follow the theme. It does now, through --plan/--plan-ink just
     above — a real pair with a user, held value for value by the twin test,
     which is the opposite of what made --act wrong. */
  /* The AI-draft well inside the card. These are the OWNER UI's own values
     (src/web/html.ts, tokens named info-soft / info-line) rather than a tint
     picked for this page: ADR-094 says the card on the front page is the same
     material as the real draft queue, not an illustration of it, and after
     ADR-110 the two surfaces share one palette. The pale green-grey that used
     to be here read as a second, weaker go-signal next to the green button
     directly below it. Move these only with their twins in html.ts. */
  --info-soft: #e9f0fc; --info-line: #aec7f0;
  --serif: "Literata", Georgia, "Times New Roman", serif;
  --sans: "Public Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --r: 6px;
  /* The scale (ADR-166). FORWARD-LOOKING: new work picks from these steps,
     and rules whose values already sat on a step were converted — but the
     hand-tuned component paddings that sit OFF the scale were left alone on
     purpose, because snapping them would move pixels across the whole site
     for consistency's sake alone. Two blocks never convert: the draft card
     (.phone/.badge/.well/.taps is the app's material, ADR-094/110, and moves
     only with html.ts) and the deliberate one-off sizes whose comments say
     why they are what they are (.quiet, .stamp, .nameplate). The owner UI
     declares the same steps since ADR-168 (except --gutter, which stays a
     layout constant of this file alone, like --col), and the twin test in
     src/web/html.test.ts compares all of them — move a step only with its
     twin in src/web/html.ts.
     Four measured near-duplicate text sizes were snapped when the scale
     landed (.92→.9, .95→.97, 1.05→1.0625, 1.1→1.15 — all under a pixel).
     Two more deliberate one-offs stay literal besides the named ones:
     the 1.2rem shared by .usp h3 and the ten points' ::marker — snapping
     it to 1.15 would visibly shrink headings, which is not what a scale
     is for. */
  --s1: .25rem; --s2: .5rem; --s3: .75rem; --s4: 1rem;
  --s5: 1.5rem; --s6: 2rem; --s7: 3rem; --s8: 4rem;
  /* The page gutter is a layout constant like --col, not a scale step. */
  --gutter: 1.2rem;
  --t-xs: .9rem; --t-sm: .97rem; --t-md: 1.0625rem; --t-lg: 1.15rem;
  /* The thumb floor (44, DESIGN.md's task-path number) and the in-flow
     button floor (48). ADR-164's rules read these. */
  --tap: 44px; --tap-cta: 48px;
  /* Prose measure. A FIXED width buys a different number of characters at
     every size set inside it, which is the whole reason there are two of
     these. Measured in the face we actually load: 38rem is 72ch at body
     size, 66ch at the hook's 1.15rem — and 74ch at the .97rem the notes use.
     32rem brings those smaller blocks back to 62-66ch. Before the split the
     front page's note ran 107ch, the policy's status note 97ch and the
     footer 91ch, all of them nominally "held to the measure".
     (The old comment here said 38rem was ~66ch at body size. It is 66ch at
     the hook's size; body is 72ch.) */
  --measure: 38rem;
  --measure-sm: 32rem;
  --col: 56rem;
  /* Edge shading for the horizontally scrollable tables. A token because the
     night palette cannot use a darker shadow at all — see the dark block. */
  --edge: rgba(0, 0, 0, .13);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--sans);
  font-size: var(--t-md);
  line-height: 1.6;
  background: var(--bg);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* Links are ink plus an underline. A stranger should be able to tell a link
   from running text without learning a colour code first. */
a {
  color: inherit;
  /* Underline in the link's own colour, dialled back — a hairline in --line-2
     was too faint under the quieter grey text to read as an affordance. The
     first declaration is the fallback for a browser without color-mix. */
  text-decoration-color: currentColor;
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
a:hover { color: var(--go); text-decoration-color: currentColor; }
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  border-radius: 3px;
}
/* On the brand ground the ink ring is near-black on dark green: measured
   1.66:1, where WCAG wants 3:1 for a focus indicator. That is every link in
   the header, the hero and the footer — the whole site's navigation for
   someone using a keyboard. Cream on the same green is 9.23:1. The offset
   puts the ring outside the control, so both its neighbours are the ground,
   including around the cream button. Two classes beat the bare
   `:focus-visible` above without !important. */
.fascia :focus-visible,
.hero :focus-visible,
footer :focus-visible {
  outline-color: var(--brand-ink);
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 20;
  background: var(--surface); color: var(--ink); font-weight: 600;
  padding: .6rem .9rem; border-radius: var(--r);
  border: 1px solid var(--control-line);
}
.skip:focus { left: .5rem; top: .5rem; }

/* ── Header. The brand ground, a mark and a name. ───────────────────── */
.fascia { background: var(--brand); color: var(--brand-ink); }
.fascia-in {
  max-width: var(--col); margin: 0 auto;
  padding: .85rem var(--gutter);
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s2) var(--gutter);
}
/* Lockup proportions come from the mark's delivery note: a 28px mark next to
   the name at ~21px, 11px apart. Set in em off the nameplate's own size so
   the three stay in proportion if the header is ever scaled. */
.nameplate {
  font-family: var(--serif); font-weight: 600;
  font-size: 1.31rem; letter-spacing: -0.005em;
  color: var(--brand-ink); text-decoration: none;
  display: inline-flex; align-items: center; gap: .52em;
}
.nameplate:hover { color: var(--brand-ink); }
/* The mark travels with the name rather than floating on its own — a lockup,
   so the two are never spaced or sized independently by a later edit. Sized
   in em so it tracks the nameplate's own size.
   NOT called `.mark`: that name is already taken by the AI-disclosure line
   inside the draft card (`.well .mark`), and a bare `.mark` setting a width
   squeezed that sentence to one character wide. */
.logo { width: 1.333em; height: 1.333em; display: block; }
/* The owner's door. Caddy forwards /login to the app hostname (ADR-059), so
   the header can offer it without the visitor knowing there are two hosts.
   Only the FIRST of the right-hand links takes margin-left:auto: two auto
   margins in a flex row split the free space between them, which parked this
   button in the middle of the strip. The sibling rule below zeroes the note's
   auto margin when this button precedes it, and leaves it alone otherwise. */
.signin {
  margin-left: auto;
  color: var(--brand-ink); text-decoration: none;
  font-size: var(--t-sm); font-weight: 600;
  padding: .34rem .8rem; border-radius: var(--r);
  border: 1px solid var(--brand-line);
}
.signin:hover { color: var(--brand-ink); background: var(--brand-fill); }

.fascia-note {
  font-size: var(--t-sm); color: var(--brand-ink-2);
  margin-left: auto;
  text-decoration-color: currentColor;
}
.signin ~ .fascia-note { margin-left: 0; }
/* The rule that used to live here gave the note its auto margin back below
   30rem, for when the strip wrapped and the note landed on its own line. It is
   gone because that can no longer happen: the note is hidden well before the
   strip wraps (see the phone block near the end of this file), so the rule
   could never take effect. */
/* The global hover turns a link green, which on the brand ground is green on
   green. Anything sitting on that ground brightens to the full cream instead. */
.fascia a:hover, .hero a:hover, footer a:hover { color: var(--brand-ink); }

main { max-width: var(--col); margin: 0 auto; padding: 0 var(--gutter) var(--s8); }
/* The front page only: main stops being the width-limiter so the opening
   block can be a full-width band of colour, and .col puts the column back
   around each piece of content. The other two pages keep the plain main. */
main.wide { max-width: none; padding-left: 0; padding-right: 0; }
.col { max-width: var(--col); margin: 0 auto; padding: 0 var(--gutter); }

/* ── The opening block: the promise, and the thing itself ───────────────
   A band of the brand ground carrying the headline and one real product
   surface next to it. The card is the same material as the owner's actual
   draft queue, not an illustration of it — it is the only evidence on the
   page, so it earns the first screen. */
.hero {
  background: var(--brand); color: var(--brand-ink);
  padding-bottom: 2.6rem;
}
.hero-in { display: grid; gap: 2rem; align-items: center; }
@media (min-width: 56rem) {
  .hero-in { grid-template-columns: minmax(0, 1fr) minmax(0, 21rem); gap: 3rem; }
}
.hero .hook { padding: 3rem 0 0; }
/* Both ancestors named: `.hook h1` further down weighs the same (0-1-1) and is
   declared later, so a colour added there would silently take the headline off
   the ground. That is the same tie that already went wrong twice here. */
.hero .hook h1 { color: var(--brand-ink); }
.hero .hook p { color: var(--brand-ink-2); }
.hero .hook p strong { color: var(--brand-ink); }
.hero .quiet { color: var(--brand-ink-2); }
/* `.hook p.stamp` further down weighs the same and is declared later, so it
   won the tie and painted the offer in the paper palette's grey — on green,
   1.5:1. Named with both ancestors to settle it on specificity, not order. */
.hero .hook p.stamp { color: var(--brand-ink-2); }
.hero .hook p.stamp b { color: var(--brand-ink); }
/* The offer (ADR-211, second round): the price as a serif figure with its two
   terms beside it, boxed on the ground with the same line and fill the
   sign-in button wears, so it reads as one object and not a footnote. Wraps
   to two rows on a phone. */
.hero .hook .offer {
  display: inline-flex; flex-wrap: wrap; align-items: center; gap: .35rem 1.1rem;
  margin: 1.4rem 0 0; padding: .75rem 1.1rem;
  border: 1px solid var(--brand-line); border-radius: var(--r);
  background: var(--brand-fill);
}
.hero .hook .offer-price {
  font-family: var(--serif); font-weight: 600; font-size: 1.75rem; line-height: 1;
  color: var(--brand-ink); white-space: nowrap;
}
.hero .hook .offer-price small { font-size: 1.05rem; margin-left: .1rem; }
.hero .hook .offer-terms { color: var(--brand-ink-2); font-size: var(--t-sm); line-height: 1.35; }
.hero .hook .offer-terms b { color: var(--brand-ink); font-weight: 600; }
/* Inverted on the ground: a green button on a green field is not a button. */
.hero .cta { background: var(--brand-ink); color: #12281c; }
.hero .cta:hover { background: #ffffff; color: #12281c; }

/* Same cap as the card it wraps, so the caption stays tied to the card instead
   of running out under the empty ground beside it.
   Capped, the card leaves ground to its right in the one-column hero, and it
   stays LEFT rather than centring: measured at 760px every element in the
   opening block starts at the same x and stops somewhere different — headline
   469px, lede 608, button 245, offer 608, card 400. The block is a left rag
   with five right edges, so the card is not an outlier, and centring it would
   make it the only thing not on the edge. */
.shot { display: grid; gap: .6rem; max-width: 25rem; }
.shot-cap {
  margin: 0; font-size: var(--t-xs); color: var(--brand-ink-2);
  max-width: none;
}
/* Every element carrying this class today is a <p>, and `p` below already
   sets the same max-width — so it currently changes nothing anywhere, and
   removing it from a <p> moves the box 0px. Kept for a non-<p> that needs
   the prose measure, but do NOT read it as protection: it is one class
   weight, so any later class setting max-width beats it. That is exactly how
   `class="note measure"` came to be doing nothing on the front page. */
.measure { max-width: var(--measure); }

/* ── Hook: the reader's problem, then the sentence that answers it. ─── */
.hook { padding: 3rem 0 1.6rem; }
.hook h1 {
  margin: 0 0 var(--s4);
  font-family: var(--serif); font-weight: 600;
  /* Ramps from the narrowest phone up. The previous clamp(2rem, 6vw, 3rem)
     only overtook its own floor at 533px, so every phone from 360 to 530 —
     which is every phone — got the identical 32px headline. */
  font-size: clamp(2.05rem, 1.35rem + 3.1vw, 3rem);
  line-height: 1.12;
  letter-spacing: -0.015em;
  text-wrap: balance;
}
/* The 19ch cap stops the headline running the full column on a wide screen.
   A phone has no full column to run into: measured at 430px the cap threw
   away 59 of the 392 available px and bought an extra line for nothing. */
@media (min-width: 34rem) {
  .hook h1 { max-width: 19ch; }
}
.hook p { margin: 0 0 1.6rem; font-size: var(--t-lg); color: var(--ink-2); }
.hook p strong { color: var(--ink); font-weight: 600; }

.cta-row { display: flex; flex-wrap: wrap; align-items: center; gap: .8rem 1.4rem; }
.cta {
  display: inline-block;
  background: var(--go); color: var(--go-ink);
  font-size: var(--t-md); font-weight: 600;
  padding: .78rem 1.4rem; border-radius: var(--r);
  text-decoration: none;
  /* Transparent border on the filled form, the same device the tap stack
     uses: the ghost twin below only recolours this edge, so a filled and a
     ghost button sit flush wherever they meet (ADR-164) — declared ONCE
     here rather than re-established per context, which is how a later edge
     change would miss one (docs/FAELDER.md, fælde 41b's shape). */
  border: 1px solid transparent;
}
/* LIVE since the error page (site/404.html): its "Gå til forsiden" is the
   site's first .cta outside .hero, so this rule and the base .cta above are
   what it renders as — the green button on paper, which is where the green
   button belongs. It was dead code until then, and the note here said so.
   Measured on both grounds when it went live, because a rule nothing has ever
   drawn is a rule nobody has ever looked at: white on #0f7a41 is 5.41:1 by day
   and #06210f on #2fae63 is 5.97:1 by night, with the hovers at 7.07 and 7.03;
   the button reads 4.83:1 against day paper and 6.22:1 against night. A test
   recomputes all of it from the tokens, so recolouring --go cannot quietly
   take it under. The .hero .cta rules above still win on the front page. */
.cta:hover { background: #0c6636; color: var(--go-ink); text-decoration: none; }
.cta:active { transform: translateY(1px); }
/* The quiet second button (ADR-164): same shape as .cta, no fill, the shared
   control edge. --control-line, not the structural hairline, because this
   border is the only thing saying "control" — 3.6:1 on paper, and the
   edge-contrast test already holds that token to 3:1 on both grounds.
   Declared AFTER .cta:hover on purpose: both are 0-2-0, so source order is
   what keeps the ghost from turning solid green under the cursor — its own
   :hover below is the one that applies. */
.cta.ghost {
  background: transparent; color: var(--ink);
  border-color: var(--control-line);
}
.cta.ghost:hover { background: var(--sunk); color: var(--ink); }
/* Contact actions (ADR-164): the call and the mail as buttons, replacing the
   read-only list rows that carried a 19px-tall phone number. Stacked full
   width on a phone, side by side from 34rem. */
.acts { display: flex; flex-wrap: wrap; gap: var(--s3); margin: 0 0 var(--s4); }
.acts .cta {
  flex: 1 1 15rem;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--tap-cta);
}
@media (min-width: 34rem) { .acts .cta { flex: 0 1 auto; } }
/* Who is behind it — prose, not an action, so it stays a line of text. */
.contact-who { color: var(--ink-2); font-size: var(--t-sm); }
.quiet { font-size: 1rem; color: var(--ink-2); }
/* Small line under the hook. Own declaration rather than a shared helper:
   `.hook p` outranks a single class, so the helper would render at hook
   body size. Set at body size rather than below it: on the front page this
   line carries the offer ("0 kr. i hele pilotperioden"), which is the fact
   that earns the phone call, and it was reading as a footnote. The policy
   page uses the same class for its date line, which is why the emphasis
   lives on an inner <b> and not on the whole line. */
.hook p.stamp {
  margin: 1.25rem 0 0;
  font-size: 1rem; color: var(--ink-2);
}
.hook p.stamp b { color: var(--ink); font-weight: 600; }

/* ── Icons (ADR-211). One inline <symbol> sprite per page, hidden, drawn
   with <use>; no icon font, no extra file. Stroke icons in the structural
   green on a soft plate. The plate is MATERIAL: it carries no meaning, and
   the heading beside it does the talking (the svg is aria-hidden). ───── */
.sprite { display: none; }
.ic {
  display: block; width: 1.25rem; height: 1.25rem;
  fill: none; stroke: currentColor; stroke-width: 1.75;
  stroke-linecap: round; stroke-linejoin: round;
}
.ic-plate {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.5rem; height: 2.5rem; border-radius: 50%; flex: none;
  background: var(--brand-soft); color: var(--brand-2);
}
/* Icons inside the two contact buttons: smaller, and a gap to the label. */
.acts .cta { gap: .55rem; }
.acts .cta .ic { width: 1.1rem; height: 1.1rem; }

/* ── Sections ───────────────────────────────────────────────────────── */
/* Grows with the column. 2.8rem is right on a phone and mean on a 1280px
   screen, where the section break was the only thing separating two topics
   and read as one continuous run of text. Floor keeps the phone unchanged. */
section { padding-top: clamp(2.8rem, 1.8rem + 2.6vw, 3.6rem); }
h2 {
  margin: 0 0 .6rem;
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(1.35rem, 3.2vw, 1.7rem);
  line-height: 1.2; letter-spacing: -0.01em;
  /* No max-width here on purpose. The longest heading on the site ("7. Har du
     henvendt dig til en håndværker, der bruger Leadmakker?") is 63ch, which
     fits one line in the column; a display measure of 24ch was tried and
     turned four one-line policy headings into two- and three-line ones. A
     heading is scanned, not read, so the prose measure does not apply. */
  text-wrap: balance;
}
/* Headings get heading leading. h3 inherited the body's 1.6, so a wrapping
   one set itself like a paragraph — on the front page that is the fourth
   card, "Kvalificer leads, og undgå spildturene", which wraps at every
   width. 1.12 / 1.2 / 1.25 is the ramp. */
h3 {
  margin: 1.6rem 0 .4rem;
  font-family: var(--serif); font-weight: 600;
  font-size: var(--t-lg); line-height: 1.25; letter-spacing: -0.005em;
  text-wrap: balance;
}
.lede { margin: 0 0 1.5rem; color: var(--ink-2); }
p { margin: 0 0 1rem; max-width: var(--measure); }

/* Emphasis, set in a face we actually ship.
   We serve two files and neither of them is an italic, so every <em> on the
   guide page was being drawn by the browser SHEARING the roman — a fake
   oblique, which is the one thing a page that ships real typefaces should not
   show. Measured: the same string at `font-style: italic` and at `normal` came
   out to the identical 124.13px advance, which is only possible when no italic
   face exists and the glyphs are simply slanted.
   The serif is the fix, and it costs no bytes: it is already loaded for every
   heading. It also stays clearly apart from <b>/<strong>, which are the sans at
   600 — so the guide's point 10, which uses both in one sentence, still reads
   as two different kinds of stress.
   Why the sizes need no correction: the two faces are one superfamily and were
   drawn to mix. Measured at 100px — x-height 50 vs 49, cap-height 67 vs 66 —
   so a serif word drops into a sans line without sitting high or low. It runs
   18 % wider, which is what a serif does and is fine for two words.
   600 is stated rather than inherited because 600 is the only weight of the
   serif we ship; asking for anything else gets the 600 file anyway, and the
   declaration would then say something untrue (the same trap as .foot-mono). */
em, i {
  font-family: var(--serif);
  font-style: normal;
  font-weight: 600;
}

/* ── The three outcomes on the front page (ADR-213: three, not four, and
   straight under the opening). Each names the problem first and then what
   we do about it — that order, always. ─────────────────────────────── */
/* Gap matched to the cards' own padding, so the grid reads as evenly spaced
   rather than as three boxes shoved together. One row of three from 44rem:
   two columns would leave the third card alone on a second row. */
.usps { display: grid; gap: 1.2rem; margin-top: 1.5rem; }
@media (min-width: 44rem) { .usps { grid-template-columns: repeat(3, 1fr); } }
.usp {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 1.15rem 1.25rem;
}
/* Icon and heading on one row (Jacob's fifth round), the heading in the
   structural green the ten points' numerals use: material, not a signal. */
.usp-head { display: flex; align-items: center; gap: .8rem; margin-bottom: .65rem; }
.usp h3 { margin: 0; font-size: 1.2rem; color: var(--brand-2); }
.usp p { margin: 0; max-width: none; color: var(--ink-2); }
.usp p + p { margin-top: .55rem; }
.usp p strong { color: var(--ink); font-weight: 600; }

/* ── Who it is for (ADR-213): the trades as a row of quiet pills, scanned
   rather than read. The quiet control edge, because a pill with the
   structural hairline disappears against paper; no fill, so it does not
   read as a button. ─────────────────────────────────────────────────── */
.trades {
  display: flex; flex-wrap: wrap; gap: .55rem;
  margin: 0 0 1rem; padding: 0; list-style: none;
}
.trades li {
  padding: .38rem .85rem; border: 1px solid var(--line-2); border-radius: 999px;
  font-size: var(--t-sm); color: var(--ink);
}
/* The last pill is the open door, on the plate material rather than a
   line, so the row ends on "and everyone else" instead of a sixth trade. */
.trades li.open { border-color: transparent; background: var(--brand-soft); color: var(--brand-2); font-weight: 600; }
/* The link on to the guide, set as a step forward rather than a word in a
   sentence. The arrow is the same glyph the guide's jump rows end on. */
.dive { margin-top: 1.2rem; }
.more { font-weight: 600; text-decoration-color: var(--line-2); }
.more::after { content: " \2192"; color: var(--brand-2); }

/* ── The sand band (ADR-211): the one section that is not paper. It pays
   its own vertical padding — the bare `section` rule sets only the top. ── */
.band { background: var(--sand); padding: clamp(2.8rem, 1.8rem + 2.6vw, 3.6rem) 0; }

/* ── Three steps on the band. No boxes: a numeral, an icon, a heading and
   one line, so the section reads differently from the three cards above it.
   A real <ol> because the order IS the information; role="list" in the
   markup keeps the semantics with list-style none. ─────────────────── */
.steps {
  display: grid; gap: 1.25rem;
  margin: 1.5rem 0 0; padding: 0; list-style: none;
  counter-reset: step;
}
@media (min-width: 44rem) { .steps { grid-template-columns: repeat(3, 1fr); gap: 2rem; } }
/* Same row form as the outcome cards (Jacob, 9/9): the numeral on its own
   line above, then icon and heading side by side, then the sentence. The
   old two-row grid put the numeral and the heading in a stack beside the
   icon, and the three steps did not line up with each other. */
.step { counter-increment: step; display: grid; gap: .35rem; align-content: start; }
.step::before {
  content: counter(step, decimal-leading-zero);
  font-family: var(--serif); font-weight: 600; font-size: var(--t-sm);
  color: var(--brand-2);
}
.step-head { display: flex; align-items: center; gap: .8rem; }
.step h3 { margin: 0; font-size: var(--t-lg); line-height: 1.25; }
.step p { margin: .35rem 0 0; max-width: none; color: var(--ink-2); }

/* ── The price card: the same sheet, a stronger edge, the figure in the
   structural green. ─────────────────────────────────────────────────── */
.pricecard {
  display: grid; gap: .6rem; justify-items: start;
  padding: 1.4rem 1.5rem; max-width: var(--measure);
  background: var(--surface); border: 1px solid var(--line-2); border-radius: var(--r);
}
.pricecard .price { color: var(--brand-2); margin: 0; }
.pricecard p { margin: 0; max-width: none; color: var(--ink-2); }
.pricecard p b { color: var(--ink); font-weight: 600; }
.pricecard .cta { margin-top: .5rem; }

/* ── The ten numbered things (the guide page). A plain ordered list with
   the numeral set in the margin; no bands, no lamps. ────────────────── */
/* Real <ol> numbering styled through ::marker, not a counter in ::before with
   list-style:none. The numbers are load-bearing — item 10 refers the reader
   back to "punkt 6" and "punkt 7" — so they have to survive a screen reader
   and carry text contrast, not decorative contrast. */
ol.ting {
  list-style: decimal;
  margin: var(--s5) 0 0; padding: 0 0 0 2.7rem;
}
ol.ting > li {
  padding: 1.15rem 0;
  border-top: 1px solid var(--line);
  max-width: var(--measure);
}
/* Closes the block. Without it the tenth point runs off into white space and
   the list looks like it was cut short rather than finished. */
ol.ting > li:last-child { border-bottom: 1px solid var(--line); }
ol.ting > li::marker {
  font-family: var(--serif); font-weight: 600;
  /* The numerals are the one place on the guide where the brand green is ink
     rather than ground. They are load-bearing (item 10 cites 6 and 7), so
     they take a green measured at 7.5:1 on paper, not a decorative tint. */
  font-size: 1.2rem; color: var(--brand-2);
}
ol.ting > li > b:first-child { font-weight: 600; }
ol.ting p { margin: .45rem 0 0; color: var(--ink-2); max-width: none; }

/* The honest small print that belongs to one item, sunk rather than hidden
   at the bottom of the page. */
.note {
  margin: .7rem 0 0; padding: .8rem .95rem;
  background: var(--sunk); border: 1px solid var(--line);
  border-radius: var(--r);
  font-size: var(--t-sm); color: var(--ink-2);
  /* NOT `none`. This rule sits after .measure with the same specificity, so
     `max-width:none` silently cancelled class="note measure" on the front
     page and the box ran the whole 56rem column — 107ch of .97rem text,
     measured at 1280px. --measure-sm is the same ~66ch at THIS size. */
  max-width: var(--measure-sm);
}
.note b { color: var(--ink); font-weight: 600; }
/* A note may hold more than one paragraph in one box (the front page's did
   until ADR-213 took the small print off it), so the paragraphs inside keep
   the box's width rather than the prose measure. */
.note p { margin: 0; max-width: none; }
.note p + p { margin-top: .6rem; }
/* Every .note keeps that one width, including the two riding inside numbered
   points on the guide. They end ~96px short of the point they belong to,
   which is what smaller text should do — letting them fill the point's own
   --measure put them at 79ch, and a rider is not meant to out-run its line.
   Spelled out rather than left to source order: the guide's notes ARE the
   <p>, so `ol.ting p { max-width: none }` matches them at 0-1-2 and outranks
   a bare `.note`. Relying on which rule came last is the same trap that let
   `max-width:none` cancel class="note measure" on the front page. */
ol.ting p.note { max-width: var(--measure-sm); }

/* ── The artifact: what the owner's tap actually looks like. Built from
   the dashboard's real material (well for inbound, tinted output well for
   the draft, action badge, stacked non-adjacent actions). ───────────── */
.spec { display: grid; gap: 1.4rem 2.2rem; align-items: start; }
@media (min-width: 54rem) {
  .spec { grid-template-columns: minmax(0, 20rem) minmax(0, 1fr); }
}
.phone {
  background: var(--surface);
  /* Carries its own ink, so the card stays a card wherever it is put. On the
     front page it sits on the brand ground, and without this it inherited
     that ground's cream text onto its own near-white wells: measured 1.0:1,
     i.e. the customer's message and the draft were invisible. */
  color: var(--ink);
  border: 1px solid var(--line-2);
  border-radius: 12px;
  overflow: hidden;
  /* The card is a phone. Both grids that hold it hand it a phone-sized column
     — 21rem in the front page's hero, 20rem in the guide's .spec — but only
     ABOVE their own breakpoints (56rem and 54rem). Below those the grid is one
     column and the card took the whole of it: measured at 760px it was 722px
     wide and the customer's message ran 91.6ch, on the one piece of evidence
     the front page has. That band is every tablet in portrait, which is a
     likely way for someone to open a link we sent them.
     25rem (400px) is chosen so the cap can only ever bite a tablet: the card
     is the column minus 2.4rem of padding, so it crosses 400px at a 439px
     viewport, and the widest phone in portrait is 430. Measured: no effect at
     438, in effect at 440, and at 430 the card is 392px with and without it.
     Above 56rem the grid column is already narrower, so it is inert there too
     — it owns only the middle. */
  max-width: 25rem;
}
.phone .top {
  background: var(--sunk); color: var(--ink-2);
  border-bottom: 1px solid var(--line);
  padding: .55rem .85rem;
  font-size: .9rem; font-weight: 600;
  display: flex; gap: .6rem; align-items: center;
}
.phone .top .when { margin-left: auto; font-weight: 400; }
.phone .body { padding: .85rem; display: grid; gap: .75rem; }
/* The action badge, drawn the way the real queue draws it (ADR-110): a SOLID
   pill, not the soft outlined one this page used to invent for itself. In a
   list of ten drafts the action is what the owner scans for, and the owner UI
   is not going to give that up to match a picture of itself — so the picture
   matches the product.
   TOKENISED since ADR-192, and the reason is the exact opposite of the one
   this note used to give. The hex was written out because the app's badge came
   from a FIXED table that did not move with the theme, so a token here would
   have drifted away from the product at night. That table is gone: the app's
   badges now carry --plan/--plan-ink like everything else, because the fixed
   colours left the book badge at 3.0:1 on the night card and made the violet
   the loudest thing on the screen. Naming the same pair is now what keeps the
   card the same material as the owner's real queue (ADR-094) instead of what
   breaks it — and the pair is a REAL token with a user, not the dead --act
   trio this sheet deleted (see the note in :root).
   The ink moves with it, which closes a gap R218 wrote down and left open:
   this card said cream while the app said white. White on the day violet is
   7.1:1 against the 6.4:1 cream gave, so the card also reads a shade better.
   html.test.ts' twin block reads this rule and fails if the background and the
   colour are not ACTION_COLORS.propose_times, and it compares the pair's
   VALUES in this file against html.ts in all four palettes. */
.badge {
  justify-self: start;
  background: var(--plan); color: var(--plan-ink);
  border: 1px solid transparent;
  font-size: .82rem; font-weight: 700;
  padding: .16rem .6rem; border-radius: 999px;
}
.well {
  background: var(--sunk);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: .7rem .8rem;
  font-size: .95rem;
}
.well .who {
  font-size: .85rem; font-weight: 600;
  color: var(--ink-2); display: block; margin-bottom: .3rem;
}
.well p { margin: 0; max-width: none; }
.well p + p { margin-top: .55rem; }
.well.output { background: var(--info-soft); border-color: var(--info-line); }
.well .mark {
  display: block; margin-top: .55rem;
  font-size: .85rem; color: var(--ink-2);
}
.taps { display: grid; gap: .45rem; }
.taps span {
  border-radius: var(--r); padding: .58rem .8rem;
  font-size: .97rem; font-weight: 600; text-align: center;
  /* Transparent border on the filled one too, so all three stack flush. */
  border: 1px solid transparent;
}
.taps .t-go { background: var(--go); color: var(--go-ink); }
.taps .t-edit { background: var(--surface); color: var(--info); border: 1px solid var(--info); }
.taps .t-no { background: var(--surface); color: var(--stop); border: 1px solid var(--stop); }
.caption { font-size: var(--t-sm); font-weight: 600; color: var(--ink-2); margin: 0 0 .5rem; }

/* ── Plain sheets: price, practicalities, contact, policy body ──────── */
.sheet {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 1.1rem 1.25rem;
}
.sheet > :last-child { margin-bottom: 0; }
.sheet h3:first-child { margin-top: 0; }
.sheets { display: grid; gap: 1rem; }
@media (min-width: 44rem) { .sheets.two { grid-template-columns: 1fr 1fr; } }

/* ── Jump list (ADR-166): the two long pages' sections as tap rows ─────
   The guide is 8.6 phone screens and the policy 12.7 with nine sections;
   this is the way past scrolling for all of it. Rows, not a box with
   prose: a thumb-height link per section, a hairline between them, an
   arrow in the margin. No underline, like the header links — the row
   IS the affordance here, borders and arrow included. The arrow takes
   the structural green (--brand-2, the ten points' numeral ink), not a
   signal colour: it points, it does not mean go.
   On the policy the list sits BEFORE the .status box on purpose —
   measured: after the box, two and a half rows cleared the fold; before
   it, all nine do. */
.toc {
  margin: var(--s2) 0 0; padding: 0; list-style: none;
  border-top: 1px solid var(--line);
  max-width: var(--measure);
}
.toc li { border-bottom: 1px solid var(--line); }
.toc a {
  display: flex; align-items: center; min-height: var(--tap);
  padding: var(--s2) 0;
  color: var(--ink); font-weight: 600; font-size: var(--t-sm);
  text-decoration: none;
}
.toc a:hover { color: var(--ink); text-decoration: underline; }
.toc a::after { content: "\2192"; margin-left: auto; color: var(--brand-2); }
/* The guide's jump rows carry an icon each (ADR-211), a size down. */
.toc a .ic-plate { width: 2rem; height: 2rem; margin-right: .75rem; }
.toc a .ic { width: 1.05rem; height: 1.05rem; }

ul.list { margin: 0 0 1rem; padding: 0; list-style: none; max-width: var(--measure); }
ul.list li { position: relative; padding: .4rem 0 .4rem 1.5rem; }
ul.list li::before {
  content: ""; position: absolute; left: .1rem; top: .95rem;
  width: .55rem; height: 2px; border-radius: 1px; background: var(--brand-2);
}
ul.list li + li { border-top: 1px solid var(--line); }
.sheet > ul.list:last-child { margin-bottom: 0; }

/* The three steps to get started (ADR-211). Numbered because they are an
   order of events, set like the ten points' numerals. */
ol.start { margin: var(--s4) 0 var(--s5); padding: 0 0 0 2.2rem; max-width: var(--measure); }
ol.start li { padding: .35rem 0; }
ol.start li::marker { font-family: var(--serif); font-weight: 600; color: var(--brand-2); }

.readout { font-family: var(--serif); font-weight: 600; }
.price { font-size: clamp(2.1rem, 6vw, 2.8rem); line-height: 1.1; display: block;
  margin-bottom: .4rem; }

/* Field only the owner can fill. Deliberately loud: ADR-059 forbids any of
   these reaching the live site, and the deploy checklist in
   docs/OPERATIONS.md checks for them. */
.todo {
  display: inline-block;
  font-family: var(--sans); font-size: var(--t-xs); font-weight: 700;
  background: var(--stop-soft); color: #8f2620;
  border: 1px dashed var(--stop); border-radius: 4px;
  padding: .1rem .4rem;
}

/* ── Status note (privacy page): honest about what is not lawyer-approved */
.status {
  background: var(--warn-soft); border: 1px solid var(--warn-line);
  border-radius: var(--r); padding: 1rem 1.2rem;
  color: var(--warn-ink-soft);
  margin: 1.4rem 0 0;
  /* Aligns the box with the lead paragraph above it instead of running the
     full column — measured at 97ch before the cap, on the first thing a
     reader meets on the policy page. */
  max-width: var(--measure);
}
.status p { max-width: none; }
.status > :last-child { margin-bottom: 0; }
.status b { color: #5a3607; }

/* ── Tables (privacy policy) ────────────────────────────────────────── */
/* The markup gives every .scroll a tabindex, a role and a name, because a
   keyboard cannot scroll a container it cannot focus — see the note in
   privatlivspolitik.html. Nothing extra is needed here: the sheet's global
   :focus-visible already draws the ring, and it must keep doing so. */
/* The four-column tables are 34rem wide at their narrowest and the phone is
   not, so they scroll sideways — and nothing said so: the reader met a table
   that appeared to stop after three columns. These four layers are the
   pure-CSS scroll hint. The two `local` gradients ride the content and slide
   out of the way; the two `scroll` shadows are pinned to the box and are
   uncovered as they go. So a shadow appears at exactly the edge that has more
   table behind it, and no JavaScript is involved. */
.scroll {
  overflow-x: auto;
  margin: 0 0 1rem;
  background:
    linear-gradient(to right, var(--bg) 40%, transparent) 0 0 / 2.2rem 100% no-repeat local,
    linear-gradient(to left, var(--bg) 40%, transparent) 100% 0 / 2.2rem 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, var(--edge), transparent) 0 0 / .8rem 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, var(--edge), transparent) 100% 0 / .8rem 100% no-repeat scroll;
}
/* Windows high contrast forces background COLOURS but leaves gradients alone,
   so the two cover layers would paint as pale bands down the sides of the
   table on a forced-black page. Nothing is lost by dropping the hint there:
   forced-colors mode also flattens the shadow it was covering. */
@media (forced-colors: active) {
  .scroll { background: none; }
}
table { border-collapse: collapse; width: 100%; min-width: 34rem; font-size: var(--t-sm); }
th, td { text-align: left; padding: .55rem .7rem; border-top: 1px solid var(--line); vertical-align: top; }
th {
  background: var(--sunk); border-top: none; color: var(--ink-2);
  font-size: var(--t-xs); font-weight: 600;
  white-space: nowrap;
}

/* ── Footer ─────────────────────────────────────────────────────────── */
/* Bookends the page with the same ground the header sits on, which doubles
   the colour on every page without putting any of it behind long prose. */
footer {
  background: var(--brand);
  color: var(--brand-ink-2);
  padding: 2.2rem 0 2.6rem;
  font-size: var(--t-sm);
}
.foot-in { max-width: var(--col); margin: 0 auto; padding: 0 var(--gutter);
  display: grid; gap: .7rem; }
/* 44rem was 91ch at this size. */
footer p { margin: 0; max-width: var(--measure-sm); }
/* 600, because 600 is the only weight of the serif we ship. Asking for 400
   got the 600 face anyway (one face, so the browser matches it regardless) —
   but the declaration said something that was not true of any file here. */
.foot-mono { font-family: var(--serif); font-weight: 600;
  font-size: var(--t-lg); color: var(--brand-ink); }

/* ── Touch: navigation is tapped with a thumb ───────────────────────────
   The header and footer links are how a reader moves between the three
   pages, and measured at 375px they were 22-37px tall — read fine, hard to
   hit. Two of the three header links have neither border nor background, so
   on those only the touch area changes; `.signin` is a visible button and
   does grow, from 37px to 44px. Prose links inside a paragraph are
   deliberately left alone: giving them a 44px box would space running text
   out to nothing.
   The gate is the POINTER, not the viewport (ADR-164). These rules lived in
   the 40rem block below and so never reached an iPad in portrait: 768px
   wide, driven by fingers, measured at 24-37px menu links and 22px footer
   links. `any-pointer`, not `pointer`, so a touch laptop whose primary
   pointer is the trackpad is still covered. MOVED here rather than repeated
   there — a media block that restates a declaration is a trap waiting for
   the base rule to change (docs/FAELDER.md, fælde 41b). The price, said out
   loud: a narrow WINDOW on a mouse-only machine no longer gets 44px
   (34-37px, still above WCAG 2.5.8's 24), because the target was never the
   width, it was the finger. */
@media (any-pointer: coarse) {
  .fascia a { display: inline-flex; align-items: center; min-height: var(--tap); }
  .foot-in > p:last-child a {
    display: inline-flex; align-items: center; min-height: var(--tap);
  }
}
/* On a narrow strip the padding comes off to pay for the taller links; on a
   tablet there is vertical room, so the strip keeps its padding and simply
   grows. Width-gated on purpose — this one really is about the viewport. */
@media (max-width: 40rem) {
  .fascia-in { padding: .45rem var(--gutter); gap: .25rem 1.1rem; }
}

/* ── The call bar (ADR-164): the one number, always under the thumb ────
   Fixed to the bottom on a phone, carrying the same two actions as the
   contact section: call, and write. It rides the SELLING pages only —
   index, the guide, the error page. The privacy policy deliberately goes
   without: that page is also read by the craftsman's own customers looking
   up their rights, and a sales bar under a legal text talks to the wrong
   person. The pages that carry the bar mark it on <body> as .has-callbar,
   which is what pays the footer clearance — a page that grew the bar
   without the class would cover its own footer.
   Width-gated at the same 40rem as the rest of the phone treatment: on a
   desktop the number is already visible in the opening block without
   scrolling. 62px tall all told (44px buttons + padding + hairline), which
   is 7.6% of a 812px screen — measured, and the reason the buttons take
   44 rather than the 48 the in-flow pair gets. */
.callbar { display: none; }
@media (max-width: 40rem) {
  /* The bar carries the same number the quiet line offers 250px above it,
     and that line was the page's last sub-24px target — so where the bar
     exists, the line goes. CSS, not markup: on a desktop the line stays.
     What is lost: the word "Jacob" leaves the first phone screen (it still
     lives in the contact section). */
  .has-callbar .cta-row .quiet { display: none; }
  .callbar {
    display: grid; grid-template-columns: 2fr 1fr; gap: var(--s2);
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 10;
    padding: var(--s2) var(--s3) calc(var(--s2) + env(safe-area-inset-bottom, 0px));
    background: var(--surface);
    border-top: 1px solid var(--line-2);
  }
  .callbar .cta {
    width: 100%; min-height: var(--tap);
    display: inline-flex; align-items: center; justify-content: center;
    padding: .5rem;
    /* No font-size here: the base .cta now sits on the same --t-md step, so
       restating it would be fælde 41b waiting for the base to change. */
  }
  /* Clearance for the fixed bar, so the footer's last line is never under
     it. On the class, not on body: the policy has no bar to clear.
     62px is the measured bar at a 16px root — but the bar's height is
     content-driven, so a reader who scales the browser font up grows it
     past any fixed constant. The 2rem is headroom that scales WITH the
     text: at 200% the bar measures ~121px and this resolves to ~126.
     Generous on purpose; the surplus is empty space below the footer. */
  body.has-callbar { padding-bottom: calc(62px + var(--s6) + env(safe-area-inset-bottom, 0px)); }
}

/* ── The opening block, tightened where height is scarcest (ADR-166) ───
   Measured before this at 375x812 with the call bar: the draft well's
   "Agentens udkast" label sat 65px below the visible fold, so the one
   piece of evidence on the page showed the customer's problem and none
   of the answer. Four distances come in, each by one scale step, and
   only inside .hero — the inner pages' hooks keep their air, and
   nothing here touches the card itself. Every declaration OVERRIDES the
   base with a different value; none restates one (fælde 41b). */
@media (max-width: 40rem) {
  .hero .hook { padding-top: var(--s5); }
  /* The lede only — a bare `.hero .hook p` also hit the stamp and handed
     its zero bottom margin 24px it never had, which alone kept the label
     under the fold. Measured, not guessed. */
  .hero .hook p.measure { margin-bottom: var(--s5); }
  .hero .hook p.stamp { margin-top: var(--s4); }
  .hero-in { gap: var(--s5); }
  .hero { padding-bottom: var(--s6); }
}

/* The lockup is wider than the bare wordmark was, and below this width the
   three header items stop fitting one row — the strip doubles from 59px to
   106px, on the screen where height is scarcest. This link is the one to
   lose: it points at "/" on both inner pages, which is exactly where the
   nameplate beside it already goes, and on the front page it points at the
   same page as the big button below it. Nothing becomes unreachable, and
   `display:none` drops it from the accessibility tree too — right here,
   because the destination is still on the page twice over.
   The threshold is the MEASURED wrap point, not the phone block's 40rem.
   Hiding it there took the link away at 640px, where the strip still has
   room to spare: on a tablet, on a phone in landscape, and for anyone at
   200 % zoom. Measured: the three items plus their gaps need 379px, so the
   strip wraps below ~417px. 27rem (432px) sits a little above that on
   purpose — the wordmark's width depends on the webfont having loaded, and
   the fallback serif is not the same width. Verified: 434px keeps all three
   on one row, 432px hides the note, and no width between produces two rows.
   Two classes, not one: `.fascia a` above is 0-1-1 and beats a bare
   `.fascia-note` at 0-1-0, so the first attempt changed nothing at all. */
@media (max-width: 27rem) {
  .fascia .fascia-note { display: none; }
}

/* ── Night variant. Same tokens and meanings; no manual switch here,
   because that needs a cookie. ──────────────────────────────────────── */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #17181a; --surface: #1e2023; --sunk: #232629;
    --ink: #ecebe8; --ink-2: #a9a7a1;
    --line: #2e3134; --line-2: #454a4f; --control-line: #767570;
    --go: #2fae63;   --go-ink: #06210f; --info: #5c96f0;
    /* The badge pair after dark (ADR-192). A muted plum, not a lighter violet:
       the day hex kept on this card at night was the brightest thing on the
       owner's screen, and the card is supposed to look like his queue, not
       like a demo. Twins in html.ts; move them together. */
    --plan: #a17ecd; --plan-ink: #23103a;
    --stop: #e2645b; --stop-soft: #2a1817; --stop-line: #6a322d;
    --warn-soft: #2a1f12; --warn-line: #6a4a24; --warn-ink-soft: #e7c493;
    /* No --act trio at night either; see the day palette for why. */
    /* The owner UI's night values for the same two tokens (html.ts). */
    --info-soft: #16202f; --info-line: #2f4d78;
    /* The brand ground goes deeper at night so the header and footer read as
       bands against the panel rather than glowing off it, and the structural
       green lifts, because #0d5c33 on a dark panel is nearly invisible. */
    --brand: #0b3222;
    --brand-ink: #eef0ea; --brand-ink-2: #adbcae;
    /* .40, not .46: the night ground is lighter relative to the cream, so it
       reaches the same ratio sooner. Measured 3.21:1, the same ~3.2 the day
       palette gets at .46. See the note in :root. */
    --brand-line: rgba(238, 240, 234, .40);
    --brand-fill: rgba(238, 240, 234, .08);
    --brand-2: #5cc98a;
    /* Night material (ADR-211). The band goes one step DARKER than the panel:
       a lighter tone collided with the card surface. The plate is the
       structural green at low alpha over the card. Measured: icon on plate
       6.0:1 (6.6 over the panel), ink on sand 15.6:1, ink-2 on sand 7.7:1. */
    --brand-soft: rgba(92, 201, 138, .14);
    --sand: #121315;
    --go-ring: rgba(47, 174, 99, .55);
    /* The edge has to shade with LIGHT here, not with more black. Measured
       against the #17181a panel: 13 % black gives 1.03:1 and even 100 % black
       only reaches 1.18:1 — below what the light palette already gets — so
       there is no darker value that works. White at 16 % gives 1.63:1. */
    --edge: rgba(255, 255, 255, .16);
  }
  .cta:hover { background: #37bd6d; }
  .status b { color: #f4dcbc; }
  .todo { color: #f0a9a2; background: #2a1817; }
}

/* ── Motion (ADR-211). All of it in this one block, so a reader who has
   turned motion off gets the page as the base rules draw it: finished and
   still. Three things: the opening rises in once on load, the draft card on
   the front page plays its sequence once (about six seconds, never a loop),
   and a card lifts 2px under the cursor. No scroll-triggered effects, and
   no identical entrance on every section. fill-mode is BACKWARDS, not
   both: the element shows its start state through the delay and returns to
   the base rules when done, so a finished sequence never pins transform and
   blocks the hover lift. The base rules are the finished state; the
   keyframes hold only starts. A test walks this block's braces and checks
   that nothing that moves is declared outside it. ──────────────────── */
@media (prefers-reduced-motion: no-preference) {
  @keyframes rise { from { opacity: 0; transform: translateY(8px); } }
  @keyframes appear { from { opacity: 0; } }
  /* A message arriving: up from below and a touch small, on a curve that
     overshoots by a hair so it lands like a chat bubble, not a slide. */
  @keyframes pop { from { opacity: 0; transform: translateY(12px) scale(.94); } }
  @keyframes ring { from { box-shadow: 0 0 0 0 var(--go-ring); } to { box-shadow: 0 0 0 14px transparent; } }

  /* The opening: its four children, then the card beside them. */
  .hero .hook > * { animation: rise .55s cubic-bezier(.16, 1, .3, 1) backwards; }
  .hero .hook > :nth-child(2) { animation-delay: .08s; }
  .hero .hook > :nth-child(3) { animation-delay: .16s; }
  .hero .hook > :nth-child(4) { animation-delay: .24s; }
  .shot { animation: rise .6s cubic-bezier(.16, 1, .3, 1) .2s backwards; }

  /* The film, front page only (.hero); the guide's copy of the card stands
     finished. The customer's message pops in, the badge appears, the whole
     draft pops in as one message (Jacob's call over a line-by-line reveal,
     which read like a slide transition), then the buttons and one ring on
     Godkend. About four seconds. */
  .hero .phone .well { transform-origin: 50% 100%; }
  .hero .phone .well:not(.output) { animation: pop .5s cubic-bezier(.2, .9, .3, 1.15) .5s backwards; }
  .hero .phone .badge { animation: appear .35s ease-out 1.5s backwards; }
  .hero .phone .well.output { animation: pop .55s cubic-bezier(.2, .9, .3, 1.15) 2.3s backwards; }
  .hero .phone .taps { animation: appear .4s ease-out 3.3s backwards; }
  .hero .phone .taps .t-go { animation: ring .9s ease-out 3.7s; }

  /* Hover: the lift and the edge, 150ms, on the cards that are cards. */
  .usp, .pricecard { transition: transform .15s ease, border-color .15s ease; }
  .usp:hover, .pricecard:hover { transform: translateY(-2px); border-color: var(--line-2); }
}
