/* ==========================================================================
   Fonts — all self-hosted. Nothing on a third-party origin is allowed in front
   of first paint, and the CSP sends font-src 'self' so nothing else would load
   anyway.

   Instrument Serif is the DISPLAY face: high-contrast, editorial, and used only
   at large sizes where its thin strokes are an asset rather than a legibility
   problem. Inter carries every word anyone actually has to read.

   Plus Jakarta Sans was removed in the editorial pass — the serif took over the
   display role and Inter took the rest, so it was 27 KB paying for nothing.
   ========================================================================== */
@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/instrument-serif-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
                 U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Instrument Serif";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/instrument-serif-latin-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
                 U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/inter-latin-var.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
                 U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Metric-matched fallback faces. Overrides adjust an OS-installed font
   (Arial, Times) so its rendered box has the same ascent/descent/x-height
   as the corresponding web font. When Inter or Instrument Serif swap in,
   the layout doesn't reflow — no CLS from font swap.

   Numbers computed from the actual woff2 files with fontkit and the
   web.dev formula (size-adjust from x-height, then ascent/descent
   overrides divided by that scale). If a font file is re-cut with
   different metrics, recompute; do not eyeball.

   If none of the local() candidates are installed (rare Linux setups),
   the browser skips this face and falls through to the rest of the
   font-family chain, which may still shift a little on that system. */
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial"), local("Helvetica Neue"), local("Helvetica"),
       local("Liberation Sans"), local("Nimbus Sans"), local("Nimbus Sans L");
  size-adjust: 105.27%;
  ascent-override: 92.02%;
  descent-override: 22.91%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Instrument Serif Fallback";
  font-style: normal;
  src: local("Times New Roman"), local("Times"),
       local("Liberation Serif"), local("Nimbus Roman"), local("Nimbus Roman No9 L");
  size-adjust: 114.03%;
  ascent-override: 86.82%;
  descent-override: 27.19%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Instrument Serif Fallback";
  font-style: italic;
  src: local("Times New Roman Italic"), local("Times Italic"),
       local("Liberation Serif Italic"), local("Nimbus Roman Italic"),
       local("Times New Roman"), local("Times"), local("Liberation Serif");
  size-adjust: 114.03%;
  ascent-override: 86.82%;
  descent-override: 27.19%;
  line-gap-override: 0%;
}

/* ==========================================================================
   SwansonX — editorial design system
   --------------------------------------------------------------------------
   TWO LAYERS OF COLOUR, AND THE DISTINCTION MATTERS:

   1. PALETTE tokens (--c-ink, --c-bone ...) are raw paint. They never change
      between themes, and nothing outside this block should use them.
   2. SEMANTIC tokens (--bg, --text, --accent ...) name a JOB, and are redefined
      per theme. Every rule below this block uses these.

   Any new rule that hardcodes a hex is a bug — it will look right in one theme
   and wrong in the other, and nothing catches it but eyes.

   THE EDITORIAL RULES, in one place, because they are what make this read as
   expensive rather than merely tidy:
     - Ink and paper, not colour. The accent is a deep blue used in small
       amounts — labels, rules, hovers — never as a wash.
     - Hairlines, not boxes. Structure comes from 1px rules and whitespace.
       Cards are the exception, not the default.
     - Air. Sections breathe at 96-160px. Crowding is what cheap looks like.
     - Scale contrast. A 104px serif headline above 18px body copy does more
       work than any amount of decoration.
   ========================================================================== */

:root {
  /* --- Palette: raw paint, theme-independent --- */
  --c-ink:        #14120E;   /* near-black, warm */
  --c-ink-soft:   #2A2620;
  --c-bone:       #FAF8F4;   /* warm paper */
  --c-bone-2:     #F2EEE7;
  --c-paper:      #FFFFFF;
  --c-grey:       #6B6357;
  --c-line:       #E2DCD1;
  --c-line-2:     #CFC6B7;

  --c-blue-deep:  #2B4C6F;   /* the accent, light theme */
  --c-blue-pale:  #A8C4DE;   /* the accent, dark theme */

  --c-night:      #12110E;   /* near-black ground, dark theme */
  --c-night-2:    #1A1815;
  --c-bone-dim:   #E8E2D8;
  --c-bone-lit:   #F7F3EC;
  --c-grey-lit:   #A29A8C;
  --c-line-dark:  #2E2A24;
  --c-line-dark2: #403A32;

  --c-green:      #0E7A55;
  --c-green-lit:  #48C79A;
  --c-amber:      #8A6A3B;
  --c-amber-lit:  #D8B57A;

  /* --- Type --- */
  --font-display: "Instrument Serif", "Instrument Serif Fallback", "Iowan Old Style", "Palatino Linotype", Georgia, "Times New Roman", serif;
  --font-body:    "Inter", "Inter Fallback", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* --- Shape ---
     Editorial means near-square. A 22px radius reads friendly-software; 3px
     reads printed. Buttons are the only thing that gets more, and not much. */
  --r-sm: 2px;
  --r:    3px;
  --r-lg: 4px;
  --maxw: 1240px;
  --maxw-text: 68ch;
  --gut: 26px;

  /* --- Motion ---
     Slower than the previous system on purpose. Premium motion is unhurried;
     the eye should never feel hurried along by the interface. */
  --ease-out:    cubic-bezier(.16, 1, .3, 1);
  --ease-spring: cubic-bezier(.34, 1.4, .64, 1);
  --ease-in-out: cubic-bezier(.65, 0, .35, 1);
  --t-quick: .2s;
  --t-base:  .38s;
  --t-slow:  1.05s;
}

/* ==========================================================================
   LIGHT THEME — ink on bone. Declared on bare :root so it is the fallback in
   every context, including renderers that report no colour scheme at all.
   ========================================================================== */
:root,
:root[data-theme="light"] {
  color-scheme: light;

  --bg:            var(--c-bone);
  --bg-alt:        var(--c-bone-2);
  --bg-sunken:     var(--c-bone-2);
  --surface:       var(--c-paper);
  --surface-2:     var(--c-bone-2);
  --surface-glass: rgba(250, 248, 244, .82);

  --text:          var(--c-ink-soft);
  --text-muted:    var(--c-grey);
  --heading:       var(--c-ink);

  --border:        var(--c-line);
  --border-strong: var(--c-line-2);
  --border-input:  #8A8275;

  --accent:        var(--c-blue-deep);
  --accent-hover:  #1B3A59;
  --accent-soft:   #E9EEF4;
  --accent-ring:   rgba(43, 76, 111, .16);

  /* Buttons are INK, not brand colour. A solid blue button is the single most
     recognisable "template" tell; ink on bone reads as printed matter. */
  --btn-bg:        var(--c-ink);
  --btn-fg:        var(--c-bone);
  --btn-bg-hover:  var(--c-blue-deep);

  --ok:            var(--c-green);
  --ok-text:       var(--c-green);
  --star:          var(--c-amber);

  /* "Feature" = the inverted bands and the footer. */
  --feature-bg:      var(--c-ink);
  --feature-bg-2:    #221F19;
  --feature-text:    #B8B0A2;
  --feature-heading: var(--c-bone);
  --feature-accent:  var(--c-amber-lit);
  --feature-border:  rgba(250, 248, 244, .14);
  --feature-card:    rgba(250, 248, 244, .04);

  /* Shadow is almost absent by design. Editorial layouts get their depth from
     rules and whitespace; a drop shadow on everything is what makes a page look
     like a dashboard. */
  --shadow-sm: none;
  --shadow:    0 1px 2px rgba(20, 18, 14, .04);
  --shadow-lg: 0 24px 60px -30px rgba(20, 18, 14, .28);

  --grain-opacity: .030;
}

