/* ==========================================================================
   Zion K Airless Spray Painter
   Dark cinematic hero → light working body. One accent: wet-paint green.
   ========================================================================== */

/* ---------- Tokens ---------- */
:root {
  /* Surfaces */
  --ink:        oklch(0.148 0.008 155);
  --ink-2:      oklch(0.205 0.010 155);
  --ink-3:      oklch(0.275 0.012 155);
  /* The whole page now runs on the hero's own palette: ink base, dusk-blue cast
     off the sky in the photograph, acid green, white type. What used to be the
     light "paper" body is a dark dusk surface, so these token names stay but
     their values flipped. */
  --paper:      oklch(0.188 0.020 242);   /* dusk surface  (was near-white) */
  --paper-2:    oklch(0.238 0.023 242);   /* raised dusk   (was off-white)  */
  --line:       oklch(0.335 0.024 242);
  --line-dark:  oklch(0.320 0.012 155);

  /* Type colours */
  --on-ink:     oklch(0.965 0.004 150);
  --on-ink-mut: oklch(0.735 0.010 150);
  --on-paper:   oklch(0.962 0.006 200);
  --on-paper-mut: oklch(0.765 0.018 220);

  /* Accent */
  --accent:     oklch(0.805 0.190 142);
  --accent-ink: oklch(0.805 0.190 142);   /* surfaces are dark now, so the bright accent reads */
  --dusk:       oklch(0.520 0.075 245);   /* the sky out of the hero photograph */
  --accent-dim: oklch(0.805 0.190 142 / 0.14);

  /* Type */
  --font: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --mono: 'Azeret Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Rhythm */
  --gut: clamp(1.25rem, 5vw, 2.5rem);
  --sec: clamp(4.5rem, 11vw, 9rem);
  --max: 76rem;
  --r:   14px;

  /* Motion */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);      /* out-quint */
  --ease-s: cubic-bezier(0.65, 0, 0.35, 1);

  /* z-scale */
  --z-base: 1;
  --z-scrim: 5;
  --z-sticky: 40;
  --z-fab: 60;
  --z-nav: 80;
  --z-skip: 100;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
}

body {
  background: var(--paper);
  color: var(--on-paper);
  font-family: var(--font);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.075rem);
  line-height: 1.6;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; }
img { height: auto; }

h1, h2, h3 {
  line-height: 1.02;
  letter-spacing: -0.035em;
  text-wrap: balance;
  font-weight: 800;
}

p { text-wrap: pretty; }

a { color: inherit; }

button, input, select { font: inherit; color: inherit; }

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

.wrap {
  width: min(100% - (var(--gut) * 2), var(--max));
  margin-inline: auto;
}

.skip {
  position: absolute;
  left: -9999px;
  z-index: var(--z-skip);
}
.skip:focus {
  left: 1rem; top: 1rem;
  padding: 0.7rem 1.1rem;
  background: var(--accent);
  color: var(--ink);
  font-weight: 700;
  border-radius: 8px;
}

/* ---------- Buttons ---------- */
.btn {
  --btn-bg: transparent;
  --btn-fg: currentColor;
  --sweep: var(--accent);
  --sweep-fg: var(--ink);
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55em;
  padding: 0.8rem 1.35rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid transparent;
  border-radius: 100px;
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: 0.005em;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: transform 0.4s var(--ease), color 0.3s var(--ease),
              box-shadow 0.4s var(--ease), border-color 0.25s;
}

/* a coat of paint rolling up from the bottom edge */
.btn::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--sweep);
  transform: translateY(101%);
  transition: transform 0.45s var(--ease);
}
.btn > * { position: relative; }

.btn:hover { transform: translateY(-3px); color: var(--sweep-fg); }
.btn:hover::before { transform: translateY(0); }
.btn:focus-visible::before { transform: translateY(0); }

/* real press feedback — squashes into the click */
.btn:active {
  transform: translateY(-1px) scale(0.975);
  transition-duration: 0.09s;
}

.btn--lg { padding: 1.05rem 1.9rem; font-size: 1rem; }
.btn--block { width: 100%; }

.btn--accent {
  --btn-bg: var(--accent);
  --btn-fg: var(--ink);
  --sweep: var(--ink);
  --sweep-fg: var(--accent);
}
.btn--accent:hover { box-shadow: 0 14px 34px oklch(0.805 0.190 142 / 0.34); }

.btn--dark {
  --btn-bg: var(--accent);
  --btn-fg: var(--ink);
  --sweep: var(--ink);
  --sweep-fg: var(--accent);
}
.btn--dark:hover { box-shadow: 0 14px 34px oklch(0.148 0.008 155 / 0.30); }

.btn--ghost {
  --btn-fg: var(--on-ink);
  --sweep: oklch(1 0 0 / 0.14);
  --sweep-fg: var(--on-ink);
  border-color: var(--line-dark);
}
.btn--ghost:hover { border-color: oklch(1 0 0 / 0.34); }

.btn--glass {
  --btn-fg: var(--on-ink);
  --sweep: var(--accent);
  --sweep-fg: var(--ink);
  background: oklch(1 0 0 / 0.10);
  border-color: oklch(1 0 0 / 0.30);
}
.btn--glass:hover {
  border-color: var(--accent);
  box-shadow: 0 14px 34px oklch(0.805 0.190 142 / 0.28);
}

/* outlined until you touch it, then it fills with paint */
.btn--hollow {
  --btn-bg: transparent;
  --btn-fg: var(--accent);
  --sweep: var(--accent);
  --sweep-fg: var(--ink);
  border-color: var(--accent);
}
.btn--hollow:hover { box-shadow: 0 14px 34px oklch(0.805 0.190 142 / 0.30); }



.areas__cta { display: flex; flex-wrap: wrap; gap: 0.7rem; }

/* ==========================================================================
   NAV — floating pill
   ========================================================================== */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--z-nav);
  padding: 0.75rem var(--gut);
  pointer-events: none;
  isolation: isolate;
  /* the transform lives here, never on .nav__inner — GSAP animates that one on
     load and an inline transform would wipe this out. */
  transition: transform 0.4s var(--ease);
}
.nav.is-away { transform: translateY(-135%); }

/* Over the hero the pill is transparent, so nav text sits directly on the
   photograph. This scrim guarantees legibility whatever the image does; it
   fades out once the solid pill takes over. */
.nav::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 160px;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(to bottom,
    oklch(0.148 0.008 155 / 0.86) 0%,
    oklch(0.148 0.008 155 / 0.72) 40%,
    oklch(0.148 0.008 155 / 0) 100%);
  transition: opacity 0.4s var(--ease);
}
.nav.is-stuck::before { opacity: 0; }

/* A real pane of glass: it blurs, brightens and over-saturates whatever passes
   underneath, with a lit top edge and a shadowed bottom one so it reads as a
   solid object with thickness rather than a translucent rectangle. */
