/* ==========================================================================
   NaiGrowth — Components
   Nav, buttons, cursor, hero layer, cards, stats, FAQ, footer, reveals.
   ========================================================================== */

/* ==========================================================================
   1. Custom cursor — a focus reticle

   Not an expanding disc with a word inside it. That pattern is on every
   templated agency site, and worse, it parks a tinted circle on top of the
   very text the pointer is over.

   This is an instrument instead: a precise dot inside four tick marks with
   an open centre, so whatever is underneath stays readable. Hovering
   something interactive rotates the reticle to 45 degrees and locks the
   ticks in, the way a camera confirms focus. Any label rides OUTSIDE the
   reticle as a small chip, below and right, never over the content.

   The native pointer is hidden only once this one is live, so a JS failure
   can never leave the page with no cursor at all.
   ========================================================================== */

.cursor-dot,
.cursor-reticle,
.cursor-label {
  position: fixed;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  pointer-events: none;
  z-index: var(--z-cursor);
  opacity: 0;
  will-change: transform;
  transition: opacity var(--t-med) var(--ease-out);
}

/* --- The dot ------------------------------------------------------------ */

.cursor-dot__shape {
  position: absolute;
  top: 0;
  left: 0;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--cursor-fg, #fff);
  box-shadow: 0 0 0 1px var(--cursor-halo, rgba(4, 5, 12, 0.45));
  transform: translate(-50%, -50%) scale(1);
  transition: transform var(--t-fast) var(--ease-out);
}

/* --- The reticle -------------------------------------------------------- */

.cursor-reticle {
  --reach: 14px;
  --tick: 6px;
  --thick: 1.5px;
}

.cursor-reticle__frame {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  transform: rotate(0deg);
  transition: transform var(--t-med) var(--ease-spring);
}

.cursor-tick {
  position: absolute;
  top: 0;
  left: 0;
  background: var(--cursor-ring, rgba(255, 255, 255, 0.46));
  border-radius: 1px;
  transition: transform var(--t-med) var(--ease-spring),
    background-color var(--t-fast) linear, height var(--t-med) var(--ease-spring),
    width var(--t-med) var(--ease-spring);
}

.cursor-tick[data-side="n"],
.cursor-tick[data-side="s"] {
  width: var(--thick);
  height: var(--tick);
  margin: calc(var(--tick) / -2) 0 0 calc(var(--thick) / -2);
}

.cursor-tick[data-side="e"],
.cursor-tick[data-side="w"] {
  width: var(--tick);
  height: var(--thick);
  margin: calc(var(--thick) / -2) 0 0 calc(var(--tick) / -2);
}

.cursor-tick[data-side="n"] { transform: translateY(calc(var(--reach) * -1)); }
.cursor-tick[data-side="s"] { transform: translateY(var(--reach)); }
.cursor-tick[data-side="e"] { transform: translateX(var(--reach)); }
.cursor-tick[data-side="w"] { transform: translateX(calc(var(--reach) * -1)); }

/* --- The label, outside the reticle ------------------------------------- */

.cursor-label__chip {
  position: absolute;
  top: 0;
  left: 0;
  transform: translate(13px, 13px) scale(0.82);
  transform-origin: 0 0;
  padding: 0.26rem 0.5rem;
  border-radius: 3px;
  border: 1px solid var(--cursor-ring-label, rgba(118, 165, 255, 0.8));
  background: var(--cursor-chip-bg, rgba(8, 11, 26, 0.92));
  font-family: var(--font-mono);
  font-size: 0.6rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--cursor-fg, #fff);
  white-space: nowrap;
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease-out), transform var(--t-med) var(--ease-spring);
}

body.cursor-ready .cursor-dot,
body.cursor-ready .cursor-reticle {
  opacity: 1;
}

/* Hide the native pointer.  The old rule was `body.cursor-ready *` — a
   universal selector that forced Chrome to recalculate cursor styles on
   EVERY element in the DOM whenever any class was toggled on body (which
   clearHoverState does during scroll).  That recalculation was expensive
   enough to collapse the document height for one frame, which is the
   scroll-jump-to-top bug.

   Inheriting `cursor:none` from body covers most elements.  The few that
   browsers override (links, buttons, inputs, textareas) need an explicit
   rule, but naming them is three orders of magnitude cheaper than `*`. */
body.cursor-ready {
  cursor: none;
}

body.cursor-ready a,
body.cursor-ready button,
body.cursor-ready [role="button"],
body.cursor-ready select,
body.cursor-ready summary,
body.cursor-ready label {
  cursor: none;
}

body.cursor-ready input,
body.cursor-ready textarea {
  cursor: text;
}

/* Text entry: native caret is restored, custom cursor is hidden */
body.cursor-ready.cursor-text .cursor-dot,
body.cursor-ready.cursor-text .cursor-reticle,
body.cursor-ready.cursor-text .cursor-label {
  opacity: 0;
}

/* Locked on: the frame turns to 45 degrees and the ticks draw in and
   lengthen. The centre stays open throughout. */
.cursor-reticle.is-hover .cursor-reticle__frame,
.cursor-reticle.is-label .cursor-reticle__frame,
body.cursor-hover .cursor-reticle__frame,
body.cursor-label .cursor-reticle__frame {
  transform: rotate(45deg);
}

.cursor-reticle.is-hover,
.cursor-reticle.is-label,
body.cursor-hover .cursor-reticle,
body.cursor-label .cursor-reticle {
  --reach: 10px;
  --tick: 9px;
}

.cursor-reticle.is-hover .cursor-tick,
.cursor-reticle.is-label .cursor-tick,
body.cursor-hover .cursor-tick,
body.cursor-label .cursor-tick {
  background: var(--cursor-ring-hover, rgba(169, 137, 255, 0.76));
}

.cursor-dot.is-hover .cursor-dot__shape,
.cursor-dot.is-label .cursor-dot__shape,
body.cursor-hover .cursor-dot__shape,
body.cursor-label .cursor-dot__shape {
  transform: translate(-50%, -50%) scale(0.6);
}

.cursor-label.is-active,
body.cursor-ready.cursor-label .cursor-label {
  opacity: 1;
}

.cursor-label.is-active .cursor-label__chip,
body.cursor-label .cursor-label__chip {
  opacity: 1;
  transform: translate(13px, 13px) scale(1);
}

/* Press: the reticle snaps shut. */
.cursor-reticle.is-press,
body.cursor-press .cursor-reticle {
  --reach: 7px;
}

.cursor-dot.is-press .cursor-dot__shape,
body.cursor-press .cursor-dot__shape {
  transform: translate(-50%, -50%) scale(1.5);
}

/* Pointer precision and motion preference both gate the whole feature. */
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .cursor-dot,
  .cursor-reticle,
  .cursor-label {
    display: none !important;
  }
  body.cursor-ready,
  body.cursor-ready a,
  body.cursor-ready button,
  body.cursor-ready [role="button"],
  body.cursor-ready input,
  body.cursor-ready textarea,
  body.cursor-ready select,
  body.cursor-ready summary,
  body.cursor-ready label {
    cursor: auto;
  }
  body.cursor-ready a,
  body.cursor-ready button {
    cursor: pointer;
  }
}

/* ==========================================================================
   2. Buttons
   ========================================================================== */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-3);
  padding: 0.95rem 1.8rem;
  border-radius: var(--r-pill);
  font-family: var(--font-body);
  font-size: var(--t-sm);
  font-weight: 600;
  letter-spacing: 0.005em;
  white-space: nowrap;
  isolation: isolate;
  overflow: hidden;
  transition: transform var(--t-med) var(--ease-out), box-shadow var(--t-med) var(--ease-out),
    border-color var(--t-med) var(--ease-out), background-color var(--t-med) var(--ease-out);
}

