/* ==========================================================================
   ETC (Et Cetera) Business Systems — Site Stylesheet
   Brand tokens pulled directly from the logo: near-black "etc" wordmark +
   soft periwinkle-blue "c". --brand-primary is a darkened, accessible
   version of the logo blue (for buttons/links on white); --brand-primary-light
   is the true logo blue, used for soft fills, badges and backgrounds.
   ========================================================================== */

:root {
  /* ---- Brand tokens (sourced from the ETC logo) ---- */
  --brand-dark:      #15171c;   /* near-black from the logo mark — header/footer bg */
  --brand-primary:   #53719c;   /* accessible darkened logo-blue — buttons, links, headings accents */
  --brand-primary-dark: #3f5878; /* hover/active state */
  --brand-primary-light: #8ab0e8; /* true logo blue — soft fills, badges, highlights */
  --brand-accent:    #8ab0e8;   /* secondary accent — small highlights only (alias of logo blue) */
  /* The same two blues as bare channel triplets, so every soft tint on the page
     — hero wash, chips, icon tiles, card glows — is rgba(var(--brand-primary-rgb), a)
     instead of a literal. Re-tinting the brand stays a one-line change, and dark
     mode re-tints with it rather than keeping the light-mode blue in every wash. */
  --brand-primary-rgb: 83, 113, 156;
  --brand-light-rgb:   138, 176, 232;
  --brand-dark-2:    #2b3242;   /* far end of the dark gradients (CTA banner, contact card) */

  /* ---- Neutrals ---- */
  --surface:         #ffffff;
  --surface-alt:      #f6f7fb;
  /* Bottom stop of a card's vertical surface gradient. A card is never a flat
     fill — it falls off very slightly toward its lower edge, which is most of
     what separates "a panel" from "a rectangle". */
  --surface-sunken:  #f7f9fd;
  /* The sticky header sits over the page and blurs what is behind it. */
  --surface-veil:    rgba(255, 255, 255, 0.85);
  --border:          #e4e7ee;
  --border-strong:   #d2d7e3;   /* outline buttons and inputs, which must read as edges */
  --text-primary:    #16192b;
  --text-secondary:  #545a72;
  /* Darkened from #8a90a6, which measured 3.1:1 on white and failed at every
     size it was used: captions, breadcrumbs, form notes, review bylines. */
  --text-muted:      #666d87;
  /* Text that sits ON a --brand-primary fill. White works on the darkened
     light-mode blue; dark mode lightens that blue, so this flips with it. */
  --on-brand:        #ffffff;

  /* Ink for the surfaces that are dark in BOTH themes — the footer, the CTA
     banner, the contact info card, a photo scrim. These deliberately do NOT
     flip: the ground under them never gets lighter. They are tokens so the
     opacities stay consistent instead of being re-guessed at each use. */
  --on-dark:         #ffffff;
  --on-dark-soft:    rgba(255, 255, 255, 0.74);  /* body copy on dark */
  --on-dark-muted:   rgba(255, 255, 255, 0.54);  /* labels, fine print */
  --on-dark-line:    rgba(255, 255, 255, 0.12);  /* hairline rules */
  --on-dark-edge:    rgba(255, 255, 255, 0.30);  /* outline-button borders */
  --on-dark-fill:    rgba(255, 255, 255, 0.08);  /* soft fills, icon tiles */
  --on-dark-hover:   #eef1f8;                    /* the white button, hovered */
  --photo-scrim:     rgba(15, 17, 22, 0.58);     /* gradient over a founder photo */
  /* Gloss along a filled button's top edge, and the sweep that crosses it on
     hover. White in both themes: it is a light source, not an ink. */
  --btn-gloss:       rgba(255, 255, 255, 0.24);
  --btn-sheen:       rgba(255, 255, 255, 0.32);

  /* The far end of the primary button's hover gradient: it darkens in light
     mode and must LIGHTEN in dark, or a dark-text button goes unreadable on
     hover. Idle carousel dots and the form's success note need the same
     treatment. */
  --brand-primary-deep: #2f4460;
  /* Ink for text sitting on a soft brand TINT rather than a solid brand fill —
     the eyebrow pill, the founder tags. It has to move the opposite way from
     --brand-primary-dark, which is a hover state and goes darker in both
     themes: on a dark ground that measured 3.2:1 on the eyebrow. */
  --on-tint:         #3f5878;
  --dot-idle:        #c3ccdb;
  --success-bg:      rgba(20, 184, 166, 0.10);
  --success-border:  rgba(20, 184, 166, 0.30);
  --success-text:    #0f766e;
  /* The fallback notice on the contact form: shown when the handoff cannot be
     confirmed, so it must read as "attention", not "error". Amber darkens in
     light mode and lightens in dark, same as --brand-primary-deep. */
  --notice-bg:       rgba(217, 119, 6, 0.10);
  --notice-border:   rgba(217, 119, 6, 0.30);
  --notice-text:     #96470a;
  --star:            #b45309;
  --ok:              #2f9e63;   /* the "running / active" dot on a status pill */
  /* Traffic lights in the fake browser chrome. The same in both themes on
     purpose — a real title bar does not repaint itself for dark mode. */
  --chrome-red:      #f2917a;
  --chrome-amber:    #f0c26e;
  --chrome-green:    #7dc793;

  /* ---- Radius ---- */
  --radius-sm: 10px;   /* inputs, small tiles */
  --radius:    16px;   /* cards, value cards, portfolio cards, FAQ rows */
  --radius-lg: 22px;   /* panels: hero card, form card, review invite, founders */
  --radius-xl: 28px;   /* the CTA banner, the largest object on any page */

  /* ---- Elevation ----
     Two or three layers each: a tight contact shadow that anchors the edge, and
     a wide soft one that gives the object height. A single-layer shadow is what
     makes a card look printed onto the page instead of lifted off it. */
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.05), 0 2px 8px -3px rgba(16, 24, 40, 0.07);
  --shadow-md: 0 1px 3px rgba(16, 24, 40, 0.06), 0 12px 28px -10px rgba(16, 24, 40, 0.14);
  --shadow-lg: 0 1px 3px rgba(16, 24, 40, 0.05), 0 18px 40px -14px rgba(16, 24, 40, 0.18), 0 44px 84px -40px rgba(16, 24, 40, 0.16);
  --shadow-glow: 0 1px 3px rgba(var(--brand-primary-rgb), 0.10), 0 20px 44px -16px rgba(var(--brand-primary-rgb), 0.38);
  --shadow-header: 0 1px 0 0 rgba(var(--brand-primary-rgb), 0.10), 0 12px 30px -22px rgba(16, 24, 40, 0.45);

  /* ---- Type scale ----
     Fluid, so phone to desktop is one continuous ramp rather than a step at each
     breakpoint. No colour here, so unlike the tokens above these live only in
     :root and are not repeated in the two dark blocks. */
  --fs-display: clamp(36px, 5.2vw, 60px);   /* the index hero, and nothing else */
  --fs-h1:      clamp(31px, 4.2vw, 46px);   /* inner-page heroes */
  --fs-h2:      clamp(27px, 3.4vw, 40px);   /* section heads */
  --fs-h3:      clamp(18.5px, 1.4vw, 21px); /* card titles */
  --fs-lead:    clamp(16.5px, 1.3vw, 19.5px);

  /* ---- Vertical rhythm ----
     One scale. A section is --space-section tall, a tight one is smaller, and
     the gap under a section head is --space-head. Nothing sets section padding
     by hand; if the page feels cramped, these three numbers are the dial. */
  --space-section:       clamp(76px, 8.5vw, 120px);
  --space-section-tight: clamp(56px, 6vw, 88px);
  --space-head:          clamp(40px, 4.4vw, 60px);

  --max-width: 1140px;
  --font-display: 'Sora', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  color-scheme: light;
}