.nav__inner {
  pointer-events: auto;
  position: relative;
  isolation: isolate;
  width: min(100%, var(--max));
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.5rem 0.5rem 0.5rem 0.85rem;
  border-radius: 100px;
  color: var(--on-ink);

  background: oklch(0.148 0.008 155 / 0.14);
  border: 0;
  backdrop-filter: blur(24px) saturate(200%) brightness(1.1);
  -webkit-backdrop-filter: blur(24px) saturate(200%) brightness(1.1);
  box-shadow: 0 10px 30px oklch(0 0 0 / 0.22);
  transition: background-color 0.45s var(--ease), border-color 0.45s var(--ease),
              box-shadow 0.45s var(--ease);
}

/* a faint specular streak travelling across the glass */
.nav__inner::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: linear-gradient(105deg,
    transparent 30%, oklch(1 0 0 / 0.07) 46%, transparent 62%);
  pointer-events: none;
}

/* denser once it's over content rather than the hero photograph */
.nav.is-stuck .nav__inner {
  background: oklch(0.148 0.008 155 / 0.30);
  box-shadow: 0 14px 40px oklch(0 0 0 / 0.34);
}

/* ---------- Brand lockup ----------
   Mark + wordmark only. The descriptor line is carried by the page copy and
   the <title>, not bolted under the logo. */
.brand {
  display: flex;
  align-items: center;
  gap: 0.62rem;
  text-decoration: none;
  margin-right: auto;
  transition: transform 0.4s var(--ease);
}
.brand:hover { transform: translateY(-1px); }
.brand__mark {
  color: var(--accent);
  flex: none;
  transition: transform 0.5s var(--ease), filter 0.4s var(--ease);
}
.brand:hover .brand__mark {
  transform: rotate(-8deg) scale(1.05);
  filter: drop-shadow(0 0 14px oklch(0.805 0.190 142 / 0.55));
}

/* the wordmark: tight, wide-cut, industrial */
.brand__text b {
  display: block;
  font-size: 1.05rem;
  font-weight: 900;
  font-stretch: 116%;
  letter-spacing: 0.055em;
  line-height: 1;
}

.nav__links { display: none; gap: 1.4rem; }
.nav__links a {
  font-size: 0.875rem;
  font-weight: 500;
  text-decoration: none;
  opacity: 0.82;
  transition: opacity 0.2s, color 0.2s;
}
.nav__links a:hover { opacity: 1; color: var(--accent); }

.nav__cta { display: flex; gap: 0.5rem; align-items: center; }
.nav__cta .btn--ghost span { display: none; }
.nav__cta .btn { padding: 0.7rem 1.1rem; }
.nav__cta .btn--ghost {
  width: 42px;
  height: 42px;
  padding: 0;
  flex: none;
}

@media (min-width: 900px) {
  .nav__links { display: flex; }
  .nav__cta .btn--ghost span { display: inline; }
  .nav__cta .btn--ghost { width: auto; height: auto; padding: 0.7rem 1.1rem; }
}

/* ==========================================================================
   HERO
   ========================================================================== */
.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  align-content: end;
  padding: 7rem var(--gut) clamp(3rem, 8vw, 5rem);
  background: var(--ink);
  color: var(--on-ink);
  overflow: hidden;
  isolation: isolate;
}

.hero__media { position: absolute; inset: 0; z-index: -2; }
.hero__img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 58% 40%;
  filter: saturate(0.82) contrast(1.06) brightness(0.78);
}

/* scrim: dark from the bottom so type always clears contrast */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(to top,
      oklch(0.148 0.008 155) 0%,
      oklch(0.148 0.008 155 / 0.94) 26%,
      oklch(0.148 0.008 155 / 0.62) 52%,
      oklch(0.148 0.008 155 / 0.30) 76%,
      oklch(0.148 0.008 155 / 0.55) 100%);
}

.hero__body {
  width: min(100%, var(--max));
  margin-inline: auto;
  position: relative;
}

.hero__title {
  font-size: clamp(2.5rem, 8.4vw, 5.25rem);
  font-weight: 900;
  font-stretch: 108%;
  letter-spacing: -0.038em;
  margin-bottom: 1.35rem;
  text-wrap: initial;
}
.hero__title .line { display: block; }
.hero__title em { font-style: normal; color: var(--accent); }

.hero__sub {
  max-width: 48ch;
  color: oklch(0.90 0.006 150);
  font-size: clamp(1.02rem, 0.97rem + 0.4vw, 1.2rem);
  line-height: 1.55;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  margin-top: 1.9rem;
}

