/* Load notes: no web-font @import (it blocked first paint on a separate request,
   and the font stack resolves to the system font on every mainstream device),
   and no whole-page fade-in — the page paints immediately. */

/* ─── Transvo Global ───────────────────────────────────────────────────────── */

/* Base reset, once for every page. Most pages also carried a copy of this in
   their own <style>; the two legal pages didn't, so they got the browser's 8px
   body margin and an indented, off-centre nav. */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }
body { font-family: var(--font); font-optical-sizing: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* Mobile browsers flash a default grey/blue highlight on tap for any link or
   button — unstyled, doesn't respect border-radius consistently, and reads
   as a glitch on a pill-shaped button (exactly what showed up on the promo
   widget's "Get it now"/"Contact us" buttons). Never set anywhere on this
   site, so it affects every tappable element. The real, custom press
   feedback is the :active{transform:scale()} rules already in place — this
   just removes the browser's own competing effect underneath them. */
a, button, [role="button"], input, textarea, select {
  -webkit-tap-highlight-color: transparent;
}

/* ─── Color tokens ────────────────────────────────────────────────────────────── */
:root {
  --font: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'SF Pro Display', 'Segoe UI', Roboto, 'Inter', system-ui, sans-serif;
  /* Light-only palette. Four values carry the system — #FFFFFF, #FAFAFA,
     #262626, #000000 — and every grey below is one of them at an alpha, so
     nothing drifts off-palette. */
  --bg:       #fafafa;   /* page canvas */
  --surface:  #ffffff;   /* section bands / cards, lifted off the canvas */
  --elevated: #ffffff;   /* dropdown / popover panel */
  --chip:     #f0f0f0;   /* grey button / chip — #262626 at ~6% over the canvas */
  --ink:      #262626;   /* body text and dark fills */
  --muted:    #6b6b6b;   /* meets AA on --bg, --surface and --chip */
  --border:   rgba(38,38,38,0.10);
  --hairline: rgba(38,38,38,0.12);  /* dividers / subtle outlines */
  --ghost:    rgba(38,38,38,0.06);  /* translucent pill fill */
  --ghost-hover: rgba(38,38,38,0.12);
  --blue:     #8a8a8a;   /* de-blued — neutral grey accent (was Transvo blue) */
  --blue-text:#6b6b6b;   /* de-blued — neutral grey for small accent text */
  /* Primary fills darken toward black on hover — the light-mode direction.
     The old #3d3d3d was a dark-mode leftover and lightened instead. */
  --ink-hover:#000000;
  --red:      #ff4438;   /* Transvo red */
  --nav-bg:   #fafafa;
  /* One page gutter for every page: nav, content and footer all start on the
     same left edge. Phones step down to 24px (see the 768px query below). */
  --gutter:   48px;
  /* Vertical rhythm: the padding every page section takes top and bottom, so
     the gap between any two sections is the same everywhere. */
  --section-y: clamp(56px, 6.5vw, 88px);
  /* Gap between a page's title block and the content it introduces. */
  --head-gap: clamp(32px, 4vw, 56px);
  /* Every content card (white panel holding text) shares this radius and a
     hairline outline; image tiles carry neither — the image is its edge. */
  --radius-card: 16px;
  --nav-bg-scrolled: #fafafa;

  /* ── Role tokens ──────────────────────────────────────────────────────────
     The rule that keeps a theme switch to one line: no page or component
     writes a literal colour that only works on one canvas. Text on an --ink
     fill is --on-ink (never #fff), an outline that must stand out is
     --ring-strong (never rgba(38,38,38,…)), and anything that differs per
     theme gets a token here plus its value in the dark block below. Values
     that reference other tokens resolve per theme on their own. */
  --on-ink:      var(--bg);              /* label / icon on an --ink fill */
  --ring-strong: color-mix(in srgb, var(--ink) 40%, transparent);  /* hover / focus outline */
  --placeholder: #e6e6e6;                /* empty image tile */
  --logo-filter: brightness(0);          /* the white wordmark, flattened to ink */
  --client-logo-filter: none;            /* client marks in full colour */
  --client-logo-opacity: 1;
  /* Controls laid over photos and video. Media stays dark in every theme,
     so these are fixed, not theme-driven. */
  --media-fill:       #ffffff;
  --media-fill-hover: #e6e6e6;
  --media-ink:        #0b0b0b;
  /* "Start a project" glow ring (see "CTA glow ring" below). */
  --cta-glow:       var(--ink);          /* the travelling light */
  --cta-glow-edge:  color-mix(in srgb, var(--ink) 16%, transparent);  /* the resting outline */
  --cta-glow-width: 1.5px;               /* ring thickness */
  --cta-glow-gap:   3px;                 /* space between pill and ring */
  --cta-glow-speed: 5s;                  /* one lap */
}
/* Dark theme — the site's only theme. Palette matched to usefirsthand.app:
   #0B0B0B canvas, #191919 surfaces/cards, pure-white ink, a #a3a3a3 muted
   grey-blue for secondary text, and a translucent-white 1px ring for pills. */
html[data-theme="dark"] {
  --bg:       #0b0b0b;
  --surface:  #191919;   /* section bands / cards on the canvas */
  --elevated: #232323;   /* dropdown / popover panel, lifted off the canvas */
  --chip:     #191919;
  --ink:      #ffffff;
  --muted:    #a3a3a3;   /* neutral light grey (our own, not Firsthand's blue-grey) */
  --blue-text:#a3a3a3;   /* de-blued — neutral grey accent text */
  --border:   rgba(255,255,255,0.08);
  --hairline: rgba(255,255,255,0.10);
  --ghost:    rgba(255,255,255,0.10);
  --ghost-hover: rgba(255,255,255,0.18);
  --ink-hover:#e2e2e2;   /* primary-pill hover fill — one solid step off --ink */
  --nav-bg:   #0b0b0b;
  --nav-bg-scrolled: #0b0b0b;
  --placeholder: #2a2a2a;
  --logo-filter: none;                   /* the wordmark is drawn white */
  /* Dark wordmarks vanish on this canvas and bright ones shout. Every file
     has a transparent background, so each flattens to one white silhouette
     and the wall reads evenly — never an inverted negative of the artwork. */
  --client-logo-filter: brightness(0) invert(1);
  --client-logo-opacity: 0.86;
}
/* The wordmark SVG is drawn white; --logo-filter adapts it to the canvas. */
.nav-logo img {
  filter: var(--logo-filter);
  transition: filter 0.3s ease;
}

/* ─── Skip link ──────────────────────────────────────────────────────────────── */
.skip-link {
  position: absolute;
  top: -48px; left: 16px;
  background: var(--surface); color: var(--ink);
  box-shadow: 0 0 0 1px var(--border);
  padding: 8px 16px; border-radius: 0 0 6px 6px;
  font-size: 14px; font-weight: 400;
  text-decoration: none; z-index: 9999;
  transition: top 0.15s ease;
}
.skip-link:focus { top: 0; }

/* ─── Base ────────────────────────────────────────────────────────────────────── */
body {
  font-family: var(--font);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: -0.011em;
  background: var(--bg);
  color: var(--ink);
  transition: background 0.3s ease, color 0.3s ease;
}

/* ─── Compound split CTA (pill + circle arrow) ──────────────────────────────── */
.cta-split {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  flex-shrink: 0;
}
.cta-split .cta-pill {
  background: var(--ink);
  color: var(--bg);
  padding: 15px 30px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0;
  white-space: nowrap;
  line-height: 1;
  transition: opacity 0.2s ease;
}
.cta-split .cta-circle {
  background: var(--ink);
  color: var(--bg);
  width: 50px; height: 50px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  flex-shrink: 0;
  transition: opacity 0.2s ease;
}
/* Scales with .cta-circle's own font-size, so the .cta-lg / .quote-strip
   variants below (which only touch font-size) resize the icon for free. */
.cta-split .cta-circle .arrow-ic { width: 1.1em; height: 0.95em; }
.cta-split:hover .cta-pill,
.cta-split:hover .cta-circle { opacity: 0.55; }
.cta-split.cta-lg .cta-pill {
  font-size: clamp(56px, 9vw, 120px);
  padding: 36px 64px;
  letter-spacing: -0.04em;
}
.cta-split.cta-lg .cta-circle {
  width: clamp(110px, 13vw, 160px);
  height: clamp(110px, 13vw, 160px);
  font-size: clamp(36px, 5vw, 60px);
}


/* ─── Accessibility: keyboard focus ─────────────────────────────────────────── */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: 5px;
}

/* ─── Inline square bullet ───────────────────────────────────────────────────── */
.sq {
  display: inline-block;
  width: 3px; height: 3px;
  background: currentColor;
  opacity: 0.5;
  vertical-align: middle;
  margin: 0 3px;
  flex-shrink: 0;
}

/* ─── Hamburger (base — pages override display) ─────────────────────────────── */
.nav-hamburger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 4px;
  flex-shrink: 0;
}
.nav-hamburger span {
  display: block;
  width: 22px; height: 2px;
  background: var(--ink);
  transform-origin: center;
  transition: transform 0.35s cubic-bezier(0.23,1,0.32,1), opacity 0.35s cubic-bezier(0.23,1,0.32,1);
}
.nav-hamburger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-hamburger.open span:nth-child(2) { opacity: 0; transform: scaleX(0); }
.nav-hamburger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }


