/* ==========================================================================
   Wild Made — components
   ========================================================================== */

/* --- Logo ---------------------------------------------------------------- */

/* Space Grotesk appears here and NOWHERE else. */
.wordmark {
  font-family: var(--font-wordmark);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
  white-space: nowrap;
}

.pixel-mark { display: block; flex: none; }
.pixel-mark rect { fill: var(--teal); }

/* Animated hero lockup: pixel W → typed "ild Made" → typeset W */
.lockup {
  display: inline-flex;
  align-items: center;
  font-size: clamp(2.25rem, 1.4rem + 4vw, 4rem);   /* 36 → 64 */
  line-height: 1;
}
.lockup__w {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.lockup__w-type { opacity: 0; transition: opacity var(--dur-slow) var(--ease); }
.lockup__w-pixel {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 0.72em; height: 0.72em;
  opacity: 1;
  transition: opacity var(--dur-slow) var(--ease);
}
.lockup__rest { white-space: pre; }
.lockup__cursor {
  display: inline-block;
  width: 0.11em;
  height: 1.16em;
  background: var(--teal);
  margin-left: 0.18em;
  opacity: 0;
}
.lockup__cursor.is-blinking { animation: cursor-blink 1s steps(1) infinite; }
@keyframes cursor-blink { 0%,49% { opacity: 1; } 50%,100% { opacity: 0; } }

/* Resting state — also the no-JS and reduced-motion state. */
.lockup.is-rest .lockup__w-type  { opacity: 1; }
.lockup.is-rest .lockup__w-pixel { opacity: 0; }
.lockup.is-rest .lockup__cursor  { opacity: 1; animation: none; }

.lockup--replayable {
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
  min-height: var(--tap);
  color: inherit;
}

/* --- Site header --------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: var(--hairline);
}
/* Vertical padding lives on the nav links and the brand, not here — that's what
   turns them into 44px touch targets without making the type any bigger. The
   header ends up ~52px tall, four more than before. */
.site-header__inner {
  max-width: var(--wrap);
  margin-inline: auto;
  padding: var(--s-1) var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
}
/* min-width matters once the wordmark is hidden below 480px and the brand link
   is a bare 20px mark — the target grows to the right, the mark stays on the
   gutter. */
.site-header__brand {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  min-width: var(--tap);
  gap: var(--s-3);
  text-decoration: none;
}
.site-header__brand .wordmark { font-size: 1.0625rem; }

/* On the home page the hero already carries a large animated lockup, so the
   header wordmark stays hidden until you scroll past it — no duplicate
   wordmark in the first viewport. Non-home pages get it immediately. */
.site-header__brand[data-reveal="scroll"] .wordmark {
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.site-header.is-scrolled .site-header__brand[data-reveal="scroll"] .wordmark {
  opacity: 1;
  transform: none;
}

.site-nav { display: flex; align-items: center; gap: var(--s-4); }
.site-nav__list {
  display: flex;
  gap: var(--s-2);
  margin: 0; padding: 0;
  list-style: none;
}
/* The padding is the point: 14px above and below a 13px line takes the tap
   area to 44px while the label itself stays exactly the same size.

   Scoped to __list, not to .site-nav a: the button beside the list is also an
   anchor, so the looser selector outranked .btn--accent on colour (0,1,1 beats
   0,1,0) and painted a white-on-teal button ink-at-70%-opacity instead — about
   2.4:1, unreadable. Keep link styling on the links. */
.site-nav__list a {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding-inline: var(--s-3);
  font-size: var(--fs-caption);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--ink);
  text-decoration: none;
  opacity: 0.7;
}
.site-nav__list a:hover,
.site-nav__list a[aria-current="page"] { opacity: 1; color: var(--teal-deep); }

@media (max-width: 640px) {
  /* Pull the last link's padding back to the gutter so the row still lines up
     with the right-hand edge of the content. */
  .site-nav__list { margin-right: calc(var(--s-3) * -1); }
  /* The button repeats a destination that is already in the list beside it, so
     it is the first thing to drop when the row runs out of room. A --solo nav
     has no list behind it — there the button IS the navigation (the preview
     pages), and hiding it leaves a prospect on a phone with nothing to tap. */
  .site-nav:not(.site-nav--solo) .btn { display: none; }
}

/* Below this the wordmark and three 44px-wide nav links cannot both fit — at
   320px they overflow by ~77px. The pixel mark is the logo's own small form
   (it is the favicon), the brand link keeps its aria-label, and the wordmark
   is still on screen in the hero and the footer. Losing it here costs less
   than a cramped nav or a tap target under the minimum. */
@media (max-width: 480px) {
  .site-header__brand .wordmark { display: none; }
  .site-nav__list a { padding-inline: var(--s-2); }
  .site-nav__list { margin-right: calc(var(--s-2) * -1); }
}

/* --- Buttons ------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: var(--tap);
  font-size: var(--fs-ui);
  font-weight: 600;
  line-height: 1.4;
  padding: 0.65rem 1.15rem;
  border-radius: var(--r);
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
.btn--primary { background: var(--ink); color: var(--paper); }
.btn--primary:hover { background: #000; color: var(--paper); }

/* White-on-teal needs the accessible variant to clear 4.5:1 */
.btn--accent { background: var(--teal-deep); color: var(--paper); }
.btn--accent:hover { background: var(--ink); color: var(--paper); }

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

.btn-row { display: flex; flex-wrap: wrap; gap: var(--s-3); }

/* Cursor motif from the logo, as the tick on every section label.

   This was once-per-page by design (PLAN §6b, same logic as the accent bar:
   it stays meaningful by staying rare). Changed deliberately — every eyebrow
   now carries it, so the label set reads as one typed system rather than one
   label wearing a decoration.

   Generated with ::after rather than a <span> in the markup: 14 labels across
   7 files, and this way none of them can forget it, double it up, or drift.
   Add a .eyebrow anywhere and it inherits the tick for free.

   The stagger is the point. Fired together, four cursors on a long page blink
   in lockstep and read as a strobe; offset, they read as separate terminals
   left running. Delays are negative so every cursor is already mid-cycle on
   load — nothing waits to start. */
.eyebrow::after {
  content: "";
  display: inline-block;
  width: 3px;
  height: 0.95em;
  background: var(--teal);
  margin-left: 0.4em;
  vertical-align: -0.12em;
  animation: cursor-blink 1.1s steps(1) infinite;
}
.section:nth-of-type(4n+2) .eyebrow::after { animation-delay: -0.27s; }
.section:nth-of-type(4n+3) .eyebrow::after { animation-delay: -0.55s; }
.section:nth-of-type(4n)   .eyebrow::after { animation-delay: -0.82s; }

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

/* --- Accent bar ----------------------------------------------------------
   Brand rule: one per screen or section, maximum. Teal only. */
.accent-bar {
  border-left: 4px solid var(--teal);
  padding: var(--s-1) 0 var(--s-1) var(--s-5);
  max-width: 34rem;
}
.accent-bar p {
  font-size: var(--fs-body-lg);
  font-weight: 500;
  line-height: 1.55;
}

/* --- Cards --------------------------------------------------------------- */

.grid { display: grid; gap: var(--s-4); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 800px) { .grid--3 { grid-template-columns: 1fr; } }
@media (max-width: 640px) { .grid--2 { grid-template-columns: 1fr; } }

.card {
  border: var(--hairline);
  border-radius: var(--r-lg);
  padding: var(--s-5);
}
.card h3 { margin-bottom: var(--s-3); }
.card p  { font-size: var(--fs-sm); line-height: 1.65; color: var(--muted); margin: 0; }

/* Numbered process steps */
.steps { counter-reset: step; list-style: none; margin: 0; padding: 0; }
.steps li {
  counter-increment: step;
  position: relative;
  padding: var(--s-5) 0 var(--s-5) 3.25rem;
  border-bottom: var(--hairline);
}
.steps li:last-child { border-bottom: 0; padding-bottom: 0; }
.steps li::before {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0; top: var(--s-5);
  font-size: var(--fs-caption);
  font-weight: 700;
  color: var(--teal-deep);
  letter-spacing: 0.08em;
}
.steps h3 { margin-bottom: var(--s-2); }
.steps p  { font-size: var(--fs-sm); color: var(--muted); max-width: var(--measure); margin: 0; }

/* Checklist — what's included / not included */
.list-check { list-style: none; margin: 0; padding: 0; }
.list-check li {
  position: relative;
  padding: var(--s-3) 0 var(--s-3) var(--s-6);
  border-bottom: var(--hairline);
  font-size: var(--fs-sm);
  line-height: 1.6;
}
.list-check li:last-child { border-bottom: 0; }
.list-check li::before {
  position: absolute; left: 0; top: var(--s-3);
  font-weight: 700;
}
.list-check--yes li::before { content: "✓"; color: var(--teal-deep); }
.list-check--no  li::before { content: "—"; color: var(--muted); }

/* --- Tag chip ------------------------------------------------------------ */
.chip {
  display: inline-block;
  font-size: var(--fs-caption);
  font-weight: 600;
  background: var(--teal-tint);
  color: var(--teal-deep);
  padding: 0.25rem 0.7rem;
  border-radius: 999px;
  letter-spacing: 0.02em;
}
.chip--plain { background: var(--surface); color: var(--muted); }

/* --- Before/after compare ------------------------------------------------ */

.compare {
  position: relative;
  border: var(--hairline);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--paper);
  touch-action: pan-y;
  container-type: inline-size;
}