.hero__scroll {
  position: absolute;
  right: var(--gut);
  bottom: clamp(3rem, 8vw, 5rem);
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  color: var(--on-ink-mut);
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.hero__scroll svg { animation: nudge 2.4s var(--ease-s) infinite; }
@keyframes nudge {
  0%, 100% { transform: translateY(-3px); opacity: 0.55; }
  50%      { transform: translateY(3px);  opacity: 1; }
}
@media (min-width: 900px) { .hero__scroll { display: flex; } }

/* ==========================================================================
   SERVICES — paint chips
   ========================================================================== */
.services {
  position: relative;
  background: #000;                 /* pure black, not the ink tone */
  color: var(--on-ink);
}

.services__stage { padding-block: var(--sec); }

.services__head {
  display: grid;
  gap: 1rem;
  margin-bottom: clamp(2.5rem, 6vw, 4rem);
}
.services__head h2 { font-size: clamp(1.95rem, 5.4vw, 3.1rem); }
.services__head p {
  max-width: 58ch;
  color: var(--on-ink-mut);
}
@media (min-width: 860px) {
  .services__head {
    grid-template-columns: 1.05fr 1fr;
    gap: 3rem;
    align-items: end;
  }
}

.chips {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

/* an actual paint chip: solid swatch over a card */
.chip {
  background: var(--ink-2);
  border: 1px solid var(--line-dark);
  border-radius: var(--r);
  overflow: hidden;
  display: grid;
  grid-template-rows: auto 1fr;
  transition: transform 0.5s var(--ease), border-color 0.35s;
}
/* No translate on hover — that lift was the cards "still lifting". Only the
   edge responds now, so a hovered card never leaves its row. */
.chip:hover { border-color: oklch(1 0 0 / 0.30); }
/* Was a solid block of paint colour. A drawn symbol says what the service is
   before the heading does; the swatch colour survives as the ink. */
.chip__paint {
  height: 88px;
  background: var(--tint);
  color: var(--swatch);
  position: relative;
  display: grid;
  place-items: center;
}
.chip__paint svg {
  width: 38px;
  height: 38px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.chip__paint::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 42%;
  background: linear-gradient(to top, oklch(0 0 0 / 0.22), transparent);
  pointer-events: none;
}
.chip__body { padding: 1.15rem 1.25rem 1.4rem; position: relative; z-index: 1; }
.chip h3 {
  font-size: 1.15rem;
  font-weight: 800;
  margin-bottom: 0.45rem;
}
.chip p {
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--on-ink-mut);
}

/* ==========================================================================
   BAND — static spec strip. Replaced the scrolling marquees: the movement was
   noise, and the same facts sit better still.
   ========================================================================== */
.band {
  position: relative;
  z-index: 2;
  background: var(--accent);
  color: var(--ink);
  padding-block: clamp(1.1rem, 2.6vw, 1.75rem);
}
.band__inner {
  display: grid;
  gap: 1rem 2rem;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
.band__item { display: grid; gap: 0.15rem; align-content: start; }
.band__item b {
  font-family: var(--mono);
  font-size: clamp(1.15rem, 2.6vw, 1.6rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1;
  word-spacing: -0.28em;
}
.band__item span {
  font-size: 0.8rem;
  line-height: 1.35;
  color: oklch(0.148 0.008 155 / 0.78);
}

/* ==========================================================================
   QUOTE CALCULATOR
   ========================================================================== */
.quote {
  background: var(--paper);
  padding-block: var(--sec);
}
.quote__head {
  max-width: 54ch;
  margin-bottom: clamp(2.2rem, 5vw, 3.25rem);
}
.quote__head h2 {
  font-size: clamp(2rem, 5.6vw, 3.35rem);
  margin-bottom: 0.85rem;
}
.quote__head p { color: var(--on-paper-mut); }

.calc {
  display: grid;
  gap: 1rem;
  align-items: start;
}
@media (min-width: 900px) {
  .calc { grid-template-columns: 1.25fr 1fr; gap: 1.5rem; }
}

.calc__controls {
  display: grid;
  gap: 1.6rem;
  padding: clamp(1.25rem, 4vw, 2rem);
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: var(--r);
}

.field { display: grid; gap: 0.85rem; border: 0; padding: 0; }
.field__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.field label, .field legend {
  font-size: 0.95rem;
  font-weight: 700;
  padding: 0;
}
.field__val {
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
  font-family: var(--mono);
}
.field__val input {
  width: 5.2ch;
  padding: 0.35rem 0.4rem;
  text-align: right;
  font-family: var(--mono);
  font-size: 1.3rem;
  font-weight: 600;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  -moz-appearance: textfield;
}
.field__val input::-webkit-outer-spin-button,
.field__val input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.field__val span { font-size: 0.95rem; color: var(--on-paper-mut); }

.hint {
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--on-paper-mut);
  max-width: 56ch;
}

/* range */
.slider {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 34px;
  background: transparent;
  cursor: pointer;
}
.slider::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 100px;
  background: linear-gradient(to right, var(--accent-ink) var(--fill, 14%), var(--line) var(--fill, 14%));
}
.slider::-moz-range-track {
  height: 6px;
  border-radius: 100px;
  background: linear-gradient(to right, var(--accent-ink) var(--fill, 14%), var(--line) var(--fill, 14%));
}
.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 28px; height: 28px;
  margin-top: -11px;
  border-radius: 50%;
  background: var(--ink);
  border: 4px solid var(--accent);
  box-shadow: 0 2px 8px oklch(0 0 0 / 0.22);
  transition: transform 0.25s var(--ease);
}
.slider::-moz-range-thumb {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--ink);
  border: 4px solid var(--accent);
  box-shadow: 0 2px 8px oklch(0 0 0 / 0.22);
}
.slider:active::-webkit-slider-thumb { transform: scale(1.12); }

/* segmented radio */
.segmented { display: grid; gap: 0.6rem; }
@media (min-width: 560px) { .segmented { grid-template-columns: 1fr 1fr; } }

.seg { cursor: pointer; }
.seg input { position: absolute; opacity: 0; width: 0; height: 0; }
.seg__box {
  display: grid;
  gap: 0.2rem;
  height: 100%;
  padding: 0.95rem 1.05rem;
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 11px;
  transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
}
.seg__box b { font-size: 0.95rem; font-weight: 700; }
.seg__box i {
  font-family: var(--mono);
  font-style: normal;
  font-size: 0.78rem;
  color: var(--on-paper-mut);
}
.seg input:checked + .seg__box {
  border-color: var(--accent-ink);
  background: var(--accent-dim);
  box-shadow: inset 0 0 0 1px var(--accent-ink);
}
.seg input:checked + .seg__box i { color: var(--on-paper); }
.seg input:focus-visible + .seg__box { outline: 3px solid var(--accent); outline-offset: 2px; }

/* checkbox */
.check {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.8rem;
  align-items: start;
  cursor: pointer;
  padding-top: 0.2rem;
}
.check input { position: absolute; opacity: 0; width: 0; height: 0; }
.check__box {
  width: 24px; height: 24px;
  margin-top: 2px;
  border: 1.5px solid var(--line);
  border-radius: 7px;
  background: var(--paper);
  display: grid;
  place-items: center;
  transition: background-color 0.2s, border-color 0.2s;
}
.check__box::after {
  content: '';
  width: 11px; height: 6px;
  border-left: 2.5px solid var(--ink);
  border-bottom: 2.5px solid var(--ink);
  transform: rotate(-45deg) scale(0);
  transition: transform 0.25s var(--ease);
}
.check input:checked + .check__box {
  background: var(--accent);
  border-color: var(--accent-ink);
}
.check input:checked + .check__box::after { transform: rotate(-45deg) scale(1); }
.check input:focus-visible + .check__box { outline: 3px solid var(--accent); outline-offset: 2px; }
.check__text { display: grid; gap: 0.15rem; }
.check__text b { font-size: 0.95rem; font-weight: 700; }
.check__text i {
  font-style: normal;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--on-paper-mut);
}

/* output panel */
.calc__out {
  position: sticky;
  top: 6rem;
  padding: clamp(1.35rem, 4vw, 2rem);
  background: var(--ink);
  color: var(--on-ink);
  border-radius: var(--r);
}
.calc__label {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--on-ink-mut);
}
.calc__total {
  display: flex;
  align-items: baseline;
  gap: 0.12em;
  margin: 0.3rem 0 1.25rem;
  font-family: var(--mono);
  font-weight: 600;
  font-size: clamp(2.6rem, 11vw, 3.9rem);
  line-height: 1;
  letter-spacing: -0.045em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  /* the thousands separator is a real space, and in a monospace face that is a
     full character width — it reads as two numbers, not one. Pull it back. */
  word-spacing: -0.34em;
}
.calc__cur { font-size: 0.5em; }