/* ==========================================================================
   DARK THEME — bone on night. Two guards so the visitor's own choice wins in
   BOTH directions: :not([data-theme="light"]) inside the media query, and
   [data-theme="dark"] outside it.
   ========================================================================== */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg:            var(--c-night);
    --bg-alt:        var(--c-night-2);
    --bg-sunken:     #0D0C0A;
    --surface:       var(--c-night-2);
    --surface-2:     #221F1A;
    --surface-glass: rgba(18, 17, 14, .82);
    --text:          var(--c-bone-dim);
    --text-muted:    var(--c-grey-lit);
    --heading:       var(--c-bone-lit);
    --border:        var(--c-line-dark);
    --border-strong: var(--c-line-dark2);
    --border-input:  #6E665A;
    --accent:        var(--c-blue-pale);
    --accent-hover:  #C6DAEE;
    --accent-soft:   #1B2530;
    --accent-ring:   rgba(168, 196, 222, .22);
    --btn-bg:        var(--c-bone-lit);
    --btn-fg:        var(--c-night);
    --btn-bg-hover:  var(--c-blue-pale);
    --ok:            var(--c-green-lit);
    --ok-text:       var(--c-green-lit);
    --star:          var(--c-amber-lit);
    --feature-bg:      #0B0A08;
    --feature-bg-2:    #171511;
    --feature-text:    #ADA496;
    --feature-heading: var(--c-bone-lit);
    --feature-accent:  var(--c-amber-lit);
    --feature-border:  rgba(250, 248, 244, .10);
    --feature-card:    rgba(250, 248, 244, .03);
    --shadow-sm: none;
    --shadow:    0 1px 2px rgba(0, 0, 0, .5);
    --shadow-lg: 0 24px 60px -30px rgba(0, 0, 0, .8);
    --grain-opacity: .045;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bg:            var(--c-night);
  --bg-alt:        var(--c-night-2);
  --bg-sunken:     #0D0C0A;
  --surface:       var(--c-night-2);
  --surface-2:     #221F1A;
  --surface-glass: rgba(18, 17, 14, .82);
  --text:          var(--c-bone-dim);
  --text-muted:    var(--c-grey-lit);
  --heading:       var(--c-bone-lit);
  --border:        var(--c-line-dark);
  --border-strong: var(--c-line-dark2);
  --border-input:  #6E665A;
  --accent:        var(--c-blue-pale);
  --accent-hover:  #C6DAEE;
  --accent-soft:   #1B2530;
  --accent-ring:   rgba(168, 196, 222, .22);
  --btn-bg:        var(--c-bone-lit);
  --btn-fg:        var(--c-night);
  --btn-bg-hover:  var(--c-blue-pale);
  --ok:            var(--c-green-lit);
  --ok-text:       var(--c-green-lit);
  --star:          var(--c-amber-lit);
  --feature-bg:      #0B0A08;
  --feature-bg-2:    #171511;
  --feature-text:    #ADA496;
  --feature-heading: var(--c-bone-lit);
  --feature-accent:  var(--c-amber-lit);
  --feature-border:  rgba(250, 248, 244, .10);
  --feature-card:    rgba(250, 248, 244, .03);
  --shadow-sm: none;
  --shadow:    0 1px 2px rgba(0, 0, 0, .5);
  --shadow-lg: 0 24px 60px -30px rgba(0, 0, 0, .8);
  --grain-opacity: .045;
}

/* Legacy aliases. Older markup, the blog templates and /admin still name the
   old brand colours; these keep those references alive AND theme-correct
   instead of leaving a stale hex behind. Prefer the semantic tokens. */
:root {
  --navy:  var(--heading);
  --blue:  var(--accent);
  --ink:   var(--text);
  --muted: var(--text-muted);
  --white: var(--surface);
  --off:   var(--surface-2);
  --font-head: var(--font-display);
}

/* ==========================================================================
   Reset + base
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal]:not(.is-visible) { opacity: 1 !important; transform: none !important; filter: none !important; }
}

body {
  font-family: var(--font-body);
  color: var(--text);
  background: var(--bg);
  line-height: 1.7;
  font-size: 18px;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background-color var(--t-base) var(--ease-out), color var(--t-base) var(--ease-out);
  overflow-x: hidden;
}

/* A single layer of fine grain over the whole page. It is what stops a flat
   bone background reading as "unstyled white" — paper has tooth. Generated
   rather than fetched (an SVG feTurbulence as a data URI), so it costs no
   request, and it is pointer-events:none so it can never intercept a click. */
body::before {
  content: "";
  position: fixed; inset: 0; z-index: 1;
  pointer-events: none;
  opacity: var(--grain-opacity);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
}

img, video { display: block; max-width: 100%; height: auto; }
svg { display: block; max-width: 100%; }
button, input, textarea, select { font: inherit; color: inherit; }

/* --- Type -------------------------------------------------------------
   The display serif carries h1 and h2 only. h3 and below go back to Inter:
   Instrument Serif is a high-contrast face whose hairlines disappear under
   about 24px, so using it for a 19px sub-heading would be choosing prettiness
   over legibility at exactly the size where legibility matters. */
h1, h2 {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--heading);
  line-height: 1.02;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
h1 { font-size: clamp(2.6rem, 1.5rem + 4.2vw, 4.8rem); }
h2 { font-size: clamp(1.9rem, 1.35rem + 2.2vw, 3.1rem); }

h3, h4 {
  font-family: var(--font-body);
  font-weight: 600;
  color: var(--heading);
  line-height: 1.3;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
h3 { font-size: clamp(1.1rem, 1rem + .4vw, 1.28rem); }
h4 { font-size: 1.02rem; }

p { text-wrap: pretty; }
em, i { font-style: italic; }

/* Links in prose: ink with a fine rule under it, going accent on hover. A blue
   link in a paragraph is the other great template tell — printed matter marks
   links by weight and rule, not by hue. */
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: none; }
p a, .post-body a, li a.inline {
  color: var(--heading);
  border-bottom: 1px solid var(--border-strong);
  padding-bottom: .04em;
  transition: color var(--t-quick) var(--ease-out), border-color var(--t-quick) var(--ease-out);
}
p a:hover, .post-body a:hover, li a.inline:hover {
  color: var(--accent); border-bottom-color: var(--accent);
}

::selection { background: var(--heading); color: var(--bg); }

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

/* ==========================================================================
   MOTION
   Three tiers, three mechanisms — see /styleguide.html for the reasoning.
   Editorial motion is slower and softer than UI motion: entrances resolve out
   of a slight blur rather than sliding, which reads as focus pulling in rather
   than as an element being moved into place.
   ========================================================================== */
@keyframes sx-rise {
  from { opacity: 0; transform: translateY(26px); filter: blur(7px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes sx-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes sx-wipe {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}
@keyframes sx-drift {
  0%, 100% { transform: translate3d(0,0,0) scale(1); }
  50%      { transform: translate3d(-2%, 2%, 0) scale(1.04); }
}
@keyframes sx-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
/* Transform-only counterpart to sx-fade. Used on LCP elements — Chrome scores
   LCP at the end of an opacity animation, but a transform-only entrance keeps
   the element painted throughout, so LCP fires when the pixels actually land. */
@keyframes sx-settle {
  from { transform: translateY(10px); }
  to   { transform: none; }
}

.anim-in     { animation: sx-rise 1.15s var(--ease-out) both;  animation-delay: var(--d, 0ms); }
.anim-fade   { animation: sx-fade 1.2s var(--ease-out) both;   animation-delay: var(--d, 0ms); }
.anim-wipe   { animation: sx-wipe 1.1s var(--ease-out) both;   animation-delay: var(--d, 0ms); }
.anim-settle { animation: sx-settle 1.1s var(--ease-out) both; animation-delay: var(--d, 0ms); }

/* --- Scroll reveal ---
   [data-reveal] is added by main.js at RUNTIME and never ships in the HTML. The
   hidden state must not exist until JS has committed to undoing it, or a
   visitor with no JS gets a page of invisible content. This is load-bearing.

   NOTE FOR SCANS: an unrevealed block computes as opacity:0 and axe scores
   transparent text as a contrast failure. Those findings are phantoms — diff
   violation TARGETS against a baseline, never raw counts. */
[data-reveal] {
  transition: opacity var(--t-slow) var(--ease-out),
              transform var(--t-slow) var(--ease-out),
              filter var(--t-slow) var(--ease-out);
}
[data-reveal]:not(.is-visible) { opacity: 0; transform: translateY(22px); filter: blur(5px); }

/* Images settle out of a gentle over-scale as they arrive. */
[data-zoom] { overflow: hidden; }
[data-zoom] img { transition: transform 1.6s var(--ease-out); }
[data-zoom]:not(.is-visible) img { transform: scale(1.07); }

.scroll-progress {
  position: fixed; inset: 0 0 auto 0; height: 2px; z-index: 200;
  background: var(--accent);
  transform: scaleX(0); transform-origin: 0 50%;
  will-change: transform; pointer-events: none;
}

/* ==========================================================================
   Layout
   ========================================================================== */
.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gut); position: relative; z-index: 2; }
.section { padding-block: clamp(72px, 9vw, 152px); }
.section--tint { background: var(--bg-alt); }
.section--navy { background: var(--feature-bg); color: var(--feature-text); position: relative; }
.section--navy h1, .section--navy h2, .section--navy h3, .section--navy h4 { color: var(--feature-heading); }

.center { text-align: center; }
.narrow { max-width: 800px; margin-inline: auto; }

/* A hairline rule. Structure in this system comes from these and from space,
   not from boxing things in. */
.rule { border: 0; border-top: 1px solid var(--border); margin: 0; }
.section--navy .rule { border-top-color: var(--feature-border); }

/* --- Eyebrow ---
   Small caps, widely letterspaced, muted. Optionally prefixed with a numeral
   via data-num, which is what gives the page its "01 / 02 / 03" spine. */
.eyebrow {
  display: flex; align-items: center; gap: 12px;
  font-family: var(--font-body);
  font-size: .72rem; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 22px;
}
.eyebrow::after { content: ""; flex: 1; height: 1px; background: var(--border); max-width: 90px; }
.center .eyebrow, .head.center .eyebrow { justify-content: center; }
.center .eyebrow::after, .head.center .eyebrow::after { display: none; }
.eyebrow[data-num]::before {
  content: attr(data-num);
  font-variant-numeric: tabular-nums;
  color: var(--accent);
  letter-spacing: .1em;
}
.section--navy .eyebrow { color: var(--feature-text); }
.section--navy .eyebrow::after { background: var(--feature-border); }
.section--navy .eyebrow[data-num]::before { color: var(--feature-accent); }

.lede {
  font-size: clamp(1.08rem, 1rem + .4vw, 1.32rem);
  color: var(--text-muted);
  line-height: 1.62;
  max-width: 62ch;
}
.center .lede, .center.lede, .narrow .lede, .narrow.lede { margin-inline: auto; }
.section--navy .lede { color: var(--feature-text); }

/* Section heading block */
.head { max-width: 860px; margin-bottom: clamp(44px, 5vw, 76px); }
.head.center { margin-inline: auto; }
.head h2 { margin-bottom: 22px; }

.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--heading); color: var(--bg); padding: 12px 18px; z-index: 999;
}
.skip-link:focus { left: 0; }

