/* ==========================================================================
   Warm skin, site-wide.

   Loaded after apple-skin.css. Same trick, one layer further: the surveyor's
   chart system is built almost entirely on CSS variables, so retuning the
   tokens re-skins all 29 content pages without touching their HTML.

   Direction, taken from startscalr.com: warm bone ground instead of cool
   white, a copper-adjacent hairline, DM Sans on display and Inter on
   everything else, uppercase eyebrow labels restored as a grammar, and a
   scroll-reveal that carries the whole page in rather than snapping it.

   Measurements below are that site's own computed values, not approximations:
   #FCFBF9 ground, #E5DFD6 hairline, display at weight 500 on -0.032em (h1)
   and -0.026em (h2), eyebrows at 13px on 0.085em, sections at ~96px.

   Two deliberate departures from the reference:

   1. The accent stays the measured teal. Copper is the reference's brand, not
      this one, and teal already clears AA on every surface here (6.14:1 on
      white, 5.98:1 on the bone ground, 7.39:1 inverted on the ink band).
   2. The geo-grid rank ramp keeps its own colours. That is data, not chrome.
   ========================================================================== */

:root {
  /* --- Ground ----------------------------------------------------------- */
  /* Bone, not white. The reference's whole warmth comes from this one move:
     the page ground is #FCFBF9 and white is reserved for raised surfaces. */
  --chart: #fcfbf9;
  --chart-2: #f5f2ed;   /* recessed warm panel */
  --chart-raised: #ffffff; /* cards, inputs, anything that sits above ground */

  --basemap: #111418;   /* the ink band */
  --basemap-2: #1a1f26;

  /* --- Ink -------------------------------------------------------------- */
  --ink: #111418;
  --ink-soft: #39414d;
  --ink-faint: #5a616b;      /* 5.98:1 on the bone ground */
  --ink-invert: #fcfbf9;
  --ink-invert-soft: #a8afba; /* 8.37:1 on the ink band */

  /* --- Rules ------------------------------------------------------------ */
  /* Warm hairlines. A cool grey rule on a bone ground reads as a smudge. */
  --rule: #e5dfd6;
  --rule-hard: #d5cdbf;
  --rule-invert: #2a3038;

  /* --- Measured teal ---------------------------------------------------- */
  --beacon: #0d6e6e;
  --beacon-lo: #0a5757;
  --beacon-focus: #12908c;
  --beacon-hi: #4fb3ae;      /* on the ink band only */
  --beacon-wash: #e8f1ef;

  --flag: #a8412f;
  --flag-wash: #f8ede8;      /* warmed to sit on the bone ground */

  /* --- Type ------------------------------------------------------------- */
  --display: "DM Sans", "Archivo", -apple-system, BlinkMacSystemFont,
    system-ui, "Segoe UI", Roboto, sans-serif;
  --ui: "Inter", -apple-system, BlinkMacSystemFont, system-ui, "Segoe UI",
    Roboto, sans-serif;
  --body: "Inter", -apple-system, BlinkMacSystemFont, system-ui, "Segoe UI",
    Roboto, sans-serif;

  /* --- Motion ----------------------------------------------------------- */
  /* One easing curve for the whole site. Fast out of the gate, long settle. */
  --ease-expressive: cubic-bezier(0.22, 0.68, 0.24, 1);

  /* --- Elevation -------------------------------------------------------- */
  /* Resting lift for cards, and the deep one for a figure presented as a
     product render. Both are warm-tinted rather than neutral black. */
  --lift: 0 1px 2px rgba(17, 20, 24, 0.04),
    0 12px 32px -20px rgba(17, 20, 24, 0.22);
  --lift-high: 0 1px 2px rgba(17, 20, 24, 0.06),
    0 24px 60px -28px rgba(17, 20, 24, 0.35);
  --product-shadow: 0 24px 60px -28px rgba(17, 20, 24, 0.45);
}

/* --- Rhythm -------------------------------------------------------------- */
/* The reference runs ~91px of section padding at desktop. That extra air is
   most of what separates it from a dense agency page. */
.band { padding-block: clamp(64px, 4vw + 40px, 96px); }
.band--tight { padding-block: clamp(44px, 3vw + 26px, 64px); }
.band--panel { background: var(--chart-2); }