.calc__break {
  display: grid;
  gap: 0.55rem;
  padding-bottom: 1.25rem;
  margin-bottom: 1.25rem;
  border-bottom: 1px solid var(--line-dark);
  font-size: 0.88rem;
}
.calc__break > div {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
}
.calc__break dt { color: var(--on-ink-mut); }
.calc__break dd {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  word-spacing: -0.34em;
}
.calc__break > div.is-off { display: none; }

.calc__fine {
  margin-top: 1rem;
  font-size: 0.76rem;
  line-height: 1.5;
  color: var(--on-ink-mut);
}

/* ==========================================================================
   PROCESS
   ========================================================================== */
.process {
  background: var(--paper-2);
  padding-block: var(--sec);
  border-block: 1px solid var(--line);
}
.process h2 {
  font-size: clamp(2rem, 5.6vw, 3.35rem);
  margin-bottom: clamp(2.2rem, 5vw, 3.25rem);
  max-width: 18ch;
}

.steps {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 2rem 1.75rem;
  counter-reset: step;
}
@media (min-width: 700px) { .steps { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1050px) { .steps { grid-template-columns: repeat(4, 1fr); gap: 1.5rem; } }

.step { display: grid; gap: 0.5rem; align-content: start; }
.step__n {
  --rule: 100%;                    /* animated 0% → 100% on scroll */
  font-family: var(--mono);
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--accent-ink);
  padding-bottom: 0.75rem;
  margin-bottom: 0.35rem;
  background-image: linear-gradient(var(--accent), var(--accent));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: var(--rule) 2px;
}
.step h3 { font-size: 1.15rem; font-weight: 800; }
.step p {
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--on-paper-mut);
}

/* ==========================================================================
   AREAS
   ========================================================================== */
.areas {
  background: var(--paper-2);
  padding-block: var(--sec);
  border-top: 1px solid var(--line);
}
.areas__inner { display: grid; gap: 2.5rem; }
@media (min-width: 880px) {
  .areas__inner { grid-template-columns: 1fr 1fr; gap: 4rem; align-items: start; }
}
.areas__copy h2 {
  font-size: clamp(1.95rem, 5.2vw, 3rem);
  margin-bottom: 1rem;
}
.areas__copy p {
  color: var(--on-paper-mut);
  max-width: 46ch;
  margin-bottom: 1.75rem;
}

.areas__list {
  list-style: none;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 0;
  border-top: 1px solid var(--line);
}
.areas__list li {
  padding: 0.7rem 0.25rem;
  border-bottom: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 0.82rem;
  color: var(--on-paper);
}

/* ==========================================================================
   SECTION EYEBROW
   The site already speaks in small mono labels — YOUR ESTIMATE, WHATSAPP &
   CALLS, the footer column heads. The sections themselves opened cold on a
   headline. This gives every one of them the same tag, so the page has a
   rhythm instead of six unrelated openings. aria-hidden: the heading beneath
   already says what the section is, and a screen reader does not need it twice.
   ========================================================================== */
.eyebrow {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.9rem;
  font-family: var(--mono);
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
}
.eyebrow::before {
  content: '';
  width: 20px;
  height: 2px;
  background: currentColor;
  flex: none;
  border-radius: 2px;
}
/* on the green closing block the accent disappears — use the ink instead */
.close .eyebrow { color: oklch(1 0 0 / 0.55); }

/* ==========================================================================
   FAQ — the questions that actually get phoned in, answered on the page.
   Deliberately not an accordion: collapsed answers are worth less to a reader
   skimming for a price, and the FAQPage markup wants them visible anyway.
   ========================================================================== */
.faq {
  position: relative;
  background: var(--paper);
  padding-block: var(--sec);
}
.faq h2 {
  font-size: clamp(1.85rem, 5vw, 2.9rem);
  margin-bottom: clamp(2rem, 4.5vw, 3rem);
  max-width: 20ch;
}
.faq__list {
  display: grid;
  gap: 0;
  margin: 0;
  border-top: 1px solid var(--line);
}
/* <details> rather than a flat list: seven answers open at once ran 1,650px on
   a phone. Google is happy to read an FAQPage out of collapsed content as long
   as the markup is in the HTML, which it is. */