/* ==========================================================================
   Buttons — ink on bone, near-square, no gradient. The arrow moves, nothing else.
   ========================================================================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .6em;
  padding: 15px 30px;
  border-radius: var(--r-lg);
  font-family: var(--font-body);
  font-weight: 500; font-size: .95rem; letter-spacing: .01em;
  border: 1px solid transparent;
  cursor: pointer; position: relative;
  transition: background-color var(--t-base) var(--ease-out),
              color var(--t-base) var(--ease-out),
              border-color var(--t-base) var(--ease-out),
              transform var(--t-quick) var(--ease-out);
  text-decoration: none !important;
  white-space: nowrap;
}
.btn svg { transition: transform var(--t-base) var(--ease-out); }
.btn:hover svg { transform: translateX(4px); }

.btn--primary { background: var(--btn-bg); color: var(--btn-fg); }
.btn--primary:hover { background: var(--btn-bg-hover); }

.btn--ghost { background: transparent; color: var(--heading); border-color: var(--border-strong); }
.btn--ghost:hover { border-color: var(--heading); background: var(--heading); color: var(--bg); }

.btn--light { background: transparent; color: var(--feature-heading); border-color: var(--feature-border); }
.btn--light:hover { background: var(--feature-heading); color: var(--feature-bg); }

.btn--lg { padding: 18px 36px; font-size: 1rem; }
.btn--block { width: 100%; }

/* .btn is white-space: nowrap on purpose — it keeps short labels on one line and
   stops the trailing arrow dropping under its own label. The cost is that a LONG
   label on a .btn--lg can neither wrap nor shrink, and 36px of padding each side
   puts it over the edge: "See everything that's included" measured 312px inside
   a 268px column at 320px wide, which scrolled the whole document sideways.
   Below 380px, let only the large buttons wrap and tighten their padding. Every
   width above this is untouched, and .btn keeps nowrap everywhere. */
@media (max-width: 380px) {
  .btn--lg { padding: 16px 22px; white-space: normal; }
}

/* A text link that behaves like a button target: label, hairline, moving arrow. */
.link-arrow {
  display: inline-flex; align-items: center; gap: .5em;
  font-weight: 500; font-size: .95rem; color: var(--heading);
  border-bottom: 1px solid var(--border-strong); padding-bottom: 4px;
  transition: color var(--t-quick) var(--ease-out), border-color var(--t-quick) var(--ease-out);
}
.link-arrow svg { transition: transform var(--t-base) var(--ease-out); }
.link-arrow:hover { color: var(--accent); border-bottom-color: var(--accent); text-decoration: none; }
.link-arrow:hover svg { transform: translateX(4px); }

/* ==========================================================================
   Header — five items, a wordmark that doubles as Home, and one disclosure menu
   ========================================================================== */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: var(--surface-glass);
  backdrop-filter: saturate(140%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--t-base) var(--ease-out), background-color var(--t-base) var(--ease-out);
}
/* No border until the page has scrolled: over the hero the header should feel
   like part of the page, not a bar bolted to the top of it. */
.site-header.is-stuck { border-bottom-color: var(--border); }

.nav { display: flex; align-items: center; justify-content: space-between; gap: 24px; height: 86px; }

.brand {
  display: inline-flex; align-items: baseline; gap: 11px;
  font-family: var(--font-display); font-weight: 400; font-size: 1.55rem;
  color: var(--heading); letter-spacing: -.01em; line-height: 1;
}
.brand:hover { text-decoration: none; }
.brand__mark { width: 27px; height: 27px; flex: none; display: grid; place-items: center; overflow: hidden; align-self: center; }
.brand__mark img { width: 25px; height: auto; }
.site-footer .brand__mark img { filter: invert(1); }
:root[data-theme="dark"] .site-header .brand__mark img { filter: invert(1); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .site-header .brand__mark img { filter: invert(1); }
}
/* The footer sits on ink in BOTH themes, so its mark always needs inverting —
   except in dark theme, where the artwork is already being inverted globally. */
:root[data-theme="dark"] .site-footer .brand__mark img { filter: invert(1); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .site-footer .brand__mark img { filter: invert(1); }
}

.nav__links { display: flex; align-items: center; gap: 38px; list-style: none; padding: 0; margin: 0; }
.nav__item { position: relative; }

.nav__link {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 0; padding: 8px 0; cursor: pointer;
  font-family: var(--font-body); font-size: .92rem; font-weight: 500; letter-spacing: .01em;
  color: var(--text); position: relative;
}
.nav__link:hover { color: var(--heading); text-decoration: none; }
.nav__link::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--heading); transform: scaleX(0); transform-origin: 0 50%;
  transition: transform var(--t-base) var(--ease-out);
}
.nav__link:hover::after { transform: scaleX(1); }
.nav__link[aria-current="page"] { color: var(--heading); }
.nav__link[aria-current="page"]::after { transform: scaleX(1); }
.nav__link .chev { transition: transform var(--t-base) var(--ease-out); }
.nav__link[aria-expanded="true"] .chev { transform: rotate(180deg); }

/* --- Disclosure submenu -------------------------------------------------
   A <button> with aria-expanded, not a hover-only <div>. Hover alone is
   unusable on touch and invisible to a keyboard, so the button is the real
   control and hover is layered on top of it for pointer users only. */
.nav__menu {
  position: absolute; top: calc(100% + 10px); left: -20px;
  min-width: 260px; padding: 10px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg);
  list-style: none; margin: 0;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity var(--t-base) var(--ease-out),
              transform var(--t-base) var(--ease-out),
              visibility 0s linear var(--t-base);
}
.nav__item.is-open .nav__menu {
  opacity: 1; visibility: visible; transform: none;
  transition: opacity var(--t-base) var(--ease-out), transform var(--t-base) var(--ease-out), visibility 0s;
}
.nav__menu a {
  display: block; padding: 11px 14px; border-radius: var(--r);
  font-size: .92rem; color: var(--text); line-height: 1.4;
  transition: background-color var(--t-quick) var(--ease-out), color var(--t-quick) var(--ease-out);
}
.nav__menu a:hover { background: var(--bg-alt); color: var(--heading); text-decoration: none; }
.nav__menu a small { display: block; font-size: .78rem; color: var(--text-muted); margin-top: 2px; }
@media (hover: hover) and (pointer: fine) {
  .nav__item--has-menu:hover .nav__menu {
    opacity: 1; visibility: visible; transform: none;
    transition: opacity var(--t-base) var(--ease-out), transform var(--t-base) var(--ease-out), visibility 0s;
  }
}

.nav__cta { display: flex; align-items: center; gap: 14px; }

.theme-toggle {
  position: relative; width: 38px; height: 38px; flex: none;
  display: grid; place-items: center;
  background: none; color: var(--text);
  border: 1px solid var(--border); border-radius: 999px; cursor: pointer;
  transition: border-color var(--t-base) var(--ease-out), color var(--t-base) var(--ease-out);
}
.theme-toggle:hover { border-color: var(--heading); color: var(--heading); }
.theme-toggle svg {
  grid-area: 1 / 1; width: 17px; height: 17px;
  transition: opacity var(--t-base) var(--ease-out), transform .5s var(--ease-spring);
}
.theme-toggle .icon-sun  { opacity: 0; transform: rotate(-90deg) scale(.4); }
.theme-toggle .icon-moon { opacity: 1; transform: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun  { opacity: 1; transform: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { opacity: 0; transform: rotate(90deg) scale(.4); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-sun  { opacity: 1; transform: none; }
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { opacity: 0; transform: rotate(90deg) scale(.4); }
}

.nav__toggle {
  display: none; background: none; border: 1px solid var(--border); border-radius: 999px;
  width: 38px; height: 38px; cursor: pointer; place-items: center; color: var(--heading);
}

@media (max-width: 1000px) {
  /* Without this the hamburger stays display:none at every width and the
     mobile menu cannot be opened at all. It was missing for exactly one
     commit, and no overflow or contrast check would ever have caught it —
     the page looked correct and simply had no working navigation. */
  .nav__toggle { display: grid; }
  .nav__links {
    position: fixed; inset: 86px 0 auto 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--bg); border-bottom: 1px solid var(--border);
    padding: 12px var(--gut) 26px;
    max-height: calc(100dvh - 86px); overflow-y: auto;
    display: none;
  }
  .nav__links.is-open { display: flex; animation: sx-fade .3s var(--ease-out) both; }
  .nav__item { border-bottom: 1px solid var(--border); }
  .nav__link { width: 100%; justify-content: space-between; padding: 18px 2px; font-size: 1.12rem; }
  .nav__link::after { display: none; }
  /* On mobile the submenu is a nested list that pushes content down rather than
     an overlay — a floating panel inside a scrolling drawer is a trap. */
  .nav__menu {
    position: static; opacity: 1; visibility: visible; transform: none;
    min-width: 0; border: 0; box-shadow: none; background: none;
    padding: 0 0 14px 2px; display: none;
  }
  .nav__item.is-open .nav__menu { display: block; }
  .nav__menu a { padding: 10px 0; font-size: 1rem; }
  .nav__cta .btn { display: none; }
}

/* ==========================================================================
   Hero — asymmetric, headline-led, with a real site as the image
   ========================================================================== */
.hero {
  position: relative;
  padding-block: clamp(56px, 8vw, 116px) clamp(56px, 7vw, 104px);
  overflow: hidden;
}
.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, .98fr);
  gap: clamp(40px, 5vw, 76px);
  align-items: center;
}
@media (max-width: 1000px) { .hero__grid { grid-template-columns: 1fr; gap: 48px; } }