/* Alternating bands are divided by their colour change. Where two bands of
   the same colour meet, a hairline does the work instead. */
.band + .band { border-top: 1px solid var(--rule); }
.band--panel + .band--panel,
.band--dark + .band--dark,
.band--dark,
.band--dark + .band,
.band--panel + .band,
.band + .band--panel { border-top: 0; }

.wrap { width: min(100% - 48px, 1120px); }
.hero .wrap,
.band--wide .wrap { width: min(100% - 48px, 1280px); }

/* --- Type ---------------------------------------------------------------- */
body {
  font-family: var(--body);
  color: var(--ink);
  background: var(--chart);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* DM Sans carries its weight optically. The reference sets display type at
   500, not 600, and buys the presence back with tighter tracking. */
h1, h2, h3, h4 { font-family: var(--display); font-weight: 500; }
h1 { letter-spacing: -0.032em; line-height: 1.04; }
h2 { letter-spacing: -0.026em; line-height: 1.1; }
h3 { font-weight: 600; letter-spacing: -0.011em; line-height: 1.3; }
h4 { font-weight: 600; letter-spacing: -0.011em; }
p, li { letter-spacing: -0.006em; }

.lede {
  font-family: var(--body);
  font-weight: 400;
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.185rem);
  line-height: 1.55;
  letter-spacing: -0.006em;
  color: var(--ink-faint);
}
.band--dark .lede, .hero .lede { color: var(--ink-invert-soft); }

/* Eyebrow labels, restored. apple-skin.css quietened these into sentence-case
   captions because Apple has no eyebrow grammar. The reference does, and it is
   load-bearing: every section opens label / heading / one-line lead. */