.faq__item { border-bottom: 1px solid var(--line); }
.faq__item summary {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding-block: clamp(0.95rem, 2.2vw, 1.25rem);
  font-weight: 800;
  font-size: clamp(0.98rem, 2.1vw, 1.12rem);
  line-height: 1.35;
  color: var(--on-paper);
  cursor: pointer;
  list-style: none;
  transition: color 0.35s var(--ease);
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary:hover { color: var(--accent); }
.faq__item summary::after {
  content: '';
  flex: none;
  margin-left: auto;
  margin-top: 0.35em;
  width: 11px;
  height: 11px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.35s var(--ease);
  opacity: 0.55;
}
.faq__item[open] summary::after { transform: rotate(-135deg); }
.faq__item[open] summary { color: var(--accent); }
.faq__item p {
  margin: 0;
  padding-bottom: clamp(1rem, 2.4vw, 1.35rem);
  padding-right: 2rem;
  max-width: 68ch;
  color: var(--on-paper-mut);
  font-size: 0.92rem;
  line-height: 1.6;
}

/* ==========================================================================
   CLOSE — contact and footer merged into one closing block, one wordmark
   ========================================================================== */
.close {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  color: oklch(0.925 0.018 150);
  padding-block: var(--sec) 0;
  /* fades up into the brand green; the final stop stays dark enough that white
     type still clears 4.5:1 on it */
  background:
    linear-gradient(to bottom,
      oklch(0.170 0.018 242) 0%,
      oklch(0.190 0.042 148) 52%,
      oklch(0.275 0.082 144) 82%,
      oklch(0.345 0.115 143) 100%);
}
.close > * { position: relative; z-index: 1; }

.close__inner { display: grid; gap: 2.5rem; }
@media (min-width: 900px) {
  .close__inner { grid-template-columns: 1.1fr 1fr; gap: 4rem; align-items: center; }
}
.close__lead h2 {
  font-size: clamp(2rem, 5.6vw, 3.35rem);
  margin-bottom: 1rem;
  color: var(--on-ink);
}
.close__lead p { color: var(--on-ink-mut); max-width: 44ch; }

.close__cards { display: grid; gap: 0.75rem; }

/* ---------- footer navigation ----------
   Sits on the green, above the small print. Doubles as the site's only real
   internal linking — every section is one click from the bottom of the page. */
.fnav {
  display: grid;
  gap: 2.25rem;
  margin-top: clamp(3rem, 7vw, 4.5rem);
  padding-top: clamp(2rem, 4vw, 2.75rem);
  border-top: 1px solid oklch(1 0 0 / 0.16);
}
@media (min-width: 700px) {
  .fnav { grid-template-columns: 1.5fr 1fr 1fr 1.2fr; gap: 2.5rem; }
}
.fnav__brand { display: grid; gap: 0.9rem; align-content: start; }
/* the same lockup as the bar, so the brand reads identically top and bottom */
.fnav__lockup { display: flex; align-items: center; gap: 0.62rem; }
.fnav__mark { color: var(--accent); line-height: 0; flex: none; }
.fnav__lockup b {
  font-size: 1.05rem;
  font-weight: 900;
  font-stretch: 116%;
  letter-spacing: 0.055em;
  line-height: 1;
  color: var(--on-ink);
}
.fnav__brand p {
  max-width: 34ch;
  font-size: 0.84rem;
  line-height: 1.6;
  color: oklch(1 0 0 / 0.66);
}
.fnav__col h2 {
  font-family: var(--mono);
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: oklch(1 0 0 / 0.55);
  margin-bottom: 0.85rem;
}
.fnav__col ul { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.9rem; }
.fnav__col a {
  position: relative;
  font-size: 0.88rem;
  color: oklch(1 0 0 / 0.86);
  text-decoration: none;
  transition: color 0.3s var(--ease);
}
/* The text is 16px tall; a thumb is not. This grows the hit area to ~40px
   without moving anything, and the row gap keeps neighbours from overlapping. */
.fnav__col a::after {
  content: '';
  position: absolute;
  inset: -12px -10px;
}
.fnav__col a:hover { color: var(--accent); }
.fnav__rates {
  margin-top: 1.1rem;
  font-family: var(--mono);
  font-size: 0.7rem;
  line-height: 1.7;
  color: oklch(1 0 0 / 0.5);
}

/* the strip of small print, sitting on the green */
.close__meta {
  display: grid;
  gap: 0.5rem;
  margin-top: clamp(3rem, 8vw, 5rem);
  padding-top: 1.5rem;
  padding-bottom: clamp(1.75rem, 4vw, 2.5rem);   /* it closes the page now */
  border-top: 1px solid oklch(1 0 0 / 0.16);
  font-size: 0.8rem;
}
@media (min-width: 780px) {
  .close__meta {
    grid-template-columns: 1fr auto;
    align-items: baseline;
    gap: 2rem;
  }
}
.close__where { font-family: var(--mono); font-size: 0.76rem; letter-spacing: 0.04em; }
.close__legal { font-size: 0.76rem; }
.close__legal a { position: relative; color: #fff; text-underline-offset: 3px; }
.close__legal a::after { content: ''; position: absolute; inset: -13px -10px; }

/* The oversized ZION K that used to bleed off the bottom is gone — it never
   settled at more than one viewport width, and the small print now closes the
   page instead. */

/* ---------- contact cards ---------- */
.ccard {
  display: grid;
  gap: 0.3rem;
  padding: 1.4rem 1.5rem;
  background: oklch(0.225 0.012 242);
  border: 1px solid oklch(1 0 0 / 0.14);
  border-radius: var(--r);
  text-decoration: none;
  box-shadow: inset 0 1px 0 oklch(1 0 0 / 0.10);
  transition: transform 0.4s var(--ease), background-color 0.3s, border-color 0.3s;
}
.ccard:hover { transform: translateY(-3px); background: oklch(0.275 0.012 155 / 0.85); }
.ccard__k {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--on-ink-mut);
}
.ccard__v {
  font-family: var(--mono);
  font-size: clamp(1.4rem, 5.5vw, 1.85rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--on-ink);
  word-spacing: -0.3em;
}
.ccard__go { font-size: 0.82rem; font-weight: 600; color: var(--accent); }

.ccard--wa {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--ink);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.ccard--wa:hover { background: oklch(0.855 0.185 142); }
.ccard--wa .ccard__k { color: oklch(0.148 0.008 155 / 0.72); }
.ccard--wa .ccard__v { color: var(--ink); }
.ccard--wa .ccard__go { color: var(--ink); }

/* ==========================================================================
   WEBGL LAYERS
   The DOM picture is always the source of truth. A canvas only takes over once
   it has actually painted a frame (JS adds .gl-on), so a failed context, a
   blocked CDN or a dead GPU just leaves the ordinary photograph in place.
   ========================================================================== */
.gl { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.hero__img { transition: opacity 0.5s var(--ease); }
.hero.gl-on .hero__img { opacity: 0; }

/* ==========================================================================
   PICKER — see it on a real roof
   ========================================================================== */
.picker { background: var(--paper); padding-block: var(--sec); }
.picker__head { margin-bottom: clamp(1.5rem, 4vw, 2.25rem); }
.picker__head h2 { font-size: clamp(2rem, 5.6vw, 3.35rem); }
.picker__head p { color: var(--on-paper-mut); margin-top: 0.6rem; max-width: 52ch; }

.picker__stage {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--r);
  background: var(--paper-2);
}
.picker__stage img { width: 100%; height: 100%; object-fit: cover; transition: opacity 0.5s var(--ease); }
.picker__stage.gl-on img { opacity: 0; }

.picker__swatches { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 1rem; }

.sw {
  --ring: transparent;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 1rem 0.55rem 0.6rem;
  background: var(--paper-2);
  border: 1.5px solid var(--line);
  border-radius: 100px;
  font-size: 0.85rem;
  font-weight: 700;
  cursor: pointer;
  transition: transform 0.35s var(--ease), border-color 0.25s, background-color 0.25s;
}
.sw::before {
  content: '';
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--sw);
  box-shadow: inset 0 0 0 2px oklch(1 0 0 / 0.35), 0 0 0 2px var(--ring);
  transition: box-shadow 0.25s var(--ease);
}
.sw:hover { transform: translateY(-2px); border-color: var(--on-paper-mut); }
.sw.is-on { --ring: var(--ink); background: var(--ink); border-color: var(--ink); color: var(--on-ink); }

.picker__note {
  margin-top: 1rem;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--on-paper-mut);
  max-width: 60ch;
}

/* ==========================================================================
   GLASS — only where something real sits behind it
   ========================================================================== */
.chip {
  background: oklch(0.225 0.012 242 / 0.92);
  box-shadow: inset 0 1px 0 oklch(1 0 0 / 0.07);
}
.calc__out {
  background: oklch(0.135 0.012 242);
  box-shadow: inset 0 1px 0 oklch(1 0 0 / 0.08), 0 24px 60px oklch(0.148 0.008 155 / 0.22);
}

/* ==========================================================================
   SECTION CONTEXT
   Sections must be positioned and clip their own overflow, otherwise the
   absolutely-placed ghost words resolve against the page instead of their
   section and end up thousands of pixels out. The child rule lifts real
   content above them: a positioned z-index:0 element otherwise paints over
   static content in the same stacking context.
   ========================================================================== */
