
@charset "UTF-8";
/* ===========================================================================
   Surrey Social Media — v9
   ---------------------------------------------------------------------------
   Design system rebuilt against five reference agencies (clay.global,
   monks.com, basicagency.com, akqa.com, deptagency.com).

   Rules taken from that study, and deliberately not broken:
     · Letter-spacing is NEVER positive — including on uppercase labels.
     · No gradients. Colour is flat and declarative.
     · No drop shadows, no rounded "cards", no hover-lift. Separation comes
       from whitespace, rules and background changes.
     · Display type is viewport-derived from a 1440 grid, not arbitrary rem.

   The site is LIGHT-LED. The hero is always light — leading with a dark hero
   is what made an earlier build read as a dark theme. Below the fold, dark
   (ink) bands give depth and mark the conversion moments. Three section
   grounds: paper / warm (light) · ink (dark). Adjacent sections never share
   one, except a dark CTA flowing into the dark footer, which is a deliberate
   grouped close separated by a hairline.

   Magenta is NOT used as a full section background — a saturated section read
   as loud and unprofessional. It lives as ACCENTS instead (the headline accent
   word, section numerals, primary buttons, form highlights) and as exactly one
   bold element: the featured pricing card. That is how a brand colour stays
   present without flooding the page.

   The [data-theme="magenta"] block below is retained for that one card and any
   future small accent panel, but no full-width section uses it.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   01. Tokens
   ------------------------------------------------------------------------ */

:root {
  /* The single lever that makes the whole system fluid on large displays.
     1rem = 10px up to 1920px, then it scales with the viewport. */
  --rem-base: 62.5%;

  /* -- Colour primitives ------------------------------------------------- */
  --ink:        #141414;   /* text, not a background — the site has no dark ground */
  --paper:      #FBFAF8;   /* main canvas */
  --warm:       #F4F1EC;   /* alternate band */
  --grey-200:   #E4E1DA;
  --grey-600:   #6E6B64;
  --grey-700:   #5A5852;

  /* -- Brand colour -------------------------------------------------------
     MAGENTA #e6248f is the primary. TEAL #05a3b2 is secondary. Both are the
     logo colours exactly as supplied, and both are used at full strength
     wherever they are legible.

     The one thing that cannot be wished away: on a light canvas #e6248f
     measures 4.02:1, and as a FILL it tops out at 4.19:1 under white and
     4.40:1 under black. There is no text colour that clears 4.5:1 against
     it. So the rule is:

       #e6248f  — everywhere text is LARGE or absent: display headline
                  accents (>=24px clears the 3:1 large-text bar at 4.02),
                  rules, underlines, borders, marks, the progress bar.
                  This is the colour the eye actually reads as the brand.
       #C41873  — the same hue, one step deeper, used ONLY where small text
                  is involved: 5.40:1 as text on paper, and 5.64:1 as a fill
                  under white text. Buttons and the magenta band use it.

     Teal is more constrained still — 2.88:1 on light means it can NEVER set
     text on a light ground. It works as a fill with INK text (6.04:1), and as
     a decorative mark. --teal-deep exists for the rare case it must be small
     text on light (5.65:1).

     Every figure above is verified by scratchpad/contrast.js, which reads this
     stylesheet rather than a copy. Re-run it after any change. */
  --magenta:      #e6248f;   /* PRIMARY, exactly as supplied */
  --magenta-deep: #C41873;   /* same hue; used when text is involved */
  --magenta-mute: #FCE4F0;   /* muted text on the magenta band, 4.70:1 */
  --teal:         #05a3b2;   /* SECONDARY, exactly as supplied */
  --teal-deep:    #026E78;   /* teal as small text on light, 5.65:1 */

  /* -- Type -------------------------------------------------------------- */
  /* ONE family: Inter. This is what the references do — BASIC/DEPT runs its
     entire site on a single grotesk and lets weight and size do the work.
     Display and body point at the same family deliberately; the two tokens
     exist so the distinction stays expressible, not because the faces differ.

     Inter is delivered as a variable font over 400–700, so every weight in
     that range is real and none can be synthesised. */
  --font-display: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;

  /* Display sizes derived from a 1440 comp: 210/1440, 135/1440, 90/1440. */
  /* Floors matter: bare vw collapsed the page-hero H1 to 20px at 320px —
     the same size as its own lead and SMALLER than prose h2s. The homepage
     hero already clamped; these bring every other display size in line. */
  --fs-mega:    clamp(5.6rem, 14.5833vw, 21rem);
  --fs-display: clamp(4.4rem, 9.375vw, 13.5rem);
  --fs-h1:      clamp(3.4rem, 6.25vw, 9rem);

  --fs-h2:  4.2rem;
  --fs-h3:  2.8rem;
  --fs-h4:  2.2rem;
  --fs-body: 1.8rem;
  --fs-small: 1.5rem;
  --fs-meta: 1.2rem;

  /* Tracking is matched per size, and never positive — the one rule every
     reference stylesheet agreed on. Back to grotesk values: Inter is drawn
     with generous default spacing for small text, so display sizes look loose
     and amateur without real negative tracking. These follow Inter's own
     published tracking guidance. */
  --tr-mega:    -.045em;
  --tr-display: -.042em;
  --tr-h1:      -.038em;
  --tr-h2:      -.032em;
  --tr-h3:      -.026em;
  --tr-body:    -.011em;
  --tr-meta:    -.02em;    /* yes — negative, even on uppercase */

  /* Line-height in percentages, tightening as size grows. */
  --lh-display: 92%;
  --lh-tight:   104%;
  --lh-head:    112%;
  --lh-body:    152%;

  /* -- Space ------------------------------------------------------------- */
  --gutter: 3.2rem;
  --maxw:   150rem;
  --sec-y:  14rem;

  /* -- Motion ------------------------------------------------------------ */
  --ease:        cubic-bezier(.5, 0, 0, 1);
  --ease-soft:   cubic-bezier(.33, 1, .68, 1);
  --ease-hard:   cubic-bezier(.77, 0, .175, 1);
  --t-fast:  .25s;
  --t-mid:   .45s;
  --t-slow:  .9s;

  /* Entrance animations queue behind the menu when it is open. */
  --menu-delay: 0ms;
}

@media (min-width: 1920px) {
  :root { --rem-base: .5vw; }
}

/* Default section theme. Any section can override the pair. */
[data-theme] { background: var(--bg); color: var(--fg); }

/* Four grounds, two of them light. A magenta-tinted "blush" ground existed
   here briefly and was dropped — the client did not want a pink background,
   and a blush that renders like paper would only have collapsed the
   alternation. Rhythm comes from paper/warm plus the dark and brand bands.

   --acc is the colour for LARGE display accents and rules, so it is the true
   #e6248f. --acc-text is for anything small and is the deeper cut. Components
   must pick the right one: getting this wrong is how a 12px label ends up at
   4.02:1. */
[data-theme="paper"] {
  --bg: var(--paper); --fg: var(--ink);
  --muted: var(--grey-700);
  --rule: rgba(20, 20, 20, .12);
  --rule-strong: rgba(20, 20, 20, .26);
  --tint: rgba(20, 20, 20, .035);
  --acc: var(--magenta);
  --acc-text: var(--magenta-deep);
  --icon: var(--teal-deep);
}
[data-theme="warm"] {
  --bg: var(--warm); --fg: var(--ink);
  --muted: var(--grey-700);
  --rule: rgba(20, 20, 20, .14);
  --rule-strong: rgba(20, 20, 20, .28);
  --tint: rgba(20, 20, 20, .045);
  --acc: var(--magenta);
  --acc-text: var(--magenta-deep);
  --icon: var(--teal-deep);
}
/* One or two dark bands per page for depth — the hero is deliberately NOT one
   of them. A page of nothing but light grounds reads flat, but leading with a
   dark hero is what made the previous build feel like a dark theme.

   The dark band is also the only ground where the raw logo teal #05a3b2 is
   legible (5.93:1), so it is where the secondary colour appears undiluted. */
[data-theme="ink"] {
  --bg: #171614; --fg: var(--paper);
  --muted: #9C9A94;
  --rule: rgba(251, 250, 248, .16);
  --rule-strong: rgba(251, 250, 248, .36);
  --tint: rgba(251, 250, 248, .05);
  --acc: var(--magenta);        /* 4.32:1 — large display accents and rules */
  --acc-text: #F45BA8;          /* 5.95:1 — small text needs the lifted cut */
  --icon: var(--teal);          /* the real logo teal, finally at full strength */
}

/* The one saturated block, used ONCE per page on the conversion moment. It is
   #C41873 rather than #e6248f because it has to carry white body text and form
   labels: white on #e6248f is 4.19:1 and fails, white on #C41873 is 5.64:1. */
[data-theme="magenta"] {
  --bg: var(--magenta-deep); --fg: #FFFFFF;
  --muted: var(--magenta-mute);
  --rule: rgba(255, 255, 255, .28);
  --rule-strong: rgba(255, 255, 255, .5);
  --tint: rgba(255, 255, 255, .1);
  --acc: #FFFFFF;
  --acc-text: #FFFFFF;
  --icon: #FFFFFF;
}

/* ---------------------------------------------------------------------------
   02. Reset
   ------------------------------------------------------------------------ */

*, *::before, *::after { box-sizing: border-box; }