/* ---- Narrow screens ------------------------------------------------------
   A desktop layout rendered into a ~300px pane puts its body copy under 10px.
   Illegible — and fatal on a site whose argument is "your site is unreadable
   on a phone". So below 700px the widget stops being a landscape drag and
   becomes an honest stack:

     BEFORE — the desktop site at its true 980px design width, zoomed down to
              fit a phone. Exactly what a non-responsive site does on iOS:
              microscopic text, pinch to zoom. The illegibility IS the point.
     AFTER  — the actual mobile layout, at a readable size.

   zoom (not transform) so the layout box shrinks with it and no manual
   heights are needed.
   ------------------------------------------------------------------------ */

/* Selectors are .compare-prefixed so they outrank the .mini / .mini--after
   base rules defined further down this file. */
.compare .mob-frame { display: none; }

@container (max-width: 700px) {
  .compare .mini--after { display: none; }
  .compare .mob-frame   { display: block; }

  /* Both panes present as a phone-width column, so the comparison is
     like-for-like: the same page, on the same screen, before and after.
     The zoom maps the 980px desktop layout down to ~353px — phone width. */
  .compare .mini--before {
    width: 980px;
    height: auto;           /* hug the content; a fixed height leaves dead space */
    aspect-ratio: auto;
    font-size: 13px;        /* render at true desktop scale, then zoom down */
    zoom: 0.36;
    margin-inline: auto;
  }
  .compare .mob-frame .mob {
    max-width: 356px;
    margin-inline: auto;
  }
  .compare .compare__pane { padding-block: var(--s-4); }
}