.eyebrow {
  font-family: var(--ui);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.085em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.eyebrow--invert { color: var(--ink-invert-soft); }

/* --- Buttons ------------------------------------------------------------- */
/* The reference's pill reads as a raised piece of glass: a tight contact
   shadow, a coloured glow beneath it, and two inset strokes for the bevel.
   Rebuilt here on a filled teal so the label keeps 6.1:1 rather than the
   reference's dark-on-light copper. */
.btn {
  font-family: var(--ui);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.006em;
  padding: 12px 24px;
  min-height: 46px;
  border-radius: 9999px;
  transition: background-color 0.2s var(--ease-expressive),
    color 0.2s var(--ease-expressive),
    border-color 0.2s var(--ease-expressive),
    box-shadow 0.25s var(--ease-expressive),
    transform 0.12s var(--ease-expressive);
}
.btn--primary {
  background: var(--beacon);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 1px 2px rgba(17, 20, 24, 0.08),
    0 10px 24px -10px rgba(13, 110, 110, 0.55),
    inset 0 -1px 1px rgba(6, 52, 52, 0.32),
    inset 0 1px 1px rgba(255, 255, 255, 0.22);
}
.btn--primary:hover {
  background: var(--beacon-focus);
  color: #fff;
  box-shadow: 0 1px 2px rgba(17, 20, 24, 0.08),
    0 14px 30px -10px rgba(13, 110, 110, 0.62),
    inset 0 -1px 1px rgba(6, 52, 52, 0.32),
    inset 0 1px 1px rgba(255, 255, 255, 0.22);
}
.btn--ghost {
  border-color: var(--rule-hard);
  color: var(--ink);
  background: var(--chart-raised);
  box-shadow: 0 1px 2px rgba(17, 20, 24, 0.04);
}
.btn--ghost:hover {
  border-color: var(--beacon);
  color: var(--beacon-lo);
  background: var(--chart-raised);
}
.band--dark .btn--ghost,
.hero .btn--ghost {
  border-color: rgba(252, 251, 249, 0.4);
  color: var(--ink-invert);
  background: rgba(252, 251, 249, 0.06);
  box-shadow: none;
}
.band--dark .btn--ghost:hover,
.hero .btn--ghost:hover {
  background: rgba(252, 251, 249, 0.14);
  border-color: var(--ink-invert);
  color: var(--ink-invert);
}
.btn:active { transform: scale(0.97); }
.btn:focus-visible { outline: 2px solid var(--beacon-focus); outline-offset: 3px; }

/* --- Cards and callouts --------------------------------------------------- */
/* White on bone, lifted. On the old cool-white ground a card could only be
   drawn with a border; on bone it can be drawn with elevation instead. */
.card {
  background: var(--chart-raised);
  border: 1px solid var(--rule);
  border-radius: 20px;
  padding: 26px;
  box-shadow: var(--lift);
}
.band--panel .card { background: var(--chart-raised); }
.band--dark .card {
  background: rgba(252, 251, 249, 0.04);
  border-color: var(--rule-invert);
  box-shadow: none;
}
.card--link {
  transition: border-color 0.2s var(--ease-expressive),
    box-shadow 0.25s var(--ease-expressive),
    transform 0.2s var(--ease-expressive);
}
.card--link:hover {
  border-color: var(--beacon);
  box-shadow: var(--lift-high);
  transform: translateY(-2px);
}
.card--link:active { transform: translateY(0) scale(0.99); }
.card__go { color: var(--beacon); font-size: 0.875rem; font-weight: 500; }

.answer, .note, .roi, .booking, .todo, .sources {
  border-radius: 20px;
  border: 1px solid var(--rule);
  background: var(--chart-raised);
}
.band--dark .answer,
.band--dark .note {
  background: rgba(252, 251, 249, 0.04);
  border-color: var(--rule-invert);
}
.answer__label, .note-head {
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.085em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.note--flag { border-color: var(--flag); background: var(--flag-wash); }

/* --- Stats ---------------------------------------------------------------- */
.stat__n {
  font-family: var(--display);
  font-weight: 500;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--beacon);
}
.band--dark .stat__n { color: var(--beacon-hi); }

/* --- FAQ ------------------------------------------------------------------ */
.faq details { border-bottom: 1px solid var(--rule); border-top: 0; }
.faq summary {
  font-family: var(--ui);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.011em;
  padding: 19px 0;
}

/* --- Forms ---------------------------------------------------------------- */
.field input,
.field textarea,
.field select,
input[type="text"], input[type="email"], input[type="tel"],
input[type="number"], input[type="search"] {
  font-family: var(--ui);
  background: var(--chart-raised);
  border-color: var(--rule);
}
.field label { font-family: var(--ui); }

/* --- Chrome --------------------------------------------------------------- */
/* The slim bar goes to ink rather than pure black, so it belongs to the same
   material as the dark sections instead of reading as a browser chrome strip. */
.site-header { background: var(--ink); }
.brand { font-family: var(--display); font-weight: 600; letter-spacing: -0.02em; }
.site-nav a,
.site-nav__trigger,
.site-header__call { font-family: var(--ui); color: rgba(252, 251, 249, 0.82); }
.site-nav a:hover,
.site-nav a[aria-current="page"],
.site-nav__item:hover .site-nav__trigger,
.site-header__call:hover { color: var(--ink-invert); }

/* Frosted sub-nav, warmed. The reference tints its sticky bar toward the page
   ground so the blur reads as the page itself out of focus, not as glass. */
.subnav {
  background: rgba(252, 251, 249, 0.82);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--rule);
}
.subnav__title {
  font-family: var(--display);
  font-weight: 600;
  letter-spacing: -0.02em;
}
.subnav__cta { font-size: 0.875rem; padding: 9px 18px; min-height: 38px; }
.navtoggle { font-family: var(--ui); border-radius: 9999px; }

@media (prefers-reduced-transparency: reduce) {
  .subnav { background: var(--chart); backdrop-filter: none; -webkit-backdrop-filter: none; }
}

/* Dark, textured, bookending the header — the site's last impression should
   read the same premium-data-grid register as its first one, not fall back
   to a plain parchment strip. */
.site-footer {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background:
    radial-gradient(circle at 12% 18%, rgba(79,179,174,.07), transparent 42%),
    radial-gradient(circle at 88% 78%, rgba(196,87,58,.05), transparent 46%),
    repeating-linear-gradient(0deg, rgba(255,255,255,.025) 0 1px, transparent 1px 48px),
    repeating-linear-gradient(90deg, rgba(255,255,255,.025) 0 1px, transparent 1px 48px),
    var(--basemap);
  color: var(--ink-invert-soft);
  padding-block: 72px;
  border-top: 1px solid var(--rule-invert);
}
/* The brand mark, low-opacity and pushed right so it reads as texture behind
   the columns rather than competing with them — a signature watermark, not
   another logo lockup. */