html {
  font-size: var(--rem-base);
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
/* Lenis owns scrolling when it is active. This build of Lenis only adds the
   `lenis` class — keying off `lenis-smooth` silently never matches, and the
   CSS smooth-scroll then fights the library frame by frame. */
html.lenis { scroll-behavior: auto !important; }
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  letter-spacing: var(--tr-body);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

h1, h2, h3, h4, h5, p, figure, blockquote, ul, ol, dl { margin: 0; }
ul, ol { padding: 0; list-style: none; }

fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
legend { padding: 0; display: block; width: 100%; }

/* The `hidden` attribute sets display:none at the UA level, which any class
   carrying its own `display` silently outranks — so `<button class="btn"
   hidden>` stays on screen. Every step of the qualifier showed its Back and
   Submit buttons at once because of exactly this. */
[hidden] { display: none !important; }

img, svg, video { display: block; max-width: 100%; }
img, video { height: auto; }

a { color: inherit; text-decoration: none; }

button, input, select, textarea {
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
}
button { background: none; border: 0; padding: 0; cursor: pointer; }

::selection { background: var(--ink); color: var(--paper); }

:focus-visible {
  outline: 2px solid var(--magenta-deep);
  outline-offset: 3px;
  border-radius: 2px;
}

/* The grain overlay. Four lines, and it is most of why flat colour stops
   reading as "template". Rendered as an inline SVG so it costs no request. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: .038;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

.skip {
  position: absolute;
  left: -9999px;
  top: 1rem;
  z-index: 10000;
  background: var(--ink);
  color: var(--paper);
  padding: 1.2rem 2rem;
  font-size: var(--fs-small);
}
.skip:focus { left: 1rem; }

/* ---------------------------------------------------------------------------
   03. Typography
   ------------------------------------------------------------------------ */

/* Display type. Back to a real grotesk weight — a sans needs mass at large
   sizes where a serif did not, and 400 at 90px reads thin and unfinished.
   Clay sets its headlines at 740; 700 is the same intent. */
.mega, .display, h1, h2, h3, h4, .h1, .h2, .h3, .h4 {
  font-family: var(--font-display);
  font-weight: 700;
  text-wrap: balance;
}

/* Let Inter's optical-size axis do what Clay pays for with separate
   "-Headlines" cuts: subtly different drawing for text vs display sizes. */
html { font-optical-sizing: auto; }

.mega {
  font-size: var(--fs-mega);
  line-height: var(--lh-display);
  letter-spacing: var(--tr-mega);
}
.display {
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  letter-spacing: var(--tr-display);
}
h1, .h1 {
  font-size: var(--fs-h1);
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-h1);
}
h2, .h2 {
  font-size: var(--fs-h2);
  line-height: var(--lh-head);
  letter-spacing: var(--tr-h2);
}
h3, .h3 {
  font-size: var(--fs-h3);
  line-height: var(--lh-head);
  letter-spacing: var(--tr-h3);
}
h4, .h4 {
  font-size: var(--fs-h4);
  line-height: var(--lh-head);
  letter-spacing: var(--tr-h3);
  font-weight: 600;
}

/* Display-scale elements that are not h1–h4. Kept as one list so the display
   face can never drift out of sync with the type scale. */
.hero__title,
.row__title,
.process__count,
.package__price,
.package__name,
.platform__name,
.step__q,
.footer__cta-title,
.footer__word,
.index-item__title {
  font-family: var(--font-display);
}

/* Weights and tracking live on the component rules further down, which are the
   single source of truth. An earlier consolidated block here was silently
   overridden by them and left grotesk values in place. */

.lead {
  font-size: 2.4rem;
  line-height: 138%;
  letter-spacing: -.022em;
  color: var(--fg);
}

.meta {
  font-size: var(--fs-meta);
  line-height: 120%;
  letter-spacing: var(--tr-meta);
  text-transform: uppercase;
  font-weight: 500;
  color: var(--muted);
}

.muted { color: var(--muted); }
.acc   { color: var(--acc); }

.measure    { max-width: 62rem; }
.measure-lg { max-width: 78rem; }

/* ---------------------------------------------------------------------------
   04. Layout
   ------------------------------------------------------------------------ */

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

.section { padding-block: var(--sec-y); position: relative; }
.section--tight { padding-block: 9rem; }
.section--flush-top { padding-top: 0; }

.rule { height: 1px; background: var(--rule); border: 0; }

/* Section index head — a number and a name on a hairline. Replaces the
   eyebrow/h2/aside block that every template ships with. */
.sec-index {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: 2rem;
  padding-bottom: 2.4rem;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 6rem;
}
/* The section numeral takes the accent. It is the smallest possible mark, but
   it repeats down every page, so the brand colour is present throughout
   without any single instance being loud — and it flips teal/magenta with the
   section's ground automatically. */
.sec-index__num { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); color: var(--acc-text); font-weight: 700; }
.sec-index__name { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); text-transform: uppercase; font-weight: 500; }
.sec-index__aside { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); color: var(--muted); text-align: right; }
.sec-index__aside a:hover { color: var(--fg); }

/* When a list follows a section index, the index's own bottom rule is the
   list's top rule. Keeping both draws two hairlines separated by an empty
   band, which reads as a rendering fault rather than as spacing. */
.sec-index + .rows,
.sec-index + .index-list,
.sec-index + .platforms,
.sec-index + .packages,
.sec-index + .faq { border-top: 0; }
.sec-index + .plat-index .plat-row:first-child { border-top: 0; }

/* ---------------------------------------------------------------------------
   05. Header
   ------------------------------------------------------------------------ */

.header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 900;
  padding-block: 2.2rem;

  /* The header is not inside a themed section, so it carries its own
     foreground/background pair. That way .btn--solid and friends resolve
     against the header's current state instead of falling through to the
     document default and inverting at the wrong moment. */
  --fg: var(--ink);
  --bg: var(--paper);
  --acc: var(--magenta);
  --acc-text: var(--magenta-deep);
  color: var(--fg);

  transition: transform var(--t-mid) var(--ease),
              background-color var(--t-mid) var(--ease),
              color var(--t-mid) var(--ease),
              backdrop-filter var(--t-mid) var(--ease);
}
/* Hides on scroll down, returns on scroll up. */
.header.is-hidden { transform: translateY(-100%); }
/* Opaque, not translucent. A blurred semi-transparent bar looks good over the
   light grounds but goes muddy grey over the ink and magenta bands, and the
   header then changes colour as you scroll. Solid paper keeps it white over
   everything, which is also one fewer compositing layer. */
.header.is-pinned {
  background: var(--paper);
  border-bottom: 1px solid rgba(20, 20, 20, .1);
}
/* The header NEVER inverts. It used to flip to the colour of whatever band was
   beneath it, which meant it turned magenta mid-scroll and — because inverting
   also flipped --acc-text to white — rendered the white-filled primary button
   with a white label. Invisible.

   It does not need to invert: the hero is always light, so the only unpinned
   state is over a light ground, and once pinned it carries its own opaque
   background. There is no ground it can sit on illegibly. */

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 3rem;
}

/* Two logo files stacked in the same grid cell, cross-faded as the header
   inverts. Both are laid out so the swap causes no reflow. */
.brand {
  display: grid;
  flex: 0 0 auto;
  width: 15.5rem;
}
.brand__logo {
  grid-area: 1 / 1;
  width: 100%;
  height: auto;
  transition: opacity var(--t-mid) var(--ease);
}
/* One logo, always full colour — the header background is always light. */
.brand__logo { opacity: 1; }

.nav { display: flex; align-items: center; gap: 3.2rem; }

.nav__link {
  position: relative;
  font-size: var(--fs-small);
  letter-spacing: -.018em;
  font-weight: 500;
  padding-block: .6rem;
  opacity: .78;
  transition: opacity var(--t-fast) var(--ease-soft);
}
.nav__link:hover, .nav__link:focus-visible { opacity: 1; }
.nav__link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--t-mid) var(--ease);
}
.nav__link:hover::after,
.nav__link[aria-current="page"]::after { transform: scaleX(1); }
.nav__link[aria-current="page"] { opacity: 1; }

/* Platform dropdown */
.nav__group { position: relative; }

/* The dropdown trigger carries a caret so the menu is discoverable before
   anyone hovers. It rotates while the panel is open — same states that open
   the panel itself, so the two can never disagree. */
.nav__link--has-menu { display: inline-flex; align-items: center; gap: .5rem; }
.nav__caret { transition: transform var(--t-fast) var(--ease-soft); }
.nav__group:hover .nav__caret,
.nav__group:focus-within .nav__caret { transform: rotate(180deg); }
.nav__panel {
  position: absolute;
  top: calc(100% + 1.4rem);
  left: -2.7rem;   /* panel offset + row padding-left, so the row ICONS (not just the anchor box) sit flush with the 'Services' label text */
  min-width: 26rem;
  background: var(--ink);
  color: var(--paper);
  border: 1px solid rgba(246, 245, 242, .14);
  padding: 1.2rem;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity var(--t-fast) var(--ease-soft),
              transform var(--t-fast) var(--ease-soft),
              visibility 0s linear var(--t-fast);
}
.nav__group:hover .nav__panel,
.nav__group:focus-within .nav__panel,
.nav__panel.is-open {
  opacity: 1;
  visibility: visible;
  transform: none;
  /* Flip visibility on the OPENING frame. `visibility` is discrete, so a
     transition defers the flip to halfway through — and an element that is
     still hidden refuses focus() silently, with no error to debug. */
  transition: opacity var(--t-fast) var(--ease-soft),
              transform var(--t-fast) var(--ease-soft),
              visibility 0s;
}
.nav__panel a {
  display: flex;
  align-items: center;
  gap: 1.2rem;
  padding: 1rem 1.4rem;
  font-size: var(--fs-small);
  letter-spacing: -.018em;
  color: rgba(246, 245, 242, .74);
  transition: color var(--t-fast) var(--ease-soft), background-color var(--t-fast) var(--ease-soft);
}
.nav__panel a:hover, .nav__panel a:focus-visible {
  color: var(--paper);
  background: rgba(246, 245, 242, .07);
}
.nav__panel svg { opacity: .55; }