.hero h1 { margin-bottom: 30px; }
/* The one place a second colour is allowed in a headline, and it is the deep
   accent set in italic — not a gradient. A gradient in display type is the
   fastest way to make an expensive layout look like a landing-page template. */
.hero h1 .hl { font-style: italic; color: var(--accent); }
.hero__sub { font-size: clamp(1.08rem, 1rem + .45vw, 1.3rem); color: var(--text-muted); max-width: 52ch; margin-bottom: 38px; line-height: 1.6; }
.hero__actions { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 40px; }

.trustline {
  display: flex; flex-wrap: wrap; gap: 10px 28px; list-style: none; padding: 0; margin: 0;
  font-size: .87rem; color: var(--text-muted);
}
.trustline li { display: flex; align-items: center; gap: 9px; }
.trustline svg { color: var(--accent); flex: none; }

/* --- The hero figure: a real portfolio site, not a wireframe --------------
   A drawn "browser mock" filled with grey bars announces that there was nothing
   real to show. A tall screenshot of an actual finished site is the single
   strongest thing this page can put next to the headline. */
/* Capped, and right-aligned inside its column. Uncapped this reached 859x1031
   CSS px on a 1920 screen -- 95% of the viewport height, and 1.6x more image
   than the largest source could fill, which is what read as "huge and blurry".
   A hero image should sit beside the headline, not replace the screen. */
.hero__figure { position: relative; margin: 0 0 0 auto; width: 100%; max-width: min(520px, 50vh); }
.hero__shot {
  position: relative; overflow: hidden;
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  background: var(--surface-2);
  aspect-ratio: 4 / 5;
}
.hero__shot img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 0;
  transition: transform 2.4s var(--ease-out);
}
.hero__figure:hover .hero__shot img { transform: scale(1.03); }
.hero__caption {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin-top: 18px; font-size: .8rem; color: var(--text-muted);
  letter-spacing: .04em;
}
.hero__caption strong { color: var(--heading); font-weight: 600; letter-spacing: 0; }
.hero__caption .dot { width: 3px; height: 3px; border-radius: 50%; background: var(--border-strong); }

/* No edge bleed. It was inflating the figure past the viewport height on any
   wide screen, and a negative margin that grows with the viewport has no upper
   bound -- the wider the display, the more wrong it got. */
@media (max-width: 1000px) {
  .hero__figure { margin-inline: auto; max-width: min(460px, calc(100vw - 52px)); }
}

/* ==========================================================================
   Grids — wide gutters, and column rules instead of card borders
   ========================================================================== */
.grid { display: grid; gap: clamp(32px, 3.4vw, 56px); }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 980px) { .grid--3, .grid--4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .grid--2, .grid--3, .grid--4 { grid-template-columns: 1fr; } }

/* --- Card ---------------------------------------------------------------
   Not a box any more. A rule across the top, generous space beneath it, and the
   rule goes to ink on hover. Boxes stack visual weight; rules organise it. */
.card {
  background: none; border: 0; border-radius: 0; box-shadow: none;
  padding: 26px 0 0;
  border-top: 1px solid var(--border);
  position: relative;
  transition: border-color var(--t-base) var(--ease-out);
}
.card::before {
  content: ""; position: absolute; top: -1px; left: 0; right: 0; height: 1px;
  background: var(--heading); transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .55s var(--ease-out);
}
.card--hover:hover::before { transform: scaleX(1); }
.card h3 { margin-bottom: 12px; }
.card p { color: var(--text-muted); font-size: .98rem; }
.section--navy .card { border-top-color: var(--feature-border); }
.section--navy .card p { color: var(--feature-text); }
.section--navy .card::before { background: var(--feature-heading); }

/* Icons lose their filled chip and become line art in the accent. */
.icon {
  width: auto; height: 26px; border-radius: 0; margin-bottom: 20px;
  display: flex; align-items: center; justify-content: flex-start;
  background: none; color: var(--accent);
}
.section--navy .icon { background: none; color: var(--feature-accent); }
.icon svg { width: 24px; height: 24px; }

/* ==========================================================================
   Media row
   DOM order is visual order — this is a plain two-column grid, so putting the
   <figure> before or after the text block is the ONLY thing choosing a side.
   Consecutive rows must alternate; inserting one at the top means every row
   below it swaps.
   ========================================================================== */
.media-row { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(36px, 4.5vw, 76px); align-items: center; }
.media-row figure { margin: 0; border-radius: var(--r-lg); overflow: hidden; border: 1px solid var(--border); box-shadow: none; }
.media-row img { display: block; width: 100%; height: auto; }
@media (max-width: 820px) { .media-row { grid-template-columns: 1fr; } }

.trust-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 0; }
.trust-list li { display: flex; align-items: flex-start; gap: 18px; padding: 22px 0; border-top: 1px solid var(--border); }
.trust-list li:last-child { border-bottom: 1px solid var(--border); }
.trust-list .icon { margin-bottom: 0; flex: none; height: auto; }
.trust-list strong { display: block; font-size: 1rem; color: var(--heading); font-weight: 600; }
.trust-list span { color: var(--text-muted); font-size: .93rem; }
.section--navy .trust-list li { border-top-color: var(--feature-border); }
.section--navy .trust-list li:last-child { border-bottom-color: var(--feature-border); }
.section--navy .trust-list strong { color: var(--feature-heading); }
.section--navy .trust-list span { color: var(--feature-text); }

/* ==========================================================================
   Steps — big serif numerals on a hairline spine
   ========================================================================== */
.steps { counter-reset: step; display: grid; gap: 0; grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .steps { grid-template-columns: 1fr; } }
.step { position: relative; padding: 30px 26px 0 0; border-top: 1px solid var(--border); }
.step::before {
  counter-increment: step; content: "0" counter(step);
  display: block; margin-bottom: 18px;
  font-family: var(--font-display); font-size: 2.4rem; line-height: 1;
  color: var(--accent); font-variant-numeric: tabular-nums;
}
.step h3 { margin-bottom: 10px; }
.step p { color: var(--text-muted); font-size: .95rem; }
.section--navy .step { border-top-color: var(--feature-border); }
.section--navy .step::before { background: none; color: var(--feature-accent); }
.section--navy .step p { color: var(--feature-text); }

/* ==========================================================================
   Stats — the numbers are the design
   ========================================================================== */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; }