.services, .quote, .process, .areas, .close, .picker {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}
.services > *, .quote > *, .process > *,
.areas > *, .picker > *, .close > * { position: relative; z-index: 1; }
.channel { z-index: 0; }

/* ==========================================================================
   SECTION BLENDING — neighbours bleed into each other instead of butting
   ========================================================================== */
.quote, .picker, .process, .areas, .faq { --blend: clamp(48px, 7vw, 110px); }
.quote::before, .picker::before,
.process::before, .areas::before, .faq::before {
  content: '';
  position: absolute;
  z-index: 0;
  inset: 0 0 auto 0;
  height: var(--blend);
  background: linear-gradient(to bottom, var(--blend-from, transparent), transparent);
  pointer-events: none;
}
.quote   { --blend-from: oklch(0.148 0.008 155 / 0.55); }
.process { --blend-from: oklch(0.188 0.020 242); }
.picker  { --blend-from: oklch(0.238 0.023 242); }
.areas   { --blend-from: oklch(0.148 0.008 155 / 0.45); }
.faq     { --blend-from: oklch(0.238 0.023 242); }

/* ==========================================================================
   PROCESS RAIL — a line drawn through the four steps
   ========================================================================== */
.steps { position: relative; }
.steps::before {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 9px;
  height: 2px;
  background: oklch(1 0 0 / 0.16);
  transform: scaleX(var(--draw, 1));
  transform-origin: 0 50%;
}
@media (max-width: 699px) { .steps::before { display: none; } }

/* ==========================================================================
   MARQUEE — the trade, running across the seams
   ========================================================================== */
.marquee {
  position: relative;
  z-index: 2;
  overflow: hidden;
  padding-block: clamp(0.7rem, 1.6vw, 1.05rem);
  background: var(--ink);
  color: var(--accent);
  border-block: 1px solid var(--line-dark);
}
.marquee--light { background: var(--accent); color: var(--ink); border-color: transparent; }
.marquee__row { display: flex; width: max-content; will-change: transform; }
.marquee__row span {
  display: inline-flex;
  align-items: center;
  gap: clamp(1.5rem, 4vw, 3rem);
  padding-right: clamp(1.5rem, 4vw, 3rem);
  font-family: var(--mono);
  font-size: clamp(0.72rem, 1.8vw, 0.92rem);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
}
.marquee__row b { font-weight: 600; }
.marquee__row i { font-style: normal; opacity: 0.5; }

/* ==========================================================================
   PAINT WIPE — full-screen transition, on nav clicks and on first load
   ========================================================================== */
.wipe {
  position: fixed;
  inset: 0;
  z-index: var(--z-skip);
  pointer-events: none;
  display: grid;
  place-items: center;
  /* +140px clears .wipe__edge, which hangs above the fill. At a flat 100%
     that ragged band was still visible at the bottom of the screen when the
     animation ended, and visibility:hidden then snapped it out of view. */
  transform: translateY(calc(100% + 140px));
  visibility: hidden;
}
.wipe__fill { position: absolute; inset: -2px; background: var(--accent); }
.wipe__edge {
  position: absolute;
  left: 0; right: 0; bottom: 100%;
  width: 100%;
  height: clamp(40px, 6vw, 80px);
  fill: var(--accent);
  display: block;
}
/* ZION stacked over K, always two lines */
.wipe__mark {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 0;
  color: var(--ink);
  opacity: 0;
}
.wipe__word {
  display: flex;
  overflow: hidden;
  font-weight: 900;
  font-stretch: 122%;
  font-size: clamp(3.2rem, 15vw, 11rem);
  line-height: 0.86;
  letter-spacing: -0.045em;
}
.wipe__word i {
  font-style: normal;
  display: block;
  transform: translateY(110%);
}
.wipe__rule {
  width: 0;
  height: 5px;
  margin-block: 0.10em;      /* sits between the two words */
  background: var(--ink);
  opacity: 0.55;
}

/* ---------- Intro wipe on load ----------
   Driven by CSS animation rather than JS so it always completes on its own —
   if the scripts never arrive, the page still uncovers. */
.is-preload .wipe {
  visibility: visible;
  transform: translateY(0);
  /* Exits DOWNWARD to +100%, which is exactly the resting state of .wipe. The
     old version lifted to -100% and then the class was removed, snapping the
     element from the top back to the bottom — that snap was the hitch. Ending
     where the base rule already sits means there is nothing left to jump to.
     No visibility keyframes either: flipping a discrete property mid-animation
     was the other source of the stutter. */
  animation: wipe-drop 1.5s cubic-bezier(0.7, 0, 0.2, 1) 2.05s forwards;
}
.is-preload .wipe__mark { animation: mark-in 0.5s ease-out 0.15s forwards; }
.is-preload .wipe__word i { animation: letter-up 0.75s cubic-bezier(0.16,1,0.3,1) forwards; }
.is-preload .wipe__word:first-child i:nth-child(1) { animation-delay: 0.20s; }
.is-preload .wipe__word:first-child i:nth-child(2) { animation-delay: 0.27s; }
.is-preload .wipe__word:first-child i:nth-child(3) { animation-delay: 0.34s; }
.is-preload .wipe__word:first-child i:nth-child(4) { animation-delay: 0.41s; }
.is-preload .wipe__word:last-child i               { animation-delay: 0.86s; }
.is-preload .wipe__rule { animation: rule-draw 0.6s cubic-bezier(0.16,1,0.3,1) 0.60s forwards; }

@keyframes mark-in   { to { opacity: 1; } }
@keyframes letter-up { to { transform: translateY(0); } }
@keyframes rule-draw { to { width: min(62vw, 22rem); } }

@keyframes wipe-drop {
  from { transform: translateY(0); }
  to   { transform: translateY(calc(100% + 140px)); }
}

@keyframes wipe-mark {
  0%   { opacity: 0; transform: translateY(18px) scale(0.92); letter-spacing: 0.75em; }
  26%  { opacity: 1; transform: translateY(0)    scale(1);    letter-spacing: 0.34em; }
  70%  { opacity: 1; transform: translateY(0)    scale(1);    letter-spacing: 0.30em; }
  100% { opacity: 0; transform: translateY(-14px) scale(1.04); letter-spacing: 0.22em; }
}

/* ==========================================================================
   DOCK — mobile action bar (replaces the old single floating button)
   ========================================================================== */
.dock {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: var(--z-fab);
  display: none;
  gap: 0.5rem;
  padding: 0.55rem 0.7rem calc(0.55rem + env(safe-area-inset-bottom));
  background: oklch(0.148 0.008 155 / 0.92);
  border-top: 1px solid oklch(1 0 0 / 0.14);
  transform: translateY(110%);
  transition: transform 0.45s var(--ease);
}
.dock.is-on { transform: translateY(0); }
/* The dock is off. Two buttons pinned to the bottom of every screen, on top of
   a bar that already carries the same actions, read as clutter rather than as
   a shortcut. The nav keeps the one CTA. Component kept for a change of mind. */