/* ─── Nav ────────────────────────────────────────────────────────────────────── */
nav {
  /* Not sticky: the bar scrolls away with the page. Kept position:relative
     rather than static so .nav-links can still centre against the bar. */
  position: relative !important;
  z-index: 200 !important;
  display: flex !important;
  align-items: center !important;
  justify-content: space-between !important;
  height: 64px !important;
  padding: 0 var(--gutter) !important;
  background: var(--nav-bg) !important;
  transition: box-shadow 0.3s ease !important;
}
@media (max-width: 768px) {
  :root { --gutter: 24px; }
  nav { padding: 0 var(--gutter) !important; }
}
nav.scrolled {
  background: var(--nav-bg-scrolled) !important;
  box-shadow: none !important;
  border-bottom: none !important;
}

/* ─── Nav structure ──────────────────────────────────────────────────────────
   Links sit beside the wordmark on the left; the utility cluster (theme
   toggle + icon buttons) and the BrandLab CTA group at the right, separated
   by a hairline so "navigate" and "act" read as two distinct zones. */
.nav-right {
  display: flex !important; align-items: center !important;
  flex: 1 1 auto !important; min-width: 0 !important;
  gap: 0 !important; margin-left: 32px !important;
}
/* Centered in the bar itself, not just in the leftover space beside the CTA —
   positioned relative to <nav> (position:fixed, so it's the containing block
   for descendants regardless of DOM nesting), not to .nav-right, so it lands
   at the true horizontal middle no matter how wide the logo or the CTA are.
   Still a DOM child of .nav-right, so the existing mobile rule that hides
   .nav-right also hides this — nothing extra needed for that. */
.nav-links {
  display: flex !important; align-items: center !important; list-style: none !important;
  gap: 24px !important;
  position: absolute !important; left: 50% !important; top: 50% !important;
  transform: translate(-50%, -50%) !important;
}
.nav-links li { list-style: none !important; }
.theme-toggle-desktop { margin-right: 14px !important; }

/* ─── Nav links — editorial text style ────────────────────────────────────────
   Regular weight at high opacity, rather than semi-bold at low opacity. The
   old pairing (500 @ 0.45) emboldened and dimmed the same text so the two
   cancelled out, and composited to 4.52:1 on --bg — passing AA by 0.02 with
   no margin. 400 @ 0.75 lands near 7:1 and reads calmer, not louder. It also
   gives .nav-active two signals to work with (weight AND brightness) where
   before it only had opacity, since the base was already 500.
   The vertical padding is hit area only: the anchors were a 15px-tall sliver
   of a 64px bar. .nav-links centres them, so nothing moves visually. */
.nav-links a {
  display: inline-flex !important;
  align-items: center !important;
  padding: 15px 0 !important;
  font-size: 13px !important;   /* match usefirsthand.com nav links */
  font-weight: 400 !important;
  color: var(--ink) !important;
  opacity: 0.75 !important;
  text-decoration: none !important;
  white-space: nowrap !important;
  transition: opacity 0.15s ease !important;
}
.nav-links a:hover { opacity: 1 !important; text-decoration: none !important; }
.nav-links a.nav-active { opacity: 1 !important; font-weight: 500 !important; }

/* ─── Nav CTA ────────────────────────────────────────────────────────────────
   Brand-blue pill: the one coloured element in the bar, so it reads as the
   primary action without needing extra weight. */
.nav-cta {
  display: inline-flex !important;
  align-items: center !important;
  gap: 5px !important;
  height: 36px !important;
  font-size: 13px !important;
  font-weight: 500 !important;
  letter-spacing: 0 !important;            /* Firsthand pills: crisp, no tracking  */
  text-transform: none !important;
  /* Solid white pill — the same treatment the hero already gives this exact
     action, so the site's primary CTA reads consistently in both places. It
     replaces a --surface chip that sat only one step off the --bg bar and so
     needed a looping pulse to get noticed. Its motion now comes from the
     "CTA glow ring" below — a slow light around the outline, not a pulse. */
  color: var(--bg) !important;
  background: var(--ink) !important;
  border: none !important;
  border-radius: 999px !important;
  padding: 0 16px !important;
  text-decoration: none !important;
  white-space: nowrap !important;
  box-shadow: none !important;
  transition: background-color 0.18s ease, transform 0.12s ease-out !important;
}
/* A solid fill step, not opacity — a fade reads as "disabled", which is why
   this hover went unnoticed: on the button most likely to be checked, dimming
   toward the dark canvas behind it made almost no visible difference. */
.nav-cta:hover { background: var(--ink-hover) !important; }
.nav-cta:active { transform: scale(0.97) !important; }

/* ─── Nav action cluster: icon buttons, hairline, then the Enroll link ───────
   Source order is CTA-then-icons; `order` puts the icons first so the CTA can
   sit last, behind the divider, without touching every page's markup. */
.nav-actions { display: flex !important; align-items: center !important; gap: 10px !important; margin-left: auto !important; }
.nav-actions .nav-icon-btn { order: 1 !important; }
.nav-actions .nav-cta { order: 2 !important; margin-left: 6px !important; }
.nav-icon-btn {
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  /* A solid filled circle reads heavier than the toggle's light track at the
     same pixel size, so it is set slightly smaller to balance optically. */
  width: 29px !important;
  height: 29px !important;
  flex-shrink: 0 !important;
  border-radius: 50% !important;
  border: 1px solid var(--ink) !important;
  background: var(--ink) !important;
  color: var(--bg) !important;
  text-decoration: none !important;
  transition: opacity 0.15s ease !important;
}
.nav-icon-btn svg { width: 14px !important; height: 14px !important; display: block !important; fill: currentColor !important; }
.nav-icon-btn:hover { opacity: 0.5 !important; }
.nav-icon-btn:active { transform: scale(0.9) !important; }

/* ─── Tablet (769–1024px): keep the whole nav on one line ─────────────────────
   Without this the Enroll pill wraps to two lines and the logo collides with the
   links, which throws the Book-a-call / Shop icon cluster out of alignment. */
@media (min-width: 769px) and (max-width: 1024px) {
  /* The gutter itself steps in here, so the nav and the content tighten
     together and keep one left edge. */
  :root { --gutter: 32px; }
  .nav-right  { gap: 18px !important; }
  .nav-links  { gap: 16px !important; }
  .nav-links a { font-size: 13px !important; }
  .nav-cta    { font-size: 13px !important; padding: 0 16px !important; }
  .nav-actions { gap: 8px !important; }
}