/* ==========================================================================
   Dark mode
   Only the tokens change; every rule below this block is written against them.
   The brand blue is lightened here because the light-mode blue was darkened
   for contrast on white and goes muddy on a dark ground — so --on-brand flips
   to near-black to keep text on a blue fill readable.

   Three selectors, in this order, so all three states work:
     :root[data-theme="dark"]                     an explicit choice
     prefers-color-scheme + :not([data-theme="light"])   the system default
     :root[data-theme="light"]                    an explicit choice to opt out

   The two blocks below are the same list twice. Add a token to one and you add
   it to the other and to :root above — all three, or none.
   ========================================================================== */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --brand-dark:      #0b0d12;
    --brand-primary:   #7fa5dd;
    --brand-primary-dark: #6b90c9;
    --brand-primary-light: #a9c6f2;
    --brand-accent:    #a9c6f2;
    --brand-primary-rgb: 127, 165, 221;
    --brand-light-rgb:   169, 198, 242;
    --brand-dark-2:    #1c2130;

    --surface:         #14171f;
    --surface-alt:     #1b1f2a;
    --surface-sunken:  #11141b;
    --surface-veil:    rgba(20, 23, 31, 0.85);
    --border:          #2b3242;
    --border-strong:   #3b4457;
    --text-primary:    #e9ecf4;
    --text-secondary:  #a7afc4;
    --text-muted:      #868ea3;
    --on-brand:        #0d1017;

    --on-dark:         #ffffff;
    --on-dark-soft:    rgba(255, 255, 255, 0.74);
    --on-dark-muted:   rgba(255, 255, 255, 0.54);
    --on-dark-line:    rgba(255, 255, 255, 0.12);
    --on-dark-edge:    rgba(255, 255, 255, 0.30);
    --on-dark-fill:    rgba(255, 255, 255, 0.08);
    --on-dark-hover:   #eef1f8;
    --photo-scrim:     rgba(8, 10, 14, 0.62);
    --btn-gloss:       rgba(255, 255, 255, 0.20);
    --btn-sheen:       rgba(255, 255, 255, 0.26);

    --brand-primary-deep: #a9c6f2;
    --on-tint:         #a9c6f2;
    --dot-idle:        #46506a;
    --success-bg:      rgba(20, 184, 166, 0.14);
    --success-border:  rgba(20, 184, 166, 0.40);
    --success-text:    #5eead4;
    --notice-bg:       rgba(245, 158, 11, 0.14);
    --notice-border:   rgba(245, 158, 11, 0.40);
    --notice-text:     #fcd34d;
    --star:            #fbbf24;
    --ok:              #4ec98a;
    --chrome-red:      #f2917a;
    --chrome-amber:    #f0c26e;
    --chrome-green:    #7dc793;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35), 0 2px 8px -3px rgba(0, 0, 0, 0.45);
    --shadow-md: 0 1px 3px rgba(0, 0, 0, 0.40), 0 12px 28px -10px rgba(0, 0, 0, 0.60);
    --shadow-lg: 0 1px 3px rgba(0, 0, 0, 0.40), 0 18px 40px -14px rgba(0, 0, 0, 0.62), 0 44px 84px -40px rgba(0, 0, 0, 0.70);
    --shadow-glow: 0 1px 3px rgba(0, 0, 0, 0.45), 0 20px 44px -16px rgba(var(--brand-primary-rgb), 0.32);
    --shadow-header: 0 1px 0 0 rgba(var(--brand-primary-rgb), 0.14), 0 12px 32px -20px rgba(0, 0, 0, 0.80);

    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --brand-dark:      #0b0d12;
  --brand-primary:   #7fa5dd;
  --brand-primary-dark: #6b90c9;
  --brand-primary-light: #a9c6f2;
  --brand-accent:    #a9c6f2;
  --brand-primary-rgb: 127, 165, 221;
  --brand-light-rgb:   169, 198, 242;
  --brand-dark-2:    #1c2130;

  --surface:         #14171f;
  --surface-alt:     #1b1f2a;
  --surface-sunken:  #11141b;
  --surface-veil:    rgba(20, 23, 31, 0.85);
  --border:          #2b3242;
  --border-strong:   #3b4457;
  --text-primary:    #e9ecf4;
  --text-secondary:  #a7afc4;
  --text-muted:      #868ea3;
  --on-brand:        #0d1017;

  --on-dark:         #ffffff;
  --on-dark-soft:    rgba(255, 255, 255, 0.74);
  --on-dark-muted:   rgba(255, 255, 255, 0.54);
  --on-dark-line:    rgba(255, 255, 255, 0.12);
  --on-dark-edge:    rgba(255, 255, 255, 0.30);
  --on-dark-fill:    rgba(255, 255, 255, 0.08);
  --on-dark-hover:   #eef1f8;
  --photo-scrim:     rgba(8, 10, 14, 0.62);
  --btn-gloss:       rgba(255, 255, 255, 0.20);
  --btn-sheen:       rgba(255, 255, 255, 0.26);

  --brand-primary-deep: #a9c6f2;
  --on-tint:         #a9c6f2;
  --dot-idle:        #46506a;
  --success-bg:      rgba(20, 184, 166, 0.14);
  --success-border:  rgba(20, 184, 166, 0.40);
  --success-text:    #5eead4;
  --notice-bg:       rgba(245, 158, 11, 0.14);
  --notice-border:   rgba(245, 158, 11, 0.40);
  --notice-text:     #fcd34d;
  --star:            #fbbf24;
  --ok:              #4ec98a;
  --chrome-red:      #f2917a;
  --chrome-amber:    #f0c26e;
  --chrome-green:    #7dc793;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35), 0 2px 8px -3px rgba(0, 0, 0, 0.45);
  --shadow-md: 0 1px 3px rgba(0, 0, 0, 0.40), 0 12px 28px -10px rgba(0, 0, 0, 0.60);
  --shadow-lg: 0 1px 3px rgba(0, 0, 0, 0.40), 0 18px 40px -14px rgba(0, 0, 0, 0.62), 0 44px 84px -40px rgba(0, 0, 0, 0.70);
  --shadow-glow: 0 1px 3px rgba(0, 0, 0, 0.45), 0 20px 44px -16px rgba(var(--brand-primary-rgb), 0.32);
  --shadow-header: 0 1px 0 0 rgba(var(--brand-primary-rgb), 0.14), 0 12px 32px -20px rgba(0, 0, 0, 0.80);

  color-scheme: dark;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }

body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--text-primary);
  background: var(--surface);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }

.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 24px;
}

/* ---------------- Buttons ---------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  /* ~50px tall at this padding — a comfortable phone target that still reads
     as a button rather than a bar on a desktop hero. */
  padding: 14px 28px;
  border-radius: 999px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15.5px;
  line-height: 1.15;
  letter-spacing: -0.005em;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.2s ease,
              background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}
.btn:hover { transform: translateY(-2px); }

/* Three layers: an inset gloss along the top edge so the gradient is lit
   rather than painted, a tight contact shadow that gives the pill an edge,
   and a wide coloured one that lifts it off the page. */
.btn-primary {
  background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-dark));
  color: var(--on-brand);
  box-shadow:
    inset 0 1px 0 var(--btn-gloss),
    0 1px 2px rgba(var(--brand-primary-rgb), 0.30),
    0 10px 24px -10px rgba(var(--brand-primary-rgb), 0.70);
}
.btn-primary:hover {
  background: linear-gradient(135deg, var(--brand-primary-dark), var(--brand-primary-deep));
  box-shadow:
    inset 0 1px 0 var(--btn-gloss),
    0 2px 4px rgba(var(--brand-primary-rgb), 0.28),
    0 18px 34px -12px rgba(var(--brand-primary-rgb), 0.80);
}

/* Filled with --surface, not transparent: sitting on the hero's tinted wash a
   see-through outline button reads as the disabled twin of the primary. */
.btn-outline {
  background: var(--surface);
  border-color: var(--border-strong);
  color: var(--text-primary);
  box-shadow: var(--shadow-sm);
}
.btn-outline:hover { border-color: var(--brand-primary); color: var(--brand-primary); box-shadow: var(--shadow-md); }

.btn-block { width: 100%; }

/* ---------------- Header / Nav ---------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--surface-veil);
  backdrop-filter: saturate(180%) blur(10px);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow-header);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 24px;
}

.logo {
  display: flex;
  align-items: center;
  gap: 11px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -0.02em;
  color: var(--text-primary);
}

/* Real logo mark (assets/logo-icon.png — the "etc" glyph, no wordmark) used in the
   header where space is tight. */
.logo-mark {
  height: 34px;
  width: auto;
  flex-shrink: 0;
}

/* The logo mark is near-black ink and vanishes on a dark header, so the white
   lockup that the footer already uses takes over. Both files are cut to the
   size the header actually renders (34px, doubled for retina) — the originals
   were 881x486 and 302 KB apiece, which is not a price worth paying twice. */
.logo-mark-dark { display: none; }
:root[data-theme="dark"] .logo-mark-light { display: none; }
:root[data-theme="dark"] .logo-mark-dark { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .logo-mark-light { display: none; }
  :root:not([data-theme="light"]) .logo-mark-dark { display: block; }
}

.logo small {
  display: block;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-muted);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

/* Full lockup (assets/logo-full.png — glyph + "ET CETERA BUSINESS SYSTEMS" wordmark)
   used in the footer and anywhere there's room to breathe. */
.logo-full {
  height: 56px;
  width: auto;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 34px;
}

.nav-links a {
  position: relative;
  font-size: 15px;
  font-weight: 600;
  color: var(--text-secondary);
  padding: 6px 0;
  transition: color 0.15s ease;
}
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: linear-gradient(90deg, var(--brand-primary), var(--brand-primary-light));
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.2s ease;
}

.nav-links a:hover,
.nav-links a[aria-current="page"] {
  color: var(--text-primary);
}
.nav-links a:hover::after,
.nav-links a[aria-current="page"]::after {
  transform: scaleX(1);
}

/* Everything on the right of the bar, grouped so .nav's space-between still
   has three children to spread rather than five. */
.nav-right { display: flex; align-items: center; gap: 14px; }
.nav-cta { display: flex; align-items: center; gap: 18px; }
/* The header CTA is three words; letting it wrap turns the bar into two rows. */
.nav-cta .btn { white-space: nowrap; }

/* Between the hamburger breakpoint and ~1060px the full bar — logo, four
   links, phone, CTA and the theme switch — wants more room than there is, and
   the number runs straight into "Contact". The phone is the item that is also
   in the footer and on the contact page, so it is the one that gives way. */
@media (max-width: 1060px) and (min-width: 901px) {
  .nav-links { gap: 26px; }
  .nav-phone { display: none; }
}
.nav-phone { font-size: 14.5px; font-weight: 600; color: var(--text-secondary); white-space: nowrap; padding: 9px 0; transition: color 0.15s ease; }
.nav-phone:hover { color: var(--brand-primary); }

.nav-toggle {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  /* 44x44 is the minimum comfortable touch target; the negative margin keeps the
     bars optically aligned with the container edge despite the wider hit area. */
  width: 44px;
  height: 44px;
  margin-right: -10px;
  padding: 0;
  background: none;
  border: none;
  border-radius: 8px;
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  width: 22px;
  height: 2px;
  border-radius: 2px;
  background: var(--text-primary);
  transition: transform 0.2s ease, opacity 0.2s ease;
}

/* Light/dark switch. Lives outside .nav-cta, which is hidden on mobile — the
   switch stays reachable at every width, beside the hamburger. */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  padding: 0;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-secondary);
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.theme-toggle:hover {
  color: var(--brand-primary);
  border-color: var(--brand-primary);
  background: rgba(var(--brand-primary-rgb), 0.10);
}
.theme-toggle svg { width: 18px; height: 18px; }