.header__cta { display: flex; align-items: center; gap: 2rem; flex: 0 0 auto; }
.header__phone {
  font-size: var(--fs-small);
  letter-spacing: -.018em;
  opacity: .72;
  transition: opacity var(--t-fast) var(--ease-soft);
}
.header__phone:hover { opacity: 1; }

/* Burger */
.burger {
  display: none;
  width: 4.4rem; height: 4.4rem;   /* 44px touch minimum — sole mobile nav control */
  margin: -0.6rem;                 /* keep the visual footprint of the old 32px box */
  position: relative;
  flex: 0 0 auto;
}
.burger span {
  position: absolute;
  left: 1rem; right: 1rem;
  height: 1.5px;
  background: currentColor;
  transition: transform var(--t-mid) var(--ease), opacity var(--t-fast) var(--ease);
}
.burger span:nth-child(1) { top: 1.8rem; }
.burger span:nth-child(2) { top: 2.6rem; }
.burger.is-open span:nth-child(1) { transform: translateY(.4rem) rotate(45deg); }
.burger.is-open span:nth-child(2) { transform: translateY(-.4rem) rotate(-45deg); }

/* Mobile overlay */
.drawer {
  position: fixed;
  inset: 0;
  z-index: 890;
  background: var(--ink);
  color: var(--paper);
  padding: 12rem var(--gutter) 4rem;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-mid) var(--ease),
              visibility 0s linear var(--t-mid);
  overflow-y: auto;
}
.drawer.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--t-mid) var(--ease), visibility 0s;
}
.drawer__list { display: flex; flex-direction: column; }
.drawer__list a {
  display: block;
  padding: 1.6rem 0;
  font-size: 3.6rem;
  font-weight: 500;
  letter-spacing: -.035em;
  border-bottom: 1px solid rgba(246, 245, 242, .13);
}
.drawer__sub {
  display: flex;
  flex-wrap: wrap;
  gap: 1.6rem 2.4rem;
  padding: 2.4rem 0;
}
.drawer__sub a {
  font-size: var(--fs-small);
  letter-spacing: -.018em;
  color: rgba(246, 245, 242, .6);
  padding: 1rem 0;                 /* 27px → 47px touch target */
  border: 0;
}
.drawer__foot { padding-top: 4rem; }
.drawer__foot a { display: block; font-size: 2rem; letter-spacing: -.03em; padding: .9rem 0; }
/* Short phones: the drawer ran 714px tall in a 650px viewport and clipped the
   email link at the fold. Tighten the two biggest gaps instead. */
@media (max-height: 700px) {
  .drawer { padding-top: 10rem; }
  .drawer__foot { padding-top: 1.6rem; }
}
/* The drawer carries the theme pair itself so .btn--solid resolves inside it. */
.drawer { --fg: var(--paper); --bg: #171614; --acc: #FFFFFF; --acc-text: #FFFFFF; }
/* While the drawer is open the header sits over the ink drawer. Unpinned it
   is transparent, which rendered the close X ink-on-ink — invisible. Force
   the pinned-paper look for the whole open state. */
body.is-locked .header {
  background: var(--paper);
  border-bottom: 1px solid rgba(20, 20, 20, .1);
}
.drawer__foot .btn { display: inline-flex; font-size: 1.5rem; padding: 1.5rem 2.4rem; }

/* ---------------------------------------------------------------------------
   06. Buttons
   ------------------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 1.2rem;
  padding: 1.5rem 2.4rem;
  font-size: var(--fs-small);
  font-weight: 500;
  letter-spacing: -.018em;
  border: 1px solid currentColor;
  background: none;
  color: inherit;
  cursor: pointer;
  transition: background-color var(--t-mid) var(--ease),
              color var(--t-mid) var(--ease),
              border-color var(--t-mid) var(--ease);
}
.btn svg { transition: transform var(--t-mid) var(--ease); }
.btn:hover svg { transform: translateX(4px); }

.btn--solid {
  background: var(--fg);
  color: var(--bg);
  border-color: var(--fg);
}
.btn--solid:hover { background: transparent; color: var(--fg); }

.btn--ghost:hover { background: var(--fg); color: var(--bg); }

/* The primary action button. Magenta is the brand's primary colour, so the
   primary action is magenta — a black button would leave the primary colour
   doing nothing but decorating headlines.
   Filled with --acc-text (#C41873), not #e6248f: a 15px white label needs
   4.5:1 and white on #e6248f is only 4.19:1. */
/* Always filled with --magenta-deep, never --acc-text. On the ink ground
   --acc-text is the LIGHTENED pink (#F45BA8) meant for small text — as a button
   fill under white it drops to ~2.4:1 and the label vanishes. #C41873 carries
   white at 5.64:1 on every ground, and reads as a solid magenta button against
   both light and dark. */
.btn--accent {
  background: var(--magenta-deep);
  border-color: var(--magenta-deep);
  color: #FFFFFF;
}
.btn--accent:hover { background: transparent; color: var(--acc-text); border-color: currentColor; }

/* On the magenta band and the featured card the fill would vanish into the
   ground, so it flips to a white button with a magenta label. */
[data-theme="magenta"] .btn--accent,
.package--featured .btn--accent { color: var(--magenta-deep); background: #FFFFFF; border-color: #FFFFFF; }
[data-theme="magenta"] .btn--accent:hover,
.package--featured .btn--accent:hover { background: transparent; color: #FFFFFF; border-color: #FFFFFF; }

.btn--sm { padding: 1.1rem 1.8rem; font-size: 1.4rem; }

.btn[disabled] { opacity: .4; cursor: not-allowed; }
.btn[disabled]:hover { background: var(--fg); color: var(--bg); }

/* A text link with a rule that wipes on hover. */
.link {
  display: inline-flex;
  align-items: center;
  gap: .8rem;
  position: relative;
  font-weight: 500;
  padding-bottom: .3rem;
}
.link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: currentColor;
  transform-origin: 100% 50%;
  transition: transform var(--t-mid) var(--ease);
}
.link:hover::after { transform: scaleX(0); }
.link svg { transition: transform var(--t-mid) var(--ease); }
.link:hover svg { transform: translate(3px, -3px); }

/* ---------------------------------------------------------------------------
   07. Hero
   ------------------------------------------------------------------------ */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding-top: 15rem;
  overflow: hidden;
}
.hero__inner { position: relative; z-index: 2; padding-bottom: 5rem; }

.hero__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 3.2rem;
  padding-bottom: 3.2rem;
  margin-bottom: 3.6rem;
  border-bottom: 1px solid var(--rule);
}
.hero__meta span { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); text-transform: uppercase; color: var(--muted); font-weight: 500; }

.hero__title {
  font-size: clamp(3.6rem, 6vw, 9.6rem);
  font-weight: 700;
  line-height: 100%;
  letter-spacing: var(--tr-h1);
  max-width: 20ch;
}

/* The accent word, with an underline that draws itself in just after the
   headline's line-mask reveal has finished. Positioned above the descender
   zone so the line's overflow-clip doesn't shear it. */
.hero__title .acc { color: var(--acc); position: relative; white-space: nowrap; }
.hero__title .acc::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  bottom: .04em;
  height: .085em;
  background: var(--acc);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform .75s var(--ease) .9s;
}
.hero__title.is-in .acc::after { transform: scaleX(1); }

/* Two-column hero: headline + supporting column left, quick-start card right,
   card top-aligned with the headline's first line. The previous full-width h1
   left a dead upper-right quadrant at desktop. */
.hero__layout {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: 4rem 6rem;
  align-items: start;
}
.hero__layout .hero__title { grid-column: 1; font-size: clamp(3.4rem, 4.9vw, 7.6rem); }
.hero__layout .hero__card { grid-column: 2; grid-row: 1 / span 2; align-self: start; }
.hero__rest {
  grid-column: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3rem;
  margin-top: 1.6rem;
}
.hero__sub { max-width: 46rem; font-size: 1.8rem; line-height: 156%; color: var(--muted); text-wrap: pretty; }
.hero__actions { display: flex; gap: 1.2rem; flex-wrap: wrap; }

.hero__trust { display: flex; flex-wrap: wrap; gap: .9rem 2.4rem; }
.hero__trust li { display: flex; align-items: center; gap: .8rem; font-size: 1.45rem; letter-spacing: -.01em; color: var(--muted); }
.hero__trust svg { color: var(--acc-text); flex: 0 0 auto; }

/* The lead card — a touch lighter than the warm ground, no shadow, no radius,
   in keeping with the rest of the site's flat panels. */
.hero__card {
  background: var(--paper);
  border: 1px solid var(--rule-strong);
  padding: 2.8rem;
  display: flex;
  flex-direction: column;
  gap: 1.8rem;
}
.hero__card-top { display: flex; align-items: center; justify-content: space-between; }
.hero__card-q { font-size: 2rem; font-weight: 600; letter-spacing: -.024em; line-height: 120%; }
.hero__chips { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .8rem; }
.hero__chip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.3rem 1.4rem;
  border: 1px solid var(--rule);
  font-size: 1.45rem;
  font-weight: 500;
  letter-spacing: -.014em;
  line-height: 1.2;
  transition: border-color var(--t-mid) var(--ease), background-color var(--t-mid) var(--ease);
}
.hero__chip svg { color: var(--acc-text); opacity: .55; flex: 0 0 auto; transition: transform var(--t-mid) var(--ease), opacity var(--t-mid) var(--ease); }
.hero__chip:hover { border-color: var(--fg); background: var(--tint); }
.hero__chip:hover svg { transform: translateX(3px); opacity: 1; }
.hero__card-note { font-size: 1.3rem; color: var(--muted); }