@media (max-width: 860px) { .stats { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 420px) { .stats { grid-template-columns: 1fr; } }
.stat { text-align: left; padding: 30px 24px 30px 0; border-top: 1px solid var(--border); background: none; border-radius: 0; box-shadow: none; }
.stat__num {
  display: block; font-family: var(--font-display); font-weight: 400;
  font-size: clamp(2.6rem, 1.8rem + 2.6vw, 4rem); line-height: 1;
  color: var(--heading); letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}
.stat__num .unit { font-size: .42em; color: var(--text-muted); margin-left: .18em; letter-spacing: .04em; }
.stat__label { display: block; margin-top: 16px; font-size: .86rem; color: var(--text-muted); line-height: 1.5; max-width: 24ch; }
/* The plain-English line under each figure. A stat block on a page aimed at
   business owners has to say what the number MEANS for them; the label above it
   only names what was measured. Wider measure than the label (30ch) because it
   is a sentence, not a caption. */
.stat__plain { display: block; margin-top: 12px; font-size: .82rem; color: var(--text); line-height: 1.55; max-width: 30ch; }
/* Third-party context and its citation. Muted, because it is supporting
   evidence rather than the claim. */
.stat__source { display: block; margin-top: 12px; font-size: .78rem; color: var(--text-muted); line-height: 1.5; max-width: 30ch; }
/* Same underline treatment `p a` gets, for the same reason (WCAG 1.4.1): these
   links sit inside a block of text and colour alone must not identify them. */
.stat__plain a, .stat__source a {
  color: var(--heading);
  border-bottom: 1px solid var(--border-strong);
  padding-bottom: .04em;
  transition: color var(--t-quick) var(--ease-out), border-color var(--t-quick) var(--ease-out);
}
.stat__plain a:hover, .stat__source a:hover { color: var(--accent); border-bottom-color: var(--accent); }
.section--navy .stat__plain { color: var(--feature-text); }
.section--navy .stat__source { color: var(--feature-text); }
/* The test-conditions footnote is a long paragraph, not the one-line aside
   .arealist__note was written for — give it a readable measure. */
.stats__note { max-width: 92ch; margin-inline: auto; text-align: left; font-size: .84rem; line-height: 1.6; }
.section--navy .stat { border-top-color: var(--feature-border); }
.section--navy .stat__num { color: var(--feature-heading); }
.section--navy .stat__num .unit, .section--navy .stat__label { color: var(--feature-text); }

/* ==========================================================================
   Testimonial — a pull quote, not a card
   ========================================================================== */
.testimonial { padding: clamp(56px, 7vw, 104px) 0 0; }
.testimonial__card { max-width: 940px; margin-inline: auto; text-align: center; background: none; border: 0; border-radius: 0; padding: 0; box-shadow: none; }
.testimonial__stars { display: flex; justify-content: center; gap: 5px; color: var(--star); margin-bottom: 30px; }
.testimonial__stars svg { width: 15px; height: 15px; flex: none; }
.testimonial__quote {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(1.6rem, 1.1rem + 2vw, 2.7rem); line-height: 1.24;
  color: var(--heading); margin: 0; letter-spacing: -.015em;
}
.testimonial__cite { display: block; margin-top: 30px; font-style: normal; font-family: var(--font-body); font-size: .84rem; font-weight: 500; letter-spacing: .12em; text-transform: uppercase; color: var(--text-muted); }
.testimonial__org { color: var(--heading); }

/* ==========================================================================
   Comparison table — hairlines only
   ========================================================================== */
.table-scroll { overflow-x: auto; border: 0; border-radius: 0; background: none; box-shadow: none; }
.table-scroll:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
table.cmp { width: 100%; border-collapse: collapse; min-width: 620px; }
table.cmp th, table.cmp td { padding: 20px 22px 20px 0; text-align: left; border-bottom: 1px solid var(--border); font-size: .95rem; }
table.cmp thead th {
  background: none; color: var(--text-muted); font-family: var(--font-body);
  font-size: .72rem; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  border-bottom-color: var(--border-strong); padding-bottom: 16px;
}
table.cmp thead th:first-child, table.cmp thead th:last-child { border-radius: 0; }
table.cmp td:first-child { font-weight: 500; color: var(--heading); }
table.cmp .yes { color: var(--ok-text); font-weight: 500; }
table.cmp .no  { color: var(--text-muted); }
.section--navy table.cmp th, .section--navy table.cmp td { border-bottom-color: var(--feature-border); }

/* ==========================================================================
   Pricing — the amount set in the display serif, columns split by rules
   ========================================================================== */
.price-grid { display: grid; gap: 0; grid-template-columns: repeat(3, 1fr); align-items: stretch; }
@media (max-width: 980px) { .price-grid { grid-template-columns: 1fr; max-width: 560px; margin-inline: auto; } }
.price {
  position: relative; display: flex; flex-direction: column; height: 100%;
  background: none; border: 0; border-top: 1px solid var(--border); border-radius: 0; box-shadow: none;
  padding: 34px 32px 34px 0;
}
@media (min-width: 981px) { .price + .price { border-left: 1px solid var(--border); padding-left: 32px; } }
.price--featured { border-top-color: var(--heading); border-top-width: 2px; }
.price__tag {
  position: static; transform: none; display: inline-block; margin-bottom: 14px;
  background: none; color: var(--accent); font-family: var(--font-body);
  font-size: .7rem; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  padding: 0; border-radius: 0;
}
.price__name { font-family: var(--font-body); font-weight: 600; color: var(--heading); font-size: 1.02rem; margin-bottom: 14px; }
.price__amt { font-family: var(--font-display); font-size: clamp(2.6rem, 2rem + 2vw, 3.6rem); font-weight: 400; color: var(--heading); letter-spacing: -.02em; line-height: 1; }
.price__amt small { font-family: var(--font-body); font-size: .9rem; font-weight: 400; color: var(--text-muted); letter-spacing: 0; }
.price__note { color: var(--text-muted); font-size: .88rem; margin-top: 10px; }
.price hr { border: 0; border-top: 1px solid var(--border); margin: 26px 0; }

.ticks { list-style: none; padding: 0; display: grid; gap: 14px; margin-bottom: 32px; }
.ticks li { display: flex; gap: 12px; align-items: flex-start; font-size: .94rem; color: var(--text); }
.ticks svg { flex: none; margin-top: 5px; color: var(--accent); }
.price .btn { margin-top: auto; }

/* ==========================================================================
   FAQ — hairline rows
   ========================================================================== */
.faq { display: grid; gap: 0; max-width: 900px; margin-inline: auto; }
.faq details { background: none; border: 0; border-top: 1px solid var(--border); border-radius: 0; padding: 0; box-shadow: none; }
.faq details:last-of-type { border-bottom: 1px solid var(--border); }
.faq summary {
  cursor: pointer; list-style: none; padding: 26px 44px 26px 0; position: relative;
  font-family: var(--font-body); font-weight: 500; color: var(--heading); font-size: 1.05rem; line-height: 1.45;
  transition: color var(--t-quick) var(--ease-out);
}
.faq summary:hover { color: var(--accent); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after, .faq summary::before {
  content: ""; position: absolute; right: 4px; top: 50%;
  width: 13px; height: 1px; background: var(--heading);
  transition: transform var(--t-base) var(--ease-out);
}
.faq summary::before { transform: translateY(-50%); }
.faq summary::after  { transform: translateY(-50%) rotate(90deg); }
.faq details[open] summary::after { transform: translateY(-50%) rotate(0deg); }
.faq details > p { padding: 0 60px 30px 0; color: var(--text-muted); font-size: .99rem; max-width: 70ch; }
.faq details[open] > p { animation: sx-fade .5s var(--ease-out) both; }

/* ==========================================================================
   CTA band — a full ink field, not a rounded box
   ========================================================================== */
.cta-band {
  background: var(--feature-bg); color: var(--feature-heading);
  border-radius: var(--r-lg); padding: clamp(56px, 7vw, 104px) clamp(28px, 5vw, 76px);
  text-align: center; box-shadow: none; position: relative; overflow: hidden;
}
.cta-band::before {
  content: ""; position: absolute; inset: -30%;
  background: radial-gradient(closest-side, rgba(250,248,244,.055), transparent);
  animation: sx-drift 26s var(--ease-in-out) infinite;
  pointer-events: none;
}
.cta-band > * { position: relative; }
.cta-band h2 { color: var(--feature-heading); margin-bottom: 22px; }
.cta-band p { color: var(--feature-text); max-width: 54ch; margin: 0 auto 38px; font-size: 1.08rem; }
.cta-band .btn-row { display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; }
.cta-band .btn--primary { background: var(--feature-heading); color: var(--feature-bg); }
.cta-band .btn--primary:hover { background: var(--feature-accent); color: var(--feature-bg); }

/* ==========================================================================
   Forms
   ========================================================================== */
.form { display: grid; gap: 26px; }
.field { display: grid; gap: 9px; }
.field label { font-weight: 500; font-size: .8rem; letter-spacing: .12em; text-transform: uppercase; color: var(--text-muted); }
.field input, .field textarea, .field select {
  width: 100%; padding: 14px 0; background: none; color: var(--text); font-size: 1.02rem;
  border: 0; border-bottom: 1px solid var(--border-input); border-radius: 0;
  transition: border-color var(--t-quick) var(--ease-out);
}
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-bottom-color: var(--heading); box-shadow: none;
}
.field select { padding-block: 13px; }
.field textarea { min-height: 130px; resize: vertical; }
.field .hint { font-size: .82rem; color: var(--text-muted); }
.hp { position: absolute; left: -9999px; }

.form-status { border-radius: var(--r); padding: 20px 22px; font-size: .97rem; line-height: 1.6; border: 1px solid; }
.form-status--ok  { background: rgba(14,122,85,.07); border-color: rgba(14,122,85,.3); color: var(--ok-text); }
.form-status--err { background: rgba(154,42,42,.07); border-color: rgba(154,42,42,.32); color: #9A2A2A; }
:root[data-theme="dark"] .form-status--err { color: #F0A0A0; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .form-status--err { color: #F0A0A0; }
}
.form-status a { color: inherit; text-decoration: underline; }

/* ==========================================================================
   Blog
   ========================================================================== */
.post-list { display: grid; gap: 0; }
.post-card {
  display: block; background: none; border: 0; border-top: 1px solid var(--border);
  border-radius: 0; padding: 38px 0; box-shadow: none;
  transition: none;
}
.post-list .post-card:last-child { border-bottom: 1px solid var(--border); }
.post-card:hover { transform: none; box-shadow: none; text-decoration: none; }
.post-card h2 { font-size: clamp(1.6rem, 1.2rem + 1.4vw, 2.3rem); margin-bottom: 14px; transition: color var(--t-base) var(--ease-out); }
.post-card:hover h2 { color: var(--accent); }
.post-card p { color: var(--text-muted); font-size: 1rem; max-width: 70ch; }
.post-meta { display: flex; flex-wrap: wrap; gap: 8px 20px; font-size: .76rem; letter-spacing: .12em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 16px; }
.post-meta .by { font-weight: 600; color: var(--accent); }

.post-header { padding-block: clamp(56px, 6vw, 88px) 0; }
.post-body { max-width: 720px; margin-inline: auto; padding-block: 44px clamp(64px, 7vw, 96px); font-size: 1.09rem; }
.post-body > * + * { margin-top: 1.2em; }
.post-body h2 { font-size: clamp(1.8rem, 1.4rem + 1.4vw, 2.4rem); margin-top: 1.8em; }
.post-body h3 { font-size: 1.2rem; margin-top: 1.8em; }
.post-body ul, .post-body ol { padding-left: 1.3em; display: grid; gap: .55em; }
.post-body blockquote {
  border-left: 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
  background: none; padding: 26px 0; margin-block: 1.8em; border-radius: 0;
  color: var(--heading); font-family: var(--font-display); font-style: normal;
  font-size: 1.5rem; line-height: 1.35;
}
.post-body code { background: var(--bg-alt); border: 1px solid var(--border); padding: .12em .42em; border-radius: 2px; font-size: .88em; }
.post-body pre { background: var(--feature-bg); color: var(--feature-text); padding: 22px; border-radius: var(--r); overflow-x: auto; font-size: .88rem; }
.post-body pre code { background: none; border: 0; padding: 0; color: inherit; }
.post-body img { border-radius: var(--r); border: 1px solid var(--border); }
.post-body hr { border: 0; border-top: 1px solid var(--border); margin: 2.4em 0; }

.byline { display: flex; align-items: center; gap: 14px; margin-top: 24px; }
.byline__pic { width: 46px; height: 46px; flex: none; border-radius: 50%; object-fit: cover; border: 0; box-shadow: none; background: var(--bg-alt); }
.byline__text { display: flex; flex-direction: column; gap: 2px; }
.byline .by { font-weight: 600; color: var(--heading); font-size: .9rem; letter-spacing: 0; text-transform: none; }
.byline .post-meta { margin-bottom: 0; }

.back-link { display: inline-flex; align-items: center; gap: 8px; font-weight: 500; font-size: .82rem; letter-spacing: .1em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 26px; }
.back-link:hover { color: var(--heading); text-decoration: none; }
.back-link svg { transition: transform var(--t-base) var(--ease-out); }
.back-link:hover svg { transform: translateX(-4px); }

.empty-note { background: none; border: 1px solid var(--border); border-radius: var(--r); padding: 32px; color: var(--text-muted); text-align: center; }

/* About portrait */
.portrait { margin: 0 auto 26px; width: 150px; position: relative; }
.portrait img { width: 150px; height: 150px; border-radius: 50%; object-fit: cover; border: 0; box-shadow: none; background: var(--bg-alt); }

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer { background: var(--feature-bg); color: var(--feature-text); padding-block: clamp(64px, 7vw, 96px) 36px; }
.footer__grid { display: grid; grid-template-columns: 1.7fr 1fr 1fr; gap: 48px; margin-bottom: 56px; }
@media (max-width: 780px) { .footer__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px) { .footer__grid { grid-template-columns: 1fr; } }
.site-footer .brand { color: var(--feature-heading); margin-bottom: 20px; }
.site-footer p { font-size: .93rem; max-width: 42ch; color: var(--feature-text); }
.footer__title { font-family: var(--font-body); color: var(--feature-heading); font-weight: 600; font-size: .72rem; letter-spacing: .16em; text-transform: uppercase; margin-bottom: 20px; }
.footer__list { list-style: none; padding: 0; display: grid; gap: 13px; }
.footer__list a { color: var(--feature-text); font-size: .93rem; transition: color var(--t-quick) var(--ease-out); }
.footer__list a:hover { color: var(--feature-heading); text-decoration: none; }
.footer__bottom { border-top: 1px solid var(--feature-border); padding-top: 28px; display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; font-size: .82rem; }
/* Legal links live here, and only .footer__list a was ever styled — a bare link
   would fall through to the page accent, which is not a colour chosen against
   the ink footer. Reuse the exact pair the rest of the footer already passes on. */
.footer__bottom a { color: var(--feature-text); transition: color var(--t-quick) var(--ease-out); }
.footer__bottom a:hover { color: var(--feature-heading); }

/* ==========================================================================
   Service-area list — plain crawlable text, set as a typographic run
   ========================================================================== */
.arealist { list-style: none; padding: 0; margin: 0 auto; max-width: 940px; display: flex; flex-wrap: wrap; justify-content: center; gap: 0; }
.arealist li { font-size: 1rem; font-weight: 400; color: var(--text); padding: 6px 0; }
.arealist li::after { content: "·"; color: var(--border-strong); margin: 0 14px; }
.arealist li:last-child::after { display: none; }
.arealist__head { text-align: center; font-size: .74rem; font-weight: 600; letter-spacing: .16em;
  text-transform: uppercase; color: var(--text-muted); margin: 0 0 18px; }
.arealist + .arealist__head { margin-top: 44px; }
.arealist__note { margin-top: 34px; color: var(--text-muted); font-size: .95rem; }

/* ==========================================================================
   Sticky mobile CTA
   visibility, not just transform — sliding it off-screen leaves its links in the
   tab order while it is marked aria-hidden, which is exactly the
   aria-hidden-focus violation. Delayed by one duration so it still animates.
   ========================================================================== */
.mobile-cta {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: none; gap: 12px; padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
  background: var(--surface-glass); backdrop-filter: blur(14px);
  border-top: 1px solid var(--border);
  transform: translateY(115%); visibility: hidden;
  transition: transform var(--t-base) var(--ease-out), visibility 0s linear var(--t-base);
}
.mobile-cta .btn { flex: 1; padding-inline: 12px; }
.mobile-cta .btn--ghost { flex: 0 0 auto; }
.mobile-cta.is-up { transform: translateY(0); visibility: visible; transition: transform var(--t-base) var(--ease-out), visibility 0s; }
@media (max-width: 820px) { .mobile-cta { display: flex; } }

/* ==========================================================================
   Utility
   ========================================================================== */
.mt-0 { margin-top: 0; }
.mb-24 { margin-bottom: 26px; }
.mb-32 { margin-bottom: 40px; }
.stack-24 > * + * { margin-top: 26px; }
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ==========================================================================
   Marquee — one seamless loop. The track holds the same group twice and moves
   exactly -50%, so the second copy lands where the first began. Duplicating in
   markup keeps it working with no JS; the duplicate is aria-hidden so a screen
   reader is not read the list twice.
   ========================================================================== */
.marquee {
  overflow: hidden; position: relative; border-block: 1px solid var(--border); padding-block: 22px;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}
.marquee__track { display: flex; width: max-content; animation: sx-marquee 46s linear infinite; will-change: transform; }
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__group { display: flex; align-items: center; gap: 56px; padding-right: 56px; }
.marquee__item {
  display: inline-flex; align-items: center; gap: 12px;
  font-family: var(--font-display); font-size: 1.25rem; color: var(--text-muted); white-space: nowrap;
}
.marquee__item svg { color: var(--accent); flex: none; }

/* ==========================================================================
   Portfolio
   ========================================================================== */
.work-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(48px, 5vw, 88px) clamp(36px, 3.5vw, 56px); }
@media (max-width: 880px) { .work-grid { grid-template-columns: 1fr; } }

.work-card {
  display: flex; flex-direction: column;
  background: none; border: 0; border-radius: 0; overflow: visible; box-shadow: none;
  transition: none;
}
.work-card:hover { transform: none; box-shadow: none; }

.work-card__shot {
  position: relative; overflow: hidden; background: var(--bg-alt);
  aspect-ratio: 1400 / 729; border-radius: var(--r-lg); border: 1px solid var(--border);
}
.work-card__shot img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 0;
  transition: transform 1.8s var(--ease-out);
}
.work-card:hover .work-card__shot img { transform: scale(1.035); }