/* Show the icon for the mode you would be switching TO. The moon is the
   default because the stylesheet's default is light. */
.theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: none; }
}

.nav-toggle:focus-visible,
.theme-toggle:focus-visible,
.nav-links a:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: -2px;
}

/* 900, not 860: at 880 the bar still tried to lay out logo + four links + CTA
   + switch on one row and the CTA wrapped to two lines. */
@media (max-width: 900px) {
  .nav-links { position: absolute; top: 100%; left: 0; right: 0; background: var(--surface);
    flex-direction: column; align-items: stretch; gap: 6px; border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-md); max-height: 0; overflow: hidden;
    transition: max-height 0.28s ease, padding 0.28s ease; padding: 0 12px; }
  /* Padding has to animate with max-height, or the panel keeps 20px of dead
     space above the first row while closed. */
  .nav-links.open { max-height: 70vh; overflow-y: auto; padding: 10px 12px 14px; }
  .nav-links li { width: 100%; }
  /* An inline <a> ignores width, and its vertical padding does not grow the line
     box — so the row collapsed to the height of the text and only the glyphs
     were tappable. display:flex + min-height gives each item a full-width 58px
     target with the label vertically centred, and the 6px gap above keeps the
     rows visibly separate instead of stacked edge to edge. */
  .nav-links a {
    display: flex;
    align-items: center;
    width: 100%;
    min-height: 58px;
    padding: 0 16px;
    font-size: 16.5px;
    border-radius: 12px;
    background: var(--surface-alt);
    color: var(--text-primary);
  }
  /* The sliding underline is a desktop hover affordance; on a filled 58px row it
     reads as a stray line, so the current page gets a left bar instead. */
  .nav-links a::after { display: none; }
  .nav-links a:active { background: var(--border); }
  .nav-links a[aria-current="page"] {
    background: rgba(var(--brand-primary-rgb), 0.12);
    box-shadow: inset 3px 0 0 var(--brand-primary);
  }
  .nav-cta { display: none; }
  .nav-toggle { display: flex; }
  .logo small { display: none; }
}

/* ---------------- Hero ---------------- */
.hero {
  position: relative;
  overflow: hidden;
  padding: clamp(72px, 9vw, 132px) 0 clamp(64px, 8vw, 112px);
  background:
    radial-gradient(1100px 620px at 6% -20%, rgba(var(--brand-primary-rgb), 0.24), transparent 62%),
    radial-gradient(920px 600px at 102% -8%, rgba(var(--brand-light-rgb), 0.28), transparent 60%),
    radial-gradient(760px 500px at 74% 112%, rgba(var(--brand-primary-rgb), 0.13), transparent 64%),
    var(--surface-alt);
  border-bottom: 1px solid var(--border);
}

/* A faint engineering grid under the wash — the thing that reads as "built by
   people who do this for a living" rather than a plain tinted band. It is
   faded out with a mask so it never meets an edge as a hard crop.
   The mask is an alpha channel, not a rendered colour: black here means
   "opaque", and it means the same thing in both themes. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(var(--brand-primary-rgb), 0.10) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(var(--brand-primary-rgb), 0.10) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(760px 460px at 12% 6%, #000, transparent 72%);
  mask-image: radial-gradient(760px 460px at 12% 6%, #000, transparent 72%);
}

/* Lifts the copy and the showcase above .hero::before, which is absolutely
   positioned and would otherwise paint over both. */
.hero .container {
  position: relative;
  z-index: 1;
  display: grid;
  /* The copy column gets the extra sliver: at --fs-display the headline needs
     the room more than the screenshot does. */
  grid-template-columns: 1.04fr 0.96fr;
  gap: clamp(40px, 5vw, 64px);
  align-items: center;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: linear-gradient(135deg, rgba(var(--brand-primary-rgb), 0.12), rgba(var(--brand-light-rgb), 0.20));
  border: 1px solid rgba(var(--brand-primary-rgb), 0.26);
  color: var(--on-tint);
  font-family: var(--font-display);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  padding: 8px 18px 8px 14px;
  border-radius: 999px;
  margin-bottom: 22px;
  backdrop-filter: blur(6px);
  box-shadow: 0 1px 2px rgba(var(--brand-primary-rgb), 0.12),
              0 8px 20px -10px rgba(var(--brand-primary-rgb), 0.55);
}
/* A slow pulse on the leading dot. The only moving thing above the fold that
   is not the carousel, and the one that says "this business is open". */
.eyebrow::before {
  content: "";
  flex: none;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--brand-primary);
  animation: eyebrow-pulse 2.8s ease-out infinite;
}
@keyframes eyebrow-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(var(--brand-primary-rgb), 0.55); }
  70%  { box-shadow: 0 0 0 8px rgba(var(--brand-primary-rgb), 0); }
  100% { box-shadow: 0 0 0 0 rgba(var(--brand-primary-rgb), 0); }
}

.hero h1 {
  font-family: var(--font-display);
  font-size: var(--fs-display);
  font-weight: 800;
  /* Display type wants a tighter line and tighter tracking than body copy —
     at 60px the default 1.1/-0.02em still reads like a paragraph. */
  line-height: 1.04;
  letter-spacing: -0.033em;
  margin-bottom: 22px;
  text-wrap: balance;
}

/* The gradient runs deep -> primary -> dark rather than through
   --brand-primary-light. This is headline text, not decoration: the logo blue
   measures 2.0:1 on the hero wash and large text needs 3:1, so the lightest
   stop here is --brand-primary at 4.6:1. Both ends of the ramp lighten in dark
   mode with the tokens, so the shimmer survives the flip. */
.hero h1 .accent {
  background: linear-gradient(100deg, var(--brand-primary-deep) 0%, var(--brand-primary) 55%, var(--brand-primary-dark) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.hero p.lead {
  font-size: var(--fs-lead);
  line-height: 1.62;
  color: var(--text-secondary);
  max-width: 48ch;
  margin-bottom: 34px;
}

.hero-actions { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 32px; }

/* Was --text-muted on a 2px rule: the rule read as a stray line and the ink
   measured 3.1:1. Now three marked items in --text-secondary. */
.hero-trust {
  display: flex; flex-direction: column; gap: 11px;
  font-size: 14.5px; color: var(--text-secondary);
}
.hero-trust span { display: flex; align-items: baseline; gap: 11px; }
.hero-trust span::before {
  content: "";
  flex: none;
  width: 6px; height: 6px;
  border-radius: 50%;
  transform: translateY(-3px);
  background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-light));
  box-shadow: 0 0 0 3px rgba(var(--brand-primary-rgb), 0.15);
}
.hero-trust strong { color: var(--text-primary); font-weight: 700; }

.hero-card {
  background: linear-gradient(180deg, var(--surface), var(--surface-sunken));
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg), 0 44px 88px -44px rgba(var(--brand-primary-rgb), 0.55);
  padding: 28px;
}
.hero-card .browser-dots { display: flex; gap: 6px; margin-bottom: 18px; }
.hero-card .browser-dots span:nth-child(1) { background: var(--chrome-red); }
.hero-card .browser-dots span:nth-child(2) { background: var(--chrome-amber); }
.hero-card .browser-dots span:nth-child(3) { background: var(--chrome-green); }
.hero-card .browser-dots span { width: 10px; height: 10px; border-radius: 50%; }
.hero-card .mock-line { height: 10px; border-radius: 6px; background: linear-gradient(90deg, rgba(var(--brand-primary-rgb), 0.16), rgba(var(--brand-light-rgb), 0.10)); margin-bottom: 10px; }
.hero-card .mock-block {
  height: 90px; border-radius: 10px;
  background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-light));
  box-shadow: inset 0 0 0 1px var(--btn-gloss), 0 10px 24px -10px rgba(var(--brand-primary-rgb), 0.55);
  margin: 16px 0;
}
.hero-card .mock-row { display: flex; gap: 10px; }
.hero-card .mock-row .mock-line { flex: 1; }

@media (max-width: 900px) {
  .hero .container { grid-template-columns: 1fr; }
  .hero { text-align: left; }
}
@media (max-width: 420px) {
  /* The eyebrow is a long sentence in a pill; at 12px it wraps to two lines
     instead of three and stops dominating the top of the page. */
  .eyebrow { font-size: 12px; padding: 7px 15px 7px 12px; }
}

/* ---------------- Section scaffolding ---------------- */
.section { padding: var(--space-section) 0; }
.section-alt {
  position: relative;
  background:
    radial-gradient(900px 440px at 92% -5%, rgba(var(--brand-light-rgb), 0.13), transparent 62%),
    radial-gradient(760px 440px at 3% 105%, rgba(var(--brand-primary-rgb), 0.09), transparent 62%),
    var(--surface-alt);
}
.section-tight { padding: var(--space-section-tight) 0; }

.section-head { max-width: 680px; margin-bottom: var(--space-head); }
.section-head.center { margin-left: auto; margin-right: auto; text-align: center; }

/* A short brand rule ahead of the label. Turns a line of small caps into a
   deliberate mark, and it works the same over "What we do" and over "01". */
.kicker {
  display: flex;
  align-items: center;
  gap: 11px;
  width: fit-content;
  font-family: var(--font-display);
  color: var(--brand-primary);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 14px;
}
.kicker::before {
  content: "";
  flex: none;
  width: 24px; height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--brand-primary), var(--brand-primary-light));
}
.section-head.center .kicker { margin-left: auto; margin-right: auto; }

.section-head h2 {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.03em;
  margin-bottom: 16px;
  text-wrap: balance;
}
.section-head p { color: var(--text-secondary); font-size: var(--fs-lead); line-height: 1.6; text-wrap: pretty; }

/* ---------------- Cards / Grids ---------------- */
.grid { display: grid; gap: clamp(20px, 2.2vw, 28px); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 860px) { .grid-3, .grid-2 { grid-template-columns: 1fr; } }