.btn svg {
  width: 17px;
  height: 17px;
  flex: none;
  transition: transform var(--t-med) var(--ease-out);
}

.btn:hover svg {
  transform: translateX(3px);
}

.btn--primary {
  background: var(--accent-grad-solid);
  /* Gold overrides this to dark ink: white on brass measures ~2:1. */
  color: var(--btn-primary-ink, #fff);
  box-shadow: 0 10px 30px rgba(76, 125, 255, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.22);
}

/* A second gradient layer cross-fades in on hover — smoother than animating
   the gradient itself, which browsers cannot interpolate. */
.btn--primary::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--accent-grad-solid-alt);
  opacity: 0;
  transition: opacity var(--t-med) var(--ease-out);
}

.btn--primary:hover {
  box-shadow: 0 18px 46px rgba(139, 92, 246, 0.44), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}

.btn--primary:hover::after {
  opacity: 1;
}

.btn--ghost {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--hairline-strong);
  backdrop-filter: blur(14px);
}

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

.btn--lg {
  padding: 1.12rem 2.3rem;
  font-size: var(--t-body);
}

.btn--block {
  width: 100%;
}

/* Magnetic buttons are translated by JS; the wrapper keeps layout stable so
   the pull never reflows neighbouring content.

   `flex: none` is load-bearing. As a flex item the wrapper shrinks by default,
   but the .btn inside it is `white-space: nowrap`, so the button overflowed
   its own wrapper and sat on top of its neighbour. That is the button overlap
   seen on every CTA row. */
.magnetic {
  display: inline-flex;
  flex: none;
  max-width: 100%;
  will-change: transform;
}

/* Same reason: a bare .btn used directly as a flex item must not be squeezed
   below its text. */
.hero__cta > .btn,
.cta__actions > .btn,
.page-head__cta > .btn {
  flex: none;
}

/* ==========================================================================
   3. Navigation
   ========================================================================== */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-nav);
  transition: transform var(--t-med) var(--ease-out), background-color var(--t-med) var(--ease-out),
    border-color var(--t-med) var(--ease-out), backdrop-filter var(--t-med) var(--ease-out);
  border-bottom: 1px solid transparent;
}

.nav--scrolled,
/* An open drawer needs a solid bar above it even at scroll position 0. */
.nav:has([data-nav-drawer][data-open="true"]) {
  background: var(--nav-bg);
  backdrop-filter: blur(22px) saturate(1.3);
  border-bottom-color: var(--hairline);
}

/* While the bar floats over the hero it sits on the dark stage, so its own
   text tokens are the dark-scheme ones in BOTH themes. Scoped to the bar
   itself — the drawer below it belongs to the page, not the hero. */
.nav:not(.nav--scrolled) .nav__inner {
  --text: #ffffff;
  --text-strong: #ffffff;
  --text-dim: rgba(255, 255, 255, 0.82);
  --text-muted: rgba(255, 255, 255, 0.64);
  --surface: rgba(255, 255, 255, 0.07);
  --surface-hover: rgba(255, 255, 255, 0.12);
  --hairline: rgba(255, 255, 255, 0.14);
  --hairline-strong: rgba(255, 255, 255, 0.24);
  color: #fff;
}

/* Drawer open at the top of the page: the bar is solid, so hand the tokens
   back to the theme. `inherit` on a custom property restores the ancestor's
   value, which is the root/theme one. */
.nav:has([data-nav-drawer][data-open="true"]):not(.nav--scrolled) .nav__inner {
  --text: inherit;
  --text-strong: inherit;
  --text-dim: inherit;
  --text-muted: inherit;
  --surface: inherit;
  --surface-hover: inherit;
  --hairline: inherit;
  --hairline-strong: inherit;
  color: inherit;
}

/* Hide on scroll-down, reveal on scroll-up — more screen for the 3D scene. */
.nav--hidden {
  transform: translateY(-104%);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
  height: 74px;
}

.nav__brand {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  flex: none;
  /* Keeps the hit area at 44px even where the logo shrinks to 32. */
  padding-block: 0.3rem;
}

.nav__brand img {
  width: 38px;
  height: 38px;
  border-radius: 10px;
  border: 1px solid var(--hairline);
}

.nav__brand-name {
  font-family: var(--font-display);
  font-size: 1.16rem;
  font-weight: 700;
  letter-spacing: -0.028em;
}

.nav__brand-name span {
  font-weight: 300;
  color: var(--text-dim);
}

.nav__links {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

.nav__link {
  position: relative;
  padding: 0.5rem 0.95rem;
  border-radius: var(--r-pill);
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--text-dim);
  transition: color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out);
}

.nav__link:hover,
.nav__link[aria-current="true"] {
  color: var(--text);
  background: var(--surface-hover);
}

.nav__actions {
  display: flex;
  align-items: center;
  /* s-3 left the switch inside the primary button's 30px glow, so it looked
     lit from the side. */
  gap: var(--s-4);
  flex: none;
}

/* --- Theme switch -------------------------------------------------------
   Two icons stacked in one 44px control; only the one for the scheme you
   would switch TO is shown, so the button always reads as an action. */
.nav__theme {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: var(--r-pill);
  border: 1px solid var(--hairline-strong);
  background: var(--surface-hover);
  color: var(--text-dim);
  transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out),
    background-color var(--t-fast) var(--ease-out);
}

.nav__theme:hover {
  color: var(--text);
  border-color: var(--accent-ink);
}

.nav__theme svg {
  position: absolute;
  width: 19px;
  height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: opacity var(--t-fast) var(--ease-out), transform var(--t-med) var(--ease-spring);
}

/* Three schemes cycle light -> dark -> gold, and the icon shown is the one
   you are switching TO, so the control always reads as an action. All three
   icons are stacked; only the next one is visible. */
.nav__theme svg {
  opacity: 0;
  transform: rotate(-60deg) scale(0.6);
}

/* On light, the next press gives you dark. */
.nav__theme .icon-moon {
  opacity: 1;
  transform: rotate(0deg) scale(1);
}

[data-theme="dark"] .nav__theme .icon-moon {
  opacity: 0;
  transform: rotate(60deg) scale(0.6);
}

/* On dark, the next press gives you gold. */
[data-theme="dark"] .nav__theme .icon-gold {
  opacity: 1;
  transform: rotate(0deg) scale(1);
}

/* On gold, the next press brings you back to light. */
[data-theme="gold"] .nav__theme .icon-sun {
  opacity: 1;
  transform: rotate(0deg) scale(1);
}

.nav__toggle {
  display: none;
  width: 44px;
  height: 44px;
  border-radius: var(--r-sm);
  border: 1px solid var(--hairline-strong);
  background: var(--surface-hover);
  place-items: center;
}

.nav__toggle span {
  display: block;
  width: 18px;
  height: 1.5px;
  background: var(--text);
  border-radius: 2px;
  transition: transform var(--t-med) var(--ease-out), opacity var(--t-fast) var(--ease-out);
}

.nav__toggle span + span {
  margin-top: 5px;
}

.nav__toggle[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(6.5px) rotate(45deg);
}
.nav__toggle[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
}
.nav__toggle[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(-6.5px) rotate(-45deg);
}

@media (max-width: 960px) {
  .nav__links,
  .nav__actions .btn {
    display: none;
  }

  .nav__toggle {
    display: grid;
  }

  /* Mobile sheet. Collapsed via max-height so it animates without JS measuring. */
  .nav__drawer {
    position: absolute;
    top: 74px;
    left: 0;
    right: 0;
    background: var(--drawer-bg);
    backdrop-filter: blur(24px);
    border-bottom: 1px solid var(--hairline);
    display: grid;
    gap: var(--s-1);
    padding: 0 var(--gutter);
    max-height: 0;
    overflow: hidden;
    transition: max-height var(--t-med) var(--ease-out), padding var(--t-med) var(--ease-out);
  }

  .nav__drawer[data-open="true"] {
    max-height: 72vh;
    overflow-y: auto;
    padding: var(--s-4) var(--gutter) var(--s-6);
  }

  .nav__drawer a {
    padding: 0.85rem 0.25rem;
    font-size: 1.05rem;
    font-weight: 500;
    border-bottom: 1px solid var(--hairline);
  }

  .nav__drawer .btn {
    margin-top: var(--s-4);
  }
}