.site-footer__art {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Kept high and right, inside the columns' own empty space, well clear of
     the copyright line sitting at the bottom of the footer. */
  object-position: 82% 22%;
  opacity: .16;
  pointer-events: none;
}
@media (max-width: 700px) {
  .site-footer__art { object-position: 85% 18%; opacity: .13; }
}
/* Extra room below the columns, so the base row reads as its own quiet strip
   at the very bottom rather than sitting inside the watermark's glow. */
.site-footer__base { margin-top: 64px; }
.site-footer__brand {
  display: flex;
  align-items: center;
  gap: .6em;
  margin: 0 0 40px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: -.01em;
  color: var(--ink-invert);
}
.site-footer__brand img {
  height: 30px; width: 30px; border-radius: 6px; flex: none;
  background: #fff; padding: 3px; object-fit: contain;
}
.site-footer .footer-head {
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.085em;
  text-transform: uppercase;
  color: var(--ink-invert);
}
.site-footer a { font-family: var(--ui); color: var(--ink-invert-soft); }
.site-footer a:hover { color: var(--ink-invert); }
.site-footer__base { border-top-color: var(--rule-invert); color: var(--ink-invert-soft); }
.site-footer__base a { color: var(--ink-invert-soft); }
.site-footer__base a:hover { color: var(--ink-invert); }

/* --- Scroll reveal -------------------------------------------------------- */
/* Two primitives. `.reveal` carries one element in; `.reveal-stagger` carries
   its own direct children in on a ladder, so a grid does not need a class on
   every cell.

   Both start 14px low and transparent and get `.is-in` from the Reveal
   component when they cross into view. The hiding rules are gated behind
   `[data-reveal-ready]`, which only that component sets, so without JS
   everything renders at full opacity: content is never hidden by a script
   that might not run. */
[data-reveal-ready] .reveal,
[data-reveal-ready] .reveal-stagger > * {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.38s var(--ease-expressive),
    transform 0.38s var(--ease-expressive);
}
[data-reveal-ready] .reveal.is-in,
[data-reveal-ready] .reveal-stagger.is-in > * {
  opacity: 1;
  transform: none;
}

/* The ladder. Past the fifth child the delay stops growing, because a long
   grid should not take two seconds to finish landing. Compressed to a quick
   ripple rather than a visible one-by-one count — paired with the observer
   firing well ahead of the fold, this settles before it's read, not during. */
.reveal-stagger > *:nth-child(2) { transition-delay: 45ms; }
.reveal-stagger > *:nth-child(3) { transition-delay: 90ms; }
.reveal-stagger > *:nth-child(4) { transition-delay: 135ms; }
.reveal-stagger > *:nth-child(5) { transition-delay: 180ms; }
.reveal-stagger > *:nth-child(n + 6) { transition-delay: 200ms; }

@media (prefers-reduced-motion: reduce) {
  [data-reveal-ready] .reveal,
  [data-reveal-ready] .reveal-stagger > * {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* --- Misc ----------------------------------------------------------------- */
.skip { background: var(--beacon); }
.tablewrap table { border-color: var(--rule); }
.geogrid { border-color: var(--rule-invert); box-shadow: var(--product-shadow); }

@media (max-width: 639px) {
  .wrap,
  .hero .wrap,
  .band--wide .wrap { width: min(100% - 32px, 1280px); }
}

/* --- Photographic bands ---------------------------------------------------
   A dark band with a photograph behind it. The image and scrim sit at
   negative z-index inside the band's own stacking context, so the band's
   background colour still shows through as the fallback if the image fails.

   The scrim is not decoration. It is what makes the type readable across a
   frame whose luminance varies, and it runs along the axis the copy sits on. */
.band--shot { position: relative; isolation: isolate; overflow: hidden; }
.band--shot > .band__shot { position: absolute; inset: 0; z-index: -2; margin: 0; display: block; }
.band--shot > .band__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Hold the subject in frame on the right while the copy sits over the
     empty, near-black left of the plate. */
  object-position: 76% center;
}
.band--shot > .band__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  /* Measured, not eyeballed. The lit instrument screens sit around the 55%
     mark and the copy reaches them; at 0.62 alpha there the lede came out at
     3.32:1 against the brightest pixel under it. These stops hold it above
     4.5:1 across the whole text block. */
  background: linear-gradient(
    100deg,
    rgba(9, 11, 14, 0.97) 0%,
    rgba(9, 11, 14, 0.94) 34%,
    rgba(9, 11, 14, 0.86) 58%,
    rgba(9, 11, 14, 0.42) 100%
  );
}
.band--shot .wrap { position: relative; }
/* Keeping the copy inside the scrim's dark zone is half the contrast fix, and
   a hero line should not run the full width of a 1280px band anyway. */