/* Very narrow screens — shrink further so the before still fits. */
@container (max-width: 400px) {
  .compare .mini--before { zoom: 0.28; }
  .compare .mob-frame .mob { max-width: 100%; }
}

/* Keep the stacked "after" to a sensible height — the first few sections make
   the point without turning the page into a scroll marathon. Counted in
   elements, not in .mob__sec: the bar is the first div, so this leaves the
   hero, the services and the reviews, then the footer closes it off. */
.compare .mob-frame .mob__sec:nth-of-type(n+5) { display: none; }
.compare__pane { position: relative; }
.compare__pane--after {
  position: absolute;
  inset: 0;
  /* Set by JS. Static fallback below keeps it usable with no JS. */
  clip-path: inset(0 0 0 50%);
  will-change: clip-path;
}
.compare__handle {
  position: absolute;
  top: 0; bottom: 0;
  left: 50%;
  width: 48px;
  margin-left: -24px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: ew-resize;
  background: none;
  border: 0;
  padding: 0;
  z-index: 3;
}
.compare__handle::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 50%;
  width: 2px;
  margin-left: -1px;
  background: var(--paper);
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.16);
}
.compare__grip {
  position: relative;
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--paper);
  border: 2px solid var(--paper);
  box-shadow: 0 2px 10px rgb(0 0 0 / 0.22);
  display: flex; align-items: center; justify-content: center;
  color: var(--ink);
  font-size: 11px;
  letter-spacing: -0.05em;
}
/* Labels live inside their own pane, so they travel with it when the widget
   stacks on mobile. */
.compare__label {
  position: absolute;
  top: var(--s-3);
  z-index: 2;
  font-size: var(--fs-caption);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  padding: 0.2rem 0.55rem;
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  color: var(--muted);
  pointer-events: none;
}
.compare__pane--before .compare__label { left: var(--s-3); }
.compare__pane--after  .compare__label { right: var(--s-3); color: var(--teal-deep); }