@media (min-width: 961px) {
  .nav__drawer {
    display: none;
  }
}

/* ==========================================================================
   5. Trust strip
   ========================================================================== */

.trust {
  position: relative;
  z-index: var(--z-content);
  padding-block: var(--s-7);
  border-block: 1px solid var(--hairline);
  background: var(--band-bg);
  backdrop-filter: blur(10px);
}

.trust__label {
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 400;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: var(--s-5);
}

.trust__logos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(1.5rem, 5vw, 3.6rem);
}

.trust__logos li {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-display);
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text-dim);
  opacity: 0.74;
  transition: opacity var(--t-med) var(--ease-out), color var(--t-med) var(--ease-out);
}

.trust__logos li:hover {
  opacity: 1;
  color: var(--text-strong);
}

.trust__logos img {
  width: 26px;
  height: 26px;
  border-radius: 6px;
}

/* ==========================================================================
   6. Glass card + service grid
   ========================================================================== */

.glass {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  backdrop-filter: blur(18px) saturate(1.2);
  overflow: hidden;
  /* Establishes the stacking context the hover state raises itself out of. */
  z-index: 0;
  transition: transform var(--t-med) var(--ease-out), border-color var(--t-med) var(--ease-out),
    background-color var(--t-med) var(--ease-out), box-shadow var(--t-med) var(--ease-out);
}

/* Specular sheen along the top edge — the single detail that sells "glass". */
.glass::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--sheen) 48%, transparent);
}

/* A hovered card has to paint ABOVE its neighbours, or its own glow shows
   through their translucent backgrounds and reads as the shadow jumping to
   the wrong box. */
.glass:hover {
  transform: translateY(-4px);
  background: var(--surface-strong);
  border-color: color-mix(in srgb, var(--accent-ink-2) 38%, transparent);
  box-shadow: var(--glow-card);
  z-index: 2;
}

.services__grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: clamp(0.9rem, 1.6vw, 1.35rem);
}

/* An asymmetric, deliberately non-template rhythm: two flagship tiles, then
   four, then two. Each card declares its own span. */
.service {
  grid-column: span 2;
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  padding: clamp(1.5rem, 2.4vw, 2.1rem);
  min-height: 15rem;
}

/* The two lead services are already wider and carry a larger icon. That is
   the hierarchy; a tinted fill on top of it just introduced a second colour
   that read as unrelated rather than as emphasis. */
.service--flagship {
  grid-column: span 3;
  min-height: 19.5rem;
}

.service--flagship h3 {
  font-size: clamp(1.32rem, 2vw, 1.62rem);
}

.service--wide {
  grid-column: span 3;
  min-height: 12rem;
}

.service__icon {
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 13px;
  background: var(--accent-grad-soft);
  border: 1px solid var(--hairline-strong);
  flex: none;
}

.service__icon svg {
  width: 22px;
  height: 22px;
  stroke: var(--accent-ink);
  fill: none;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.service--flagship .service__icon {
  width: 54px;
  height: 54px;
}

.service--flagship .service__icon svg {
  width: 26px;
  height: 26px;
  stroke: var(--accent-ink-2);
}

.service h3 {
  letter-spacing: -0.024em;
}

.service p {
  color: var(--text-muted);
  font-size: var(--t-sm);
  flex-grow: 1;
}

.service__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: auto;
  padding-top: var(--s-2);
}

.service__tags li {
  padding: 0.32rem 0.7rem;
  border-radius: var(--r-pill);
  border: 1px solid var(--hairline);
  background: var(--chip-bg);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--text-muted);
}

.service--flagship .service__tags li {
  border-color: color-mix(in srgb, var(--accent-ink-2) 30%, transparent);
  color: var(--text-dim);
}

@media (max-width: 1000px) {
  .services__grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .service,
  .service--wide {
    grid-column: span 2;
  }
  .service--flagship {
    grid-column: span 4;
    min-height: 16rem;
  }
}

@media (max-width: 620px) {
  .services__grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .service,
  .service--flagship,
  .service--wide {
    grid-column: span 1;
    min-height: 0;
  }
}

/* ==========================================================================
   7. Showcase / work grid
   ========================================================================== */

.showcase__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
  gap: clamp(0.9rem, 1.6vw, 1.35rem);
}

.work {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  padding: clamp(1.5rem, 2.4vw, 2rem);
}

.work__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
}

.work__sector {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 400;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.work__metric {
  font-family: var(--font-display);
  font-size: clamp(2rem, 3.5vw, 2.7rem);
  font-weight: 600;
  letter-spacing: -0.045em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.work__metric-label {
  font-size: var(--t-sm);
  color: var(--text-dim);
}

.work p {
  color: var(--text-muted);
  font-size: var(--t-sm);
}

.work__platforms {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: auto;
  padding-top: var(--s-3);
  border-top: 1px solid var(--hairline);
}

.work__platforms li {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.01em;
  color: var(--text-faint);
  padding: 0.24rem 0.62rem;
  border-radius: var(--r-pill);
  background: var(--chip-bg);
}

/* ==========================================================================
   8. Benefits / feature list
   ========================================================================== */

.benefits {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: clamp(1.4rem, 3vw, 2.6rem);
}

.benefit {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding-top: var(--s-5);
  border-top: 1px solid var(--hairline);
}

.benefit__num {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--accent-ink-2);
}

.benefit h3 {
  font-size: var(--t-h4);
  letter-spacing: -0.015em;
}

.benefit p {
  color: var(--text-muted);
  font-size: var(--t-sm);
}

/* ==========================================================================
   9. Stats band
   Four figures used to sit alone in a flat white pill with nothing to say for
   themselves. A number on its own is a claim; a number with its scope under
   it is evidence. So each cell now carries the figure, what it counts, and
   one line saying where it comes from, and the band gets a heading that
   frames the whole set instead of hiding it from everyone but a screen
   reader. The rail above each figure is a measuring tick: it is the only
   moving part, and it extends on hover.
   ========================================================================== */

.stats__head {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  max-width: 46rem;
  margin-bottom: clamp(2rem, 4vw, 3.2rem);
}

.stats__lead {
  color: var(--text-dim);
  font-size: var(--t-lead);
  max-width: 44rem;
}

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: 1px;
  background: var(--hairline);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  overflow: hidden;
}

.stat {
  position: relative;
  background: var(--stat-bg);
  padding: clamp(1.6rem, 2.6vw, 2.3rem) clamp(1.3rem, 2vw, 1.9rem);
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  transition: background-color var(--t-med) var(--ease-out);
}

/* A short measuring tick above the figure. It is the cell's only animation,
   which is what keeps a four-up grid from looking like it is fidgeting. */
.stat__rail {
  width: 30px;
  height: 2px;
  border-radius: 2px;
  background: var(--accent-grad-solid);
  margin-bottom: 0.45rem;
  transition: width var(--t-med) var(--ease-spring);
}

.stat:hover {
  background: var(--stat-bg-hover);
}

.stat:hover .stat__rail {
  width: 68px;
}

.stat__num {
  font-family: var(--font-display);
  font-size: clamp(2.2rem, 4.2vw, 3.1rem);
  font-weight: 600;
  letter-spacing: -0.05em;
  line-height: 1;
  color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}