.dock__btn {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  min-height: 52px;
  border-radius: 100px;
  font-size: 0.95rem;
  font-weight: 800;
  text-decoration: none;
  transition: transform 0.12s var(--ease), filter 0.2s;
}
.dock__btn:active { transform: scale(0.965); }
.dock__btn--wa { background: var(--accent); color: var(--ink); }
.dock__btn--quote {
  background: transparent;
  color: var(--accent);
  border: 1.5px solid var(--accent);
}

/* ==========================================================================
   MOBILE LAYOUT
   Not a narrowed desktop: the grids that only work with width become swipe
   rails, the calculator goes edge to edge with its total pinned, and the
   process becomes a proper vertical timeline.
   ========================================================================== */
@media (max-width: 899px) {

  /* nothing is pinned to the bottom any more */
  body { padding-bottom: 0; }

  /* the spec strip is desktop furniture — on a phone it was a green wall
     between the work and the price */
  .band { display: none; }

  /* ---- chrome ----
     The bar and the dock together held 158px of an 812px screen and carried
     the same two actions. The bar loses its duplicate CTA, gets shorter, and
     turns properly opaque so headings stop reading through it. */
  .nav { padding: 0.5rem var(--gut); }
  /* both of these were a couple of pixels short of a thumb */
  .nav__cta .btn--ghost { min-width: 44px; min-height: 44px; }
  .brand { padding-block: 0.35rem; }

  .nav__inner {
    gap: 0.5rem;
    padding: 0.35rem 0.35rem 0.35rem 0.7rem;
    /* A fixed element blurring everything that passes under it re-renders that
       whole region every scroll frame. It is the second reason the phone
       stuttered, and at 93% opacity there is nothing left to see through. */
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: oklch(0.148 0.008 155 / 0.72);
  }
  .nav__inner::after { display: none; }
  .nav.is-stuck .nav__inner {
    background: oklch(0.148 0.008 155 / 0.93);
    box-shadow: 0 10px 30px oklch(0 0 0 / 0.4);
  }
  /* an in-page link should land the heading below the bar, not behind it */
  section, .band { scroll-margin-top: 82px; }

  /* ---- rhythm ----
     Measured: every section boundary was 126–131px of nothing. --sec is
     padding-block, so it lands on BOTH sides of every seam and doubles —
     3.4rem each side plus the heading's own margin is what produced that.
     2.4rem gives a ~77px seam, which still separates the sections but stops
     each one opening with half a screen of empty. Desktop is untouched. */
  :root { --sec: clamp(1.9rem, 6vw, 5rem); }

  /* The seam is only half of it. Every section also opens with an eyebrow, a
     heading and a heading margin before any real content, and those were all
     still on desktop values. Trimmed together, or closing the seam alone just
     moves the hole down a few pixels. */
  .eyebrow { margin-bottom: 0.6rem; }
  .quote__head { margin-bottom: 1.6rem; }
  .faq h2 { margin-bottom: 1.4rem; }
  .process h2,
  .areas__copy h2,
  .close__lead h2 { margin-bottom: 0.8rem; }
  .areas__copy p { margin-bottom: 1.4rem; }

  /* the same doubling inside the closing block */
  .close__inner { gap: 1.75rem; }
  .fnav { margin-top: 2rem; padding-top: 1.75rem; }
  .close__meta { margin-top: 1.9rem; padding-top: 1.25rem; }

  /* ---- hero: two buttons of equal weight, not a ragged pair ---- */
  .hero__actions { gap: 0.6rem; }
  .hero__actions .btn { flex: 1 1 100%; justify-content: center; }

  /* ---- services: four rows, not a rail ----
     A swipe rail hides the count. The heading promises four surfaces and you
     could only ever see one and a sliver, so the swatch turns into an edge
     band and all four stack where they can be counted at a glance. */
  .chips {
    display: grid;
    grid-auto-flow: row;
    grid-template-columns: 1fr;
    gap: 0.6rem;
    overflow: visible;
    padding-inline: 0;
    margin-inline: 0;
  }
  .chip {
    grid-template-rows: auto;
    grid-template-columns: 74px 1fr;
    align-items: stretch;
  }
  .chip__paint { height: auto; }
  .chip__paint svg { width: 34px; height: 34px; }
  .chip__paint::after { display: none; }
  .chip__body { padding: 0.95rem 1.05rem 1.05rem; }
  .chip h3 { font-size: 1.02rem; margin-bottom: 0.3rem; }
  .chip p { font-size: 0.83rem; line-height: 1.5; }

  /* ---- calculator: full bleed, and the total rides along at the bottom ---- */
  .calc { gap: 0; }
  .calc__controls {
    border-radius: 0;
    border-inline: 0;
    margin-inline: calc(var(--gut) * -1);
    padding-inline: var(--gut);
  }
  /* The total used to dock to the bottom of the screen. At 354px tall it
     covered the call-out control it was meant to sit under, and floating it
     left a hole where it belongs in the flow. It does not need to float: the
     controls are 525px, so slider and total already share one screen. */
  .calc__out {
    position: static;
    border-radius: var(--r);
    margin-top: 0.75rem;
    box-shadow: 0 18px 40px oklch(0 0 0 / 0.28);
  }
  .calc__total { font-size: clamp(2.4rem, 14vw, 3.4rem); }

  /* ---- process: a real vertical timeline ---- */
  .steps {
    grid-template-columns: 1fr;
    gap: 0;
    padding-left: 2.6rem;
  }
  .steps::before {
    display: block;
    left: 0.85rem; right: auto; top: 0.4rem; bottom: 0.4rem;
    width: 2px; height: auto;
    background: var(--line);
    transform: scaleY(var(--draw, 1));
    transform-origin: 50% 0;
  }
  .step { position: relative; padding-block: 1.1rem; }
  .step__n {
    position: absolute;
    left: -2.6rem; top: 1.25rem;
    width: 1.7rem; height: 1.7rem;
    display: grid;
    place-items: center;
    padding: 0;
    margin: 0;
    border-radius: 50%;
    background-image: none;
    background-color: var(--ink);
    color: var(--accent);
    font-size: 0.62rem;
  }

  /* ---- picker: the whole palette, wrapped ----
     Same fault as the cards: on a rail you saw two of the five colours, so you
     could not tell what there was to choose from. */
  .picker__swatches {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.4rem;
  }
  /* sixteen colours: the chip has to be tight or the palette becomes a wall —
     but not so tight that it stops being a thumb-sized target */
  .sw {
    padding: 0.4rem 0.6rem 0.4rem 0.4rem;
    gap: 0.45rem;
    font-size: 0.75rem;
    min-width: 0;
    min-height: 46px;
  }
  .sw::before { width: 20px; height: 20px; flex: none; }
  .sw span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .picker__stage { aspect-ratio: 4 / 3; }

  /* ---- areas: tags, not a table ----
     Fourteen towns on a two-column grid ran seven rows and 650px, because every
     cell was as wide as the longest name. Let each one be its own width and the
     same list wraps into four. */
  .areas__list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    border-top: 0;
  }
  .areas__list li {
    padding: 0.48rem 0.8rem;
    border: 1px solid var(--line);
    border-radius: 100px;
    font-size: 0.72rem;
  }
  .areas__cta .btn { flex: 1; }
}