/* The affordance, stated where the interaction actually is rather than in the
   copy further up the page — because it is only true in drag mode. Below 700px
   the widget is a stack with no handle to drag, so the hint goes with it. The
   page must never instruct a phone user to do something the page won't let
   them do; that is the exact failure this site is selling against. */
.compare__hint {
  position: absolute;
  bottom: var(--s-3);
  left: 50%;
  transform: translateX(-50%);
  z-index: 4;
  font-size: var(--fs-caption);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  padding: 0.2rem 0.55rem;
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  color: var(--muted);
  pointer-events: none;
  white-space: nowrap;
}
@container (max-width: 700px) { .compare__hint { display: none; } }
.compare.is-stacked .compare__hint,
.no-js .compare__hint { display: none; }

/* Stacked mode — used with no JS, and on narrow screens (see below).
   `relative`, not `static`: it lays out in flow either way, but static would
   hand the absolutely-positioned "After" label back to .compare as its
   containing block — which parked it in the top-right corner of the BEFORE
   pane, labelling the dated site as the redesign. */
.compare.is-stacked .compare__pane--after,
.no-js .compare__pane--after {
  position: relative;
  inset: auto;
  clip-path: none !important;
  border-top: var(--hairline);
}
.compare.is-stacked .compare__handle,
.no-js .compare__handle { display: none; }

/* --- Miniature site renders ---------------------------------------------
   The before/after panes are live HTML, not screenshots — sharp at any
   resolution, responsive, and near-zero weight. Everything is scoped under
   .mini so it cannot leak into the real page.
   ------------------------------------------------------------------------ */

.mini {
  --mini-pad: clamp(0.75rem, 0.4rem + 1.2vw, 1.5rem);
  /* Wide enough to read as a browser window, short enough that neither page
     leaves a slab of dead white below its content. */
  aspect-ratio: 2 / 1;
  overflow: hidden;
  container-type: inline-size;
  font-size: clamp(9px, 0.55rem + 0.55vw, 13px);
  line-height: 1.45;
}