/* ─── Mobile CTA ─────────────────────────────────────────────────────────────── */
/* Same solid white pill as .nav-cta — this *is* the nav CTA below 768px,
   where .nav-right is hidden, so the two should not diverge. */
.mobile-cta {
  display: block !important;
  background: var(--ink) !important;
  color: var(--bg) !important;
  border: none !important;
  box-shadow: none !important;
  border-radius: 999px !important;
  padding: 13px 20px !important;
  font-weight: 500 !important;
  font-size: 14px !important;
  letter-spacing: 0 !important;
  text-align: left !important;
  margin-top: 20px !important;
  transition: opacity 0.2s ease !important;
}
/* Label keeps its own colour on hover — per-page `.mobile-nav a:hover` rules
   must never recolour it (they turned it grey/white on the white pill). Same
   0.82 fade as .nav-cta so the two "Start a project" pills stay identical. */
.mobile-cta:hover { opacity: 0.82 !important; color: var(--bg) !important; }
.mobile-cta:active { transform: scale(0.97) !important; }

/* ─── CTA glow ring ───────────────────────────────────────────────────────────
   Every "Start a project" pill carries a thin outline, set --cta-glow-gap
   off its edge, with a light that travels round it on a loop — after the
   CTA card on userillo.com. One ::before layer: a conic gradient whose
   start angle is a registered property (so it animates smoothly), masked
   down to the --cta-glow-width band of its padding. Colour, width, gap and
   speed are tokens at the top of this file.
   Deliberately no filter: an earlier blurred halo behind the pill (z -1,
   filter: blur) rendered as a hard-edged black box in Safari. */