/* ---------------------------------------------------------------------------
   08. Line-mask reveal
   ------------------------------------------------------------------------ */

/* The negative-margin / positive-padding pair is the part that is usually
   missed: without it the clip box shears the descenders off g, y and p. */
.lines .line {
  display: block;
  overflow-y: clip;
  margin-top: -.1em;    padding-top: .1em;
  margin-bottom: -.2em; padding-bottom: .1em;
}
.lines .line > span {
  display: block;
  transform: translateY(105%);
  transition: transform var(--t-slow) var(--ease);
  transition-delay: calc(var(--i, 0) * 70ms + var(--menu-delay));
}
.lines.is-in .line > span { transform: none; }

/* Generic scroll reveal */
.rise {
  opacity: 0;
  transform: translateY(2.4rem);
  transition: opacity var(--t-slow) var(--ease-soft),
              transform var(--t-slow) var(--ease-soft);
  transition-delay: calc(var(--i, 0) * 60ms + var(--menu-delay));
}
.rise.is-in { opacity: 1; transform: none; }

/* ---------------------------------------------------------------------------
   09. Marquee — client names, not invented logos
   ------------------------------------------------------------------------ */

.marquee {
  overflow: hidden;
  border-block: 1px solid var(--rule);
  padding-block: 2.6rem;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.marquee__track {
  display: flex;
  width: max-content;
  gap: 5.6rem;
  animation: slide 48s linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__item {
  font-size: 1.6rem;
  font-weight: 500;
  letter-spacing: -.025em;
  color: var(--muted);
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 5.6rem;
}
.marquee__item::after {
  content: "";
  width: .5rem; height: .5rem;
  background: var(--rule-strong);
  border-radius: 50%;
}
@keyframes slide { to { transform: translateX(-50%); } }

/* ---------------------------------------------------------------------------
   09b. Imagery — editorial frames and the full-bleed statement band
   ------------------------------------------------------------------------ */

/* An editorial image block. The image starts slightly oversized and settles
   as the frame reveals (via the shared .rise/.is-in observer), which reads as
   a considered entrance rather than a pop-in. Flat corners, no shadow — the
   same panel language as the rest of the site. */
.frame {
  overflow: hidden;
  position: relative;
}
.frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transform: scale(1.08);
  transition: transform 1.2s var(--ease);
}
.frame.is-in img { transform: scale(1); }
.frame--43 { aspect-ratio: 4 / 3; }
.frame--32 { aspect-ratio: 3 / 2; }
.frame--tall { aspect-ratio: 4 / 5; }

/* Full-bleed image band with a flat ink scrim (uniform opacity — not a
   gradient) and display type. The one image-led statement moment per page. */
.img-band {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  min-height: 56vh;
  padding-block: 8rem;
  color: var(--paper);
}
.img-band__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.img-band::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(18, 17, 16, .5);
}
.img-band .wrap { position: relative; z-index: 2; }
.img-band__title {
  font-size: clamp(3.2rem, 5.2vw, 7.6rem);
  font-weight: 700;
  letter-spacing: var(--tr-h1);
  line-height: 102%;
  max-width: 16ch;
}
.img-band__row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 4rem;
  flex-wrap: wrap;
}

/* The statement marquee — oversized outlined service words drifting across a
   thin band. Pure type, no claims, and the same outline treatment as the
   footer wordmark so the two read as one voice. */
.statement { overflow: hidden; padding-block: 5rem; }
.statement .marquee__track { gap: 6.4rem; animation-duration: 36s; }
.statement__word {
  font-size: clamp(5.6rem, 8vw, 11rem);
  font-weight: 700;
  letter-spacing: -.03em;
  line-height: 1;
  white-space: nowrap;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--rule-strong);
  display: flex;
  align-items: center;
  gap: 6.4rem;
}
.statement__word::after {
  content: "";
  width: 1rem; height: 1rem;
  border-radius: 50%;
  background: var(--acc);
  -webkit-text-stroke: 0;
}
.statement:hover .marquee__track { animation-play-state: paused; }

/* ---------------------------------------------------------------------------
   10. Rows — services as full-width numbered rows
   ------------------------------------------------------------------------ */

.rows { border-top: 1px solid var(--rule); }

.row {
  display: grid;
  grid-template-columns: 8rem minmax(0, 1fr) minmax(0, 1fr) 5rem;
  align-items: start;
  gap: 3.2rem;
  padding-block: 4.8rem;
  border-bottom: 1px solid var(--rule);
  position: relative;
  transition: padding var(--t-mid) var(--ease);
}
.row::before {
  content: "";
  position: absolute;
  inset: 0 calc(var(--gutter) * -.5);
  background: var(--tint);
  opacity: 0;
  transition: opacity var(--t-mid) var(--ease);
  pointer-events: none;
}
.row:hover::before { opacity: 1; }

.row__num  { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); color: var(--muted); font-weight: 500; padding-top: .9rem; }
.row__title { font-size: clamp(2.6rem, 3vw, 4rem); font-weight: 600; letter-spacing: -.032em; line-height: 108%; }
.row__body  { color: var(--muted); font-size: 1.7rem; line-height: 156%; }
.row__list  { display: flex; flex-wrap: wrap; gap: .8rem 1.6rem; margin-top: 1.8rem; max-width: 40rem; /* forces a deliberate 2+2 chip wrap instead of ragged 3+1 */ }
.row__list li {
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-meta);
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--rule);
  padding: .6rem 1.1rem;
}
.row__go {
  justify-self: end;
  padding-top: .8rem;
  color: var(--muted);
  transition: color var(--t-mid) var(--ease), transform var(--t-mid) var(--ease);
}
.row:hover .row__go { color: var(--fg); transform: translate(4px, -4px); }

/* Closing note under a rows list. Mirrors the row grid so the text starts on
   the rows' body column instead of floating as an orphaned paragraph. */
.rows-outro {
  display: grid;
  grid-template-columns: 8rem minmax(0, 1fr) minmax(0, 1fr) 5rem;
  gap: 3.2rem;
  padding-top: 3.2rem;
}
.rows-outro p { grid-column: 3; font-size: 1.7rem; line-height: 160%; }
@media (max-width: 860px) {
  .rows-outro { grid-template-columns: 5rem minmax(0, 1fr); gap: 2.4rem; }
  .rows-outro p { grid-column: 2; }
}
@media (max-width: 480px) {
  .rows-outro { grid-template-columns: minmax(0, 1fr); }
  .rows-outro p { grid-column: auto; }
}

/* ---------------------------------------------------------------------------
   11. Index list — insights as an editorial index
   ------------------------------------------------------------------------ */

.index-list { border-top: 1px solid var(--rule); }

.index-item { position: relative; border-bottom: 1px solid var(--rule); }
.index-item__link {
  display: grid;
  grid-template-columns: 11rem minmax(0, 1fr) 14rem 3rem;
  align-items: center;
  gap: 2.4rem;
  padding-block: 2.8rem;
}
.index-item__date { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); text-transform: uppercase; color: var(--muted); }
.index-item__title {
  font-size: clamp(2rem, 2.1vw, 2.7rem);
  font-weight: 500;
  letter-spacing: -.026em;
  line-height: 124%;
  transition: transform var(--t-mid) var(--ease);
}
.index-item__cat { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); text-transform: uppercase; color: var(--muted); text-align: right; }
.index-item__go { justify-self: end; color: var(--muted); transition: transform var(--t-mid) var(--ease), color var(--t-mid) var(--ease); }

.index-item:hover .index-item__title { transform: translateX(1.2rem); }
.index-item:hover .index-item__go { color: var(--fg); transform: translate(3px, -3px); }

/* Homepage variant: category leads the row, the (2023) dates demote to a
   muted trailing slot — recency is not this list's selling point. */
.index-list--home .index-item__link { grid-template-columns: 11rem minmax(0, 1fr) 9rem 3rem; }
.index-list--home .index-item__date { text-align: right; }
.index-list--home .index-item__cat { text-align: left; }

/* Thumbnail revealed on hover, tracking the cursor. */
.index-item__thumb {
  position: absolute;
  top: 50%;
  left: 42%;
  width: 22rem;
  aspect-ratio: 4 / 3;
  transform: translate(-50%, -50%) scale(.9);
  opacity: 0;
  pointer-events: none;
  z-index: 3;
  overflow: hidden;
  transition: opacity var(--t-mid) var(--ease), transform var(--t-mid) var(--ease);
}
.index-item__thumb img { width: 100%; height: 100%; object-fit: cover; }
.index-item:hover .index-item__thumb { opacity: 1; transform: translate(-50%, -50%) scale(1); }

/* ---------------------------------------------------------------------------
   12. Split — generic two-column editorial block
   ------------------------------------------------------------------------ */