.stat__label {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 400;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* Pinned to the bottom so the supporting lines share one baseline across the
   row however long the label above each one runs. */
.stat__note {
  margin-top: auto;
  padding-top: 0.55rem;
  font-size: var(--t-sm);
  line-height: 1.5;
  color: var(--text-muted);
  text-wrap: pretty;
}

/* ==========================================================================
   10. Testimonials
   ========================================================================== */

.quotes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: clamp(0.9rem, 1.6vw, 1.35rem);
}

.quote {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  padding: clamp(1.6rem, 2.6vw, 2.2rem);
}

.quote blockquote {
  font-size: var(--t-lead);
  line-height: 1.52;
  color: var(--text);
  letter-spacing: -0.012em;
  flex-grow: 1;
}

.quote figcaption {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding-top: var(--s-4);
  border-top: 1px solid var(--hairline);
}

.quote__avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--accent-grad-solid);
  font-family: var(--font-display);
  font-weight: 650;
  font-size: 0.92rem;
  color: var(--btn-primary-ink, #fff);
  flex: none;
}

.quote__who {
  font-size: var(--t-sm);
  font-weight: 600;
}

.quote__role {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.02em;
  color: var(--text-muted);
}

/* ==========================================================================
   11. FAQ accordion
   ========================================================================== */

.faq {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--hairline);
}

.faq__item {
  border-bottom: 1px solid var(--hairline);
}

.faq__q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
  padding: clamp(1.1rem, 2vw, 1.5rem) 0;
  text-align: left;
  font-family: var(--font-display);
  font-size: var(--t-h4);
  font-weight: 550;
  letter-spacing: -0.015em;
  color: var(--text);
  transition: color var(--t-fast) var(--ease-out);
}

.faq__q:hover {
  color: var(--accent-ink-2);
}

.faq__sign {
  position: relative;
  width: 20px;
  height: 20px;
  flex: none;
}

.faq__sign::before,
.faq__sign::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 14px;
  height: 1.5px;
  background: currentColor;
  border-radius: 2px;
  transform: translate(-50%, -50%);
  transition: transform var(--t-med) var(--ease-out), opacity var(--t-fast) var(--ease-out);
}

.faq__sign::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.faq__q[aria-expanded="true"] .faq__sign::after {
  transform: translate(-50%, -50%) rotate(0deg);
  opacity: 0;
}

/* grid-template-rows 0fr -> 1fr animates to intrinsic height with no JS
   measurement, so answers stay in the DOM for crawlers at all times. */
.faq__a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--t-med) var(--ease-out);
}

.faq__a > div {
  overflow: hidden;
}

.faq__item[data-open="true"] .faq__a {
  grid-template-rows: 1fr;
}

.faq__a p {
  color: var(--text-muted);
  font-size: var(--t-sm);
  max-width: 62ch;
  padding-bottom: clamp(1.1rem, 2vw, 1.5rem);
}

/* ==========================================================================
   14. Scroll reveal
   Opacity+transform only, so reveals never trigger layout.
   ========================================================================== */

/* Reveals are opt-in on scripting being available.
   Hiding content with opacity:0 and relying on JS to clear it means that if
   the script never runs — blocked, errored, a crawler on a tight render
   budget — the page ships 49 invisible sections. Gating on `scripting:
   enabled` makes "visible" the default and the animation the enhancement,
   with no flash of hidden content and no extra request. Browsers without the
   media feature simply render everything, which is the safe direction. */
[data-reveal] {
  opacity: 1;
  transform: none;
}

@media (scripting: enabled) {
  /* 26px over 0.8s meant a section was still settling well after it had
     arrived, which on a fast scroll reads as the page wobbling under you.
     Shorter travel over a shorter time lands before the eye gets there. */
  [data-reveal] {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 0.45s var(--ease-out), transform 0.45s var(--ease-out);
  }

  [data-reveal].is-revealed {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* ==========================================================================
   15. Section bands
   On a light page an unbroken single ground reads as a long scroll with no
   landmarks. Alternating bands give the eye somewhere to rest without adding
   borders everywhere. In dark they are near-invisible by design.
   ========================================================================== */

.section--band {
  background: var(--band-bg);
  border-block: 1px solid var(--hairline);
}

/* ==========================================================================
   16. Platform explainer
   One card per review platform, written to be read by a client rather than by
   a marketer: what it is, who reads it, what we actually do, how long it takes.
   ========================================================================== */

.platforms__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20.5rem), 1fr));
  gap: clamp(0.9rem, 1.6vw, 1.35rem);
}

.platform {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  padding: clamp(1.4rem, 2.4vw, 2rem);
}

/* Start-aligned: a two-line "Read by" caption would otherwise leave the logo
   floating halfway down the block. */
.platform__head {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
}

.platform__logo {
  width: 42px;
  height: 42px;
  flex: none;
  border-radius: 11px;
  border: 1px solid var(--hairline);
  background: var(--surface-strong);
  object-fit: contain;
  padding: 5px;
  margin-top: 1px;
}

/* Platforms we work but whose mark we do not ship an asset for get a drawn
   icon rather than an approximation of their logo. */
.platform__logo--icon {
  display: grid;
  place-items: center;
  padding: 0;
  background: var(--accent-grad-soft);
}

.platform__logo--icon svg {
  width: 21px;
  height: 21px;
  fill: none;
  stroke: var(--accent-ink);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.platform__head h3 {
  font-size: var(--t-h3);
  letter-spacing: -0.022em;
  line-height: 1.1;
}

.platform__who {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  margin-top: 2px;
}

.platform__facts {
  display: grid;
  gap: var(--s-4);
  margin: 0;
}

.platform__facts dt {
  font-family: var(--font-mono);
  font-size: 0.64rem;
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--accent-ink);
  margin-bottom: 0.3rem;
}

.platform__facts dd {
  margin: 0;
  font-size: var(--t-sm);
  color: var(--text-dim);
}

.platform__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-5);
  margin-top: auto;
  padding-top: var(--s-4);
  border-top: 1px solid var(--hairline);
}

.platform__meta > li {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.platform__meta span {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.platform__meta strong {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--text);
}

/* ==========================================================================
   17. Phase timeline
   A single vertical rail. Horizontal step-strips break badly on phones and
   force the copy into unreadable columns; a rail reads identically at 320px
   and at 2560px.
   ========================================================================== */

.phases {
  position: relative;
  display: grid;
  gap: clamp(1.6rem, 3vw, 2.4rem);
  max-width: 54rem;
  padding-left: 0;
}

/* The rail stops short at both ends so it does not dangle past the first and
   last markers. */
.phases::before {
  content: "";
  position: absolute;
  left: 1.22rem;
  top: 1.4rem;
  bottom: 1.4rem;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(
    180deg,
    var(--blue) 0%,
    var(--violet) 55%,
    color-mix(in srgb, var(--violet) 15%, transparent) 100%
  );
  opacity: 0.55;
}

.phase {
  position: relative;
  padding-left: 4rem;
}

.phase__dot {
  position: absolute;
  left: 0;
  top: 0;
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--hairline-strong);
  background: var(--bg-raise);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--accent-ink);
}

.phase__when {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-ink-2);
  margin-bottom: 0.35rem;
}

.phase h3 {
  font-size: var(--t-h3);
  letter-spacing: -0.022em;
  margin-bottom: var(--s-2);
}

.phase p {
  color: var(--text-dim);
  font-size: var(--t-sm);
  max-width: 58ch;
}

.phase__out {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: var(--s-3);
}

.phase__out li {
  padding: 0.3rem 0.7rem;
  border-radius: var(--r-pill);
  border: 1px solid var(--hairline);
  background: var(--chip-bg);
  font-family: var(--font-mono);
  font-size: 0.66rem;
  color: var(--text-muted);
}

@media (max-width: 480px) {
  .phases::before {
    left: 0.97rem;
  }
  .phase {
    padding-left: 3.1rem;
  }
  .phase__dot {
    width: 2rem;
    height: 2rem;
    font-size: 0.64rem;
  }
}