.card {
  position: relative;
  /* isolate keeps the z-index juggling below (glow at 0, content at 1, accent
     bar at 2) inside the card instead of racing the rest of the page. */
  isolation: isolate;
  background: linear-gradient(180deg, var(--surface), var(--surface-sunken));
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 34px 32px 32px;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.3s ease, transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.3s ease;
}
.card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 2;
  height: 3px;
  background: linear-gradient(90deg, var(--brand-primary), var(--brand-primary-light));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
/* Brand light warming the top-right corner on hover, under the content. */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(440px 260px at 88% -14%, rgba(var(--brand-light-rgb), 0.32), transparent 68%);
  opacity: 0;
  transition: opacity 0.35s ease;
}
.card > * { position: relative; z-index: 1; }
.card:hover::before { transform: scaleX(1); }
.card:hover::after { opacity: 1; }
.card:hover {
  box-shadow: var(--shadow-glow);
  transform: translateY(-6px);
  border-color: rgba(var(--brand-primary-rgb), 0.45);
}

.card-icon {
  width: 54px;
  height: 54px;
  border-radius: 15px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, rgba(var(--brand-primary-rgb), 0.16), rgba(var(--brand-light-rgb), 0.32));
  border: 1px solid rgba(var(--brand-primary-rgb), 0.22);
  box-shadow: inset 0 1px 0 var(--btn-gloss), 0 10px 20px -12px rgba(var(--brand-primary-rgb), 0.70);
  color: var(--brand-primary);
  font-size: 24px;
  margin-bottom: 20px;
  transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.35s ease;
}
.card:hover .card-icon {
  transform: translateY(-2px) scale(1.06) rotate(-4deg);
  box-shadow: inset 0 1px 0 var(--btn-gloss), 0 16px 28px -14px rgba(var(--brand-primary-rgb), 0.85);
}

.card h3 { font-family: var(--font-display); font-size: var(--fs-h3); font-weight: 700; line-height: 1.25; margin-bottom: 11px; letter-spacing: -0.018em; }
.card p { color: var(--text-secondary); font-size: 15.5px; line-height: 1.62; }
/* The vertical padding is hit area, not spacing — margin-top absorbs it so the
   link sits where it looks like it should while being ~30px tall to tap. */
.card a.card-link { display: inline-flex; align-items: center; gap: 6px; margin-top: 12px; padding: 4px 0; font-family: var(--font-display); font-size: 14px; font-weight: 700; color: var(--brand-primary); }

/* ---------------- Stats strip ---------------- */
.stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
  padding: 40px 0;
}
.stat .stat-value {
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 800;
  letter-spacing: -0.02em;
  background: linear-gradient(120deg, var(--brand-primary), var(--brand-primary-light));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.stat .stat-label { font-size: 14px; color: var(--text-secondary); margin-top: 4px; }
@media (max-width: 760px) { .stats { grid-template-columns: repeat(2, 1fr); } }

/* ---------------- Process steps ---------------- */
.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(26px, 3vw, 34px); counter-reset: step; }
.step { position: relative; padding-top: 8px; }
.step-num {
  position: relative; z-index: 1;
  width: 44px; height: 44px; border-radius: 14px;
  background: linear-gradient(140deg, var(--brand-primary), var(--brand-primary-dark));
  color: var(--on-brand);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display);
  font-weight: 800; font-size: 16px; margin-bottom: 18px;
  box-shadow: inset 0 1px 0 var(--btn-gloss), 0 10px 22px -10px rgba(var(--brand-primary-rgb), 0.75);
}
/* A hairline from each number to the next, so four steps read as one path
   instead of four unrelated blocks. Desktop row only — stacked, it would be
   a line pointing sideways at nothing. */
.step:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 30px;
  left: 56px;
  right: calc(-1 * clamp(26px, 3vw, 34px));
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, rgba(var(--brand-primary-rgb), 0.40), rgba(var(--brand-primary-rgb), 0.05));
}
.step h3 { font-family: var(--font-display); font-size: 17.5px; font-weight: 700; letter-spacing: -0.015em; margin-bottom: 9px; }
.step p { font-size: 15px; line-height: 1.6; color: var(--text-secondary); }
@media (max-width: 860px) {
  .steps { grid-template-columns: 1fr; }
  .step:not(:last-child)::after { display: none; }
}

/* ---------------- CTA banner ---------------- */
.cta-banner {
  position: relative;
  overflow: hidden;
  background: linear-gradient(135deg, var(--brand-dark), var(--brand-dark-2));
  color: var(--on-dark);
  border: 1px solid var(--on-dark-line);
  border-radius: var(--radius-xl);
  padding: clamp(34px, 5vw, 64px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 36px;
  flex-wrap: wrap;
  box-shadow: var(--shadow-lg), 0 44px 84px -44px rgba(var(--brand-primary-rgb), 0.65);
}
.cta-banner::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(640px 360px at 92% -10%, rgba(var(--brand-light-rgb), 0.30), transparent 66%),
    radial-gradient(480px 320px at -5% 110%, rgba(var(--brand-primary-rgb), 0.38), transparent 66%);
  pointer-events: none;
}
.cta-banner > * { position: relative; z-index: 1; }
/* The banner is a flex row of two blocks. The copy flexes into whatever the
   buttons leave; the buttons never shrink. Without the basis the copy sprawls
   to full width, the row wraps, and half the panel sits empty. */
.cta-banner > div:first-child { flex: 1 1 340px; max-width: 56ch; }
/* Shrinkable, or the two-button banner on the home page pushes "Call (336)
   814-5803" past the panel edge and .cta-banner's overflow:hidden clips it. */
.cta-banner .hero-actions { margin: 0; flex: 0 1 auto; min-width: 0; }
/* Below this the row cannot hold a button beside the copy at all, so the
   buttons become full-width rows instead of being squeezed. */
@media (max-width: 620px) {
  .cta-banner .hero-actions { flex: 1 1 100%; }
  .cta-banner .hero-actions .btn { width: 100%; }
}
.cta-banner h2 { font-family: var(--font-display); font-size: clamp(25px, 3.2vw, 36px); font-weight: 800; line-height: 1.1; margin-bottom: 10px; letter-spacing: -0.03em; text-wrap: balance; }
.cta-banner p { color: var(--on-dark-soft); font-size: 16px; line-height: 1.6; }
.cta-banner .btn-primary {
  background: var(--on-dark);
  color: var(--brand-dark);
  box-shadow: var(--shadow-md);
}
.cta-banner .btn-primary:hover {
  background: var(--on-dark-hover);
  box-shadow: var(--shadow-lg);
}
/* The sheen is a white sweep; on a white button there is nothing to see. */
.cta-banner .btn-primary::after { display: none; }
.cta-banner .btn-outline { background: var(--on-dark-fill); border-color: var(--on-dark-edge); color: var(--on-dark); box-shadow: none; }
.cta-banner .btn-outline:hover { background: var(--on-dark-line); border-color: var(--on-dark); color: var(--on-dark); box-shadow: none; }

/* ---------------- Lists w/ check icons ---------------- */
.check-list { display: grid; gap: 15px; }
.check-list li { display: flex; align-items: flex-start; gap: 13px; font-size: 15.5px; line-height: 1.55; color: var(--text-secondary); }
.check-list li::before {
  content: "✓";
  flex-shrink: 0;
  width: 24px; height: 24px; border-radius: 8px;
  margin-top: 1px;
  background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-light)); color: var(--on-brand);
  display: flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: 800;
  box-shadow: inset 0 1px 0 var(--btn-gloss), 0 5px 12px -5px rgba(var(--brand-primary-rgb), 0.75);
}

/* ---------------- Service detail rows ---------------- */
/* The copy column gets slightly less room than the panel: the screenshots are
   the argument on this page, and the copy is already inside a comfortable measure. */
.service-row {
  display: grid; grid-template-columns: 0.92fr 1.08fr; gap: clamp(36px, 5vw, 64px);
  align-items: center; padding: clamp(48px, 6vw, 76px) 0;
  border-bottom: 1px solid var(--border);
}
.service-row:last-child { border-bottom: none; }
.service-row.reverse .service-visual { order: 2; }
@media (max-width: 900px) { .service-row, .service-row.reverse .service-visual { grid-template-columns: 1fr; order: initial; } .service-row { grid-template-columns: 1fr; } }

.service-visual {
  border-radius: var(--radius-lg);
  background:
    radial-gradient(460px 300px at 22% 10%, rgba(var(--brand-primary-rgb), 0.15), transparent 66%),
    radial-gradient(380px 280px at 86% 94%, rgba(var(--brand-light-rgb), 0.20), transparent 66%),
    var(--surface-alt);
  border: 1px solid var(--border);
  padding: 34px;
  min-height: 240px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* These sit directly on the page background, so they need their own lift or
     they read as flat blocks of tint. */
  box-shadow: var(--shadow-md);
}

/* The hosting preview fills its panel edge to edge — the browser frame IS the
   panel, rather than floating inside one. */
.service-visual.has-preview {
  padding: 0; overflow: hidden; background: var(--surface);
  align-items: stretch;
}
.service-visual.has-preview .browser-mockup { display: flex; flex-direction: column; }

/* Screenshot panels beside each service.
   These were CSS wireframes — grey bars standing in for a website. The one
   labelled "a live client site we manage" showed empty boxes, which is a poor
   thing to put next to a claim. Both now hold the actual screenshots, so the
   panels say something true and the section has real work in it. */

.shot { overflow: hidden; background: var(--surface-alt); }
.shot img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
}
/* Anchored to the top: these are home pages, and the header and hero are the
   part worth showing when the frame is shorter than the screenshot. */
.shot-desktop { aspect-ratio: 16 / 9; }
.shot-phone { aspect-ratio: 400 / 690; border-radius: 9px; }