.work-card__body { padding: 26px 0 0; display: flex; flex-direction: column; flex: 1; }
.work-card__kind {
  display: flex; align-items: center; gap: 12px;
  font-size: .7rem; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 16px;
}
.work-card__body h3 { font-family: var(--font-display); font-weight: 400; font-size: clamp(1.5rem, 1.2rem + 1vw, 2rem); letter-spacing: -.015em; margin-bottom: 14px; }
.work-card__body p { color: var(--text-muted); font-size: .97rem; margin-bottom: 22px; max-width: 52ch; }
.work-card__links { margin-top: auto; display: flex; flex-wrap: wrap; gap: 10px 26px; }
.work-card__links a {
  display: inline-flex; align-items: center; gap: .5em;
  font-size: .92rem; font-weight: 500; color: var(--heading);
  border-bottom: 1px solid var(--border-strong); padding-bottom: 4px;
  transition: color var(--t-quick) var(--ease-out), border-color var(--t-quick) var(--ease-out);
}
.work-card__links a:hover { color: var(--accent); border-bottom-color: var(--accent); text-decoration: none; }
.work-card__links a svg { transition: transform var(--t-base) var(--ease-out); }
.work-card__links a:hover svg { transform: translateX(4px); }

/* Tag list: a typographic run separated by rules, not a row of pills. */
.tags { display: flex; flex-wrap: wrap; gap: 0 14px; margin-bottom: 24px; list-style: none; padding: 0; }
.tags li { font-size: .78rem; letter-spacing: .08em; text-transform: uppercase; color: var(--text-muted); }
.tags li::after { content: "/"; color: var(--border-strong); margin-left: 14px; }
.tags li:last-child::after { display: none; }

/* Live vs concept. The distinction is the point, so it is set as a label with a
   dot rather than hidden in a coloured pill. */
.badge-concept {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: .7rem; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  color: var(--text-muted); background: none; border: 0; padding: 0; margin: 0;
}
.badge-concept::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--border-strong); }
.badge-live { color: var(--ok-text); }
.badge-live::before { background: var(--ok); }