.split {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 6rem 8rem;
  align-items: start;
}
.split--even { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.split__aside { position: sticky; top: 12rem; }

.stack { display: flex; flex-direction: column; gap: 2.4rem; }
.stack--lg { gap: 4rem; }

/* Scroll-scrubbed word-fill statement. JS wraps each word in .wf and turns
   them on with scroll progress; <em> words resolve to the accent. Without JS
   or with reduced motion the text simply renders fully inked. */
.think-statement {
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 4vw, 5.6rem);
  font-weight: 700;
  letter-spacing: var(--tr-h2);
  line-height: 118%;
  max-width: 24ch;
  text-wrap: pretty;
}
.think-statement em { font-style: normal; }
.think-statement .wf { color: rgba(20, 20, 20, .16); transition: color .3s var(--ease-soft); }
.think-statement .wf.is-on { color: var(--ink); }
.think-statement em .wf.is-on { color: var(--magenta-deep); }
.no-js .think-statement .wf { color: var(--ink); }
.no-js .think-statement em { color: var(--magenta-deep); }
@media (prefers-reduced-motion: reduce) {
  .think-statement .wf { color: var(--ink); }
  .think-statement em { color: var(--magenta-deep); }
}

/* ---------------------------------------------------------------------------
   13. Process — sticky numbered steps
   ------------------------------------------------------------------------ */

.process { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: 8rem; }
.process__rail { position: sticky; top: 14rem; align-self: start; }
.process__count {
  font-size: clamp(8rem, 12vw, 18rem);
  line-height: .84;
  font-weight: 700;
  letter-spacing: -.055em;
}
.process__count sup { font-size: .28em; vertical-align: super; color: var(--muted); letter-spacing: -.02em; }

.process__step {
  display: grid;
  grid-template-columns: 8rem minmax(0, 1fr);
  gap: 3.2rem;
  padding-block: 4rem;
  border-top: 1px solid var(--rule);
}
.process__step:last-child { border-bottom: 1px solid var(--rule); }
.process__step-num { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); color: var(--muted); font-weight: 500; }
.process__step h3 { margin-bottom: 1.2rem; }
.process__step p { color: var(--muted); font-size: 1.7rem; line-height: 156%; }

/* ---------------------------------------------------------------------------
   14. Packages
   ------------------------------------------------------------------------ */

.packages { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); border-top: 1px solid var(--rule); }

.package {
  display: flex;
  flex-direction: column;
  padding: 4rem 2.8rem;
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  transition: background-color var(--t-mid) var(--ease);
}
.package:first-child { border-left: 1px solid var(--rule); }
.package:hover { background: var(--tint); }
/* The featured tier carries the brand magenta. Putting the primary colour at
   the pricing decision is the one place where brand and conversion do the same
   job — and on an otherwise light page it is what the eye lands on first.
   #C41873 rather than #e6248f because it carries white body text and a 15px
   feature list: white on #e6248f is 4.19:1 and fails, on #C41873 it is 5.64:1. */
.package--featured {
  background: var(--magenta-deep);
  color: #FFFFFF;
  border-color: rgba(255, 255, 255, .28);
  --acc: #FFFFFF;
  --acc-text: #FFFFFF;
  --rule: rgba(255, 255, 255, .28);
}
.package--featured:hover { background: #B31468; }
.package--featured .package__lead,
.package--featured .package__period,
.package--featured .package__items li { color: var(--magenta-mute); }
.package--featured .package__lead { border-color: rgba(255, 255, 255, .28); }

.package__flag {
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-meta);
  text-transform: uppercase;
  color: var(--acc);
  margin-bottom: 1.6rem;
  min-height: 1.4rem;
}
.package--featured .package__flag { color: #FFFFFF; }
.package__name { font-size: 2rem; font-weight: 600; letter-spacing: -.026em; }
/* Tabular figures so the four price tiers align column to column. Inter is
   lining by default, so no lnum override is needed — that was a Zodiak fix. */
.package__price {
  font-size: 4.4rem;
  font-weight: 700;
  letter-spacing: -.042em;
  line-height: 1.08;
  margin-top: 1.6rem;
  font-variant-numeric: tabular-nums;
}
.package__price sup { font-size: .42em; vertical-align: super; }
.package__period { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); text-transform: uppercase; color: var(--muted); margin-top: .4rem; }
.package__lead { color: var(--muted); font-size: 1.5rem; line-height: 152%; margin-top: 2rem; padding-bottom: 2.4rem; border-bottom: 1px solid var(--rule); }
.package--featured .package__lead { border-color: rgba(246, 245, 242, .16); }
.package__items { display: flex; flex-direction: column; gap: 1.1rem; margin-top: 2.4rem; flex: 1; }
.package__items li { display: flex; gap: 1rem; font-size: 1.5rem; line-height: 142%; color: var(--muted); }
.package__items svg { flex: 0 0 auto; margin-top: .3rem; color: var(--icon); }
.package--featured .package__items svg { color: #FFFFFF; }
.package .btn { margin-top: 3.2rem; justify-content: center; }

.package-custom {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 4rem;
  align-items: center;
  padding: 5rem 2.8rem;
  border: 1px solid var(--rule);
  border-top: 0;
}

/* ---------------------------------------------------------------------------
   15. Platform tiles
   ------------------------------------------------------------------------ */

.platforms { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid var(--rule); }
.platform {
  display: flex;
  flex-direction: column;
  gap: 1.4rem;
  padding: 3.6rem 2.8rem;
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  transition: background-color var(--t-mid) var(--ease);
}
.platform:nth-child(3n) { border-right: 0; }

/* Odd-count grids (the platform pages list 5 "other" platforms): span the
   last tile so the grid closes cleanly instead of leaving an empty cell with
   a hairline stopping mid-width. */
.platforms--odd .platform:last-child { grid-column: span 2; border-right: 0; }
.platform:hover { background: var(--tint); }

/* Head row: icon + name + arrow on ONE line. The old anatomy floated the icon
   alone with the arrow far right, then a gap, then the name — three sparse
   rows that read disjointed and cost ~60px per tile. Inline head ties the
   icon to the name it identifies and makes the grid scan like a list. */
.platform__head { display: flex; align-items: center; gap: 1.2rem; min-width: 0; }
.platform__name {
  font-size: 2rem;
  font-weight: 600;
  letter-spacing: -.026em;
  min-width: 0;                    /* long names ellipsis-safe inside flex */
}
.platform p { font-size: 1.5rem; line-height: 152%; color: var(--muted); }

/* Teal owns ICONOGRAPHY, magenta owns type accents and actions. That split is
   what gives the secondary colour a real job instead of leaving it stranded in
   the logo. The channel icon only — the arrow is a UI affordance and answers
   the hover in magenta like every other action cue.
   --teal-deep, not --teal: #05a3b2 is 2.88:1 on light and misses even the 3:1
   non-text bar, so the raw logo teal cannot mark anything on a light ground. */
.platform__head > svg { color: var(--icon); flex: 0 0 auto; }
.platform__go {
  margin-left: auto;
  color: var(--muted);
  flex: 0 0 auto;
  transition: color var(--t-mid) var(--ease), transform var(--t-mid) var(--ease);
}
.platform:hover .platform__go { color: var(--acc-text); transform: translate(3px, -3px); }

/* ---------------------------------------------------------------------------
   15b. Platform index — monumental type rows (homepage)
   ------------------------------------------------------------------------ */

.plat-index { border-bottom: 1px solid var(--rule); }

.plat-row {
  display: flex;
  align-items: center;
  gap: 2.4rem;
  padding-block: 2.4rem;
  border-top: 1px solid var(--rule);
  min-width: 0;
}
.plat-row__num {
  flex: 0 0 auto;
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-meta);
  font-weight: 700;
  color: var(--muted);
  transition: color var(--t-mid) var(--ease);
}
.plat-row__name {
  font-family: var(--font-display);
  font-size: clamp(3.2rem, 6vw, 8.4rem);
  font-weight: 700;
  letter-spacing: var(--tr-h1);
  line-height: 1;
  white-space: nowrap;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color var(--t-mid) var(--ease);
}

/* The image lives INSIDE the text line: a zero-width slot that opens to
   ~1.6em on hover, pushing the arrow along the line. Height is em-based so
   the slot always matches the type size it sits in. */
.plat-row__visual {
  flex: 0 0 auto;
  width: 0;
  height: clamp(3.2rem, 6vw, 8.4rem);
  overflow: hidden;
  position: relative;
  transition: width .5s var(--ease);
}
.plat-row__visual img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.plat-row:hover .plat-row__visual,
.plat-row:focus-visible .plat-row__visual { width: clamp(6rem, 10vw, 14rem); }

.plat-row__go {
  flex: 0 0 auto;
  margin-left: auto;
  color: var(--muted);
  transition: color var(--t-mid) var(--ease), transform var(--t-mid) var(--ease);
}
.plat-row:hover .plat-row__num { color: var(--acc-text); }
.plat-row:hover .plat-row__go { color: var(--acc-text); transform: translate(4px, -4px); }

/* Touch devices get the clean type index; the hover slot never opens. */
@media (hover: none) {
  .plat-row:hover .plat-row__visual { width: 0; }
}

/* ---------------------------------------------------------------------------
   15c. Price ladder — the pricing preview shows the real prices
   ------------------------------------------------------------------------ */

.price-ladder { border-bottom: 1px solid var(--rule); }