/* --- BEFORE: an authentically dated small-business site ------------------ */
.mini--before {
  background: #fff;
  font-family: 'Times New Roman', Times, serif;
  color: #222;
}
.mini--before .mini__bar {
  background: linear-gradient(#3a6ea5, #1e4a7a);
  color: #fff;
  padding: 0.7em var(--mini-pad);
  text-align: center;
}
.mini--before .mini__logo { font-size: 1.85em; font-weight: bold; text-shadow: 1px 1px 2px rgb(0 0 0 / 0.5); }
.mini--before .mini__tag  { font-size: 0.95em; font-style: italic; }
.mini--before .mini__nav {
  background: #ddd;
  border-bottom: 1px solid #999;
  padding: 0.35em var(--mini-pad);
  text-align: center;
  font-size: 0.9em;
}
.mini--before .mini__nav span { color: #00c; text-decoration: underline; margin: 0 0.5em; }
.mini--before .mini__body { padding: var(--mini-pad); text-align: center; }
.mini--before .mini__h { font-size: 1.15em; font-weight: bold; margin-bottom: 0.5em; }
.mini--before .mini__p { font-size: 0.92em; margin-bottom: 0.8em; }
.mini--before .mini__cols { display: flex; gap: 0.6em; justify-content: center; font-size: 0.85em; }
.mini--before .mini__col { border: 1px solid #bbb; padding: 0.5em; flex: 1; }
.mini--before .mini__news {
  margin-top: 1em;
  border: 1px solid #bbb;
  background: #f4f4f0;
  padding: 0.6em 0.8em;
  text-align: left;
  font-size: 0.82em;
  line-height: 1.5;
}
.mini--before .mini__news b { display: block; margin-bottom: 0.3em; }
.mini--before .mini__news div { margin-bottom: 0.3em; }
.mini--before .mini__hit { margin-top: 0.9em; font-size: 0.8em; color: #666; }
.mini--before .mini__foot {
  margin-top: 1.4em;
  padding-top: 0.7em;
  border-top: 1px solid #ccc;
  font-size: 0.78em;
  color: #555;
  line-height: 1.5;
}

/* --- AFTER: the redesign -------------------------------------------------
   Deliberately NOT the Wild Made design system, and that is the entire point
   of the section. A prospect looking at this has to see *their* website. If
   the mockup turns up wearing my typeface and my teal, the honest reading is
   "he's going to drop me into his own template" — which is the opposite of
   what's being sold.

   So it gets a heating engineer's design language instead: a proportional
   sans against the brand's mono, navy and flame against teal, photographs of
   the work against white space, and buttons sized for a cold hand outdoors.

   Every value is scoped to --hp-* on the two mockup roots. Nothing below
   references a Wild Made token and nothing leaks out. To re-skin a preview
   for a different trade, override the colours on the mockup root itself:

     <div class="mob" style="--hp-navy:#2F4536; --hp-flame:#8A5A2B;">

   Keep white text on --hp-flame above 4.5:1 if you change it — the whole
   site argues for usability, so the mockups have to pass too.
   ------------------------------------------------------------------------ */

.mini--after,
.mob {
  --hp-navy:    #0F2A44;   /* white on it: 14.6:1 */
  --hp-flame:   #C8461A;   /* white on it:  4.8:1 — the only CTA colour */
  --hp-amber:   #E8A33A;   /* stars and the logo mark; decorative only */
  --hp-sand:    #F7F4EF;
  --hp-line:    #E4DED4;
  --hp-ink:     #17262F;
  --hp-body:    #4C4C48;   /* on white: 8.6:1 */
  --hp-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
             'Helvetica Neue', Arial, sans-serif;
}

/* Every img here sits in a box with a definite height (aspect-ratio or a
   fixed thumb), so cover-cropping is safe and layout never depends on the
   file having loaded — which is what keeps the phone's scroll maths stable. */
.mini--after img,
.mob img { display: block; width: 100%; height: 100%; object-fit: cover; }

.mini--after {
  background: #fff;
  font-family: var(--hp-font);
  color: var(--hp-ink);
  display: flex;
  flex-direction: column;
}

/* The number, above everything, before the visitor has done anything.
   Left-aligned rather than pushed to both ends: the widget's own "After"
   label is absolutely positioned in the top-right corner of this pane, and
   anything parked out there gets sat on. */
.mini__util {
  display: flex; align-items: center; gap: 1.4em;
  background: var(--hp-navy);
  color: #C6D5E4;
  padding: 0.5em var(--mini-pad);
  font-size: 0.78em;
}
.mini__util b { color: #fff; }

.mini--after .mini__bar {
  display: flex; align-items: center; gap: 1.3em;
  padding: 0.75em var(--mini-pad);
  border-bottom: 1px solid var(--hp-line);
}
.mini--after .mini__logo {
  display: flex; align-items: center; gap: 0.55em;
  font-weight: 800; font-size: 1.05em; letter-spacing: -0.015em;
  color: var(--hp-navy);
}
.mini--after .mini__logo b { font-weight: 400; color: var(--hp-body); }
.mini__mark {
  width: 2em; height: 2em; flex: none;
  border-radius: 5px;
  background: var(--hp-navy);
  padding: 0.4em;
  fill: var(--hp-amber);
}
.mini--after .mini__nav {
  display: flex; gap: 1.15em;
  margin-left: auto;
  font-size: 0.82em; font-weight: 600; color: var(--hp-body);
}
.mini--after .mini__cta {
  background: var(--hp-flame); color: #fff;
  padding: 0.6em 1em; border-radius: 6px;
  font-size: 0.82em; font-weight: 700;
}

.mini__hero {
  flex: 1; min-height: 0;
  display: grid; grid-template-columns: 1.05fr 0.95fr;
}
.mini__hero-copy {
  background: var(--hp-sand);
  padding: var(--mini-pad);
  display: flex; flex-direction: column; justify-content: center;
}
.mini__kicker {
  font-size: 0.72em; font-weight: 800; text-transform: uppercase;
  letter-spacing: 0.09em; color: var(--hp-flame); margin-bottom: 0.8em;
}
.mini--after .mini__h {
  font-size: 2.05em; font-weight: 800; line-height: 1.04;
  letter-spacing: -0.03em; margin-bottom: 0.4em; max-width: 12ch;
  color: var(--hp-navy);
}
.mini--after .mini__p {
  font-size: 0.9em; color: var(--hp-body); line-height: 1.5;
  max-width: 32ch; margin-bottom: 1.05em;
}
.mini--after .mini__row { display: flex; flex-wrap: wrap; gap: 0.5em; margin-bottom: 1em; }
.mini--after .mini__btn {
  padding: 0.7em 1.05em; border-radius: 7px; font-size: 0.85em; font-weight: 700;
  background: var(--hp-flame); color: #fff;
}
.mini--after .mini__btn--alt {
  background: #fff; color: var(--hp-navy); border: 1.5px solid var(--hp-navy);
}
.mini__trust {
  display: flex; align-items: center; gap: 0.45em;
  font-size: 0.8em; font-weight: 600; color: var(--hp-body);
}
.mini--after .mini__stars { color: var(--hp-amber); letter-spacing: 0.06em; }

.mini__hero-media { position: relative; overflow: hidden; }
.mini__badge {
  position: absolute; left: 0; bottom: 0;
  background: var(--hp-navy); color: #fff;
  font-size: 0.72em; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase;
  padding: 0.55em 0.9em;
  border-top-right-radius: 7px;
}

.mini__strip { display: flex; border-top: 1px solid var(--hp-line); }
.mini__strip > div {
  flex: 1;
  padding: 0.8em 1em;
  border-left: 1px solid var(--hp-line);
  font-size: 0.78em; color: var(--hp-body);
}
.mini__strip > div:first-child { border-left: 0; }
.mini__strip b {
  display: block; margin-bottom: 0.15em;
  font-size: 1.05em; font-weight: 700; color: var(--hp-navy);
}

/* --- Phone frame --------------------------------------------------------- */

.phone {
  --phone-w: 260px;
  width: var(--phone-w);
  flex: none;
  border: 9px solid #17171A;
  border-radius: 34px;
  background: #17171A;
  box-shadow: 0 18px 45px -18px rgb(0 0 0 / 0.4);
  overflow: hidden;
  position: relative;
}
.phone::before {           /* notch */
  content: "";
  position: absolute;
  top: 0; left: 50%;
  transform: translateX(-50%);
  width: 84px; height: 17px;
  background: #17171A;
  border-radius: 0 0 11px 11px;
  z-index: 3;
}
.phone__screen {
  position: relative;
  height: 500px;
  overflow: hidden;
  border-radius: 25px;
  background: var(--paper);
}
.phone__scroller {
  will-change: transform;
  transition: transform 90ms linear;
}
@media (prefers-reduced-motion: reduce) {
  .phone__scroller { transition: none; }
}

.phone-demo {
  display: flex;
  gap: var(--s-7);
  align-items: center;
  flex-wrap: wrap;
}
.phone-demo__copy { flex: 1 1 20rem; min-width: 0; }

/* Mobile render of the redesign, inside the phone.
   Shares the --hp-* palette declared with .mini--after above. Every block
   below has to survive being used *without* its photo, because
   preview/_template.html builds a prospect mockup from these same classes
   and a new prospect has sent no photographs yet. */
.mob {
  font-family: var(--hp-font);
  color: var(--hp-ink);
  background: #fff;
  font-size: 12px;
  line-height: 1.5;
}
.mob__bar {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  /* Top padding clears the phone frame's notch (17px tall). The logo is now
     a mark plus two words, so it reaches far enough across to sit under it. */
  padding: 27px 14px 12px;
  border-bottom: 1px solid var(--hp-line);
}
.mob__logo {
  display: flex; align-items: center; gap: 7px;
  font-weight: 800; font-size: 13.5px; letter-spacing: -0.015em;
  color: var(--hp-navy);
}
.mob__logo b { font-weight: 400; color: var(--hp-body); }
.mob__mark {
  width: 24px; height: 24px; flex: none;
  border-radius: 6px; padding: 5px;
  background: var(--hp-navy); fill: var(--hp-amber);
}
/* The call pill, not a hamburger. A menu hides the one thing they came for. */
.mob__call {
  background: var(--hp-flame); color: #fff;
  padding: 9px 15px; border-radius: 999px;
  font-size: 11.5px; font-weight: 700;
}
.mob__burger { display: grid; gap: 3px; }
.mob__burger i { display: block; width: 18px; height: 2px; border-radius: 2px; background: var(--hp-navy); }

.mob__sec { padding: 18px 14px; border-bottom: 1px solid var(--hp-line); }

/* Hero. The photo carries the headline; the buttons sit below it on solid
   ground, because a tap target over a busy image is a tap target you can't
   see the edges of. */
.mob__sec--hero { padding: 0; border-bottom: 0; }
.mob__hero { position: relative; aspect-ratio: 4 / 3; display: flex; align-items: flex-end; }
.mob__hero img { position: absolute; inset: 0; }
.mob__hero::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgb(15 42 68 / 0.10) 0%, rgb(15 42 68 / 0.70) 55%, rgb(15 42 68 / 0.95) 100%);
}
.mob__hero-in { position: relative; z-index: 1; padding: 14px; }
.mob__kicker {
  display: inline-block;
  background: var(--hp-flame); color: #fff;
  font-size: 9.5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.1em;
  padding: 4px 8px; border-radius: 4px; margin-bottom: 9px;
}
.mob__hero .mob__h { color: #fff; }
.mob__hero .mob__p { color: rgb(255 255 255 / 0.88); margin: 0; }
.mob__actions { padding: 14px; border-bottom: 1px solid var(--hp-line); }

.mob__h {
  font-size: 23px; font-weight: 800; line-height: 1.08;
  letter-spacing: -0.03em; margin: 0 0 8px; color: var(--hp-navy);
}
.mob__p { color: var(--hp-body); font-size: 12.5px; line-height: 1.55; margin: 0 0 14px; }
.mob__btn {
  display: block; text-align: center;
  background: var(--hp-flame); color: #fff;
  padding: 14px; border-radius: 8px;
  font-size: 13.5px; font-weight: 700; margin-bottom: 8px;
}
.mob__btn--alt { background: #fff; color: var(--hp-navy); border: 1.5px solid var(--hp-navy); }
.mob__trust {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  margin-top: 12px;
  font-size: 11.5px; font-weight: 600; color: var(--hp-body);
}
.mob__label {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--hp-flame); font-weight: 800; margin-bottom: 10px;
}
.mob__card {
  border: 1px solid var(--hp-line); border-radius: 9px;
  background: #fff;
  padding: 10px; margin-bottom: 8px;
  box-shadow: 0 1px 2px rgb(15 42 68 / 0.05);
}
/* Only the cards that have a photo go sideways. The plain .mob__card stays a
   block so the reviews card — stars, then quote, then name — still stacks. */
.mob__card--media { display: flex; align-items: center; gap: 11px; }
.mob__thumb { width: 58px; height: 58px; flex: none; border-radius: 6px; overflow: hidden; }
.mob__card b { display: block; font-size: 12.5px; font-weight: 700; color: var(--hp-navy); margin-bottom: 2px; }
.mob__card span { display: block; color: var(--hp-body); font-size: 11px; line-height: 1.45; }
.mob__stars { color: var(--hp-amber); font-size: 11.5px; letter-spacing: 0.1em; }

.mob__sec--reviews { background: var(--hp-navy); border-bottom: 0; }
.mob__sec--reviews .mob__label { color: var(--hp-amber); }
.mob__sec--reviews .mob__card {
  background: rgb(255 255 255 / 0.07);
  border-color: rgb(255 255 255 / 0.18);
  box-shadow: none;
}
.mob__sec--reviews .mob__card b { color: #fff; }
.mob__sec--reviews .mob__card span { color: rgb(255 255 255 / 0.78); }
/* Three classes deep on purpose — the rule above is (0,2,1) and would
   otherwise repaint the stars in body-text grey. */
.mob__sec--reviews .mob__card .mob__stars { color: var(--hp-amber); }

.mob__map { aspect-ratio: 16 / 9; border-radius: 9px; overflow: hidden; margin-bottom: 11px; }

.mob__foot {
  padding: 16px 14px 20px;
  background: var(--hp-navy); color: rgb(255 255 255 / 0.72);
  font-size: 11px; line-height: 1.6;
}
.mob__foot b { display: block; color: #fff; font-size: 12.5px; font-weight: 700; margin-bottom: 4px; }

/* --- Contact layout ------------------------------------------------------ */

.contact-cols {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: var(--s-8);
  align-items: start;
}
@media (max-width: 800px) {
  .contact-cols { grid-template-columns: 1fr; gap: var(--s-7); }
}

.note-box {
  margin-top: var(--s-6);
  border: var(--hairline);
  border-radius: var(--r-lg);
  background: var(--surface);
  padding: var(--s-5);
}
.note-box h3 { margin-bottom: var(--s-3); }
.note-box p  { font-size: var(--fs-sm); color: var(--muted); margin: 0; line-height: 1.65; }

/* --- Form ---------------------------------------------------------------- */

.field { margin-bottom: var(--s-5); }

.field label {
  display: block;
  font-size: var(--fs-h3);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  margin-bottom: var(--s-2);
}
.field__opt {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  color: var(--muted);
}

.field input,
.field textarea {
  width: 100%;
  font-family: var(--font-mono);
  font-size: var(--fs-body);
  line-height: 1.5;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 0.7rem 0.85rem;
  transition: border-color var(--dur-fast) var(--ease);
}
.field textarea { resize: vertical; min-height: 7rem; }

.field input:hover,
.field textarea:hover { border-color: var(--muted); }

.field input:focus-visible,
.field textarea:focus-visible {
  border-color: var(--teal-deep);
  outline: var(--focus-ring);
  outline-offset: 1px;
}

/* Only flag an invalid field once the user has actually typed something —
   :invalid alone shouts at empty required fields before anyone has started. */
.field input:not(:placeholder-shown):invalid,
.field textarea:not(:placeholder-shown):invalid { border-color: #B3413A; }

/* Honeypot — hidden from people, still reachable by bots that ignore CSS. */
.field--trap {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* --- Bio / portrait ------------------------------------------------------ */

.bio {
  display: flex;
  gap: var(--s-7);
  align-items: flex-start;
  flex-wrap: wrap;
}
.bio__text { flex: 1 1 26rem; min-width: 0; }

.portrait { flex: 0 0 260px; margin: 0; }
@media (max-width: 700px) {
  .portrait { flex-basis: 100%; max-width: 260px; }
}
.portrait img {
  width: 100%;
  border-radius: var(--r-lg);
  border: var(--hairline);
}
.portrait figcaption { margin-top: var(--s-3); }

/* --- Concept disclaimer --------------------------------------------------
   Used by preview/_template.html, where it is required on every page. /work/
   carries its statement in the accent bar instead — one per page, not three. */
.disclaimer {
  font-size: var(--fs-caption);
  color: var(--muted);
  line-height: 1.55;
  border-top: var(--hairline);
  padding-top: var(--s-3);
  margin-top: var(--s-4);
}

/* --- Footer -------------------------------------------------------------- */

.site-footer {
  border-top: var(--hairline);
  padding-block: var(--s-7) var(--s-8);
  font-size: var(--fs-caption);
  color: var(--muted);
}
.site-footer__inner {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-5);
  justify-content: space-between;
  align-items: flex-start;
}
.site-footer a { color: var(--muted); text-decoration: none; }
.site-footer a:hover { color: var(--teal-deep); text-decoration: underline; }

/* The brand row is identical on all seven pages. It lives here rather than as
   an inline style repeated in each one, so the values stay in a single place. */
.site-footer__brand {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-2);
}
.site-footer__brand .wordmark { font-size: 0.95rem; }
.site-footer__tagline { margin: 0; }

/* Same 44px treatment as the nav. The negative inline margin keeps the first
   link flush with the column above it despite the new padding. */
.site-footer__links {
  display: flex;
  gap: var(--s-1);
  flex-wrap: wrap;
  margin-inline: calc(var(--s-3) * -1);
}
.site-footer__links a {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  min-width: var(--tap);
  justify-content: center;
  padding-inline: var(--s-3);
}

/* --- Big email CTA ------------------------------------------------------- */
.email-cta {
  font-size: clamp(1.25rem, 0.8rem + 2.2vw, 2rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 3px solid var(--teal);
  padding-bottom: 0.1em;
  display: inline-flex;
  align-items: flex-end;
  min-height: var(--tap);
  word-break: break-word;
}

/* A text link that stands alone as the action for its block — not one sitting
   inside a sentence, which WCAG exempts. Reads as a link, taps like a button. */
.link-action {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-weight: 600;
}
.email-cta:hover { color: var(--teal-deep); }

/* --- Scroll reveal (subtle, opt-out) -------------------------------------
   Content is VISIBLE by default. The hidden state is only applied once
   site.js has confirmed IntersectionObserver support and that reduced motion
   is off — so a failed script, a throttled background tab, or a mid-page
   entry can never leave the page blank. Never invert this. */
.reveal { opacity: 1; transform: none; }

html.can-reveal .reveal:not(.is-in) {
  opacity: 0;
  transform: translateY(10px);
}
html.can-reveal .reveal {
  transition: opacity 500ms var(--ease), transform 500ms var(--ease);
}

@media (prefers-reduced-motion: reduce) {
  html.can-reveal .reveal:not(.is-in) { opacity: 1; transform: none; }
}