.browser-mockup { width: 100%; }
.browser-mockup .browser-topbar {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 14px; background: var(--surface-alt); border-bottom: 1px solid var(--border);
}
.browser-mockup .browser-dots { display: flex; gap: 6px; }
.browser-mockup .browser-dots span { width: 9px; height: 9px; border-radius: 50%; background: var(--border); }
.browser-mockup .url-bar {
  flex: 1; background: var(--surface); border: 1px solid var(--border); border-radius: 999px;
  padding: 5px 13px; font-size: 12px; color: var(--text-muted);
  display: flex; align-items: center; gap: 6px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.browser-mockup .url-bar .lock { font-size: 10.5px; }
.browser-mockup .preview-caption {
  padding: 12px 18px 16px; font-size: 12.5px; color: var(--text-muted);
  border-top: 1px solid var(--border);
}

/* Status pills under the hosting preview — the point of the "management"
   service is the things you never have to think about, so name them. */
.mock-status { display: flex; flex-wrap: wrap; gap: 8px; padding: 14px 18px 0; }
.status-pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px; font-weight: 600; color: var(--text-secondary);
  background: var(--surface-alt); border: 1px solid var(--border);
  border-radius: 999px; padding: 5px 11px;
}
.status-pill::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--text-muted); flex-shrink: 0;
}
.status-pill.ok::before { background: var(--ok); }

/* "Design & build": one site shown twice, desktop and phone, because that is
   the claim the copy makes. The phone hangs past the frame's bottom-right
   corner; the parent's extra bottom and right padding is what keeps it inside
   the panel instead of clipping against the edge. */
.service-visual.has-design { padding: 34px 46px 58px 34px; }
.design-mockup { position: relative; width: 100%; max-width: 400px; margin: 0; }
.dm-browser {
  border-radius: 12px; overflow: hidden; background: var(--surface);
  border: 1px solid var(--border); box-shadow: var(--shadow-lg);
}
.dm-phone {
  position: absolute; right: -30px; bottom: -34px; width: 108px;
  padding: 6px; border-radius: 18px; background: var(--surface);
  border: 1px solid var(--border); box-shadow: var(--shadow-md);
}
.dm-phone-screen { border-radius: 13px; background: var(--surface-alt); padding: 6px 6px 8px; }
.dm-phone-notch { width: 26px; height: 4px; border-radius: 3px; background: var(--border); margin: 1px auto 7px; }

.mockup-caption {
  margin-top: 18px; font-size: 12.5px; color: var(--text-muted);
  /* Clear of the phone, which overhangs this corner. */
  padding-right: 84px;
}

@media (max-width: 480px) {
  .service-visual.has-design { padding: 22px 30px 44px 22px; }
  .dm-phone { width: 84px; right: -14px; bottom: -26px; }
  .mockup-caption { padding-right: 64px; }
}

/* ---------------- Founders (About page) ---------------- */
.founders { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(24px, 3vw, 40px); max-width: 900px; margin: 0 auto; }
@media (max-width: 700px) { .founders { grid-template-columns: 1fr; max-width: 420px; } }

.founder-card {
  background: linear-gradient(180deg, var(--surface), var(--surface-sunken));
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-md);
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.3s ease, border-color 0.3s ease;
}
.founder-card:hover { transform: translateY(-8px); box-shadow: var(--shadow-glow); border-color: rgba(var(--brand-primary-rgb), 0.45); }

.founder-photo { position: relative; aspect-ratio: 1 / 1; background: var(--surface-alt); overflow: hidden; }
.founder-photo img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 25%; display: block; transition: transform 0.35s ease; }
.founder-card:hover .founder-photo img { transform: scale(1.06); }
.founder-photo::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to top, var(--photo-scrim) 0%, transparent 42%);
  pointer-events: none;
}
/* Was a white pill with --brand-primary text: fine on white, but dark mode
   lightens that blue and the pill dropped to about 2.5:1. A brand fill with
   --on-brand flips correctly and reads as a badge rather than a sticker. */
.founder-badge {
  position: absolute; left: 18px; bottom: 18px; z-index: 1;
  background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-dark));
  color: var(--on-brand);
  font-family: var(--font-display);
  font-size: 11.5px; font-weight: 700;
  letter-spacing: 0.09em; text-transform: uppercase;
  padding: 7px 15px; border-radius: 999px;
  box-shadow: inset 0 1px 0 var(--btn-gloss), 0 8px 18px -8px rgba(var(--brand-primary-rgb), 0.85);
}

.founder-body { padding: 28px 30px 32px; }
.founder-body h3 { font-family: var(--font-display); font-size: 23px; font-weight: 800; margin-bottom: 13px; letter-spacing: -0.025em; }
.founder-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 17px; }
.founder-tags span {
  background: linear-gradient(135deg, rgba(var(--brand-primary-rgb), 0.09), rgba(var(--brand-light-rgb), 0.16));
  border: 1px solid rgba(var(--brand-primary-rgb), 0.22); border-radius: 999px;
  padding: 5px 13px; font-size: 12.5px; color: var(--on-tint); font-weight: 600;
}
.founder-body p.founder-bio { color: var(--text-secondary); font-size: 15.5px; line-height: 1.65; }

.service-copy .kicker { margin-bottom: 10px; }
.service-copy h3 { font-family: var(--font-display); font-size: clamp(23px, 2.4vw, 30px); font-weight: 800; line-height: 1.12; margin-bottom: 16px; letter-spacing: -0.03em; text-wrap: balance; }
.service-copy p.desc { color: var(--text-secondary); font-size: 16px; line-height: 1.62; margin-bottom: 24px; }

/* ---------------- Who we help chips ---------------- */
.chip-cloud { display: flex; flex-wrap: wrap; gap: 11px; }
.chip-cloud.center { justify-content: center; }
.chip-cloud span {
  background: linear-gradient(135deg, rgba(var(--brand-primary-rgb), 0.08), rgba(var(--brand-light-rgb), 0.14));
  border: 1px solid rgba(var(--brand-primary-rgb), 0.22); border-radius: 999px;
  padding: 10px 18px; font-size: 14.5px; color: var(--text-secondary); font-weight: 600;
  box-shadow: var(--shadow-sm);
  transition: background 0.22s ease, border-color 0.22s ease, color 0.22s ease,
              transform 0.22s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.22s ease;
}
.chip-cloud span:hover {
  background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-light));
  border-color: transparent; color: var(--on-brand); transform: translateY(-3px);
  box-shadow: 0 10px 22px -10px rgba(var(--brand-primary-rgb), 0.80);
}

/* ---------------- Values ---------------- */
.value-card {
  position: relative;
  overflow: hidden;
  background: linear-gradient(180deg, var(--surface), var(--surface-sunken));
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 26px 28px 26px 32px;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.3s ease, transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.3s ease;
}
/* The accent moved off border-left and onto a pseudo-element so it can be a
   gradient and can widen on hover without shifting the text. */
.value-card::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 4px;
  background: linear-gradient(180deg, var(--brand-primary), var(--brand-primary-light));
  transition: width 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.value-card:hover { box-shadow: var(--shadow-glow); transform: translateY(-4px); border-color: rgba(var(--brand-primary-rgb), 0.45); }
.value-card:hover::before { width: 7px; }
.value-card h3 { font-family: var(--font-display); font-size: 17.5px; font-weight: 700; letter-spacing: -0.015em; margin-bottom: 7px; }
.value-card p { color: var(--text-secondary); font-size: 15px; line-height: 1.6; }

/* ---------------- Pricing -------------------------------------------------
   Three tiers. The middle one is featured on the same dark panel treatment as
   .cta-banner — dark in BOTH themes on purpose, so its ink comes from the
   --on-dark-* family rather than --text-*, which would flip out from under it.
   The tier figure on that panel uses --brand-primary-light: the solid
   --brand-primary is the *button* blue, tuned for white text on it, and at
   40px on near-black it reads muddy.
-------------------------------------------------------------------------- */
.pricing-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(20px, 2.2vw, 28px);
  align-items: stretch;
  /* The featured card's badge hangs above its top edge; without this the
     section's reveal transform slides it under the heading above. */
  padding-top: 14px;
}
/* Three tiers stop being comparable well before the usual 860px: the feature
   lines start wrapping every other word. Stack early and cap the width so a
   single column does not stretch to a 1200px ribbon. */
@media (max-width: 980px) {
  .pricing-grid { grid-template-columns: 1fr; max-width: 460px; margin: 0 auto; }
}

.price-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: linear-gradient(180deg, var(--surface), var(--surface-sunken));
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 34px 30px 32px;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.3s ease, transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.3s ease;
}
.price-card:hover {
  box-shadow: var(--shadow-glow);
  transform: translateY(-6px);
  border-color: rgba(var(--brand-primary-rgb), 0.45);
}

.price-head { margin-bottom: 18px; }
.price-card h2 {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 700;
  letter-spacing: -0.018em;
  line-height: 1.25;
  margin-bottom: 6px;
}
.price-for { font-size: 14px; line-height: 1.5; color: var(--text-muted); }

.price-amount { display: flex; align-items: baseline; gap: 6px; margin-bottom: 8px; }
.price-figure {
  font-family: var(--font-display);
  font-size: clamp(34px, 3.6vw, 42px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--brand-primary);
}
.price-period { font-size: 15px; color: var(--text-muted); }

.price-setup {
  font-size: 12.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  padding-bottom: 22px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 22px;
}

/* flex-grow on the list is what keeps the three "Get started" buttons on one
   line across tiers that carry four, five and five features. */