/* A tablet has the width for two cards abreast — one per row left 600px of
   empty card. Still all four in view, which is the point. */
@media (min-width: 620px) and (max-width: 899px) {
  .chips { grid-template-columns: 1fr 1fr; }
  .picker__swatches { grid-template-columns: repeat(3, 1fr); }
}

/* ==========================================================================
   MOTION PREFERENCES
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .btn:hover, .ccard:hover, .dock__btn:active { transform: none; }
}

/* ==========================================================================
   FINISH — the surface qualities that separate expensive from ordinary.
   No new elements and no layout changes: this is depth, type refinement and
   slower, fewer, better-eased transitions.
   ========================================================================== */

/* ---- Type: tighter and more optical at display sizes ---- */
h1, .hero__title { letter-spacing: -0.042em; }
h2 { letter-spacing: -0.038em; }
.hero__sub, .services__head p, .quote__head p,
.picker__head p, .areas__copy p, .close__lead p {
  line-height: 1.55;
  letter-spacing: -0.005em;
  max-width: 46ch;              /* a measure that actually reads */
}
.chip p, .step p { line-height: 1.6; letter-spacing: -0.003em; }

/* ---- Depth: hairline edge + layered shadow instead of a flat 1px box ---- */
.chip, .calc__controls, .calc__out, .ccard, .picker__stage {
  border-color: oklch(1 0 0 / 0.09);
  box-shadow:
    0 1px 0 oklch(1 0 0 / 0.05) inset,
    0 2px 6px oklch(0 0 0 / 0.22),
    0 12px 28px oklch(0 0 0 / 0.18),
    0 40px 80px oklch(0 0 0 / 0.14);
}
.chip { background-image: linear-gradient(oklch(1 0 0 / 0.028), transparent 42%); }

/* ---- Motion: slower, gentler, unified. Restraint reads as expensive. ---- */
:root { --ease: cubic-bezier(0.22, 1, 0.36, 1); }

.btn { transition-duration: 0.55s; }
.btn:hover { transform: translateY(-2px); }        /* was -3px */
.btn::before { transition-duration: 0.55s; }
.chip { transition: border-color 0.5s var(--ease), box-shadow 0.5s var(--ease); }
.ccard:hover { transform: translateY(-2px); }
.sw:hover { transform: translateY(-1px); }

/* ---- Detail: a focus ring that looks designed, not default ---- */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: 6px;
}

/* ---- The band earns a hairline instead of butting into the sections ---- */
.band { box-shadow: 0 1px 0 oklch(0 0 0 / 0.25) inset, 0 -1px 0 oklch(0 0 0 / 0.25) inset; }

/* ==========================================================================
   MOBILE APPEAR EFFECTS
   Only opacity and transform, which the compositor handles without touching
   layout or paint. `.js-reveal` is set by the inline head script and only when
   scripting is on, so with JS off nothing here applies and nothing is hidden.
   ========================================================================== */
@media (max-width: 899px) {
  .js-reveal [data-reveal],
  .js-reveal .chip,
  .js-reveal .step,
  .js-reveal .ccard,
  .js-reveal .sw,
  .js-reveal .areas__list li,
  .js-reveal .faq__item,
  .js-reveal .fnav__brand,
  .js-reveal .fnav__col,
  .js-reveal .calc__controls,
  .js-reveal .calc__out,
  .js-reveal .picker__stage,
  .js-reveal .quote__head,
  .js-reveal .areas__copy,
  .js-reveal .close__lead,
  .js-reveal .faq h2,
  .js-reveal .process h2 {
    opacity: 0;
    transform: translate3d(0, 18px, 0);
  }
  /* the swatch grid reads better arriving as chips than as rows */
  .js-reveal .sw { transform: translate3d(0, 10px, 0) scale(0.96); }
  .js-reveal .areas__list li { transform: translate3d(0, 10px, 0); }

  /* The doubled class is not a typo and must not be "tidied" away.
     Some of the hiding selectors above end in a type — `.areas__list li`,
     `.faq h2` — which makes them (0,2,1). A plain `.js-reveal .is-in` is
     (0,2,0) and LOSES to them, so those elements were given the class, were
     never revealed, and sat at opacity 0 permanently: the town tags, the FAQ
     heading and the process heading were all invisible on a phone.
     `.is-in.is-in` is (0,3,0) and beats every hiding rule here. */
  .js-reveal .is-in.is-in {
    opacity: 1;
    transform: none;
    transition:
      opacity 0.65s var(--ease) var(--rd, 0ms),
      transform 0.65s var(--ease) var(--rd, 0ms);
  }
}

/* ==========================================================================
   MOBILE PAINT BUDGET
   Decoration a phone re-rasterises while you scroll. Desktop keeps all of it.
   This block has to sit last: the finish pass above sets the same properties
   at the same specificity, and a media query adds none — the first version of
   this lived higher up the file and was silently overridden.
   ========================================================================== */
@media (max-width: 899px) {
  /* An 80px blur radius on nine elements. A shadow that wide is re-rasterised
     across a huge area every time its element repaints, and six of the nine
     sit in the top half of the page. One tight shadow does the same job at
     this size. */
  .chip, .calc__controls, .calc__out, .ccard, .picker__stage {
    box-shadow:
      0 1px 0 oklch(1 0 0 / 0.05) inset,
      0 2px 8px oklch(0 0 0 / 0.3);
  }
  /* nothing hovers on a touch screen, and box-shadow is the expensive half */
  .chip { background-image: none; transition: border-color 0.5s var(--ease); }

  /* A three-function filter on a full-screen photograph. The scrim carries a
     flat ink layer instead, which is a plain composite. */
  .hero__img { filter: none; }
  .hero::after {
    background:
      linear-gradient(to top,
        oklch(0.148 0.008 155) 0%,
        oklch(0.148 0.008 155 / 0.94) 26%,
        oklch(0.148 0.008 155 / 0.62) 52%,
        oklch(0.148 0.008 155 / 0.30) 76%,
        oklch(0.148 0.008 155 / 0.55) 100%),
      oklch(0.148 0.008 155 / 0.24);
  }
}