.band--shot h1 { max-width: 24ch; }
.band--shot .lede { max-width: 52ch; }
.band--shot.band--tight { padding-block: clamp(56px, 4vw + 32px, 88px); }

/* Portrait: the plate has no empty column, so the scrim goes bottom-heavy and
   the copy sits in the darkest part of the frame. */
@media (max-width: 833px) {
  .band--shot > .band__shot img { object-position: 66% center; }
  .band--shot > .band__scrim {
    background: linear-gradient(
      to top,
      rgba(9, 11, 14, 0.97) 0%,
      rgba(9, 11, 14, 0.92) 48%,
      rgba(9, 11, 14, 0.62) 100%
    );
  }
}

/* --- Page banner ----------------------------------------------------------
   For artwork that carries its own wordmark and headline. That art cannot be
   a background for page copy without the two sets of type colliding, so it is
   shown whole, full bleed, and nothing is laid over it. */
.page-banner {
  margin: 0;
  display: block;
  background: var(--chart-2);
  border-bottom: 1px solid var(--rule);
}
.page-banner img { display: block; width: 100%; height: auto; }

/* Card variant, for art that is not banner-shaped. A 4:3 plate run full bleed
   is 944px tall at desktop and pushes the whole page below the fold, and its
   logo sits high enough in the frame that cropping to a letterbox would cut
   it. Constraining the width instead keeps the composition intact and makes it
   read as a plate rather than a stretched header. */
.page-banner--card {
  border-bottom: 1px solid var(--rule);
  padding: clamp(28px, 4vw, 56px) 24px;
}
.page-banner--card img {
  max-width: min(100%, 720px);
  margin-inline: auto;
  border-radius: 20px;
  border: 1px solid var(--rule);
  box-shadow: var(--lift);
}

/* --- Split headlines ------------------------------------------------------
   Every section heading assembles character by character as it scrolls in,
   which is the reference's most pervasive piece of motion: one h1 and ten h2s
   carry it there. The hero is split on the server; the rest are split by the
   Reveal component, so this has to be available on all 29 content pages and
   not only on the homepage.

   Gated behind [data-reveal-ready] like every other reveal, so the characters
   render in place if the script never runs. */
.ap-split-word { display: inline-block; white-space: nowrap; }
.ap-split-ch { display: inline-block; will-change: transform, opacity; }

[data-reveal-ready] .ap-split .ap-split-ch {
  opacity: 0;
  filter: blur(6px);
  transform: translateY(0.14em);
  transition: opacity 0.32s var(--ease-expressive),
    filter 0.32s var(--ease-expressive),
    transform 0.32s var(--ease-expressive);
}
[data-reveal-ready] .ap-split.is-in .ap-split-ch {
  opacity: 1;
  filter: blur(0);
  transform: none;
}
@media (prefers-reduced-motion: reduce) {
  [data-reveal-ready] .ap-split .ap-split-ch {
    opacity: 1;
    filter: none;
    transform: none;
    transition: none;
  }
}

/* The real sentence, kept for assistive technology and crawlers while the
   split copy beside it is aria-hidden. */
.ap-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
  /* Off-screen text is still selectable, so a split heading copied out came
     back doubled: once from this copy and once from the visible characters.
     Excluding it from selection leaves the visible text to be copied. */
  -webkit-user-select: none;
  user-select: none;
}