/* ==========================================================================
   18. Contact channels
   Four ways in, each stating what it is good for and how fast it answers, so
   nobody has to guess which one gets a reply.
   ========================================================================== */

/* ==========================================================================
   19. Light-scheme lift
   Translucent surfaces read as cards on black because the ground is darker
   than they are. On a light ground they need a real edge and a real shadow,
   or the whole page flattens into one sheet of paper.
   ========================================================================== */

.glass {
  box-shadow: var(--shadow-sm);
}

/* ==========================================================================
   20. Small-screen corrections
   Checked at 320 / 360 / 390 / 414 / 768 / 1024 / 1280 / 1440 / 2560.
   ========================================================================== */

/* The bar carries a wordmark, a theme switch and a menu button. Below ~400px
   those three plus the gutters overrun the viewport, so the brand gives way
   first — it is the one element that still reads at a smaller size. */
@media (max-width: 400px) {
  .nav__inner {
    height: 64px;
    gap: var(--s-3);
  }

  .nav__brand {
    gap: 0.5rem;
  }

  .nav__brand img {
    width: 32px;
    height: 32px;
    border-radius: 8px;
  }

  .nav__brand-name {
    font-size: 1rem;
  }

  .nav__theme,
  .nav__toggle {
    width: 40px;
    height: 40px;
  }

  .nav__drawer {
    top: 64px;
  }
}

@media (max-width: 560px) {
  /* Three proof figures side by side at 320px leaves ~90px each; stacking two
     per row keeps the numbers at a size worth reading. */
  .hero__proof {
    gap: var(--s-4) var(--s-5);
  }

  .hero__proof-num {
    font-size: 1.38rem;
  }

  .btn,
  .btn--lg {
    /* Long labels ("Get a free reputation audit") must wrap rather than push
       the page into a horizontal scroll. */
    white-space: normal;
    text-align: center;
  }

  .hero__cta .btn,
  .cta__actions .btn,
  .page-head__cta .btn,
  .hero__cta .magnetic,
  .cta__actions .magnetic,
  .page-head__cta .magnetic {
    width: 100%;
  }

  .platform__meta {
    gap: var(--s-4);
  }
}

@media (max-width: 520px) {
  .footer__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .footer__about {
    grid-column: span 1;
  }

  .footer__bottom {
    gap: var(--s-2);
  }
}

/* Very wide displays: the shell is capped, but the hero overlay sitting hard
   left against a 2560px sphere looks accidental. Nudge the content inward. */
@media (min-width: 1700px) {
  .hero__inner {
    max-width: 48rem;
  }
}

/* Wide screens: the rail stays, but the phase splits into a schedule — when
   and what on the left, the detail on the right. Stacked, it left the right
   half of a 1440px viewport empty and read as an unfinished section. */
@media (min-width: 1060px) {
  .phases {
    max-width: none;
  }

  .phase {
    display: grid;
    grid-template-columns: 15rem minmax(0, 1fr);
    grid-template-areas:
      "when  desc"
      "title desc"
      ".     tags";
    column-gap: clamp(2rem, 4vw, 3.5rem);
    align-items: start;
  }

  .phase__when {
    grid-area: when;
    margin-bottom: 0.2rem;
  }

  .phase h3 {
    grid-area: title;
  }

  .phase p {
    grid-area: desc;
    max-width: 64ch;
  }

  .phase__out {
    grid-area: tags;
    margin-top: var(--s-4);
  }
}

.cta__direct-label {
  color: var(--text-muted);
}

/* ==========================================================================
   21. Service cards are links now
   Each one opens its own page, so the card needs an explicit "this is
   clickable" affordance rather than relying on the cursor alone.
   ========================================================================== */

.service {
  text-decoration: none;
}

.service__more {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--hairline);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-ink);
  transition: gap var(--t-fast) var(--ease-out);
}

.service__more svg {
  width: 14px;
  height: 14px;
  flex: none;
  transition: transform var(--t-med) var(--ease-out);
}

.service:hover .service__more svg {
  transform: translateX(4px);
}

.service__tags {
  margin-top: auto;
}

/* ==========================================================================
   22. Service detail pages
   Same component vocabulary as the home page, one extra layout: a compact
   page header (no WebGL — these pages load from search and must be fast) and
   a two-column body.
   ========================================================================== */

.page-head {
  position: relative;
  padding-block: clamp(7rem, 12vw, 9.5rem) clamp(2.5rem, 5vw, 4rem);
  overflow: hidden;
}

.page-head::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(46% 70% at 82% 10%, rgba(139, 92, 246, 0.3), transparent 70%),
    radial-gradient(38% 60% at 94% 40%, rgba(76, 125, 255, 0.26), transparent 72%);
}

.page-head > * {
  position: relative;
}

.crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  margin-bottom: var(--s-5);
}

.crumbs a {
  color: var(--text-dim);
  padding-block: 0.4rem;
}

.crumbs a:hover {
  color: var(--accent-ink);
}

.page-head h1 {
  max-width: 20ch;
}

.page-head__lead {
  margin-top: var(--s-5);
  max-width: 54ch;
  font-size: var(--t-lead);
  color: var(--text-dim);
}

.page-head__cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-5);
  margin-top: var(--s-6);
}

/* --- Body columns ------------------------------------------------------- */

.svc-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(2rem, 4vw, 3.5rem);
}

@media (min-width: 1000px) {
  .svc-body {
    grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
    align-items: start;
  }
}

.svc-prose h2 {
  font-size: clamp(1.5rem, 2.6vw, 2.1rem);
  margin-top: var(--s-7);
  margin-bottom: var(--s-4);
}

.svc-prose h2:first-child {
  margin-top: 0;
}

.svc-prose p {
  color: var(--text-dim);
  margin-bottom: var(--s-4);
  max-width: 68ch;
}

.svc-list {
  display: grid;
  gap: var(--s-3);
  margin: var(--s-5) 0 var(--s-6);
}

.svc-list li {
  position: relative;
  padding-left: 2rem;
  color: var(--text-dim);
}

.svc-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 11px;
  height: 11px;
  border-radius: 3px;
  background: var(--accent-grad-solid);
}

.svc-list strong {
  display: block;
  color: var(--text-strong);
  font-weight: 600;
}

/* --- Sticky summary ----------------------------------------------------- */

.svc-aside {
  display: grid;
  gap: var(--s-4);
}

@media (min-width: 1000px) {
  .svc-aside {
    position: sticky;
    top: 6.5rem;
  }
}

.svc-card {
  padding: clamp(1.3rem, 2.4vw, 1.8rem);
}

.svc-card h3 {
  font-size: var(--t-h4);
  margin-bottom: var(--s-4);
}

.svc-facts {
  display: grid;
  gap: var(--s-3);
  margin: 0;
}

.svc-facts div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s-4);
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--hairline);
}

.svc-facts div:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.svc-facts dt {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.svc-facts dd {
  margin: 0;
  font-size: var(--t-sm);
  font-weight: 600;
  text-align: right;
}

.svc-related {
  display: grid;
  gap: 0.15rem;
}

.svc-related a {
  display: block;
  padding: 0.7rem 0;
  font-size: var(--t-sm);
  color: var(--text-dim);
  border-bottom: 1px solid var(--hairline);
  transition: color var(--t-fast) var(--ease-out);
}

.svc-related a:last-child {
  border-bottom: 0;
}

.svc-related a:hover {
  color: var(--accent-ink);
}

/* The home-page platform cards are summaries now: the full explainer lives on
   each platform's own page, so these only have to be scannable and equal in
   height. Uneven walls of text are what made the grid look untidy. */
.platform__summary {
  color: var(--text-dim);
  font-size: var(--t-sm);
  flex-grow: 1;
}

.platform .service__more {
  margin-top: var(--s-4);
}

.platform__meta {
  margin-top: 0;
}

/* ==========================================================================
   23. Clientele marquee
   One continuous row rather than a grid. The track is duplicated and the
   inner wrapper is translated by exactly 50%, so the loop wraps with no seam
   and no JS. The copy is aria-hidden: a screen reader hears nine clients once.
   ========================================================================== */

.clients-band {
  overflow: hidden;
}

/* A centred label with a rule running out to each side, which is what makes
   the band read as a divider rather than as another section. */
.clients__label {
  display: flex;
  align-items: center;
  gap: var(--s-5);
  margin-bottom: clamp(1.8rem, 3.5vw, 2.8rem);
  font-family: var(--font-mono);
  font-size: var(--t-eyebrow);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--text-muted);
}