.price-ladder__row {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 2fr) 10rem 3rem;   /* fixed value track: all five rows share column edges */
  align-items: center;
  gap: 2.4rem;
  padding-block: 2rem;
  border-top: 1px solid var(--rule);
}
.price-ladder__name { font-weight: 600; letter-spacing: -.024em; font-size: 1.7rem; display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.price-ladder__flag {
  white-space: nowrap;
  font-size: 1.1rem;
  letter-spacing: var(--tr-meta);
  text-transform: uppercase;
  font-weight: 700;
  color: var(--acc-text);
  border: 1px solid currentColor;
  padding: .3rem .7rem;
}
.price-ladder__lead { font-size: 1.5rem; color: var(--muted); line-height: 140%; text-wrap: pretty; }
.price-ladder__price {
  justify-self: end;
  text-align: right;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 2.4rem;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.price-ladder__price small { font-size: 1.2rem; font-weight: 500; color: var(--muted); letter-spacing: -.01em; }
.price-ladder__row.is-featured .price-ladder__price { color: var(--acc-text); }
.price-ladder__go { justify-self: end; color: var(--muted); transition: color var(--t-mid) var(--ease), transform var(--t-mid) var(--ease); }
.price-ladder__row:hover .price-ladder__go { color: var(--acc-text); transform: translate(3px, -3px); }

@media (max-width: 860px) {
  .price-ladder__row { grid-template-columns: minmax(0, 1fr) auto 3rem; }
  .price-ladder__lead { display: none; }   /* leads live one click away on the packages grid */
}

/* ---------------------------------------------------------------------------
   16. FAQ
   ------------------------------------------------------------------------ */

.faq { border-top: 1px solid var(--rule); }
.faq__item { border-bottom: 1px solid var(--rule); }
.faq__q {
  width: 100%;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2.4rem;
  align-items: center;
  text-align: left;
  padding-block: 2.8rem;
  font-size: clamp(1.8rem, 1.6vw, 2.2rem);
  font-weight: 500;
  letter-spacing: -.028em;
  line-height: 132%;
}
.faq__icon { position: relative; width: 1.6rem; height: 1.6rem; flex: 0 0 auto; }
.faq__icon::before, .faq__icon::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto;
  height: 1px;
  background: currentColor;
  transition: transform var(--t-mid) var(--ease);
}
.faq__icon::after { transform: rotate(90deg); }
.faq__item.is-open .faq__icon::after { transform: rotate(0); }

.faq__a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--t-mid) var(--ease);
}
.faq__item.is-open .faq__a { grid-template-rows: 1fr; }
.faq__a > div { overflow: hidden; }
.faq__a p {
  max-width: 72ch;
  color: var(--muted);
  font-size: 1.7rem;
  line-height: 158%;
  padding-bottom: 3rem;
}

/* ---------------------------------------------------------------------------
   17. Qualifier — the lead engine
   ------------------------------------------------------------------------ */

/* Modelled on the multi-step qualifier the reference sites use instead of a
   contact box: it segments the enquiry before a human reads it, and each
   screen asks for one thing, which is what keeps completion high. */
.qualifier { max-width: 78rem; }

.qualifier__progress {
  display: flex;
  gap: .8rem;
  margin-bottom: 4rem;
}
.qualifier__progress span {
  height: 2px;
  flex: 1;
  background: var(--rule);
  overflow: hidden;
}
.qualifier__progress span::after {
  content: "";
  display: block;
  height: 100%;
  /* Follows the ground like every other accent. Hardcoding --teal here left
     the rail at 2.92:1 once the qualifier moved onto the teal brand band —
     below the 3:1 floor for UI, and effectively invisible. */
  background: var(--acc);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--t-mid) var(--ease);
}
.qualifier__progress span.is-done::after { transform: scaleX(1); }

/* No JS means the scroll-reveal IntersectionObserver never runs, so every
   `.rise` / line-mask target would stay at its hidden start state and the whole
   page would render blank. Force them all visible up front — same end state the
   observer produces, and the same thing the reduced-motion block does. This has
   to come before the form rules below, which also depend on content showing. */
.no-js .rise { opacity: 1 !important; transform: none !important; }
.no-js .lines .line > span { transform: none !important; }

.step { display: none; }
.no-js .step { display: block; }   /* JS off: every step shows as one long form */
.step.is-active { display: block; animation: stepIn var(--t-mid) var(--ease) both; }
@keyframes stepIn {
  from { opacity: 0; transform: translateY(1.2rem); }
  to   { opacity: 1; transform: none; }
}

/* Without JS the qualifier is a single scrollable form: hide the step
   machinery (progress bar, step counter, Continue/Back) and reveal the plain
   Submit — the one control that works with a normal POST. The !important is
   needed only to beat the global `[hidden] { display: none !important }` on
   the Submit button. */
.no-js .qualifier__progress,
.no-js .step__count,
.no-js [data-next],
.no-js [data-prev] { display: none; }
.no-js [data-submit] { display: inline-flex !important; }
.no-js .step + .step { margin-top: 4.8rem; padding-top: 4.8rem; border-top: 1px solid var(--rule); }

.step__q {
  font-size: clamp(2.4rem, 3.2vw, 4rem);
  font-weight: 700;
  letter-spacing: -.034em;
  line-height: 112%;
  margin-bottom: 1.2rem;
}
/* The question is focused on each step change so screen readers announce the
   new screen instead of content silently swapping underneath. That focus is
   programmatic, never keyboard-driven, so the ring would only ever read as a
   rendering fault — the announcement still happens without it. */
.step__q:focus, .step__q:focus-visible { outline: none; }
.step__hint { color: var(--muted); font-size: 1.6rem; margin-bottom: 3.2rem; }

.choices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.2rem; }
.choice { position: relative; }
.choice input { position: absolute; opacity: 0; width: 100%; height: 100%; cursor: pointer; margin: 0; }
.choice__box {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: 2rem;
  border: 1px solid var(--rule);
  transition: border-color var(--t-mid) var(--ease), background-color var(--t-mid) var(--ease);
  cursor: pointer;
  height: 100%;
}
.choice:hover .choice__box { border-color: var(--rule-strong); }
.choice input:checked + .choice__box { border-color: var(--fg); background: var(--tint); }
.choice input:focus-visible + .choice__box { outline: 2px solid var(--acc); outline-offset: 3px; }
.choice__label { font-weight: 500; letter-spacing: -.024em; font-size: 1.7rem; }
.choice__sub { font-size: 1.4rem; color: var(--muted); line-height: 140%; }

.field { display: flex; flex-direction: column; gap: .8rem; margin-bottom: 2rem; }
.field label { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); text-transform: uppercase; color: var(--muted); font-weight: 500; }
.field input, .field textarea, .field select {
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule-strong);
  padding: 1.2rem 0;
  font-size: 1.8rem;
  letter-spacing: -.02em;
  transition: border-color var(--t-mid) var(--ease);
}
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none;
  border-color: var(--acc);
}
.field textarea { resize: vertical; min-height: 10rem; }
/* Placeholders are real text and get read as such. --grey-400 came in at
   2.23:1 on paper, which is below even the 3:1 floor for non-essential text;
   --grey-600 clears 4.5:1 while still sitting clearly behind a typed value. */
.field input::placeholder, .field textarea::placeholder { color: var(--grey-600); }
.field--error input, .field--error textarea { border-color: var(--acc); }
.field__error { font-size: 1.4rem; color: var(--acc-text); }

/* Step-level message for the radio screens, injected by JS when Continue is
   pressed with nothing chosen. Slides in so the feedback is unmissable —
   before this existed, a failed Continue looked like a dead button. */
.step__error {
  display: flex;
  align-items: center;
  gap: .8rem;
  margin-top: 1.8rem;
  font-size: 1.5rem;
  font-weight: 500;
  letter-spacing: -.014em;
  color: var(--acc-text);
  animation: errIn .3s var(--ease) both;
}
.step__error::before {
  content: "!";
  flex: 0 0 auto;
  width: 1.8rem;
  height: 1.8rem;
  display: grid;
  place-items: center;
  border: 1px solid currentColor;
  border-radius: 50%;
  font-size: 1.2rem;
  font-weight: 700;
}
@keyframes errIn {
  from { opacity: 0; transform: translateY(-.4rem); }
  to   { opacity: 1; transform: none; }
}

.field--hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.step__nav { display: flex; gap: 1.2rem; margin-top: 3.6rem; align-items: center; }
.step__count { margin-left: auto; font-size: var(--fs-meta); letter-spacing: var(--tr-meta); color: var(--muted); text-transform: uppercase; }

.form-note { font-size: 1.4rem; color: var(--muted); margin-top: 2rem; line-height: 150%; }

.alert { padding: 2rem 2.4rem; border: 1px solid var(--rule-strong); margin-bottom: 3.2rem; font-size: 1.6rem; line-height: 152%; }
.alert--ok { border-color: var(--acc); }

/* ---------------------------------------------------------------------------
   17b. The full enquiry form (/contact-us/)
   Posts to /contact-handler.php over AJAX via assets/js/forms.js. The classes
   below are the contract that file depends on: .form-alert (+ .ok/.err),
   .field--invalid, span.field-error and .btn__label.
   ------------------------------------------------------------------------ */

.form { max-width: 78rem; }

/* Two-up on desktop, stacked on phones. */
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 0 3.2rem; }
@media (max-width: 700px) { .form__row { grid-template-columns: 1fr; gap: 0; } }

/* Status line, shown by forms.js after a submit. Mirrors .alert but lives
   inside the form so the message sits where the eye already is. */
.form-alert {
  padding: 1.8rem 2.2rem;
  border: 1px solid var(--rule-strong);
  border-left-width: 3px;
  margin-bottom: 3.2rem;
  font-size: 1.6rem;
  line-height: 152%;
}
.form-alert.ok  { border-left-color: var(--acc); }
.form-alert.err { border-left-color: var(--acc-text); }

/* Server- and client-side field errors render identically: forms.js feeds the
   handler's {field: message} map straight into the validator. */
.field--invalid input,
.field--invalid textarea,
.field--invalid select { border-color: var(--acc-text); }