.price-features { display: grid; align-content: start; gap: 12px; flex-grow: 1; margin-bottom: 26px; }
.price-features li {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--text-secondary);
}
.price-features li::before {
  content: "✓";
  flex-shrink: 0;
  width: 21px; height: 21px; border-radius: 7px;
  display: flex; align-items: center; justify-content: center;
  margin-top: 1px;
  background: linear-gradient(135deg, rgba(var(--brand-primary-rgb), 0.14), rgba(var(--brand-light-rgb), 0.26));
  border: 1px solid rgba(var(--brand-primary-rgb), 0.20);
  color: var(--brand-primary);
  font-size: 12px;
  font-weight: 700;
}

/* ---- The featured tier ---- */
.price-card-featured {
  background: linear-gradient(135deg, var(--brand-dark), var(--brand-dark-2));
  border-color: var(--on-dark-line);
  color: var(--on-dark);
  box-shadow: var(--shadow-lg), 0 44px 84px -44px rgba(var(--brand-primary-rgb), 0.65);
}
.price-card-featured:hover {
  border-color: var(--on-dark-edge);
  box-shadow: var(--shadow-lg), 0 50px 90px -44px rgba(var(--brand-primary-rgb), 0.78);
}
.price-card-featured .price-for,
.price-card-featured .price-period,
.price-card-featured .price-setup { color: var(--on-dark-muted); }
.price-card-featured .price-features li { color: var(--on-dark-soft); }
.price-card-featured .price-setup { border-bottom-color: var(--on-dark-line); }
.price-card-featured .price-figure { color: var(--brand-primary-light); }
.price-card-featured .price-features li::before {
  background: var(--on-dark-fill);
  border-color: var(--on-dark-edge);
  color: var(--on-dark);
}
/* Same reason as .cta-banner: a brand-blue button on a near-black panel has
   almost no edge against it, and the white sweep has nothing to sweep over. */
.price-card-featured .btn-primary {
  background: var(--on-dark);
  color: var(--brand-dark);
  box-shadow: var(--shadow-md);
}
.price-card-featured .btn-primary:hover { background: var(--on-dark-hover); box-shadow: var(--shadow-lg); }
.price-card-featured .btn-primary::after { display: none; }

.price-badge {
  position: absolute;
  top: -13px;
  left: 30px;
  padding: 5px 13px;
  border-radius: 999px;
  /* Stays inside the button-blue range on purpose. --brand-primary-light is a
     FILL colour, not a ground for --on-brand: white on it measures 2.2:1, so a
     gradient running out to it left the right half of "Most popular"
     illegible in light mode while dark mode looked fine. */
  background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-dark));
  color: var(--on-brand);
  font-family: var(--font-display);
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  box-shadow: var(--shadow-sm);
}

.pricing-note {
  text-align: center;
  font-size: 13.5px;
  color: var(--text-muted);
  margin-top: clamp(28px, 3vw, 40px);
}

/* ---------------- Contact ---------------- */
.contact-grid { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 48px; align-items: start; }
@media (max-width: 900px) { .contact-grid { grid-template-columns: 1fr; } }

.contact-info-card {
  position: relative;
  overflow: hidden;
  background: linear-gradient(160deg, var(--brand-dark), var(--brand-dark-2));
  color: var(--on-dark);
  border: 1px solid var(--on-dark-line);
  border-radius: var(--radius-lg);
  padding: clamp(28px, 3.4vw, 42px);
  box-shadow: var(--shadow-lg);
}
.contact-info-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(460px 300px at 100% -10%, rgba(var(--brand-light-rgb), 0.26), transparent 66%),
    radial-gradient(360px 260px at -10% 110%, rgba(var(--brand-primary-rgb), 0.30), transparent 66%);
  pointer-events: none;
}
.contact-info-card > * { position: relative; z-index: 1; }
.contact-info-card h3 { font-family: var(--font-display); font-size: 21px; font-weight: 800; letter-spacing: -0.02em; margin-bottom: 9px; }
.contact-info-card p.muted { color: var(--on-dark-soft); font-size: 15px; margin-bottom: 30px; }
.contact-method { display: flex; gap: 15px; align-items: flex-start; margin-bottom: 22px; }
.contact-method .ci-icon {
  width: 42px; height: 42px; border-radius: 13px;
  background: var(--on-dark-fill); border: 1px solid var(--on-dark-line);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 17px;
}
.contact-method .ci-label { font-family: var(--font-display); font-size: 11.5px; font-weight: 700; color: var(--on-dark-muted); text-transform: uppercase; letter-spacing: 0.09em; margin-bottom: 3px; }
.contact-method .ci-value { font-size: 15.5px; font-weight: 600; }
.contact-method .ci-value.placeholder { color: var(--on-dark-muted); font-weight: 500; font-style: italic; }

.contact-form-card {
  background: linear-gradient(180deg, var(--surface), var(--surface-sunken));
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: clamp(28px, 3.4vw, 42px);
  box-shadow: var(--shadow-md);
}
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 560px) { .form-row { grid-template-columns: 1fr; } }

.field { margin-bottom: 18px; }
.field label { display: block; font-size: 13.5px; font-weight: 600; margin-bottom: 8px; color: var(--text-primary); }
.field input, .field select, .field textarea {
  width: 100%;
  min-height: 46px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  font-size: 15px;
  font-family: inherit;
  color: var(--text-primary);
  background: var(--surface-alt);
  transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--brand-primary); background: var(--surface);
  box-shadow: 0 0 0 4px rgba(var(--brand-primary-rgb), 0.18);
}
.field textarea { resize: vertical; min-height: 120px; }
.form-note { font-size: 12.5px; color: var(--text-muted); margin-top: 14px; }
.form-success { display: none; background: var(--success-bg); border: 1px solid var(--success-border); color: var(--success-text); padding: 14px 16px; border-radius: var(--radius-sm); font-size: 14px; margin-bottom: 18px; }
.form-success.show { display: block; }

/* Shown when the send could not be confirmed — a failed POST, or a mailto:
   handoff that may never have opened a mail client. Carries the address and
   phone so a visitor whose browser swallowed the handoff still has a way to
   reach us instead of a silent dead end. */
.form-notice {
  display: none;
  background: var(--notice-bg);
  border: 1px solid var(--notice-border);
  color: var(--notice-text);
  padding: 14px 16px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  margin-bottom: 18px;
}
.form-notice.show { display: block; }
.form-notice a { color: inherit; font-weight: 600; text-decoration: underline; }
.form-notice a:hover, .form-notice a:focus-visible { text-decoration: none; }
.form-notice .fallback-line { margin: 8px 0 0; }

/* Button while a submit is in flight. Keeps the exact box so the card does
   not reflow under the cursor mid-click. */
.btn[aria-busy="true"] { opacity: 0.72; cursor: progress; }

/* Honeypot. Off-screen rather than display:none so bots that skip hidden
   fields still fill it, and never focusable by a real visitor. */
.hp-field {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden; opacity: 0;
}

/* ---------------- Client reviews ---------------- */
/* The grid is empty until a review is pasted into index.html by hand, so it
   must collapse to nothing rather than leave a gap above the invite. */
.review-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: clamp(20px, 2.2vw, 28px);
}
.review-grid:empty { display: none; }
.review-grid:not(:empty) { margin-bottom: clamp(36px, 4vw, 56px); }

.review-card {
  position: relative;
  overflow: hidden;
  margin: 0;
  background: linear-gradient(180deg, var(--surface), var(--surface-sunken));
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 30px 30px 28px;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 16px;
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.3s ease, border-color 0.3s ease;
}
/* An oversized quote mark as a watermark, not as punctuation — the blockquote
   keeps its own curly quotes, this is the thing that makes the card read as a
   testimonial before anyone has read a word of it. */
.review-card::before {
  content: "\201D";
  position: absolute;
  top: -26px; right: 16px;
  font-family: var(--font-display);
  font-size: 132px;
  font-weight: 800;
  line-height: 1;
  color: rgba(var(--brand-primary-rgb), 0.11);
  pointer-events: none;
}
.review-card > * { position: relative; }
.review-card:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow-glow);
  border-color: rgba(var(--brand-primary-rgb), 0.45);
}
.review-stars { color: var(--star); font-size: 15px; letter-spacing: 0.14em; }
/* The quote is the loudest thing in the card, so it gets --text-primary.
   The byline underneath is what steps back. */
.review-card blockquote {
  margin: 0;
  font-size: 16px;
  line-height: 1.68;
  color: var(--text-primary);
}
.review-card blockquote::before { content: "\201C"; }
.review-card blockquote::after  { content: "\201D"; }
.review-card figcaption {
  margin-top: auto;
  padding-top: 17px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.review-name { font-family: var(--font-display); font-weight: 700; font-size: 15.5px; letter-spacing: -0.01em; color: var(--text-primary); }
.review-meta { font-size: 13.5px; color: var(--text-secondary); }

/* Invitation to leave one. Doubles as the section's whole content until the
   first review is published, so it has to stand on its own. */
.review-invite {
  position: relative;
  overflow: hidden;
  max-width: 760px;
  margin: 0 auto;
  background: linear-gradient(180deg, var(--surface), var(--surface-sunken));
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: clamp(30px, 4vw, 48px);
  box-shadow: var(--shadow-lg);
}
/* Until the first review is published this panel IS the section, so it gets
   the treatment of a finished object — a lit top edge and a brand wash — and
   reads as "we are asking you for one", not as a grid that failed to load. */
.review-invite::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(680px 320px at 50% -35%, rgba(var(--brand-light-rgb), 0.26), transparent 70%);
}
.review-invite::after {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--brand-primary), var(--brand-primary-light), var(--brand-primary));
}
.review-invite > * { position: relative; }

.review-invite-head { text-align: center; margin-bottom: 26px; }
/* A quote mark in a brand tile above the heading. The oversized line-height is
   a deliberate optical nudge: the glyph hangs near the cap line, so the line
   box has to be taller than the tile to drop it into the middle, and the
   tile's overflow clips whatever hangs past. */