.clients__label::before,
.clients__label::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--hairline-strong), transparent);
}

.clients__label span {
  flex: none;
  text-align: center;
}

.marquee {
  position: relative;
  width: 100%;
  /* `clip` rather than `hidden`: hidden still creates a scroll container, so
     anything focused inside it shunts the whole track sideways and the logos
     never line up again. clip cannot be scrolled at all. */
  overflow: clip;
  /* The band's paint is independent of the rest of the page, so the browser
     does not re-rasterise neighbouring sections on every animation frame. */
  contain: content;
  /* Logos fade out at both edges instead of being cut off mid-glyph. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}

.marquee__inner {
  display: flex;
  width: max-content;
  /* Promoted to its own compositor layer up front. Without this the first
     frames of the loop stutter while the layer is created. */
  will-change: transform;
  transform: translate3d(-50%, 0, 0);
  backface-visibility: hidden;
  /* Starts at -50% and runs to 0, so the logos travel left to right. */
  animation: marquee-ltr 60s linear infinite;
}

@keyframes marquee-ltr {
  from {
    transform: translate3d(-50%, 0, 0);
  }
  to {
    transform: translate3d(0, 0, 0);
  }
}

/* Hovering anywhere on the band holds it still so a name can be read, and
   clicked if that client has a site. */
.marquee:hover .marquee__inner,
.marquee:focus-within .marquee__inner,
.marquee:active .marquee__inner {
  animation-play-state: paused;
}

/* Without a pointer there is no hover, so a moving logo can never be tapped
   reliably. On touch the band becomes a swipeable row instead. */
@media (hover: none) {
  .marquee {
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }

  .marquee::-webkit-scrollbar {
    display: none;
  }

  .marquee__inner {
    animation: none;
    transform: none;
    will-change: auto;
  }

  .marquee__track[aria-hidden="true"] {
    display: none;
  }
}

.marquee__track {
  display: flex;
  align-items: center;
  flex: none;
  gap: clamp(2.2rem, 4.5vw, 4.5rem);
  padding-right: clamp(2.2rem, 4.5vw, 4.5rem);
}

.client > a,
.client > span {
  display: inline-flex;
  align-items: center;
  gap: 0.72rem;
  /* Generous padding gives a moving target a hit area worth aiming at. */
  padding: var(--s-3) var(--s-4);
  margin-inline: calc(var(--s-4) * -1);
  border-radius: var(--r-pill);
  white-space: nowrap;
  transition: background-color var(--t-fast) var(--ease-out);
}

.client > a:hover,
.client > a:focus-visible {
  background: var(--surface-hover);
}

.client img {
  width: 40px;
  height: 40px;
  flex: none;
  border-radius: 9px;
  object-fit: contain;
  /* A light desaturation only. Full grayscale made nine real logos read as
     placeholders, which defeats the point of showing them. */
  filter: grayscale(0.3);
  opacity: 0.88;
  /* Transform eases; filter and opacity snap. Easing a filter across 18 images
     is the one thing in this band that actually costs frames. */
  transition: transform var(--t-med) var(--ease-spring), filter var(--t-fast) linear,
    opacity var(--t-fast) linear;
}

.client__name {
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.4vw, 1.2rem);
  font-weight: 600;
  letter-spacing: -0.022em;
  color: var(--text-dim);
  transition: color var(--t-med) var(--ease-out);
}

.client__name span {
  font-weight: 400;
  color: var(--text-muted);
}

/* Hover lifts the individual logo, not the whole row. */
.client:hover img {
  filter: none;
  opacity: 1;
  transform: scale(1.1);
}

.client:hover .client__name {
  color: var(--text-strong);
}

/* The Wondershare mark is a single-colour glyph on transparency, so on a dark
   ground it disappears. Single-colour marks flip with the scheme; the logos
   that carry their own coloured tile are left alone. */
[data-theme="dark"] .client img[src$="wondershare.png"],
[data-theme="gold"] .client img[src$="wondershare.png"] {
  filter: grayscale(0.3) invert(1);
}

[data-theme="dark"] .client:hover img[src$="wondershare.png"],
[data-theme="gold"] .client:hover img[src$="wondershare.png"] {
  filter: invert(1);
}

/* Motion is the whole point of a marquee, so with reduced motion it becomes a
   plain scrollable row rather than a frozen one with half a logo showing. */
@media (prefers-reduced-motion: reduce) {
  .marquee {
    overflow-x: auto;
    -webkit-mask-image: none;
    mask-image: none;
  }

  .marquee__inner {
    animation: none;
  }

  .marquee__track[aria-hidden="true"] {
    display: none;
  }
}

/* ==========================================================================
   24. Field validation
   The message sits under its own field rather than in the form-wide status
   line, so there is never any doubt about which input is being complained
   about. It is empty until a rule fails, and collapses to nothing when clear.
   ========================================================================== */

.field__error {
  display: block;
  min-height: 0;
  font-size: var(--t-xs);
  line-height: 1.4;
  color: var(--field-error);
  transition: min-height var(--t-fast) var(--ease-out);
}

.field__error:not(:empty) {
  margin-top: 0.3rem;
}

.field input[aria-invalid="true"],
.field select[aria-invalid="true"],
.field textarea[aria-invalid="true"] {
  border-color: var(--field-error);
  background: var(--field-error-bg);
}

/* Colour alone must not be the only signal, so an invalid field also gets a
   weight of ring that a valid one never has. */
.field input[aria-invalid="true"]:focus,
.field select[aria-invalid="true"]:focus,
.field textarea[aria-invalid="true"]:focus {
  border-color: var(--field-error);
  box-shadow: 0 0 0 3px var(--field-error-ring);
}

/* ==========================================================================
   25. Hero
   Full-bleed two-column at desktop, stacked on a phone. The shell is wider
   than the page's 1240px because the hero is the one place the screen should
   be used edge to edge; everything below stays on the narrower measure.
   ========================================================================== */

.hero {
  position: relative;
  padding-block: clamp(6.5rem, 11vw, 9rem) clamp(3.5rem, 7vw, 6rem);
  overflow: hidden;
}

/* A single wide wash instead of the old radial glows. Flat enough that the
   headline sits on an even ground at every width. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(118deg, transparent 38%, rgba(76, 125, 255, 0.1) 72%, rgba(139, 92, 246, 0.14) 100%);
}

.hero__shell {
  position: relative;
  z-index: var(--z-content);
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: grid;
  gap: clamp(2.5rem, 5vw, 4.5rem);
  align-items: center;
}

@media (min-width: 1040px) {
  .hero__shell {
    grid-template-columns: minmax(0, 1.04fr) minmax(0, 1fr);
  }
}

.hero__copy {
  display: grid;
  gap: var(--s-5);
  justify-items: start;
}

.hero h1 {
  /* No gradient fill. A two-stop sweep across the one line a crawler weighs
     most is decoration bought at the cost of legibility. */
  max-width: 17ch;
  margin: 0;
}