/* ==========================================================================
   STYLEGUIDE
   Every specimen renders with the SAME tokens and components as the rest of the
   site. Nothing here is a drawing of the design system — it is the system.
   ========================================================================== */
.sg-nav {
  position: sticky; top: 86px; z-index: 20;
  background: var(--surface-glass); backdrop-filter: saturate(140%) blur(14px);
  border-bottom: 1px solid var(--border);
}
/* The SCROLLER must be the element that directly wraps the overflowing list.
   Putting overflow-x on .sg-nav and leaving .wrap inside it let the <ul> spill
   out of .wrap (which does not clip) and widened the whole document. */
.sg-nav .wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.sg-nav ul { display: flex; gap: 30px; list-style: none; padding: 16px 0; margin: 0; white-space: nowrap; width: max-content; }
.sg-nav a { display: inline-block; font-size: .78rem; font-weight: 500; letter-spacing: .12em; text-transform: uppercase; color: var(--text-muted); }
.sg-nav a:hover { color: var(--heading); text-decoration: none; }

.sg-block { padding-block: clamp(60px, 7vw, 110px); border-bottom: 1px solid var(--border); scroll-margin-top: 160px; }
.sg-block:last-child { border-bottom: 0; }
.sg-block > .head { margin-bottom: 44px; }

.sg-why {
  border-left: 0; border-top: 1px solid var(--border);
  background: none; padding: 24px 0 0; border-radius: 0;
  color: var(--text); font-size: .99rem; margin-top: 34px; max-width: 78ch;
}
.sg-why strong { color: var(--heading); font-weight: 600; }
.sg-why code { font-size: .88em; color: var(--heading); background: var(--bg-alt); padding: .1em .4em; border-radius: 2px; }
.sg-why + .sg-why { margin-top: 26px; }

/* Colour swatches */
.sw-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(196px, 1fr)); gap: 26px; }
.sw { border: 0; border-radius: 0; overflow: visible; background: none; box-shadow: none; }
.sw__chip { height: 96px; border-radius: var(--r); border: 1px solid var(--border); }
.sw__meta { padding: 16px 0 0; }
.sw__name { display: block; font-family: var(--font-body); font-weight: 600; font-size: .86rem; color: var(--heading); }
.sw__role { display: block; font-size: .8rem; color: var(--text-muted); margin-top: 4px; line-height: 1.45; }
.sw__hex, .sw__ratio {
  display: inline-block; margin-top: 12px; margin-right: 8px;
  font-size: .7rem; font-weight: 600; letter-spacing: .06em; padding: 0;
  background: none; color: var(--text-muted); border: 0; font-variant-numeric: tabular-nums;
}
.sw__ratio.is-pass { color: var(--ok-text); }

/* Type specimen */
.sg-type { display: grid; gap: 0; }
.sg-type__row { display: grid; grid-template-columns: 150px 1fr; gap: 28px; align-items: baseline; padding: 26px 0; border-top: 1px solid var(--border); }
.sg-type__spec { font-size: .7rem; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.sg-type__sample { color: var(--heading); font-family: var(--font-display); font-weight: 400; letter-spacing: -.02em; line-height: 1.05; }
.sg-type__sample--body { font-family: var(--font-body); font-weight: 400; color: var(--text); letter-spacing: 0; line-height: 1.7; }
@media (max-width: 640px) { .sg-type__row { grid-template-columns: 1fr; gap: 10px; } }

/* Rulers and boxes */
.sg-scale { display: grid; gap: 16px; }
.sg-scale__row { display: grid; grid-template-columns: 110px 1fr; gap: 20px; align-items: center; }
.sg-scale__label { font-size: .74rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.sg-scale__bar { height: 20px; border-radius: 1px; background: var(--heading); }

.sg-demo { display: flex; flex-wrap: wrap; gap: 24px; align-items: flex-start; }
.sg-demo > * { margin: 0; }
.sg-box { width: 124px; height: 88px; background: var(--bg-alt); border: 1px solid var(--border); display: grid; place-items: center; font-size: .74rem; font-weight: 500; color: var(--text-muted); text-align: center; padding: 8px; line-height: 1.4; }

/* Token tables */
.sg-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; margin-bottom: 40px; }
.sg-scroll:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.sg-scroll .sg-table { min-width: 560px; margin-bottom: 0; }
.sg-table { width: 100%; border-collapse: collapse; font-size: .92rem; }
.sg-table th, .sg-table td { text-align: left; padding: 16px 20px 16px 0; border-bottom: 1px solid var(--border); vertical-align: top; }
.sg-table thead th { font-family: var(--font-body); color: var(--text-muted); font-size: .7rem; font-weight: 600; letter-spacing: .16em; text-transform: uppercase; }
.sg-table code { background: var(--bg-alt); border: 1px solid var(--border); padding: .12em .45em; border-radius: 2px; font-size: .86em; color: var(--heading); white-space: nowrap; }
.sg-table td:last-child { color: var(--text-muted); }

/* Do / Don't */
.sg-rules { display: grid; grid-template-columns: 1fr 1fr; gap: 36px; }
@media (max-width: 700px) { .sg-rules { grid-template-columns: 1fr; } }
.sg-rule { border: 0; border-top: 2px solid var(--border); background: none; border-radius: 0; padding: 24px 0 0; }
.sg-rule h3 { font-size: .74rem; font-weight: 600; letter-spacing: .16em; text-transform: uppercase; margin-bottom: 14px; }
.sg-rule p { font-size: .95rem; color: var(--text-muted); max-width: 46ch; }
.sg-rule--do { border-top-color: var(--ok); }
.sg-rule--do h3 { color: var(--ok-text); }
.sg-rule--dont { border-top-color: #9A2A2A; }
.sg-rule--dont h3 { color: #9A2A2A; }
:root[data-theme="dark"] .sg-rule--dont { border-top-color: #E08585; }
:root[data-theme="dark"] .sg-rule--dont h3 { color: #F0A0A0; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .sg-rule--dont { border-top-color: #E08585; }
  :root:not([data-theme="light"]) .sg-rule--dont h3 { color: #F0A0A0; }
}

/* Motion specimens */
.sg-motion { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 30px; }
.sg-motion__cell { background: none; border: 0; border-top: 1px solid var(--border); border-radius: 0; padding: 22px 0 0; }
.sg-motion__name { font-size: .86rem; font-weight: 600; color: var(--heading); margin-bottom: 6px; }
.sg-motion__meta { font-size: .76rem; color: var(--text-muted); margin-bottom: 18px; font-variant-numeric: tabular-nums; }
.sg-motion__track { height: 30px; background: var(--bg-alt); border-radius: 999px; position: relative; overflow: hidden; }
.sg-motion__dot { position: absolute; top: 5px; left: 5px; width: 20px; height: 20px; border-radius: 50%; background: var(--heading); transition: transform 1s var(--ease-out); }
.sg-motion__cell:hover .sg-motion__dot { transform: translateX(calc(100% + 120px)); }
.sg-motion__cell[data-ease="spring"] .sg-motion__dot { transition-timing-function: var(--ease-spring); }
.sg-motion__cell[data-ease="in-out"] .sg-motion__dot { transition-timing-function: var(--ease-in-out); }
.sg-motion__cell[data-ease="linear"] .sg-motion__dot { transition-timing-function: linear; }

/* ===================================================================
   LANDING PAGE (/get-a-website.html)
   -------------------------------------------------------------------
   A single-offer page. Loud where it counts, but built out of the same
   semantic tokens as everything else — a hardcoded hex here would look
   correct in one theme and nothing would catch it in the other.
   =================================================================== */

/* --- proof strip ------------------------------------------------- */
.lp-shots {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 2vw, 24px);
  margin-top: clamp(36px, 5vw, 56px);
}
@media (max-width: 1100px) { .lp-shots { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 700px)  { .lp-shots { grid-template-columns: 1fr; } }

.lp-shot { margin: 0; }

/* The screenshots are 1400x729. Declaring the same ratio on the frame means
   object-fit never crops an edge off a headline — the mistake that rendered
   "THE DIRT" as "HE DIRT" on the work cards. */
.lp-shot picture,
.lp-shot img {
  display: block;
  width: 100%;
  aspect-ratio: 1400 / 729;
  object-fit: cover;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: var(--bg-sunken);
}

.lp-shot img { transition: transform .5s cubic-bezier(.16,1,.3,1); }
@media (hover: hover) {
  .lp-shot:hover img { transform: scale(1.03); }
}
.lp-shot picture { overflow: hidden; border-radius: 3px; }

.lp-shot figcaption {
  margin-top: 12px;
  font-size: .9rem;
  font-weight: 500;
  color: var(--text);
}
.lp-shot figcaption span {
  display: block;
  margin-top: 2px;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* --- price row ---------------------------------------------------- */
.lp-prices {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 2vw, 22px);
  margin-top: clamp(32px, 4vw, 48px);
  align-items: stretch;
}
@media (max-width: 780px) { .lp-prices { grid-template-columns: 1fr; } }

.lp-price {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(22px, 3vw, 30px);
  border-top: 2px solid var(--border);
  background: none;
}

/* The one being recommended is the only one that gets a full edge. Everything
   else on this site is hairlines and space, so a single boxed column reads as
   emphasis rather than as decoration. */
.lp-price--lead {
  border: 1px solid var(--accent);
  border-top-width: 2px;
  border-radius: 3px;
  background: var(--surface);
}

.lp-price__tag {
  margin: 0 0 10px;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: .66rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}
.lp-price__name {
  margin: 0;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.lp-price__amt {
  margin: 10px 0 0;
  font-family: var(--font-display, Georgia, serif);
  font-size: clamp(2.4rem, 5vw, 3.2rem);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--text);
}
.lp-price__note {
  margin: 14px 0 0;
  font-size: .95rem;
  line-height: 1.6;
  color: var(--text-muted);
}

.lp-fineprint {
  margin-top: 14px;
  font-size: .88rem;
  color: var(--text-muted);
}

/* --- inline figure in a media row --------------------------------- */
.lp-figure { margin: 0; }
.lp-figure img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: 3px;
}

/* --- landing page: turned up ---------------------------------------
   Everything here is scoped to `main.lp` so the rest of the site keeps
   its own restraint. The site caps h1 at 77px because the HOME headline
   is fourteen words; this page's is five, so it can carry the size the
   type scale was designed for. */

.lp .hero h1 {
  font-size: clamp(2.9rem, 8.4vw, 6.4rem);
  line-height: 0.94;
  letter-spacing: -0.025em;
}
.lp .hero__sub {
  font-size: clamp(1.08rem, 1.6vw, 1.42rem);
  line-height: 1.55;
  max-width: 30ch;
}
.lp .section h2 {
  font-size: clamp(2rem, 4.4vw, 3.9rem);
  line-height: 1.02;
}
.lp .section > .wrap > .head { margin-bottom: clamp(30px, 4vw, 52px); }
.lp .section { padding-block: clamp(64px, 9vw, 132px); }

/* Buttons carry more weight on a page whose only job is the click. */
.lp .btn--lg {
  padding: 21px 40px;
  font-size: 1.14rem;
  letter-spacing: .012em;
}
@media (max-width: 560px) {
  .lp .btn--lg { width: 100%; }
}

/* Repeated calls to action between sections. */
.lp-midcta {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  justify-content: center;
  margin-top: clamp(34px, 4vw, 52px);
}
@media (max-width: 560px) { .lp-midcta { flex-direction: column; } }

/* Two columns instead of three: the screenshots are the argument, so they
   get the room to actually be read at a glance. */
.lp .lp-shots { grid-template-columns: repeat(2, 1fr); gap: clamp(18px, 2.4vw, 32px); }
@media (max-width: 780px) { .lp .lp-shots { grid-template-columns: 1fr; } }

.lp .lp-shot figcaption { margin-top: 15px; font-size: 1rem; }
.lp .lp-shot figcaption span { font-size: .74rem; }

.lp .lp-price__amt { font-size: clamp(2.9rem, 6vw, 4.2rem); }
.lp .lp-price { padding: clamp(26px, 3.4vw, 38px); }

/* ---------------------------------------------------------------------------
   Scope estimator (#est, services page)

   A price you can argue with. The controls sit left, the arithmetic sits right,
   and on a phone the arithmetic comes second because the questions have to be
   answered before the number means anything. Nothing here invents colour: the
   accent marks the total and the control states, exactly as elsewhere.
--------------------------------------------------------------------------- */
.est {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(28px, 4vw, 48px);
  align-items: start;
}
@media (min-width: 900px) {
  .est { grid-template-columns: 1fr .82fr; }
}

.est__controls { display: grid; gap: clamp(24px, 3vw, 34px); }

.est__field { border: 0; padding: 0; margin: 0; display: grid; gap: 11px; }
.est__label {
  font-weight: 500; font-size: .8rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-muted); padding: 0;
}
.est__hint { font-size: .82rem; color: var(--text-muted); margin: 0; }

.est__out {
  font-family: var(--font-display);
  font-size: 1.5rem; color: var(--heading); font-variant-numeric: tabular-nums;
}

/* Range: the one control that carries the whole widget, so it gets a real
   track rather than the browser default, in both themes. */
.est input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; background: none; padding: 12px 0; margin: 0; cursor: pointer;
}
.est input[type="range"]::-webkit-slider-runnable-track {
  height: 2px; background: var(--border-strong); border-radius: 2px;
}
.est input[type="range"]::-moz-range-track {
  height: 2px; background: var(--border-strong); border-radius: 2px;
}
.est input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 22px; height: 22px; margin-top: -10px;
  background: var(--accent); border: 0; border-radius: 50%;
  transition: transform var(--t-quick) var(--ease-spring);
}
.est input[type="range"]::-moz-range-thumb {
  width: 22px; height: 22px;
  background: var(--accent); border: 0; border-radius: 50%;
}
.est input[type="range"]:active::-webkit-slider-thumb { transform: scale(1.15); }
.est input[type="range"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; }

.est__opt {
  display: flex; align-items: flex-start; gap: 11px;
  font-size: .99rem; line-height: 1.5; color: var(--text); cursor: pointer;
  padding: 3px 0;
}
.est__opt input { accent-color: var(--accent); width: 17px; height: 17px; margin: 2px 0 0; flex: none; }
.est__opt:hover span { color: var(--heading); }

/* Result panel */
.est__result {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: clamp(22px, 3vw, 32px);
  position: sticky; top: 96px;
}
@media (max-width: 899px) { .est__result { position: static; } }

.est__total { display: grid; gap: 6px; padding-bottom: 20px; border-bottom: 1px solid var(--border); }
.est__total-label {
  font-size: .74rem; font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-muted);
}
.est__amt {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(2.6rem, 5vw, 3.6rem); line-height: 1;
  color: var(--accent); font-variant-numeric: tabular-nums;
}
.est__note { font-size: .84rem; color: var(--text-muted); line-height: 1.5; }