.review-invite-head::before {
  content: "\201C";
  display: block;
  width: 56px; height: 56px;
  margin: 0 auto 18px;
  overflow: hidden;
  border-radius: 18px;
  font-family: var(--font-display);
  font-size: 62px;
  font-weight: 800;
  line-height: 92px;
  text-align: center;
  color: var(--on-brand);
  background: linear-gradient(140deg, var(--brand-primary), var(--brand-primary-dark));
  box-shadow: inset 0 1px 0 var(--btn-gloss), 0 14px 30px -14px rgba(var(--brand-primary-rgb), 0.85);
}
.review-invite-head h3 {
  font-family: var(--font-display);
  font-size: clamp(21px, 2.2vw, 26px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.025em;
  margin-bottom: 10px;
  text-wrap: balance;
}
.review-invite-head p { color: var(--text-secondary); font-size: 15.5px; line-height: 1.6; max-width: 46ch; margin: 0 auto; text-wrap: pretty; }

/* Closed, this is the only call to action in the section, so it is a real
   filled button rather than an outline. */
.review-details summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: fit-content;
  min-width: 236px;
  min-height: 50px;
  margin: 0 auto;
  padding: 14px 30px;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15.5px;
  border-radius: 999px;
  border: 1px solid transparent;
  color: var(--on-brand);
  background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-dark));
  box-shadow:
    inset 0 1px 0 var(--btn-gloss),
    0 1px 2px rgba(var(--brand-primary-rgb), 0.30),
    0 10px 24px -10px rgba(var(--brand-primary-rgb), 0.70);
  transition: background 0.2s ease, color 0.2s ease, box-shadow 0.2s ease,
              border-color 0.2s ease, transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.review-details summary::-webkit-details-marker { display: none; }
.review-details summary:hover {
  background: linear-gradient(135deg, var(--brand-primary-dark), var(--brand-primary-deep));
  transform: translateY(-2px);
  box-shadow:
    inset 0 1px 0 var(--btn-gloss),
    0 2px 4px rgba(var(--brand-primary-rgb), 0.28),
    0 18px 34px -12px rgba(var(--brand-primary-rgb), 0.80);
}
.review-details summary:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 3px;
}
/* Open, the button has done its job and the form is the loud thing, so it
   steps back to a quiet outline. */
.review-details[open] summary {
  background: transparent;
  color: var(--brand-primary);
  border-color: var(--border-strong);
  box-shadow: none;
  margin-bottom: 28px;
}
.review-details[open] summary:hover {
  background: rgba(var(--brand-primary-rgb), 0.08);
  border-color: var(--brand-primary);
  transform: none;
  box-shadow: none;
}

/* Checkbox sits beside its label rather than above it, unlike the text fields. */
.consent-field {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
/* The checkbox must opt OUT of the text-field sizing above (width:100%,
   min-height:46px, padding) or it stretches into a 13x46 sliver. */
.consent-field input[type="checkbox"] {
  width: 17px;
  height: 17px;
  min-height: 0;
  padding: 0;
  margin: 2px 0 0;
  flex: 0 0 auto;
  border-radius: 4px;
  accent-color: var(--brand-primary);
  cursor: pointer;
}
.consent-field input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
}
.consent-field label {
  margin-bottom: 0;
  font-weight: 500;
  font-size: 13.5px;
  color: var(--text-secondary);
  line-height: 1.5;
}

@media (max-width: 560px) {
  .review-invite { padding: 26px 20px; }
  .review-card { padding: 24px 22px 22px; }
  .review-card::before { font-size: 108px; top: -20px; right: 12px; }
  .review-details summary { min-width: 0; width: 100%; padding: 14px 20px; }
}

/* ---------------- FAQ ---------------- */
/* Wrapper around the FAQ list — was an inline style on the page. */
.faq-list { max-width: 760px; margin: 0 auto; }

.faq-item {
  background: linear-gradient(180deg, var(--surface), var(--surface-sunken));
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px 26px;
  margin-bottom: 14px;
  box-shadow: var(--shadow-sm);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.faq-item:hover { border-color: rgba(var(--brand-primary-rgb), 0.45); box-shadow: var(--shadow-md); }
.faq-item[open] { border-color: rgba(var(--brand-primary-rgb), 0.45); box-shadow: var(--shadow-glow); }
.faq-item summary { cursor: pointer; font-family: var(--font-display); font-weight: 700; font-size: 16px; letter-spacing: -0.015em; list-style: none; display: flex; justify-content: space-between; align-items: center; gap: 16px; }
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: 4px; border-radius: 4px; }
.faq-item summary::after {
  content: "+"; flex-shrink: 0; width: 30px; height: 30px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, rgba(var(--brand-primary-rgb), 0.13), rgba(var(--brand-light-rgb), 0.24));
  border: 1px solid rgba(var(--brand-primary-rgb), 0.20);
  font-size: 17px; font-weight: 700; color: var(--brand-primary);
  transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), background 0.2s ease, border-color 0.2s ease;
}
.faq-item[open] summary::after { transform: rotate(45deg); background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-light)); border-color: transparent; color: var(--on-brand); }
.faq-item p { margin-top: 15px; color: var(--text-secondary); font-size: 15.5px; line-height: 1.62; }

/* ---------------- Footer ---------------- */
.site-footer {
  position: relative;
  overflow: hidden;
  background: var(--brand-dark);
  color: var(--on-dark-soft);
  padding: clamp(56px, 6vw, 84px) 0 30px;
}
.site-footer::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: 3px;
  z-index: 1;
  background: linear-gradient(90deg, var(--brand-primary), var(--brand-primary-light), var(--brand-primary));
}
/* A single brand glow in the top-left, so the footer is the same kind of
   surface as the hero rather than a flat black band under the page. */
.site-footer::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  background: radial-gradient(820px 420px at 10% -20%, rgba(var(--brand-light-rgb), 0.13), transparent 66%);
}
.site-footer .container { position: relative; z-index: 1; }
.footer-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: 40px; margin-bottom: 44px; }
@media (max-width: 760px) { .footer-grid { grid-template-columns: 1fr; } }
.footer-grid h4 { color: var(--on-dark); font-family: var(--font-display); font-size: 12.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.11em; margin-bottom: 18px; }
.footer-grid li { margin-bottom: 11px; font-size: 14.5px; }
.footer-grid a { transition: color 0.18s ease; }
.footer-grid a:hover { color: var(--on-dark); }
.footer-grid a:focus-visible { outline: 2px solid var(--brand-primary-light); outline-offset: 3px; border-radius: 4px; }
.footer-logo { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.footer-tagline { font-size: 14.5px; line-height: 1.6; max-width: 34ch; color: var(--on-dark-muted); }
.footer-bottom { border-top: 1px solid var(--on-dark-line); padding-top: 26px; display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px; font-size: 13px; color: var(--on-dark-muted); }

/* ---------------- Page hero (inner pages) ---------------- */
.page-hero {
  position: relative;
  overflow: hidden;
  padding: clamp(56px, 7vw, 96px) 0 clamp(52px, 6vw, 84px);
  background:
    radial-gradient(940px 460px at 8% -22%, rgba(var(--brand-primary-rgb), 0.18), transparent 62%),
    radial-gradient(760px 440px at 102% -5%, rgba(var(--brand-light-rgb), 0.20), transparent 62%),
    var(--surface-alt);
  border-bottom: 1px solid var(--border);
}
/* Same grid as the index hero, dialled down — the inner pages are shorter and
   the pattern would otherwise be the loudest thing on them. See .hero::before
   for why the mask uses a literal black. */
.page-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(var(--brand-primary-rgb), 0.08) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(var(--brand-primary-rgb), 0.08) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(680px 360px at 10% 10%, #000, transparent 72%);
  mask-image: radial-gradient(680px 360px at 10% 10%, #000, transparent 72%);
}
.page-hero .container { position: relative; z-index: 1; }
.page-hero .kicker { margin-bottom: 16px; }
.page-hero h1 { font-family: var(--font-display); font-size: var(--fs-h1); font-weight: 800; line-height: 1.06; letter-spacing: -0.032em; margin-bottom: 18px; text-wrap: balance; }
.page-hero p { color: var(--text-secondary); font-size: var(--fs-lead); line-height: 1.62; max-width: 62ch; text-wrap: pretty; }

.breadcrumb { font-size: 13px; color: var(--text-muted); margin-bottom: 20px; }
.breadcrumb a { color: var(--text-muted); transition: color 0.15s ease; }
.breadcrumb a:hover { color: var(--brand-primary); }
.breadcrumb a:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: 3px; border-radius: 3px; }

/* ==========================================================================
   Hero showcase carousel - rotating portfolio of recent client sites
   ========================================================================== */
.showcase { display: flex; flex-direction: column; }
.hero-card.showcase {
  position: relative;
  padding: 12px 12px 16px;
  background: linear-gradient(180deg, var(--surface), var(--surface-sunken));
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg), 0 48px 92px -46px rgba(var(--brand-primary-rgb), 0.60);
}
/* A blurred brand halo behind the frame. Without it the card floats on the
   hero wash with nothing tying it to the page. z-index -1 works because
   .hero .container is the stacking context. */
.hero-card.showcase::before {
  content: "";
  position: absolute;
  inset: -12% -7% -18%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(var(--brand-light-rgb), 0.45), transparent 72%);
  filter: blur(30px);
  pointer-events: none;
}