span.field-error {
  display: block;
  margin-top: .6rem;
  font-size: 1.4rem;
  color: var(--acc-text);
  animation: errIn .3s var(--ease) both;
}

/* Services multi-select — real checkboxes, visually hidden, with the label
   drawn as the control so it stays keyboard- and screen-reader-navigable. */
.svc-check { display: flex; flex-wrap: wrap; gap: 1rem; margin-top: .4rem; }
.svc-check input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.svc-check label {
  cursor: pointer;
  padding: 1rem 1.6rem;
  border: 1px solid var(--rule-strong);
  border-radius: 100px;
  font-size: 1.5rem;
  font-weight: 500;
  letter-spacing: -.014em;
  text-transform: none;
  color: inherit;
  transition: border-color var(--t-mid) var(--ease), background var(--t-mid) var(--ease);
}
.svc-check label:hover { border-color: currentColor; }
.svc-check input:checked + label { background: var(--acc); border-color: var(--acc); color: #fff; }
.svc-check input:focus-visible + label { outline: 2px solid var(--acc); outline-offset: 2px; }

.form__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2.4rem;
  margin-top: 3.6rem;
  flex-wrap: wrap;
}
.form button[type="submit"][disabled] { opacity: .6; cursor: progress; }

/* ---------------------------------------------------------------------------
   18. Page hero (inner pages)
   ------------------------------------------------------------------------ */

.page-hero { padding-block: 20rem 8rem; }
.page-hero__meta {
  display: flex;
  gap: 1rem 2.4rem;
  flex-wrap: wrap;
  padding-bottom: 2.4rem;
  margin-bottom: 3.2rem;
  border-bottom: 1px solid var(--rule);
}
.page-hero__meta span, .page-hero__meta a { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); text-transform: uppercase; color: var(--muted); }
.page-hero__meta a:hover { color: var(--fg); }
.page-hero h1 { max-width: 18ch; }
.page-hero__lead { margin-top: 3.2rem; max-width: 62rem; font-size: 2rem; line-height: 150%; color: var(--muted); text-wrap: pretty; }

/* ---------------------------------------------------------------------------
   19. Article
   ------------------------------------------------------------------------ */

.article { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 9fr); gap: 8rem; }
.article__aside { position: sticky; top: 14rem; align-self: start; display: flex; flex-direction: column; gap: 2.4rem; }
.article__aside dt { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); text-transform: uppercase; color: var(--muted); margin-bottom: .6rem; }
.article__aside dd { margin: 0; font-size: 1.6rem; letter-spacing: -.02em; }

.prose { max-width: 72ch; font-size: 1.85rem; line-height: 168%; }
.prose > * + * { margin-top: 2.8rem; }
.prose > :first-child { margin-top: 0; }   /* legal pages open with equal rhythm whether p or h2 comes first */
.prose h2 { font-size: 3.2rem; letter-spacing: -.032em; line-height: 116%; margin-top: 6rem; }
.prose h3 { font-size: 2.4rem; letter-spacing: -.028em; line-height: 122%; margin-top: 4.8rem; }
.prose p { color: #2A2926; }
.prose strong { font-weight: 600; }
.prose a { color: var(--acc-text); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.prose ul, .prose ol { display: flex; flex-direction: column; gap: 1.2rem; padding-left: 2.2rem; }
.prose ul li { list-style: none; position: relative; }
.prose ul li::before {
  content: "";
  position: absolute;
  left: -2.2rem; top: .85em;
  width: .6rem; height: 1px;
  background: var(--rule-strong);
}
.prose ol { list-style: decimal; }
.prose ol li { list-style: decimal; }
.prose img { margin-block: 4rem; width: 100%; mix-blend-mode: multiply; /* legacy article vectors have baked-in white mattes; multiply sits them onto the paper ground instead of rendering white boxes */ }
.prose blockquote {
  border-left: 1px solid var(--rule-strong);
  padding-left: 3.2rem;
  font-size: 2.2rem;
  line-height: 142%;
  letter-spacing: -.024em;
}
.prose figure { margin-block: 4rem; }
.prose figcaption { font-size: 1.4rem; color: var(--muted); margin-top: 1.2rem; }

.article__hero-img { width: 100%; aspect-ratio: 16 / 7; object-fit: cover; margin-bottom: 8rem; }

/* ---------------------------------------------------------------------------
   20. Footer
   ------------------------------------------------------------------------ */

/* A hairline at the top so that where a dark CTA section flows straight into
   the dark footer, the seam reads as intentional rather than as one giant
   black block. Invisible where a light section precedes it. */
.footer { padding-block: 10rem 3rem; border-top: 1px solid var(--rule); overflow: hidden; }
.footer__top {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 3fr) minmax(0, 3fr);
  gap: 6rem 4rem;
  padding-bottom: 8rem;
  border-bottom: 1px solid var(--rule);
}
.footer__cta-title { font-size: clamp(2.8rem, 4vw, 5.2rem); font-weight: 700; letter-spacing: -.038em; line-height: 104%; max-width: 14ch; }
.footer__contact { display: flex; flex-direction: column; gap: 1rem; margin-top: 3.2rem; }
.footer__contact a { font-size: 2rem; letter-spacing: -.03em; width: fit-content; }

/* These h4s are column labels, not headings — 12px uppercase, so they take
   label weight rather than the h4 display weight. */
.footer__col .footer__col-h {
  font-family: var(--font);
  font-size: var(--fs-meta);
  letter-spacing: var(--tr-meta);
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 500;
  margin-bottom: 2rem;
}
.footer__col ul { display: flex; flex-direction: column; gap: 1rem; }
.footer__col a { display: inline-block; padding-block: .8rem; margin-block: -.8rem; font-size: 1.6rem; letter-spacing: -.02em; color: var(--muted); transition: color var(--t-fast) var(--ease-soft); }
.footer__col a:hover { color: var(--fg); }
.footer__col address { font-style: normal; font-size: 1.6rem; line-height: 168%; color: var(--muted); }

.footer__socials { display: flex; gap: 1rem; margin-top: 2.4rem; }
.footer__socials a {
  width: 4.4rem; height: 4.4rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--rule);
  color: var(--muted);
  transition: color var(--t-fast) var(--ease-soft), border-color var(--t-fast) var(--ease-soft);
}
.footer__socials a:hover { color: var(--fg); border-color: var(--rule-strong); }

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1.6rem 3rem;
  padding-top: 3rem;
}
.footer__bottom p, .footer__bottom a { font-size: var(--fs-meta); letter-spacing: var(--tr-meta); color: var(--muted); text-transform: uppercase; }
.footer__bottom a { display: inline-block; padding-block: .9rem; margin-block: -.9rem; }
.footer__bottom a:hover { color: var(--fg); }
.footer__legal { display: flex; gap: 2.4rem; flex-wrap: wrap; }

/* The wordmark that closes the page. */
.footer__word {
  /* Oversized on purpose and cropped by the footer's overflow:hidden — the
     wordmark bleeds past both gutters so the crop reads deliberate. At the
     old 14.58vw it stopped ~225px short of the grid edge at 1440. */
  margin-inline: calc(var(--gutter) * -1);
  font-size: 18.8vw;   /* sized so the glyphs bleed past the RIGHT edge too — 16.5vw stopped 138px short at 1440 */
  line-height: .78;
  font-weight: 700;
  letter-spacing: -.05em;
  color: transparent;
  -webkit-text-stroke: 1px var(--rule);
  margin-top: 8rem;
  white-space: nowrap;
  user-select: none;
}

/* ---------------------------------------------------------------------------
   20b. Signature motion layer
   ------------------------------------------------------------------------ */

/* Cursor follower. White dot in difference blend, so it self-inverts against
   every ground — dark over paper, light over ink — without per-section logic.
   JS creates it only on fine pointers with motion allowed; it never exists on
   touch devices. */
.cursor-dot {
  position: fixed;
  top: 0; left: 0;
  z-index: 10001;                 /* above the grain overlay */
  width: 1rem; height: 1rem;
  border-radius: 50%;
  background: #fff;
  mix-blend-mode: difference;
  pointer-events: none;
  opacity: 0;
  transition: opacity .3s var(--ease-soft),
              width .3s var(--ease),
              height .3s var(--ease);
}
.cursor-dot.is-live { opacity: 1; }
.cursor-dot.is-hover { width: 4.4rem; height: 4.4rem; }

/* Magnetic buttons: JS drives the translate; this only makes the spring-back
   smooth. Deliberately no transform transition while hovering (the JS updates
   are the motion). */
.btn.is-magnetic { transition-property: background-color, color, border-color, transform; }
.btn.is-magnetic:not(:hover) { transition-duration: var(--t-mid); transform: none; }
.btn.is-magnetic:hover { transition-duration: var(--t-fast); }   /* tight follow while engaged, soft spring on release */

/* Statement-band image: 12% overscan covers the ±6% parallax drift so the
   band never shows an edge mid-scroll. */
.img-band__img { transform: scale(1.12); will-change: transform; }

/* Page-exit transition: main fades and lifts for 160ms before navigation.
   The destination's own reveal choreography plays the entrance. */
main { transition: opacity .16s ease, transform .16s ease; }
.is-leaving main { opacity: 0; transform: translateY(-1rem); }

/* Article reading progress — a magenta hairline across the very top. */
.read-progress {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 10000;
  height: 2px;
  background: var(--magenta);
  transform: scaleX(0);
  transform-origin: 0 50%;
  pointer-events: none;
}