.hero__lead {
  font-size: var(--t-lead);
  color: var(--text-dim);
  max-width: 54ch;
  margin: 0;
}

.hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
}

/* The price, the turnaround and the no-retainer promise used to run together
   as one 0.72rem mono line under the buttons, which is the typographic
   signature of small print you are meant to skim past. It is the opposite:
   it answers the last question a visitor has before they click. Three ticked
   items, in the body face, at a size someone can actually read. */
.hero__terms {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem clamp(1rem, 2.4vw, 1.9rem);
  margin: calc(var(--s-4) * -1) 0 0;
  padding: 0;
  list-style: none;
}

.hero__terms li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--t-sm);
  color: var(--text-dim);
  line-height: 1.4;
}

.hero__terms b {
  font-weight: 600;
  color: var(--text-strong);
}

/* A tick, drawn rather than loaded: one path, inherits the accent, and needs
   no icon font or sprite request. */
.hero__terms svg {
  flex: none;
  width: 18px;
  height: 18px;
  padding: 2px;
  border-radius: 50%;
  background: var(--tick-bed);
  fill: none;
  stroke: var(--tick-ink);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@media (max-width: 440px) {
  /* Stacked, so no promise ever breaks across two lines mid-phrase. */
  .hero__terms {
    flex-direction: column;
    gap: 0.45rem;
  }
}

.hero__proof {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4) clamp(1.5rem, 3.5vw, 3rem);
  margin: var(--s-3) 0 0;
  padding-top: var(--s-5);
  border-top: 1px solid var(--hairline);
  width: 100%;
  max-width: 44rem;
}

.hero__proof li {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.hero__proof-num {
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 2.4vw, 1.75rem);
  font-weight: 650;
  letter-spacing: -0.04em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.hero__proof-label {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ==========================================================================
   26. The page-one panel
   A search results page is the thing this business operates on, so the hero
   shows one: the same brand query before and after the work.
   ========================================================================== */

.serp {
  margin: 0;
  width: 100%;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-md);
  background: rgba(10, 14, 28, 0.72);
  backdrop-filter: blur(16px);
  box-shadow: 0 30px 70px -30px rgba(0, 0, 0, 0.8);
  overflow: hidden;
}

.serp__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: 0.85rem 1rem;
  border-bottom: 1px solid var(--hairline);
}

.serp__query {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--text-dim);
}

.serp__query svg {
  width: 15px;
  height: 15px;
  flex: none;
  fill: none;
  stroke: var(--text-muted);
  stroke-width: 1.8;
  stroke-linecap: round;
}

.serp__example {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  padding: 0.2rem 0.55rem;
}

.serp__switch {
  display: flex;
  gap: 2px;
  padding: 0.6rem 1rem 0;
}

.serp__switch button {
  flex: 1;
  padding: 0.55rem 0.5rem;
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  border-bottom: 2px solid transparent;
  transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out);
}

.serp__switch button[aria-pressed="true"] {
  color: var(--text);
  border-bottom-color: var(--accent-ink);
}

.serp__list {
  display: grid;
  margin: 0;
  padding: 0.3rem 0 0;
}

/* `display: grid` on a class outranks the UA's [hidden] rule, so without this
   both states render at once. Same trap the form status line fell into. */
.serp__list[hidden] {
  display: none;
}

.serp__row {
  display: grid;
  grid-template-columns: 1.6rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.8rem;
  padding: 0.72rem 1rem;
  border-bottom: 1px solid var(--hairline);
}

.serp__row:last-child {
  border-bottom: 0;
}

.serp__pos {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.serp__text {
  display: grid;
  gap: 1px;
  min-width: 0;
}

.serp__title {
  font-size: 0.86rem;
  color: var(--text);
  /* A long result title truncates the way a real one does rather than
     pushing the panel wider than its column. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.serp__domain {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-muted);
}

.serp__tag {
  font-family: var(--font-mono);
  font-size: 0.64rem;
  letter-spacing: 0.06em;
  padding: 0.22rem 0.5rem;
  border-radius: var(--r-pill);
  border: 1px solid var(--hairline-strong);
  color: var(--text-muted);
  white-space: nowrap;
}

/* Status colour is semantic and deliberately not the brand accent, so a
   problem row never reads as a highlighted one. */
.serp__row[data-kind="risk"] .serp__tag {
  color: #ff9f8a;
  border-color: rgba(255, 110, 85, 0.45);
  background: rgba(255, 110, 85, 0.1);
}

.serp__row[data-kind="rival"] .serp__tag,
.serp__row[data-kind="weak"] .serp__tag {
  color: #e8c07a;
  border-color: rgba(220, 170, 90, 0.4);
  background: rgba(220, 170, 90, 0.08);
}

.serp__row[data-kind="owned"] .serp__tag,
.serp__row[data-kind="strong"] .serp__tag {
  color: #8fe0b6;
  border-color: rgba(70, 200, 140, 0.42);
  background: rgba(70, 200, 140, 0.1);
}

.serp__row[data-kind="owned"],
.serp__row[data-kind="strong"] {
  background: rgba(70, 200, 140, 0.035);
}

.serp__note {
  margin: 0;
  padding: 0.75rem 1rem 0.9rem;
  border-top: 1px solid var(--hairline);
  font-size: var(--t-xs);
  color: var(--text-muted);
}

@media (max-width: 420px) {
  .serp__row {
    grid-template-columns: 1.4rem minmax(0, 1fr);
    row-gap: 0.35rem;
  }
  .serp__tag {
    grid-column: 2;
    justify-self: start;
  }
}

/* ==========================================================================
   27. Contact
   Two columns on a wide screen: why to get in touch on the left, the form on
   the right. Centred in a 1240px shell it read as a narrow strip with two
   empty margins, which is the opposite of what a conversion section wants.
   ========================================================================== */

.contact__shell {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.contact__grid {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  align-items: start;
}

@media (min-width: 1040px) {
  .contact__grid {
    grid-template-columns: minmax(0, 0.82fr) minmax(0, 1fr);
  }
}

.contact__aside {
  display: grid;
  gap: clamp(1.2rem, 2.5vw, 1.8rem);
}

.channels {
  display: grid;
  gap: 0.7rem;
}

.channel {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0.9rem;
  align-items: start;
  padding: clamp(1rem, 2vw, 1.25rem);
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  transition: border-color var(--t-fast) var(--ease-out),
    background-color var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out);
}

.channel:hover {
  border-color: var(--accent-ink);
  background: var(--surface-strong);
  transform: translateY(-2px);
}

.channel__icon {
  width: 38px;
  height: 38px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 11px;
  background: var(--accent-grad-soft);
  border: 1px solid var(--hairline-strong);
}

.channel__icon svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: var(--accent-ink);
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.channel__body {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.channel__name {
  font-family: var(--font-mono);
  font-size: 0.64rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.channel__value {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
}

.channel__note {
  font-size: var(--t-xs);
  color: var(--text-muted);
}

/* What happens next, because the gap between sending a form and hearing back
   is where most enquiries are abandoned. */
.contact__promise {
  padding: clamp(1.1rem, 2.2vw, 1.5rem);
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  background: var(--band-bg);
}

.contact__promise h3 {
  font-size: var(--t-h4);
  margin-bottom: var(--s-4);
}

.contact__promise ol {
  display: grid;
  gap: 0.65rem;
  counter-reset: step;
  margin-bottom: var(--s-4);
}

.contact__promise li {
  position: relative;
  padding-left: 2rem;
  font-size: var(--t-sm);
  color: var(--text-dim);
  counter-increment: step;
}

.contact__promise li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: 0.05em;
  width: 1.35rem;
  height: 1.35rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--hairline-strong);
  font-family: var(--font-mono);
  font-size: 0.66rem;
  color: var(--accent-ink);
}

.contact__promise > p {
  margin: 0;
  font-size: var(--t-xs);
  color: var(--text-muted);
}

/* --- The form panel ----------------------------------------------------- */

.cta {
  position: relative;
  padding: clamp(1.5rem, 3vw, 2.3rem);
  border-radius: var(--r-xl);
  border: 1px solid var(--hairline-strong);
  background: var(--cta-bg);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}

.cta__title {
  font-size: clamp(1.35rem, 2.4vw, 1.9rem);
  line-height: 1.1;
  letter-spacing: var(--track-h2);
  margin: var(--s-3) 0 0;
  max-width: 24ch;
}

.cta__form {
  margin: clamp(1.4rem, 2.6vw, 2rem) 0 0;
  padding: 0;
  border: 0;
  background: none;
  backdrop-filter: none;
  box-shadow: none;
  max-width: none;
}

.form-actions {
  display: flex;
  margin-top: var(--s-5);
}

.form-actions .btn {
  width: 100%;
}

/* ==========================================================================
   28. Footer
   A closing CTA band, then a four-track grid where the brand block and the
   contact block carry real content rather than a third and fourth list of
   links padding out the width.
   ========================================================================== */

.footer {
  position: relative;
  z-index: var(--z-content);
  border-top: 1px solid var(--hairline);
  background: var(--footer-bg);
  padding-block: clamp(2.5rem, 5vw, 4rem) var(--s-6);
  margin-top: calc(var(--section-y) * 0.62);
}

/* The footer used to widen itself past the page frame. Now the frame is the
   wide one, so it simply inherits .shell and lines up with everything else. */

.footer__cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
  padding: clamp(1.3rem, 3vw, 2.1rem) clamp(1.3rem, 3vw, 2.3rem);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-lg);
  background: var(--cta-bg);
  margin-bottom: clamp(2.2rem, 4.5vw, 3.5rem);
}