/* Fake browser chrome so the dark screenshot reads as a site on a screen */
.showcase-chrome {
  display: flex; align-items: center; gap: 10px;
  padding: 2px 4px 10px;
}
.showcase-chrome .browser-dots { display: flex; gap: 6px; flex-shrink: 0; }
.showcase-chrome .browser-dots span { width: 9px; height: 9px; border-radius: 50%; }
.showcase-chrome .browser-dots span:nth-child(1) { background: var(--chrome-red); }
.showcase-chrome .browser-dots span:nth-child(2) { background: var(--chrome-amber); }
.showcase-chrome .browser-dots span:nth-child(3) { background: var(--chrome-green); }
.showcase-url {
  flex: 1; text-align: center;
  font-size: 11.5px; font-weight: 600; color: var(--text-muted);
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 999px; padding: 5px 14px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.showcase-window {
  position: relative; width: 100%; aspect-ratio: 16 / 9;
  overflow: hidden; background: var(--surface-alt);
  border-radius: 12px;
  box-shadow: inset 0 0 0 1px var(--border);
}

.showcase-slide {
  position: absolute; inset: 0; display: block;
  opacity: 0; visibility: hidden; transform: scale(1.015);
  transition: opacity .6s ease, transform .6s ease, visibility .6s;
}
.showcase-slide.is-active { opacity: 1; visibility: visible; transform: scale(1); }
.showcase-slide img {
  width: 100%; height: 100%; object-fit: cover; object-position: center top;
  display: block; position: relative; z-index: 1;
  border: 0;
  border-radius: 12px;
}

.portfolio-section { background: var(--surface-alt); }
/* Four projects: a 2x2 grid keeps every screenshot legible, where a third
   column would leave one card stranded on its own row. */
.portfolio-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(20px, 2.2vw, 28px); }
.portfolio-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: linear-gradient(180deg, var(--surface), var(--surface-sunken));
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.3s ease, border-color 0.3s ease;
}
.portfolio-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-glow); border-color: rgba(var(--brand-primary-rgb), 0.45); }
.portfolio-card:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: 3px; }
.portfolio-image { aspect-ratio: 16 / 9; overflow: hidden; background: var(--surface-alt); border-bottom: 1px solid var(--border); }
.portfolio-image img { width: 100%; height: 100%; object-fit: cover; object-position: center top; transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1); }
.portfolio-card:hover .portfolio-image img { transform: scale(1.04); }
.portfolio-card-body {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 6px; padding: 18px 22px 20px; margin-top: auto;
}
.portfolio-card-body h3 { font-family: var(--font-display); font-size: 17px; font-weight: 700; line-height: 1.25; letter-spacing: -0.015em; }
.portfolio-card-body span {
  color: var(--brand-primary); font-family: var(--font-display); font-size: 13.5px; font-weight: 700;
  transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}
.portfolio-card:hover .portfolio-card-body span { transform: translateX(4px); }
/* Not-yet-live work: same card, but the label must not read as a dead link */
.portfolio-card:not(a) { cursor: default; }
.portfolio-card:not(a) .portfolio-card-body span { color: var(--text-muted); font-weight: 600; }
.portfolio-card:not(a):hover { transform: none; box-shadow: var(--shadow-sm); border-color: var(--border); }
.portfolio-card:not(a):hover .portfolio-image img { transform: none; }
.portfolio-card:not(a):hover .portfolio-card-body span { transform: none; }

@media (max-width: 860px) { .portfolio-grid { grid-template-columns: 1fr; max-width: 560px; margin: 0 auto; } }

/* Shown only when the screenshot is missing or fails to load */
.showcase-fallback {
  position: absolute; inset: 0; z-index: 0;
  display: flex; align-items: center; justify-content: center; text-align: center;
  padding: 20px; font-family: var(--font-display); font-weight: 600; font-size: 15px;
  color: var(--brand-primary);
  background: linear-gradient(135deg, var(--surface-alt), var(--border));
}

.showcase-footer {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-top: 12px; padding: 0 4px;
}
.showcase-caption { font-size: 12.5px; color: var(--text-muted); }
.showcase-caption strong { color: var(--text-primary); font-weight: 700; }

.showcase-dots { display: flex; gap: 7px; }
.showcase-dots button {
  position: relative;
  width: 10px; height: 10px; padding: 0; border: 0; border-radius: 999px;
  background: var(--dot-idle); cursor: pointer; transition: background .25s, width .25s;
}
/* A 10px dot is the right size to look at and the wrong size to hit. The
   pseudo-element gives each one a ~30px target without changing the mark. */
.showcase-dots button::after {
  content: ""; position: absolute; inset: -10px;
}
.showcase-dots button:hover { background: var(--brand-primary-light); }
.showcase-dots button:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: 3px; }
.showcase-dots button[aria-selected="true"] {
  background: var(--brand-primary); width: 26px;
}

@media (max-width: 720px) {
  .showcase-footer { flex-direction: column; align-items: flex-start; gap: 8px; }
}

/* ---------------- Scroll reveal -------------------------------------------
   Sections fade and lift into place the first time they scroll into view.
   The hidden state applies only under `.js-motion`, a class the inline script
   in each page's <head> sets before the body paints. So: no JS means no class
   means the page renders fully visible, and because the class lands before
   first paint there is no flash of visible-then-hidden content.

   Keep this selector list in sync with REVEAL_SELECTOR in js/main.js — the CSS
   hides them, the JS decides when each one un-hides.
-------------------------------------------------------------------------- */
.js-motion .section-head,
.js-motion .card,
.js-motion .value-card,
.js-motion .price-card,
.js-motion .portfolio-card,
.js-motion .founder-card,
.js-motion .step,
.js-motion .faq-item,
.js-motion .service-row,
.js-motion .cta-banner,
.js-motion .chip-cloud,
.js-motion .contact-info-card,
.js-motion .contact-form-card,
.js-motion .review-card,
.js-motion .review-invite {
  opacity: 0;
  transform: translateY(18px);
  /* Decelerating ease — moves off quickly, settles slowly. Reads as "arriving"
     rather than "sliding". */
  transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
              transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: var(--reveal-delay, 0s);
}

/* JS adds this the first time the element crosses into view, then stops
   watching it — reveals happen once, not on every scroll past. */
.js-motion .is-revealed {
  opacity: 1;
  transform: none;
}

/* ---------------- Button motion ------------------------------------------
   Hover lift already lives up in the buttons section; this adds the light
   sweep across a primary button and a press state that actually depresses.
-------------------------------------------------------------------------- */
.btn {
  position: relative;
  overflow: hidden;
}

/* A soft highlight that crosses the button once per hover. Skewed so the edge
   reads as a reflection rather than a moving bar. */
.btn-primary::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: -60%;
  width: 45%;
  background: linear-gradient(100deg, transparent, var(--btn-sheen), transparent);
  transform: skewX(-18deg);
  opacity: 0;
  pointer-events: none;
}
.btn-primary:hover::after { animation: btn-sheen 0.75s ease forwards; }

@keyframes btn-sheen {
  0%   { left: -60%; opacity: 0; }
  20%  { opacity: 1; }
  100% { left: 115%; opacity: 0; }
}

.btn-outline:hover { background: rgba(var(--brand-primary-rgb), 0.07); }

/* Overrides the .btn:hover lift — a click should land, not keep floating.
   The short duration keeps the press feeling immediate. */
.btn:active {
  transform: translateY(0) scale(0.97);
  transition-duration: 0.07s;
}

.btn:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 3px;
}

/* The arrow in "Learn more →" leans toward the link on card hover. */
.card-link { transition: transform 0.2s ease, color 0.2s ease; }
.card:hover .card-link { transform: translateX(4px); color: var(--brand-primary-dark); }

/* ---------------- Focus ---------------------------------------------------
   Everything clickable that did not already carry a ring. Keyboard-only, so
   it costs a mouse user nothing and is the difference between usable and not
   for everyone else.
-------------------------------------------------------------------------- */
.card-link:focus-visible,
.nav-phone:focus-visible,
.logo:focus-visible,
.showcase-slide:focus-visible,
.form-notice a:focus-visible,
.contact-info-card a:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 3px;
  border-radius: 4px;
}
.showcase-slide:focus-visible { outline-offset: -3px; border-radius: 12px; }

@media (prefers-reduced-motion: reduce) {
  .showcase-slide { transition: none; transform: none; }
  .showcase-slide.is-active { transform: none; }

  /* Reveal targets stay put and stay visible — the content still arrives, it
     just does not travel to get there. */
  .js-motion .section-head,
  .js-motion .card,
  .js-motion .value-card,
  .js-motion .price-card,
  .js-motion .portfolio-card,
  .js-motion .founder-card,
  .js-motion .step,
  .js-motion .faq-item,
  .js-motion .service-row,
  .js-motion .cta-banner,
  .js-motion .chip-cloud,
  .js-motion .contact-info-card,
  .js-motion .contact-form-card,
  .js-motion .review-card,
  .js-motion .review-invite {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .btn:hover { transform: none; }
  .btn:active { transform: none; }
  .btn-primary:hover::after { animation: none; }

  /* Smooth scrolling is motion too — an in-page jump should just arrive. */
  html { scroll-behavior: auto; }

  /* The "we are open" dot stops blinking; it stays visible. */
  .eyebrow::before { animation: none; }

  /* Every hover lift on the page. The colour and shadow change stays, so the
     affordance survives — nothing moves to deliver it. */
  .card:hover,
  .value-card:hover,
  .portfolio-card:hover,
  .founder-card:hover,
  .review-card:hover,
  .chip-cloud span:hover,
  .review-details summary:hover {
    transform: none;
  }
  .card:hover .card-icon,
  .card:hover .card-link,
  .portfolio-card:hover .portfolio-image img,
  .portfolio-card:hover .portfolio-card-body span,
  .founder-card:hover .founder-photo img {
    transform: none;
  }
  /* Accents appear instead of sweeping. The FAQ plus still rotates to an x —
     that is the open/closed state, not decoration — it just does it at once. */
  .card::before,
  .card::after,
  .card-icon,
  .value-card::before,
  .nav-links a::after,
  .faq-item summary::after {
    transition: none;
  }
}