/* Sticky mobile CTA — bottom right, phones only. Square corners and the
   magenta-deep fill so it reads as part of the button system, not a floating
   Material blob; no shadow per the no-elevation rule (the saturated fill
   separates it from both light and ink grounds on its own). Exists in the
   DOM on every page except /contact-us/, but only ever displays below 620px. */
.sticky-cta {
  position: fixed;
  right: 1.6rem;
  bottom: calc(1.6rem + env(safe-area-inset-bottom, 0px));
  z-index: 880;                     /* under the drawer (890) and header (900) */
  display: none;
  align-items: center;
  gap: 1rem;
  padding: 1.5rem 2rem;             /* ~50px tall — clears the 44px touch bar */
  background: var(--magenta-deep);
  color: #FFFFFF;
  font-size: 1.5rem;
  font-weight: 500;
  letter-spacing: -.018em;
}
.sticky-cta svg { flex: 0 0 auto; }

@media (max-width: 620px) {
  .sticky-cta {
    display: flex;
    opacity: 0;
    transform: translateY(1.2rem);
    pointer-events: none;
    transition: opacity .3s var(--ease-soft), transform .3s var(--ease-soft);
  }
  .sticky-cta.is-on { opacity: 1; transform: none; pointer-events: auto; }
  /* Never fight the open drawer. */
  body.is-locked .sticky-cta { opacity: 0; pointer-events: none; }
}

@media (prefers-reduced-motion: reduce) {
  .sticky-cta { transition: none; transform: none; }
}

/* Sibling-dim: hovering one item quietly recedes the others. Opacity-only,
   hover-capable devices only, and gated to .is-in so it can never outrank the
   entrance reveal's hidden state. */
@media (hover: hover) {
  .rows:hover .row.is-in:not(:hover),
  .index-list:hover .index-item.is-in:not(:hover),
  .plat-index:hover .plat-row.is-in:not(:hover) { opacity: .45; }
  .row.is-in, .index-item.is-in, .plat-row.is-in { transition: opacity .3s var(--ease-soft), background-color var(--t-mid) var(--ease); }
}

/* Row numerals ignite on hover — the same accent logic the section indices
   already use, extended to the interaction. */
.row { transition: background-color var(--t-mid) var(--ease); }
.row__num { transition: color var(--t-mid) var(--ease), transform var(--t-mid) var(--ease); }
.row:hover .row__num { color: var(--acc-text); transform: translateX(.4rem); }

@media (prefers-reduced-motion: reduce) {
  .cursor-dot, .read-progress { display: none; }
  .img-band__img { transform: none; }
  main { transition: none; }
}

/* ---------------------------------------------------------------------------
   21. Responsive
   ------------------------------------------------------------------------ */

@media (max-width: 1100px) {
  :root { --sec-y: 10rem; --gutter: 2.8rem; --fs-h2: 3.4rem; }

  /* Tight sections scale with the rhythm. Fixed at 9rem they became LARGER
     than regular sections (8rem) on phones — the hierarchy inverted. Keeps
     the desktop 9:14 ratio. */
  .section--tight { padding-block: 6.5rem; }

  .nav, .header__phone { display: none; }
  .burger { display: block; }

  .split, .process, .article { grid-template-columns: minmax(0, 1fr); gap: 4.8rem; }
  .article__meta-dup { display: none; }   /* duplicates the hero's date · read-time line once stacked */
  .article__aside { flex-direction: row; flex-wrap: wrap; gap: 2.4rem 4.8rem; align-items: baseline; }
  .split__aside, .article__aside { position: static; }

  /* The rail holds only the big count; hiding just the count left an empty
     grid row framed by two hairlines — exactly the "rendering fault" band the
     section-index comment warns about. Remove the whole rail and the first
     step's duplicate top rule. */
  .process__rail { display: none; }
  .process .process__step:first-child { border-top: 0; padding-top: 0; }

  /* The enquiry form kept its desktop 78rem cap after the split stacked,
     leaving a dead right strip and three mismatched right edges. Full width
     once single-column. */
  .qualifier { max-width: none; }

  /* 2+1 rag under the CTAs read unconsidered — stack the ticks as a list. */
  .hero__trust { flex-direction: column; align-items: flex-start; gap: 1rem; }

  /* Stacked aside frames rendered at full editorial ratio — a whole viewport
     of photo before any copy. Crop wide once the split is single-column. */
  .split__aside .frame { aspect-ratio: 16 / 9; }

  .packages { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .package:nth-child(odd) { border-left: 1px solid var(--rule); }
  .platforms { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .platform:nth-child(3n) { border-right: 1px solid var(--rule); }
  .platform:nth-child(2n) { border-right: 0; }
  .platforms--odd .platform:last-child { border-right: 0; }

  .index-item__thumb { display: none; }
}

@media (max-width: 860px) {
  .row { grid-template-columns: 5rem minmax(0, 1fr); gap: 1.6rem 2.4rem; }
  .row__go { display: none; }
  .row__body { grid-column: 2; }

  .index-item__link { grid-template-columns: minmax(0, 1fr) 3rem; gap: .8rem 2rem; }
  .index-item__date { grid-row: 1; }
  .index-list--home .index-item__link { grid-template-columns: minmax(0, 1fr) 3rem; }
  .index-list--home .index-item__cat { grid-row: 1; grid-column: 1; }
  .index-list--home .index-item__date { grid-row: 3; grid-column: 1; text-align: left; }
  /* Column 1 ONLY — spanning 1/-1 ran long title lines underneath the
     row-spanning arrow in column 2. */
  .index-item__title { grid-column: 1; grid-row: 2; }
  .index-item__cat { grid-column: 1; grid-row: 3; text-align: left; }
  .index-item__go { grid-column: 2; grid-row: 1 / span 3; align-self: center; }
  .index-item:hover .index-item__title { transform: none; }

  .hero__layout { grid-template-columns: minmax(0, 1fr); gap: 3.6rem; }
  .hero__layout .hero__title, .hero__layout .hero__card, .hero__rest { grid-column: 1; }
  .hero__layout .hero__card { grid-row: auto; }   /* DOM order: h1, card, rest — card right under the headline */

  .footer__top { grid-template-columns: minmax(0, 1fr); }
  .package-custom { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 480px) {
  /* The desktop hanging-number gutters survived to phone widths and squeezed
     copy to ~170-214px columns (35-45% of the screen empty under a two-digit
     number). Single column: number above title, everything full measure. */
  .row { grid-template-columns: minmax(0, 1fr); gap: .8rem 0; padding-block: 3.6rem; }
  .row__num { padding-top: 0; }
  .row__body { grid-column: auto; }

  .process__step { grid-template-columns: minmax(0, 1fr); gap: .8rem; padding-block: 3.2rem; }

  /* '02 THE / DIFFERENCE' stagger: the right-aligned aside was stealing the
     name's width. Aside drops to its own row, left-aligned. */
  .sec-index { grid-template-columns: auto 1fr; }
  .sec-index__aside { grid-column: 1 / -1; text-align: left; margin-top: .2rem; }
}

@media (max-width: 620px) {
  :root { --sec-y: 8rem; --gutter: 2rem; --fs-h2: 2.8rem; --fs-h3: 2.2rem; }
  .section--tight { padding-block: 5rem; }

  .hero { padding-top: 12rem; }
  .hero__chips { grid-template-columns: minmax(0, 1fr); }

  /* The 20px lead matched the clamped H1 floor too closely — cap it so the
     display/body ratio survives on phones. */
  .page-hero__lead { font-size: 1.7rem; }

  /* Step 1's Continue sat ~105px under the fold at 320x650. Tighter choice
     cards pull the whole step into one screen. */
  .choice__box { padding: 1.6rem; }
  .choices { gap: .8rem; }
  .step__hint { margin-bottom: 2rem; }

  /* Logo + CTA + burger stop fitting comfortably here. The CTA goes rather
     than the burger: the drawer carries the phone number and email, so the
     route to contact survives — a cramped header does not. */
  .header__cta .btn { display: none; }
  .brand { width: 13rem; }

  .packages, .platforms { grid-template-columns: minmax(0, 1fr); }
  .platforms--odd .platform:last-child { grid-column: auto; }   /* span 2 would mint an implicit column and overflow */

  /* Phones: the grid is a six-item NAV list — compact rows, not six tall
     editorial boxes. With the inline head this brings a tile from ~195px to
     ~110px, so the whole section fits in well under two screens. */
  .platform { padding: 2rem; gap: .8rem; }
  .platform p { font-size: 1.4rem; }
  .platform__name { font-size: 1.8rem; }
  .package, .platform { border-left: 1px solid var(--rule); border-right: 1px solid var(--rule); }

  .choices { grid-template-columns: minmax(0, 1fr); }
  .lead { font-size: 2rem; }
  .page-hero { padding-block: 14rem 6rem; }
  .prose { font-size: 1.7rem; }
  .prose h2 { font-size: 2.6rem; }
  .drawer__list a { font-size: 2.8rem; }
  .step__nav { flex-wrap: wrap; }
  .step__count { margin-left: 0; width: 100%; order: -1; }
}

@media (max-width: 400px) {
  :root { --gutter: 1.6rem; }
  .btn { padding: 1.3rem 1.8rem; }
}

/* ---------------------------------------------------------------------------
   22. Motion preferences & print
   ------------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .lines .line > span { transform: none; }
  .rise { opacity: 1; transform: none; }
  .marquee__track { animation: none; }
}

@media print {
  .header, .drawer, .footer__word, body::after { display: none !important; }
  body { background: #fff; color: #000; }
  .section { padding-block: 2rem; }
}