.footer__cta-text h2 {
  font-size: clamp(1.2rem, 2.3vw, 1.65rem);
  letter-spacing: -0.028em;
  margin: 0;
}

.footer__cta-text p {
  margin: 0.35rem 0 0;
  font-size: var(--t-sm);
  color: var(--text-dim);
}

.footer__cta .btn {
  flex: none;
}

.footer__grid {
  display: grid;
  gap: clamp(1.8rem, 3.5vw, 3rem);
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 760px) {
  .footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1100px) {
  .footer__grid {
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.25fr);
  }
}

.footer__brand p {
  color: var(--text-muted);
  font-size: var(--t-sm);
  max-width: 40ch;
  margin-top: var(--s-4);
}

.footer__facts {
  display: grid;
  gap: 0.55rem;
  margin-top: var(--s-5);
}

.footer__facts div {
  display: flex;
  gap: 0.6rem;
  align-items: baseline;
  font-size: var(--t-xs);
}

.footer__facts dt {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  flex: none;
  min-width: 9rem;
}

.footer__facts dd {
  margin: 0;
  color: var(--text-dim);
}

.footer__col h3 {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: var(--s-4);
}

.footer__col a {
  display: inline-block;
  min-width: 2.75rem;
  padding-block: 0.52rem;
  font-size: var(--t-sm);
  line-height: 1.3;
  color: var(--text-dim);
  transition: color var(--t-fast) var(--ease-out);
}

.footer__col a:hover {
  color: var(--accent-ink);
}

/* --- Contact channels in the footer ------------------------------------- */

.footer__channels {
  display: grid;
  gap: 0.45rem;
}

.fchan {
  display: grid !important;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0.7rem;
  align-items: center;
  padding: 0.6rem 0.7rem !important;
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  background: var(--surface);
  transition: border-color var(--t-fast) var(--ease-out),
    background-color var(--t-fast) var(--ease-out);
}

.fchan:hover {
  border-color: var(--accent-ink);
  background: var(--surface-strong);
}

.fchan__icon {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  background: var(--accent-grad-soft);
}

.fchan__icon svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: var(--accent-ink);
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.fchan__text {
  display: grid;
  gap: 1px;
  min-width: 0;
}

.fchan__label {
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.fchan__value {
  font-size: 0.86rem;
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
}

.fchan__note {
  font-size: 0.7rem;
  color: var(--text-muted);
}

/* --- Bottom bar --------------------------------------------------------- */

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3) var(--s-5);
  margin-top: clamp(2.2rem, 4.5vw, 3.5rem);
  padding-top: var(--s-5);
  border-top: 1px solid var(--hairline);
  font-size: var(--t-xs);
  color: var(--text-faint);
}

.footer__bottom p {
  margin: 0;
}

.footer__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 1.1rem;
}

.footer__meta a {
  display: inline-block;
  padding-block: 0.5rem;
  color: var(--text-dim);
  transition: color var(--t-fast) var(--ease-out);
}

.footer__meta a:hover {
  color: var(--accent-ink);
}

.footer__terms {
  color: var(--text-faint);
}

@media (max-width: 860px) {
  .footer__cta {
    flex-direction: column;
    align-items: flex-start;
  }
  .footer__cta .btn {
    width: 100%;
  }
}

/* ==========================================================================
   29. Form fields
   Restored after the contact rewrite: these rules were inside the old
   centred-CTA block and went with it, which left every input unstyled.
   ========================================================================== */

.field-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* Wider row gap than column gap: an error message needs somewhere to sit
     without crowding the label of the field below it. */
  column-gap: var(--s-4);
  row-gap: var(--s-5);
}

@media (max-width: 620px) {
  .field-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  margin-bottom: var(--s-5);
}

.field-grid .field {
  margin-bottom: 0;
}

.field label {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.field label span {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  color: var(--text-faint);
}

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 0.85rem 1.05rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--field-border);
  background: var(--input-bg);
  color: var(--text);
  font-size: var(--t-sm);
  transition: border-color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out),
    box-shadow var(--t-fast) var(--ease-out);
}

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

.field textarea {
  resize: vertical;
  min-height: 7rem;
  line-height: 1.6;
}

/* The native arrow is invisible on a dark field, so draw one. */
.field select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237f8db0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.9rem center;
  background-size: 17px;
  padding-right: 2.6rem;
  cursor: pointer;
}

/* Options render in the OS menu, which does not inherit the page's palette. */
.field select option {
  background: var(--option-bg);
  color: var(--text);
}

.field input::placeholder,
.field textarea::placeholder {
  color: var(--text-faint);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--accent-ink);
  background: var(--bg-raise);
  box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.2);
}

.field__error {
  display: block;
  font-size: var(--t-xs);
  line-height: 1.4;
  color: var(--field-error);
}

.field__error:not(:empty) {
  margin-top: 0.3rem;
}

.field input[aria-invalid="true"],
.field select[aria-invalid="true"],
.field textarea[aria-invalid="true"] {
  border-color: var(--field-error);
  background: var(--field-error-bg);
}

.field input[aria-invalid="true"]:focus,
.field select[aria-invalid="true"]:focus,
.field textarea[aria-invalid="true"]:focus {
  border-color: var(--field-error);
  box-shadow: 0 0 0 3px var(--field-error-ring);
}

.form-status {
  display: block;
  margin-top: var(--s-4);
  padding: 0.8rem 1.05rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--hairline-strong);
  background: var(--surface);
  font-size: var(--t-sm);
  color: var(--text-dim);
  text-align: center;
}

/* `display: block` on a class outranks the UA's [hidden] rule, which left an
   empty bordered bar sitting under the button before any submit. */
.form-status[hidden] {
  display: none;
}

.form-status[data-state="ok"] {
  border-color: var(--ok-border);
  background: var(--ok-bg);
  color: var(--ok-text);
}

.form-status[data-state="error"] {
  border-color: var(--field-error);
  background: var(--field-error-bg);
  color: var(--field-error);
  font-weight: 500;
}