.est__table { width: 100%; border-collapse: collapse; margin: 20px 0 0; font-size: .92rem; }
.est__table caption {
  text-align: left; font-size: .74rem; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-muted); padding-bottom: 10px;
}
.est__table th, .est__table td { padding: 9px 0; vertical-align: top; text-align: left; }
.est__table th { font-weight: 400; color: var(--text); padding-right: 16px; }
.est__table td {
  text-align: right; white-space: nowrap; color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.est__table tbody tr + tr th, .est__table tbody tr + tr td { border-top: 1px solid var(--border); }
.est__table tfoot th, .est__table tfoot td {
  border-top: 1px solid var(--border-strong); font-weight: 600; color: var(--heading);
  padding-top: 12px;
}

.est__fine { font-size: .86rem; color: var(--text-muted); line-height: 1.6; margin: 18px 0 22px; }
.est__aside { margin-top: clamp(30px, 4vw, 44px); font-size: .97rem; }

/* Brief actions under the estimate. The alt line stays hidden until the script
   unhides it, because without JS the button is an ordinary link to the contact
   form and promising an email app would be a lie. */
.est__send-alt {
  margin: 12px 0 0; font-size: .84rem; color: var(--text-muted); line-height: 1.55;
}
.est__send-alt .link-arrow {
  background: none; border: 0; padding: 0; font: inherit; color: var(--accent);
  cursor: pointer; text-decoration: underline; text-underline-offset: 3px;
}
.est__send-alt .link-arrow:hover { color: var(--heading); }
.est__send-alt .link-arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.est__print { display: none; }

/* ---------------------------------------------------------------------------
   Print: the page reduces to the brief, so "Save as PDF" in the print dialog
   produces a document worth attaching to an email. Everything that is
   navigation, persuasion or interaction is dropped.
--------------------------------------------------------------------------- */
@media print {
  .site-header, .site-footer, .skip-link, #estAlt,
  #main > section:not(#pricing) { display: none !important; }

  #pricing { padding: 0 !important; background: none !important; }
  #pricing .head { margin-bottom: 18px; text-align: left; }
  #pricing .head .eyebrow, #pricing .lede { display: none; }
  #pricing .est__controls, #pricing .est__aside, #pricing .btn,
  #estDirect { display: none !important; }

  .est { display: block !important; }
  .est__result {
    border: 0 !important; padding: 0 !important; position: static !important;
    background: none !important;
  }
  .est__amt { color: #000 !important; font-size: 2.4rem; }
  .est__total { border-bottom: 1px solid #999; }

  .est__print { display: grid !important; grid-template-columns: 9rem 1fr; gap: 4px 14px; margin: 18px 0 0; }
  .est__print dt { font-weight: 600; }
  .est__print dd { margin: 0; }

  .est__table { page-break-inside: avoid; }
  .est__fine { font-size: .8rem; }

  /* Ink, not screen paint. */
  body { background: #fff !important; color: #000 !important; }
  .est__note, .est__fine, .est__table td, .est__table caption { color: #333 !important; }
  .est__table th { color: #000 !important; }
}

/* The direct-send fallback. Reuses .form/.field wholesale; this only handles
   the seam where it sits under the estimate. */
.est__direct {
  margin-top: 18px; padding-top: 20px; border-top: 1px solid var(--border);
  display: grid; gap: 16px;
}
.est__direct-why {
  margin: 0; font-size: .86rem; line-height: 1.55; color: var(--text-muted);
}
.est__direct .field label { font-size: .74rem; }
.est__direct .form-status { font-size: .88rem; padding: 14px 16px; }
.est__send-alt .link-arrow + .link-arrow { margin-left: 10px; }