@property --cta-glow-a { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
@keyframes cta-glow-turn { to { --cta-glow-a: 360deg; } }

.nav-cta,
.mobile-cta,
.hero-cta-primary { position: relative !important; }

.nav-cta::before, .mobile-cta::before, .hero-cta-primary::before {
  content: '';
  position: absolute;
  inset: calc(-1 * var(--cta-glow-gap));
  border-radius: inherit;
  pointer-events: none;
  animation: cta-glow-turn var(--cta-glow-speed) linear infinite;
  padding: var(--cta-glow-width);
  background: conic-gradient(from var(--cta-glow-a),
    var(--cta-glow-edge) 0%,
    var(--cta-glow-edge) 52%,
    color-mix(in srgb, var(--cta-glow) 45%, var(--cta-glow-edge)) 72%,
    var(--cta-glow) 86%,
    var(--cta-glow-edge) 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
/* Still for anyone who asks for less motion: the resting ring stays, with
   the light parked at the top right. */
@media (prefers-reduced-motion: reduce) {
  .nav-cta::before, .mobile-cta::before, .hero-cta-primary::before {
    animation: none; --cta-glow-a: 300deg;
  }
}

/* ─── Theme toggle (segmented sun / moon) ────────────────────────────────────── */
.theme-toggle {
  display: inline-flex; align-items: center;
  gap: 2px; padding: 3px;
  background: rgba(38,38,38,0.07);
  border-radius: 999px;
  border: none;
  cursor: pointer;
  flex-shrink: 0;
  position: relative;
  transition: background 0.3s ease;
}
html[data-theme="dark"] .theme-toggle {
  background: rgba(255,255,255,0.10);
}
/* A single thumb slides between the two halves rather than each segment
   swapping its own background — that is what makes the switch feel iOS-smooth.
   Travel = segment width (28px) + the 2px gap. */
.theme-toggle::before {
  content: '';
  position: absolute; top: 3px; left: 3px;
  width: 28px; height: 26px;
  border-radius: 999px;
  background: #ffffff;
  box-shadow: none;
  transform: translateX(0);
  transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1), background 0.3s ease;
}
html[data-theme="dark"] .theme-toggle::before {
  transform: translateX(30px);
  background: rgba(255,255,255,0.22);
  box-shadow: none;
}
.theme-toggle .seg {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 26px;
  border-radius: 999px;
  color: var(--muted);
  transition: color 0.25s ease;
  pointer-events: none;
  position: relative; z-index: 1;
}
.theme-toggle .seg svg { width: 13px; height: 13px; display: block; }
html[data-theme="light"] .theme-toggle .seg-sun,
html:not([data-theme="dark"]) .theme-toggle .seg-sun { color: var(--ink); }
html[data-theme="dark"] .theme-toggle .seg-moon { color: #fafafa; }
@media (prefers-reduced-motion: reduce) {
  .theme-toggle::before { transition: none; }
}

/* ─── Scroll reveal ─────────────────────────────────────────────────────────── */
.reveal {
  opacity: 0;
  transform: translateY(20px);
  transition:
    opacity 0.85s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.85s cubic-bezier(0.22, 1, 0.36, 1);
}
.reveal.in-view { opacity: 1; transform: translateY(0); }
/* Reduced motion keeps the fade (it aids comprehension — you still know
   something appeared) but drops the slide, site-wide, on every page that
   uses .reveal. */
@media (prefers-reduced-motion: reduce) {
  .reveal { transform: none; transition: opacity 0.3s ease; }
}

/* ─── Press feedback ──────────────────────────────────────────────────────────
   Every real button/pill/CTA link on the site follows a `-btn`/`-cta`/`-pill`
   naming convention (already true of dashboard.html's own :active rules) —
   this extends that same instant, on-press feedback to the public pages,
   which had none. Scoped to actual <a>/<button> elements only, never to a
   wrapping <section>/<div> that merely shares part of the class name.

   :not(.roles-toggle-btn) — a scale-from-centre press only reads right on
   something small enough that its whole box moves together. This name just
   happens to end in "-btn" while actually being a full-width row header (see
   open roles): scaling it from the row's centre visibly flings the label
   sideways, which is the "text jumps right and back" bug this excludes. */
a[class*="-btn"]:not(.roles-toggle-btn), button[class*="-btn"]:not(.roles-toggle-btn),
a[class*="-cta"], button[class*="-cta"],
a[class*="-pill"], button[class*="-pill"] {
  transition: transform 120ms ease-out;
}
a[class*="-btn"]:not(.roles-toggle-btn):active, button[class*="-btn"]:not(.roles-toggle-btn):active,
a[class*="-cta"]:active, button[class*="-cta"]:active,
a[class*="-pill"]:active, button[class*="-pill"]:active {
  transform: scale(0.97);
}

/* ─── Arrow-morph icon ────────────────────────────────────────────────────────
   Shared by every "Label →" link/button site-wide (nav CTAs, secondary CTAs,
   role/project links, form submits). At rest it's a quiet chevron; hovering
   (or keyboard-focusing) the parent link swaps it for a bolder full arrow that
   slides into place. Scoped to real <a>/<button> ancestors so it works no
   matter what that component's own class is named. */
.arrow-ic { position: relative; display: inline-block; width: 16px; height: 14px; vertical-align: -2px; flex-shrink: 0; }
.arrow-ic svg {
  position: absolute; inset: 0;
  transition: opacity 180ms cubic-bezier(0.23,1,0.32,1), transform 180ms cubic-bezier(0.23,1,0.32,1);
}
.arrow-ic .am-chevron { opacity: 1; transform: translateX(0) scale(1); }
.arrow-ic .am-arrow   { opacity: 0; transform: translateX(-3px) scale(0.92); }
@media (hover: hover) and (pointer: fine) {
  a:hover .arrow-ic .am-chevron, button:hover:not(:disabled) .arrow-ic .am-chevron { opacity: 0; transform: translateX(4px) scale(0.92); }
  a:hover .arrow-ic .am-arrow, button:hover:not(:disabled) .arrow-ic .am-arrow { opacity: 1; transform: translateX(0) scale(1); }
}
a:focus-visible .arrow-ic .am-chevron, button:focus-visible:not(:disabled) .arrow-ic .am-chevron { opacity: 0; transform: translateX(4px) scale(0.92); }
a:focus-visible .arrow-ic .am-arrow, button:focus-visible:not(:disabled) .arrow-ic .am-arrow { opacity: 1; transform: translateX(0) scale(1); }
@media (prefers-reduced-motion: reduce) {
  .arrow-ic svg { transition-duration: 140ms; }
  .arrow-ic .am-chevron, .arrow-ic .am-arrow { transform: none !important; }
}

/* ─── Section labels ─────────────────────────────────────────────────────────── */
.section-label {
  color: var(--muted) !important;
  font-size: 14px !important;
  font-weight: 300 !important;

  text-transform: uppercase !important;
}

/* ─── Ampersand — SF Pro (no serif override) ─────────────────────────────────── */
.amp { font-style: normal; }

/* ─── Filled pill CTAs ───────────────────────────────────────────────────────── */
.process-btn,
.hero-enroll,
.inv-cta,
.price-cta,
.modal-download-btn {
  border-radius: 999px !important;
  background: var(--ink) !important;
  color: var(--bg) !important;
  border: 1px solid var(--ink) !important;
  white-space: nowrap !important;
  cursor: pointer !important;
  transition: opacity 0.2s ease !important;
  display: inline-block !important;
  width: fit-content !important;
  align-self: flex-start !important;
  text-align: left !important;
}
.process-btn:hover,
.hero-enroll:hover,
.inv-cta:hover,
.price-cta:hover,
.modal-download-btn:hover {
  opacity: 0.6 !important;
}
.modal-download-btn:disabled { opacity: 0.35 !important; cursor: not-allowed !important; }
.process-btn:active,
.hero-enroll:active,
.inv-cta:active,
.price-cta:active,
.modal-download-btn:not(:disabled):active {
  transform: scale(0.97) !important;
}

/* ─── Primary CTA — solid fill, one hover behaviour, everywhere ──────────────
   The site's one always-prominent action per view: the hero and closing
   "Start a project"/"Start here", and the contact form's "Send Inquiry". Same
   treatment .nav-cta already had on its own (fill:var(--ink), text:var(--bg)) —
   these three used to be repainted grey by the "filled pill" groups below
   (opacity-hover here, then the grey-ring group further down); pulled out of
   both so there's exactly one place this is decided.
   Hover is a solid fill step (--ink-hover), never opacity — a fade reads as
   "disabled", not "interactive". */
.final-cta-btn,
.submit-btn {
  background: var(--ink) !important;
  color: var(--bg) !important;
  border-color: transparent !important;
  box-shadow: none !important;
  transition: background-color 0.18s ease, transform 0.12s ease-out !important;
}
.final-cta-btn:hover,
.submit-btn:hover {
  background: var(--ink-hover) !important;
  color: var(--bg) !important;
  opacity: 1 !important;
  transform: none !important;
}
.final-cta-btn:active,
.submit-btn:active {
  transform: scale(0.97) !important;
}

/* Primary on dark media: the home hero's "Start a project" sits on the video,
   which stays dark whatever the page theme, so it takes the inverse primary —
   white pill, near-black label, one solid step darker on hover — the
   --media-* tokens, which hold in every theme. */
.hero-cta-primary {
  background: var(--media-fill) !important;
  color: var(--media-ink) !important;
  border-color: transparent !important;
  box-shadow: none !important;
  transition: background-color 0.18s ease, transform 0.12s ease-out !important;
}
.hero-cta-primary:hover { background: var(--media-fill-hover) !important; color: var(--media-ink) !important; opacity: 1 !important; }
.hero-cta-primary:active { transform: scale(0.97) !important; }

/* ─── Active filter state ────────────────────────────────────────────────────── */
.filter-btn.active {
  background: var(--ink) !important;
  color: var(--bg) !important;
  border-bottom-color: transparent !important;
}

/* ─── Badges ─────────────────────────────────────────────────────────────────── */
.badge-new, .badge-featured {
  display: inline-block;
  font-size: 14px; font-weight: 300;
 text-transform: uppercase;
  color: var(--surface); background: var(--ink);
  padding: 3px 7px; border-radius: 999px;
  vertical-align: middle; line-height: 1.4;
}

/* ─── Form states ────────────────────────────────────────────────────────────── */
.state-success { color: var(--muted) !important; }
.req { color: var(--ink); }

/* ─── Accordion ─────────────────────────────────────────────────────────────── */
.accordion-panel {
  transition: grid-template-rows 0.5s cubic-bezier(0.22, 1, 0.36, 1) !important;
}

/* ─── Footer layout (global) ─────────────────────────────────────────────────── */
footer {
  background: var(--bg) !important;
  transition: background 0.3s ease !important;
  padding: 48px var(--gutter) !important;
  display: grid !important;
  /* Responsive: columns flow to fill the row — two across on desktop/tablet,
     one on phones — so no track is ever left idle. */
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)) !important;
  align-items: stretch !important;
  gap: 16px !important;
}
/* Firsthand-style card: white fill, 1px ink/10 ring, generous radius. */
footer > div {
  background: var(--surface) !important;
  border-radius: var(--radius-card) !important;
  box-shadow: 0 0 0 1px var(--border) !important;
  padding: 28px !important;
}
.footer-bottom {
  background: var(--bg) !important;

  padding: 20px var(--gutter) 40px !important;
  display: flex !important;
  align-items: center !important;
  justify-content: space-between !important;
}
.footer-copy {
  font-size: 12px !important;
  font-weight: 300 !important;
  color: var(--muted) !important;
}
.footer-legal {
  display: flex !important;
  gap: 20px !important;
  align-items: center !important;
}
.footer-legal a {
  font-size: 12px !important;
  font-weight: 300 !important;
  color: var(--muted) !important;
  text-decoration: none !important;
  transition: color 0.2s ease !important;
  position: relative !important;
}
.footer-legal a:hover { color: var(--ink) !important; }
.footer-legal a + a::before {
  content: '·' !important;
  position: absolute !important;
  left: -13px !important;
  top: 50% !important;
  transform: translateY(-50%) !important;
  color: var(--muted) !important;
  pointer-events: none !important;
  text-decoration: none !important;
}
.footer-address {
  font-size: 14px;
  font-weight: 300;
  color: var(--muted);
  line-height: 1.75;
  margin-top: 10px;
  padding: 0 2px;
}

/* ─── Footer city times ──────────────────────────────────────────────────────── */
.footer-times {
  display: flex;
  gap: 48px;
  padding: 20px var(--gutter);
  background: var(--bg);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  transition: background 0.3s ease;
}
.ft-city { display: flex; align-items: baseline; gap: 10px; }
.ft-sep { display: inline-block; width: 3px; height: 3px; background: var(--ink); vertical-align: middle; font-size: 0; align-self: center; }
.ft-label-full, .ft-label-short {
  font-size: 11px; font-weight: 300;
  text-transform: uppercase;
  color: var(--muted);
}
/* Legacy .ft-label support */
.ft-label {
  font-size: 11px; font-weight: 300;
  text-transform: uppercase;
  color: var(--muted);
}
.ft-label-short { display: none; }
.ft-time {
  font-size: 11px; font-weight: 300;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* ─── Theme toggle — desktop vs mobile ──────────────────────────────────────── */
.theme-toggle-mobile { display: none !important; }

/* Footer contact sub-labels */
.footer-contact-label {
  display: block !important;
  font-size: 14px !important;
  font-weight: 300 !important;
  color: var(--muted) !important;
  margin-top: 14px !important;
  margin-bottom: 4px !important;
}
.footer-contact-label:first-of-type { margin-top: 0 !important; }

/* Footer col label */
.footer-col-label {
  color: var(--muted) !important;
  font-size: 14px !important;
  font-weight: 400 !important;
  text-transform: uppercase !important;
  margin-bottom: 16px !important;
}

/* Footer CTA — filled rectangle */
.footer-cta-link {
  display: inline-block !important;
  background: var(--ink) !important;
  color: var(--surface) !important;
  border: none !important;
  border-radius: 0 !important;
  font-weight: 300 !important;
  letter-spacing: 0 !important;
  padding: 13px 24px !important;
  text-decoration: none !important;
  transition: opacity 0.22s ease !important;
}
.footer-cta-link:hover { opacity: 0.6 !important; }

/* Footer link row wrapper */
.footer-links-row {
  display: flex !important;
  flex-wrap: wrap !important;
  align-items: center !important; /* default (stretch) forced every pill to
    the copy-circle's 38px height, so each pill's text sat against its own
    padding-top with all the extra stretched space left below it — the real
    source of the "Email"/"Start a project" imbalance. Centering lets each
    pill size to its own content instead. */
  gap: 10px !important;
  margin-top: 0 !important;
  margin-left: -2px !important;
}
/* This row is flex, so `gap` alone owns the spacing — .footer-link's
   margin-right (a leftover from when these were inline-block) was stacking
   on top of it for an uneven 14px, and the copy circle carried its own
   ad-hoc -3px/+9px offsets on top of that. Zeroed so all three sit on one
   even 10px rhythm, matching the social row below. */
.footer-links-row > .footer-link { margin-right: 0 !important; margin-left: 0 !important; }

/* Footer link pills */
.footer-link,
.footer-social a {
  display: inline-block !important;
  font-size: 14px !important;
  font-weight: 300 !important;
  color: var(--ink) !important;
  background: rgba(38,38,38,0.08) !important;
  border-radius: 999px !important;
  padding: 9px 18px !important;
  margin-right: 6px !important;
  margin-bottom: 0 !important;
  text-decoration: none !important;
  transition: background 0.2s ease !important;
}
html[data-theme="dark"] .footer-link,
html[data-theme="dark"] .footer-social a {
  background: rgba(255,255,255,0.1) !important;
}
.footer-link:hover,
.footer-social a:hover {
  background: rgba(38,38,38,0.16) !important;
  color: var(--ink) !important;
  opacity: 1 !important;
  text-decoration: none !important;
}
html[data-theme="dark"] .footer-link:hover,
html[data-theme="dark"] .footer-social a:hover {
  background: rgba(255,255,255,0.18) !important;
}

/* ─── Footer "Email" pill — copies the address on tap ────────────────────────
   The copy control lives INSIDE the Email pill now; it used to be a separate
   circle beside it. Tapping copies hello@transvo.co and the pill morphs to
   "Email copied" with a check (FLIP measure/snap/animate, same technique as
   the small-business promo's pill<->card), then reverts on its own — it does
   not open a mail client. The anchor keeps its mailto: href only as the
   fallback for no-JS and for a blocked clipboard. Keeps the .footer-link
   class for its shared pill background/hover, so only the inner row, icon and
   tooltip are added here. Shown at every width: with the separate circle gone
   the row has room for the full "Email copied" label even at 375px. Built by
   initFooterCopyBtn() in global.js — no per-page markup changes. */
/* ─── Text morph runtime (window.tvoMorphText in global.js) ───────────────────
   Shared by the footer copy-email button and the contact form's submit button.
   The engine writes every timing inline; these rules only supply the layout
   the technique needs.

   .tm-run must be inline-block — transforms are ignored on non-replaced inline
   boxes, and the whole effect is transform-driven. white-space:pre keeps the
   spaces that a run may start or end with, which normal collapsing would eat
   and which would shift every measurement after it.

   .tm-measuring is for callers: they need one frame with the new state applied
   to measure the target size, and that frame must not itself animate. */
.tm-host { position: relative; }
.tm-run { display: inline-block; white-space: pre; }
.tm-ghost { position: absolute; top: 0; left: 0; white-space: pre; pointer-events: none; }
.tm-ghost > span { position: absolute; top: 0; display: inline-block; white-space: pre; }
.tm-measuring, .tm-measuring * { transition: none !important; animation: none !important; }

.footer-copy-link { position: relative; cursor: pointer; }
/* The inner row is what the FLIP resizes and what clips the label while the
   box is still growing. overflow:hidden stays OFF the pill on purpose: the
   tooltip is an absolutely-positioned child opening above the pill, and a
   clipping pill swallows it. */
.footer-copy-link .fcb-content {
  display: inline-flex; align-items: center; gap: 7px;
  overflow: hidden; white-space: nowrap;
}
.footer-copy-link .fcb-content.morphing {
  transition: width 0.4s cubic-bezier(0.22,1,0.36,1);
}
.footer-copy-link .fcb-label { display: inline-block; }
/* Icon swap crossfades (opacity+scale on stacked, absolutely-positioned
   icons) instead of snapping via display:none — the same technique as the
   site's .arrow-ic chevron/arrow swap, so the glyph and the label move on the
   same frames. */
.footer-copy-link .fcb-icon-wrap { position: relative; width: 14px; height: 14px; flex-shrink: 0; }
.footer-copy-link .fcb-icon-wrap svg {
  position: absolute; inset: 0;
  transition: opacity 0.3s cubic-bezier(0.22,1,0.36,1), transform 0.3s cubic-bezier(0.22,1,0.36,1);
}
.footer-copy-link .fcb-icon-copy  { opacity: 1; transform: scale(1); }
.footer-copy-link .fcb-icon-check { opacity: 0; transform: scale(0.7); }
.footer-copy-link.copied .fcb-icon-copy  { opacity: 0; transform: scale(0.7); }
.footer-copy-link.copied .fcb-icon-check { opacity: 1; transform: scale(1); }
/* Tooltip opens upward — this pill sits at the bottom of the page, so
   downward would risk clipping under the fold. Rest state only; once
   copied, the button's own label already says so. */
.footer-copy-tip {
  position: absolute; bottom: calc(100% + 10px); left: 50%;
  transform: translate(-50%, 4px);
  background: var(--elevated); color: var(--ink);
  font-size: 12px; font-weight: 500; white-space: nowrap;
  padding: 7px 12px; border-radius: 9px;
  box-shadow: 0 6px 20px rgba(0,0,0,0.22), 0 0 0 1px var(--border);
  opacity: 0; pointer-events: none;
  transition: opacity 0.15s ease-out, transform 0.15s ease-out;
}
/* Caret. A rotated square rather than a border triangle, because a triangle
   made of borders can't carry the tooltip's own 1px outline — this one takes
   two real borders on the two edges that end up facing outward once rotated,
   so the notch joins the card's edge seamlessly. Sits half-overlapping the
   card's bottom edge to hide the seam. */
.footer-copy-tip::after {
  content: ''; position: absolute;
  top: 100%; left: 50%;
  width: 9px; height: 9px;
  margin-left: -4.5px; margin-top: -4.5px;
  background: var(--elevated);
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  border-bottom-right-radius: 2px;
  transform: rotate(45deg);
}
@media (hover: hover) and (pointer: fine) {
  .footer-copy-link:not(.copied):hover .footer-copy-tip,
  .footer-copy-link:not(.copied):focus-visible .footer-copy-tip { opacity: 1; transform: translate(-50%, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .footer-copy-link .fcb-content.morphing { transition-duration: 0.12s !important; }
  .footer-copy-link .fcb-icon-wrap svg, .footer-copy-tip { transition-duration: 0.12s; transition-delay: 0s; }
}

/* Footer social row — same flex construction and gap as .footer-links-row
   above, so "Get in touch" and "Connect with us" space identically. It used
   to be display:block, where the gap was really inline-block whitespace
   (~3.6px) plus margin-right:6px, which is why the two rows never matched. */
.footer-social {
  display: flex !important;
  flex-wrap: wrap !important;
  align-items: center !important;
  gap: 10px !important;
  margin-top: 0 !important;
  margin-left: -2px !important;
}
.footer-social > a { margin-right: 0 !important; margin-left: 0 !important; }

/* Single pill direct child of footer column */
footer > div > .footer-link {
  margin-left: -2px !important;
}
.footer-copy, .footer-legal a { color: var(--muted) !important; }
.footer-legal a { text-decoration: none !important; }
.footer-legal a:hover { color: var(--ink) !important; opacity: 1 !important; }

/* ─── Dark mode: page-level overrides ───────────────────────────────────────── */
html[data-theme] .filter-wrap {
  background: var(--bg) !important;
  border-bottom-color: var(--hairline) !important;
}
html[data-theme] .work-hero {
  background: var(--bg) !important;
}
html[data-theme] .work-grid-section {
  background: var(--bg) !important;
}
html[data-theme] .grid-thumb {
  background: var(--chip) !important;
}
html[data-theme] .ph-light { background: var(--placeholder) !important; }
/* .filter-btn base/:hover/.active used to be redeclared here with a literal
   #232323 hover fill. Removed — see "Secondary / outline pills" further down,
   which is the actual, current definition; this one was a silent duplicate
   that happened to win the hover fill (a literal colour beats a var()-based
   one of equal specificity — see that section's comment) while losing
   everywhere else, which is how the lift became the only visible hover cue. */
html[data-theme] footer > div {
  background: var(--surface) !important;
}
html[data-theme="dark"] .footer-times {

}
html[data-theme] .hamburger span,
html[data-theme] .nav-hamburger span {
  background: var(--ink) !important;
}
/* Dark-only site: the theme toggle has no purpose — hide every variant. */
.theme-toggle,
.theme-toggle-desktop,
.theme-toggle-mobile { display: none !important; }

/* Mobile slide-out menu — panel matched to the canvas. */
html[data-theme] .mobile-nav {
  background: var(--bg) !important;
}
html[data-theme] .mobile-nav a {
  color: var(--ink) !important;
  border-color: var(--hairline) !important;
}
/* Plain links only. The CTA pill is white, so fading its label toward white
   made "Start a project" vanish on hover/tap. Also the one hover treatment
   for every page's menu links: step down to --muted with no extra opacity
   dim (several pages stacked a 0.45 fade on top, dropping to ~2:1 contrast). */
html[data-theme] .mobile-nav a:not(.mobile-cta):hover {
  color: var(--muted) !important;
  opacity: 1 !important;
}
html[data-theme] .mobile-nav .mobile-cta {
  background: var(--ink) !important;
  color: var(--bg) !important;
  box-shadow: none !important;
}

/* ─── CTA arrows ─────────────────────────────────────────────────────────────── */
.more-work-text, .enroll-text {
  transition: color 0.35s cubic-bezier(0.22, 1, 0.36, 1) !important;
}
.more-work-arrow, .enroll-arrow {
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1) !important;
}

/* ─── Global mobile overrides (≤768px) ───────────────────────────────────────── */
@media (max-width: 768px) {
  /* Hide desktop nav, show hamburger */
  .nav-right { display: none !important; }
  .nav-hamburger { display: flex !important; }

  /* Toggle + hamburger grouped on right side of nav */
  .theme-toggle-mobile { margin-left: auto !important; margin-right: 12px !important; }

  /* Mobile nav pill: fit to text */
  .mobile-cta { align-self: flex-start !important; }

  /* Prevent iOS zoom on form focus */
  input, textarea, select { font-size: max(16px, 1em) !important; }

  /* Footer: single column */
  footer {
    grid-template-columns: 1fr !important;
    padding: 32px var(--gutter) !important;
    gap: 16px !important;
  }
  footer > div {
    padding: 24px 22px !important;
    border-radius: 16px !important;
  }
  .footer-bottom {
    padding: 16px var(--gutter) 32px !important;
    flex-direction: column !important;
    align-items: flex-start !important;
    gap: 8px !important;
  }
  /* Footer legal links: underline on mobile */
  .footer-legal a { text-decoration: underline !important; }

  /* Timezone strip: single row with clear gaps; scrolls if it can't fit. */
  .footer-times {
    flex-wrap: nowrap !important;
    justify-content: flex-start !important;
    gap: 20px !important;
    padding: 14px var(--gutter) !important;
    overflow-x: auto !important;
    scrollbar-width: none !important;
    -webkit-overflow-scrolling: touch !important;
  }
  .footer-times::-webkit-scrollbar { display: none !important; }
  .footer-times .ft-sep { display: none !important; }
  .ft-city { gap: 6px !important; flex-shrink: 0 !important; }
  .ft-label-full { display: none !important; }
  .ft-label-short { display: inline !important; font-size: 11px !important; }
  .ft-time { font-size: 11px !important; }

  /* Theme toggle: hide desktop copy, show mobile copy */
  .theme-toggle-desktop { display: none !important; }
  .theme-toggle-mobile {
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
  }

  /* cta-split.cta-lg: scale down so it doesn't overflow narrow screens */
  .cta-split.cta-lg .cta-pill {
    font-size: clamp(28px, 7vw, 44px) !important;
    padding: 18px 32px !important;
    letter-spacing: -0.03em !important;
  }
  .cta-split.cta-lg .cta-circle {
    width: clamp(52px, 13vw, 68px) !important;
    height: clamp(52px, 13vw, 68px) !important;
    font-size: clamp(20px, 5vw, 28px) !important;
  }
}


/* ─── Mobile: comfortable tap targets ────────────────────────────────────────
   Touch guidance asks for ~44px. These rules grow the *hit area* (padding or
   min-height) without changing how anything looks, so the layout is untouched
   while every control becomes reliably tappable on a phone.
--------------------------------------------------------------------------- */
@media (max-width: 768px) {
  /* Primary nav controls */
  .nav-hamburger {
    min-width: 44px !important; min-height: 44px !important;
    margin-right: -10px !important;
    align-items: center !important;
  }
  .nav-logo { min-height: 44px !important; display: inline-flex !important; align-items: center !important; }
  /* Do NOT change the toggle's padding/height here: the sliding thumb is
     absolutely positioned against a 3px inset, so padding changes knock it
     out of alignment. Grow the touch target with an invisible overlay. */
  .theme-toggle { position: relative !important; }
  .theme-toggle::after { content: ''; position: absolute; inset: -7px; }

  /* Inline text CTAs — keep the type size, grow the touch row */
  .hero-cta-secondary,
  .see-all,
  .path-cta,
  .post-back,
  .pdp-back,
  .nf-cta-secondary,
  .contact-email,
  .footer-legal a,
  .footer-times a {
    display: inline-flex !important;
    align-items: center !important;
    min-height: 44px !important;
  }

  /* Footer link pills already have padding; guarantee the height. The copy
     control now lives inside the Email pill, so it shares the target. */
  .footer-link,
  .footer-social a { min-height: 44px !important; display: inline-flex !important; align-items: center !important; }

  /* Dismiss / stepper buttons need a real square */
  .modal-close,
  .nl-close,
  .checkout-close,
  .cal-nav-btn {
    min-width: 44px !important; min-height: 44px !important;
    display: inline-flex !important; align-items: center !important; justify-content: center !important;
  }

  /* Choice chips inside the checkout sheet */
  .co-contact-opt { min-height: 44px !important; }

  /* Filter chips are horizontally scrollable; make them thumb-friendly */
  .filter-btn, .sf-btn { min-height: 40px !important; }
}

/* Standalone links that sit alone in a paragraph (legal pages' contact block)
   are real targets, not inline prose links — give them a tappable row. */
@media (max-width: 768px) {
  .legal-section p > a:only-child {
    display: inline-flex !important;
    align-items: center !important;
    min-height: 44px !important;
  }
}

/* ─── Content cards ───────────────────────────────────────────────────────────
   The "Think / Make / Move" method cards on home and about (were defined twice). */
.method-card {
  background: var(--surface); border-radius: var(--radius-card);
  box-shadow: 0 0 0 1px var(--border);
  padding: 36px 32px;
}
@media (max-width: 768px) { .method-card { padding: 28px 24px; } }

/* Role tags (careers + about open roles): grey chips, the same fill as the
   filter chips, so they read as tags rather than white-on-white. */
.role-tag {
  font-size: 12px; font-weight: 400; color: var(--muted);
  background: var(--chip); border-radius: 999px;
  padding: 5px 12px; white-space: nowrap;
}

/* ─── Image loading ───────────────────────────────────────────────────────────
   Lazy images stay invisible until they've loaded, then fade in over their
   tile's placeholder fill — instead of flashing the alt text and a broken-
   image icon while a large file downloads. Scoped to html.tvo-js (set by
   global.js) so images still show if the script ever fails. */
html.tvo-js img[loading="lazy"] { opacity: 0; transition: opacity 0.4s cubic-bezier(0.23, 1, 0.32, 1); }
html.tvo-js img[loading="lazy"].is-loaded { opacity: 1; }
@media (prefers-reduced-motion: reduce) { html.tvo-js img[loading="lazy"] { transition: none; } }

/* ─── Type scale ───────────────────────────────────────────────────────────────
   Four heading steps and one label style for the whole site. Every page's own
   title / section / card / eyebrow class is mapped here, so a size changes in
   one place. `html` in front lifts these one notch above the single-class
   rules in each page's <style>, which is what lets the scale win without
   deleting every page rule by hand. Fluid via clamp(), so no breakpoints.
--------------------------------------------------------------------------- */
:root {
  --t-display: clamp(40px, 4.6vw, 68px);   /* page titles */
  --t-section: clamp(28px, 2.8vw, 42px);   /* section headings */
  --t-card:    clamp(19px, 1.6vw, 24px);   /* card / list-item titles */
}
html .hero-headline, html .wh-title, html .nh-title, html .display-title,
html .book-title, html .shop-lead, html .careers-title, html .legal-header h1,
html .post-title, html .project-head-title, html .final-cta-headline, html .ethos-title {
  font-size: var(--t-display); font-weight: 300;
  letter-spacing: -0.03em; line-height: 1.04;
}
html .positioning-headline, html .trust-headline, html .build-title,
html .featured-title, html .nl-title, html .more-heading,
html .more-projects-label, html .method-title {
  font-size: var(--t-section); font-weight: 300;
  letter-spacing: -0.02em; line-height: 1.1;
}
html .work-card-title, html .card-title, html .more-card-title,
html .route-title, html .role-name {
  font-size: var(--t-card); font-weight: 300;
  letter-spacing: -0.01em; line-height: 1.25;
}
/* Eyebrow: small uppercase label above a heading or section. 400, not 300 —
   at 11px a 300 weight breaks up on non-retina screens. */
html .section-label, html .section-label-sm, html .proof-label, html .book-label,
html .pdp-includes-label, html .nl-eyebrow, html .co-eyebrow, html .careers-eyebrow,
html .legal-header-eyebrow, html .legal-toc-label, html .project-rule-label,
html .role-type, html .route-badge, html .roles-label {
  font-size: 11px; font-weight: 400;
  letter-spacing: 0.12em; line-height: 1.4; text-transform: uppercase;
}

/* ─── "More" pill — "See all work" / "Read something else" ───────────────────
   A secondary action, so it takes the secondary pill: the same grey chip as
   the footer pills and filter chips, rather than a white pill with an outline
   that read as a stray card. One definition for both pages. */
.more-pill {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 9px;
  font-size: 14px; font-weight: 300; color: var(--ink);
  background: var(--ghost); border: none; border-radius: 999px;
  padding: 11px 20px; text-decoration: none; white-space: nowrap;
  transition: background-color 0.2s ease, transform 0.16s cubic-bezier(0.23, 1, 0.32, 1);
}
.more-pill svg { flex-shrink: 0; transition: transform 0.2s ease; }
.more-pill:active { transform: scale(0.97); }
@media (hover: hover) and (pointer: fine) {
  .more-pill:hover { background: var(--ghost-hover); }
  .more-pill:hover svg { transform: translateX(4px); }
}

/* ─── Client logo grid ────────────────────────────────────────────────────────
   One component for every page that shows clients. The logos themselves are
   listed once, in CLIENT_LOGOS in global.js, and rendered into any element
   carrying [data-client-logos] — add a client there and every page updates.
   Static and full colour: the logos are the content, so nothing moves.
--------------------------------------------------------------------------- */
.logo-grid {
  display: flex; flex-wrap: wrap;
  width: 100%;
  list-style: none; padding: 0; margin: 0;
}
.logo-grid .logo-break { display: none; }
.logo-grid .logo-img {
  display: block; width: auto; object-fit: contain;
  filter: var(--client-logo-filter); opacity: var(--client-logo-opacity);
}
/* Air Ghana's bird swoops well above its wordmark, so the artwork's bounding
   box is taller than the part the eye reads. Centring the box sits the words
   ~4px low next to every other logo, whose box IS its wordmark. Lift it back
   onto the row's optical centre line — a percentage, so the nudge keeps its
   proportion at every size. */
.logo-grid .logo-slot.is-lifted .logo-img { transform: translateY(-7%); }

/* Desktop: two rows of seven, each spread edge to edge, so the first logo sits
   on the content's left edge and the last on its right — flush with the
   headline above. Heights come from --h (area-normalised, see CLIENT_LOGOS). */
@media (min-width: 901px) {
  /* --logo-inset: set by the host section to its own label's side padding,
     so the grid's outer logos land exactly under the label's edges. */
  .logo-grid { justify-content: space-between; align-items: center; row-gap: 28px;
               padding-inline: var(--logo-inset, 56px); }
  .logo-grid .logo-break { display: block; flex-basis: 100%; height: 0; }
  .logo-grid .logo-slot { flex: 0 0 auto; display: flex; align-items: center; height: 52px; }   /* = the tallest mark (emblems) */
  .logo-grid .logo-img { height: var(--h, 32px); }
}

/* Tablet and phone: an even grid of cells, logos centred in each. */
@media (max-width: 900px) {
  .logo-grid { justify-content: center; }
  .logo-grid .logo-slot {
    flex: 0 0 33.333%; height: 120px;
    display: flex; align-items: center; justify-content: center; padding: 0 20px;
  }
  .logo-grid .logo-img { height: 34px; max-width: 160px; }
  .logo-grid .logo-slot.is-emblem .logo-img { height: 52px; }
}
@media (max-width: 560px) {
  .logo-grid .logo-slot { flex-basis: 50%; height: 96px; padding: 0 12px; }
  .logo-grid .logo-img { height: 28px; max-width: 136px; }
  .logo-grid .logo-slot.is-emblem .logo-img { height: 44px; }
}

/* ─── Very small phones (<=360px) ────────────────────────────────────────────
   The timezone strip is forced onto one line; at 320px that is ~2px too wide
   and drags the whole page into horizontal scroll. Tighten it and let it
   scroll within itself rather than pushing the page.
--------------------------------------------------------------------------- */
@media (max-width: 360px) {
  .footer-times {
    padding: 12px 14px !important;
    gap: 0 !important;
    overflow-x: auto !important;
    scrollbar-width: none !important;
  }
  .footer-times::-webkit-scrollbar { display: none !important; }
  .ft-city { gap: 4px !important; }
  .ft-label-short, .ft-time { font-size: 11px !important; }
}

/* ─── Section eyebrow — one treatment, one rhythm ─────────────────────────────
   These labels all play the same role: a small caps line introducing the block
   beneath it. They had drifted to 11/12/13/14px with gaps ranging from 0 to
   48px, so no two sections opened the same way. Canonical: 11px, uppercase,
   0.1em tracking, muted, with a 28px gap to the content it introduces.
   (.section-label-sm sits in a flex header row beside a link, so its
   margin-bottom is inert there — the type treatment still unifies.)
--------------------------------------------------------------------------- */
.section-label,
.section-label-sm,
.next-label,
.proof-label,
.project-band-label,
.inv-eyebrow,
.shop-hero-eyebrow {
  font-size: 11px !important;
  font-weight: 300 !important;
  line-height: 1.4 !important;
  letter-spacing: 0.1em !important;
  text-transform: uppercase !important;
  color: var(--muted) !important;
  margin-bottom: 28px !important;
}
/* In the flex header row the eyebrow sits beside a link, so the stacked-label
   margin is inert and would only pad the row's height. */
.section-header .section-label-sm { margin-bottom: 0 !important; }

/* ─── Nav v2 (OpenAI-inspired): single-icon toggle · Company dropdown · Enter BrandLab ↗ ─── */

/* Desktop theme toggle → a single icon of the mode you'll switch TO.
   Scoped to -desktop so the mobile pill toggle stays exactly as-is. */
.theme-toggle-desktop {
  background: transparent !important;
  padding: 0 !important; gap: 0 !important;
  width: 36px !important; height: 36px !important;
  border-radius: 999px !important; justify-content: center !important;
  margin-left: 18px !important; margin-right: 0 !important;   /* sits just after Company */
}
.theme-toggle-desktop::before { display: none !important; }   /* remove the sliding knob */
.theme-toggle-desktop .seg { display: none !important; width: auto !important; height: auto !important; }
.theme-toggle-desktop .seg svg { width: 18px !important; height: 18px !important; }
/* show the OPPOSITE mode's icon: moon while light, sun while dark */
html:not([data-theme="dark"]) .theme-toggle-desktop .seg-moon { display: inline-flex !important; color: var(--ink) !important; }
html[data-theme="dark"] .theme-toggle-desktop .seg-sun { display: inline-flex !important; color: #fafafa !important; }
.theme-toggle-desktop:hover { background: rgba(38,38,38,0.07) !important; }
html[data-theme="dark"] .theme-toggle-desktop:hover { background: rgba(255,255,255,0.10) !important; }

/* Company dropdown */
.nav-has-menu { position: relative !important; list-style: none !important; }
.nav-menu-trigger {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: inherit; font-size: 16px; font-weight: 400;
  color: var(--ink); opacity: 0.45;
  background: none; border: none; cursor: pointer; padding: 0; margin: 0;
  white-space: nowrap; transition: opacity 0.15s ease;
}
.nav-has-menu:hover .nav-menu-trigger,
.nav-menu-trigger[aria-expanded="true"],
.nav-menu-trigger.nav-active { opacity: 0.85; }
.nav-chevron { display: inline-block; font-size: 10px; line-height: 1; transition: transform 0.2s ease; }
.nav-has-menu:hover .nav-chevron,
.nav-menu-trigger[aria-expanded="true"] .nav-chevron { transform: rotate(180deg); }
/* invisible hover-bridge so the menu doesn't close crossing the gap */
.nav-has-menu::after { content: ''; position: absolute; top: 100%; left: 0; right: 0; height: 14px; }
.nav-menu {
  position: absolute; top: calc(100% + 10px); left: -12px; transform: translateY(-6px);
  min-width: 208px; padding: 8px;
  background: var(--elevated); border: none; border-radius: 16px;
  box-shadow: none;   /* flat — separation comes from the lifted panel colour */
  display: flex; flex-direction: column;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
  z-index: 210;
}
.nav-has-menu:hover .nav-menu, .nav-menu.open {
  opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0);
}
.nav-menu a {
  display: block; padding: 11px 14px; border-radius: 10px;
  font-size: 15px; font-weight: 400; color: var(--ink) !important; opacity: 0.82;
  text-decoration: none !important; white-space: nowrap;
  transition: opacity 0.15s ease, background 0.15s ease;
}
.nav-menu a:hover { opacity: 1; background: var(--ghost); }
.nav-menu a.nav-active { opacity: 1; font-weight: 500; }

/* Enter BrandLab — OpenAI-style ↗ arrow */
.nav-cta-arr { display: inline-block; margin-left: 1px; font-size: 0.95em; line-height: 1; }

/* ─── Filled "surface" pill — the remaining grey-ring family ──────────────────
   A lifted #191919 chip, white label, 1px translucent-white ring: filter and
   sort active states, checkout/discount/newsletter/download actions, and the
   proposal work-carousel dots. This used to also cover .hero-cta-primary and
   .final-cta-btn ("Start a project" / "Start here") with .nav-cta carved out
   as "the only white button" — the site has since moved to a real 4-tier
   button system (see the button-system spec) where solid white/var(--ink) IS
   the primary treatment, not an exception to it: .nav-cta, .hero-cta-primary,
   .final-cta-btn and .submit-btn all share it now (defined above, in
   "Filled pill CTAs"). !important is required to override the per-page inline
   rules and inline style attributes. */
.cta-split .cta-pill,
.cta-split .cta-circle,
.filter-btn.active,
.sf-btn.active,
.slot-btn.selected,
.co-discount-apply,
.checkout-pay-btn,
.process-btn,
.meet-btn,
.nl-btn,
.modal-download-btn {
  background: var(--surface) !important;
  color: var(--ink) !important;
  border-color: transparent !important;
  box-shadow: 0 0 0 1px var(--border) !important;
  /* Animate only bg + ring so hover is one smooth motion (no instant jump). */
  transition: background 0.18s ease, box-shadow 0.18s ease !important;
}
.cta-split:hover .cta-pill,
.cta-split:hover .cta-circle,
.co-discount-apply:hover,
.checkout-pay-btn:hover,
.meet-btn:hover,
.nl-btn:hover,
.nl-close:hover,
.modal-download-btn:hover {
  background: var(--chip) !important;
  color: var(--ink) !important;
  border-color: transparent !important;
  box-shadow: 0 0 0 1px var(--hairline) !important;
  /* Cancel the per-page opacity-dim hovers so the pill only lifts, not fades. */
  opacity: 1 !important;
  transform: none !important;
}
/* Press feedback for this whole filled-pill family. Declared after :hover
   above (and !important) so it wins the brief hover+press overlap of a
   normal click against that block's `transform: none !important`. */
.cta-split .cta-pill:active,
.cta-split .cta-circle:active,
.filter-btn:active,
.sf-btn:active,
.slot-btn.selected:active,
.co-discount-apply:active,
.checkout-pay-btn:active,
.process-btn:active,
.meet-btn:active,
.nl-btn:active,
.nl-close:active,
.view-gallery-btn:active,
.modal-download-btn:active,
.btn-book:not(:disabled):active,
.role-apply:active {
  transform: scale(0.97) !important;
}

/* ─── Secondary / outline pills — flat ghost, no ring ─────────────────────────
   The site's secondary buttons drop the translucent-white 1px ring (the
   "liquid glass" look) for the flatter fill used on the proposal pages: a
   plain --ghost pill that brightens to --ghost-hover and lifts 1px on hover,
   and presses to 0.97. The prominent primary CTAs (hero, checkout, downloads,
   submit) keep their own solid treatment and are untouched by this block. */
html[data-theme] .filter-btn,
html[data-theme] .sf-btn {
  background: var(--ghost) !important;
  color: var(--muted) !important;
  border: none !important;
  box-shadow: none !important;
  transition: background-color 0.18s ease, color 0.18s ease,
              transform 0.16s cubic-bezier(0.23, 1, 0.32, 1) !important;
}
.view-gallery-btn,
.process-btn {
  background: var(--ghost) !important;
  color: var(--ink) !important;
  border-color: transparent !important;
  box-shadow: none !important;
  transition: background-color 0.18s ease, color 0.18s ease,
              transform 0.16s cubic-bezier(0.23, 1, 0.32, 1) !important;
}
/* No lift — fill brightening is the entire hover signal. A translateY here
   was the "buttons subtly go up" the 1px lift was meant to add polish but
   reads as unwanted motion on anything pressable; fill alone is a cleaner
   and quieter "this is interactive". */
html[data-theme] .filter-btn:hover,
html[data-theme] .sf-btn:hover,
.view-gallery-btn:hover,
.process-btn:hover {
  background: var(--ghost-hover) !important;
  color: var(--ink) !important;
  border-color: transparent !important;
  box-shadow: none !important;
  opacity: 1 !important;
  transform: none !important;
}
html[data-theme] .filter-btn.active,
html[data-theme] .sf-btn.active {
  background: var(--ink) !important;
  color: var(--bg) !important;
  border-color: transparent !important;
  box-shadow: none !important;
}
.filter-btn:active,
.sf-btn:active,
.view-gallery-btn:active,
.process-btn:active {
  transform: scale(0.97) !important;
}
