/* WhiteSpace Studio — one-page studio site.
   Every colour, size, space and timing comes from tokens.css.
   Layout and motion rules follow docs/design-language.md. */

/* Base --------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  interpolate-size: allow-keywords;
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.motion body {
  transition: background-color var(--dur-theme) var(--ease-out), color var(--dur-theme) var(--ease-out);
}

img, svg { display: block; max-width: 100%; }
a { color: inherit; }
h1, h2, h3, p, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
h1, h2, h3 { font-weight: 400; }

::selection { background: var(--accent); color: var(--accent-fg); }

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

.section { padding-block: var(--section-lg); }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.skip {
  position: fixed;
  top: 12px; left: 12px;
  z-index: 100;
  padding: 10px 16px;
  background: var(--fg);
  color: var(--bg);
  border-radius: var(--radius-pill);
  transform: translateY(-200%);
}
.skip:focus { transform: none; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* Type primitives ---------------------------------------------------- */

.label,
.caption {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: var(--fg-muted);
}

.label {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Edition's 10px dot. Rosewood, the brighter burgundy, so it reads as
   colour at this size (wine looks near-black when this small). */
.label::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--rosewood);
  flex: none;
}

[data-theme]:not([data-theme="paper"]) .label::before { background: var(--accent); }

.label-center { justify-content: center; }
.label-plain::before { content: none; }

.h2 {
  font-family: var(--font-display);
  font-size: var(--text-h2);
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
}

.side-title {
  font-family: var(--font-body);
  font-weight: 300;
  font-size: var(--text-h5);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  max-width: 17ch;
}

/* Section opener: full-width hairline, then the mono label (Edition home) */
.opener {
  width: 100%;
  padding-top: 22px;
  margin-bottom: clamp(40px, 5.5vw, 80px);
  border-top: var(--hairline) solid var(--line);
}

/* Pill button --------------------------------------------------------
   Edition's button: outline pill, arrow on the right. On hover the arrow
   fades out to the right while a twin fades in on the left and the label
   slides across to make room. */

.pill {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.44rem 1.12rem;
  border: var(--hairline) solid currentColor;
  border-radius: var(--radius-pill);
  background: transparent;
  color: inherit;
  font: 400 var(--text-button)/1.4 var(--font-body);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur-ui), color var(--dur-ui), border-color var(--dur-ui);
}

.pill-label,
.pill-arrow { transition: transform var(--dur-ui) var(--ease-ui), opacity var(--dur-ui) var(--ease-ui); }

.pill-arrow {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 1rem;
  height: 1.75rem;
  font-size: 1.1em;
}

.pill-arrow.is-left {
  position: absolute;
  left: 0;
  opacity: 0;
}

.pill:hover .pill-arrow.is-left  { opacity: 1; transform: translateX(1.12rem); }
.pill:hover .pill-label          { transform: translateX(1.5rem); }
.pill:hover .pill-arrow.is-right { opacity: 0; transform: translateX(1.12rem); }

/* Fill on hover: the page's theme colour on paper, inverted on a theme */
.pill:hover { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
body:not([data-theme="paper"]) .pill:hover { background: var(--fg); color: var(--bg); border-color: var(--fg); }

/* Primary (solid) pill: filled in the text colour; on hover it empties
   to the outline style, the reverse of a normal pill */
.pill.is-solid { background: var(--fg); color: var(--bg); border-color: var(--fg); }
body .pill.is-solid:hover { background: transparent; color: var(--fg); border-color: var(--fg); }

/* The CTA button stays a white fill while the page fades behind it */
body .pill.pill-cta:hover { background: var(--paper); color: var(--ink); border-color: var(--ink); }

/* Nav ---------------------------------------------------------------- */

.nav {
  position: fixed;
  inset: 0 0 auto;
  z-index: 50;
  color: var(--fg);
  transition: transform 0.45s var(--ease-ui), background-color var(--dur-theme) var(--ease-out), color var(--dur-theme) var(--ease-out);
}

.nav.is-scrolled { background: var(--bg); }
.nav.is-hidden { transform: translateY(-100%); }

/* Reading progress (Edition's insight pages): a 6px bar fixed just below
   the nav. When the nav hides it rises to the very top of the screen;
   while the foundation-pricing bar is stuck to the top, it sits just
   under that bar instead. The script sets its position and fill. */
.progress {
  position: fixed;
  inset: 0 0 auto;
  z-index: 40;
  height: 6px;
  overflow: hidden;
  pointer-events: none;
  transform: translateY(var(--progress-top, 0px));
}

.progress-bar {
  height: 100%;
  background: var(--fg);
  transform: translateX(-100%);
  transition: background-color var(--dur-theme) var(--ease-out);
  will-change: transform;
}

.nav-inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
  padding: 13.5px var(--gutter);
}

.nav-logo { justify-self: start; }
.nav-logo { display: flex; }
.nav-logo svg { width: clamp(120px, 9.5vw, 140px); height: auto; }  /* wordmark only */

/* Nav: 20px links, muted, with the current section's link (and the one
   hovered) in full text colour. */
.nav-links { display: flex; }

.nav-links a {
  display: block;
  padding: 8px 1.11rem;
  font-size: var(--text-button);
  line-height: 1.45;
  text-decoration: none;
  color: var(--fg-faint);
  transition: color 0.5s;
}

/* Hovering any link takes over: only the hovered one is dark */
.nav-links a.is-active,
.nav-links a:hover { color: var(--fg); }
.nav-links:hover a.is-active:not(:hover) { color: var(--fg-faint); }

.nav .pill { justify-self: end; }

/* 1. Header: Edition's services page ----------------------------------
   One huge centred serif headline. 232px above, 160px below at desktop. */

.page-header {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
  padding: 112px var(--gutter) 40px;
}

/* The headline block takes the free height and sits centred in it */
.page-header-main {
  display: flex;
  flex: 1;
  flex-direction: column;
  justify-content: center;
  padding-block: 48px;
}

/* Plain headline in the text colour; each line is its own span */
.page-title {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 80rem;
  margin-inline: auto;
  text-align: center;
  font-family: var(--font-display);
  font-size: var(--text-mega);
  font-weight: 400;
  line-height: 0.94;
  letter-spacing: var(--tracking-mega);
  text-wrap: balance;
}

/* Keep each line whole where there's room; phones let them wrap */
@media (min-width: 768px) {
  .page-title { max-width: none; }
  .page-title span { white-space: nowrap; }
}

.motion .page-title { animation: title-in 1s var(--ease-out) 0.1s both; }

/* Bottom bar (Edition home): coordinates, one line, live Auckland clock */
/* Hairlines join the three items across the gaps between them */
.hero-bar {
  display: grid;
  grid-template-columns: auto 1fr auto 1fr auto;
  align-items: center;
  gap: 24px;
}

.hero-bar-line { height: var(--hairline); background: var(--line); }

.hero-meta {
  font: 400 var(--text-label)/1.2 var(--font-mono);
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.hero-lead { font-size: var(--text-button); line-height: 1.4; text-align: center; }

.hero-clock {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
}

.clock-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--status-closed);
}
.clock-dot.is-open { background: var(--status-open); }

.motion .hero-bar { animation: title-in 1s var(--ease-out) 0.4s both; }

@keyframes title-in {
  from { opacity: 0; transform: translateY(24px); }
}

/* Shared drifting track */
.strip-track {
  display: flex;
  align-items: center;
  gap: 32px;
  width: max-content;
  will-change: transform;
}

/* 2. Scroll text + key numbers -------------------------------------
   Two screens tall. The inner block pins for the whole run: the words blur
   in one by one as it locks to the top, then the numbers spring up. */

.scroll-text { position: relative; height: 300vh; height: 300svh; }

/* "Who we design for" links here: late in the pinned run, once the strip is in */
.scroll-text-anchor { position: absolute; left: 0; top: calc(0.85 * (100% - 100svh)); }
.scroll-text-anchor.is-about { top: calc(0.45 * (100% - 100svh)); }

.scroll-text-sticky {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100vh;
  min-height: 100svh;
  padding-block: 72px 32px;
  overflow: hidden;
}

.scroll-text-wrap {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: clamp(48px, 7.8vw, 112px);
  min-height: 50vh;
  min-height: 50svh;
  padding-inline: var(--gutter);
}

.scroll-text-headline {
  max-width: 58rem;  /* Edition's headline container */
  text-align: center;
  font-size: var(--text-statement);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}

/* Second half of the pinned run (--rise: 0 → 1): the paragraph eases a
   little smaller and moves up, and the sector strip rises from below to
   sit at the bottom of the screen; the paragraph ends centred in the space
   above it. The script sets --lift from the screen size. */
.motion .scroll-text-headline {
  transform-origin: 50% 0;
  transform: translateY(calc(var(--rise, 0) * var(--lift, 0px))) scale(calc(1 - 0.16 * var(--rise, 0)));
}

.motion .scroll-text .sectors {
  position: absolute;
  left: 0;
  right: 0;
  bottom: clamp(24px, 4vh, 48px);
  padding-block: 0;
  transform: translateY(calc((1 - var(--rise, 0)) * 75vh));
}

html:not(.motion) .scroll-text { height: auto; }
html:not(.motion) .scroll-text-sticky { position: static; overflow: visible; }

/* Each word's opacity, lift and blur are set by the script on every frame,
   straight from the scroll position, so the reveal tracks the scroll. */
.motion .scroll-text-headline .word {
  display: inline-block;
  opacity: 0;
  will-change: opacity, transform, filter;
}

/* Who we design for: a compact strip (inside the pinned scroll text) -----
   A short heading, then small uniform photo cards that drift and drag. */

.sectors { padding-block: var(--section-md); }

/* The label sits a little above the strip */
.sectors .opener { margin-bottom: clamp(28px, 3vw, 40px); border-top: 0; }


.strip {
  overflow: hidden;
  touch-action: pan-y;
  cursor: grab;
  user-select: none;
}
.strip.is-dragging { cursor: grabbing; }

html:not(.motion) .strip { overflow-x: auto; padding-inline: var(--gutter); }

/* The "Drag" pill replaces the pointer on desktop */
@media (hover: hover) and (min-width: 992px) {
  .motion [data-cursor],
  .motion [data-cursor] * { cursor: none; }
}

.sectors .strip-track { align-items: flex-start; gap: 16px; padding-left: var(--gutter); }

.photo-card {
  flex: none;
  width: clamp(200px, 17vw, 250px);
}

.photo-card img {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--radius-tile);
  background: var(--surface);
  pointer-events: none;
}

.photo-card-name {
  margin-top: 12px;
  font-size: var(--text-small);
  font-weight: 400;
  line-height: 1.3;
}

.photo-card-note {
  margin-top: 4px;
  font: 400 var(--text-micro)/1.4 var(--font-mono);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: var(--fg-muted);
}

/* 4. Foundation pricing countdown: a sticky header for the services ------
   One centred mono line between hairlines. It sits at the top of the
   services section and sticks to the top of the screen through all three
   bands, taking on each band's colour as the page fades. */

/* In its place (top of the services) it sits quietly in the page colour
   between hairlines. Once it sticks to the top of the screen (or whenever
   the page has turned burgundy for the websites band), or just under
   the nav while the nav is showing (sliding with it), it turns bright lime
   with ink text so the deadline stands out from every band. It parks on
   top of Capabilities once the services are passed. */
.deadline {
  position: sticky;
  top: var(--nav-shown, 0px);
  z-index: 20;
  background-color: var(--bg);
  color: var(--fg);
}
.motion .deadline { transition: top 0.45s var(--ease-ui), background-color 0.3s var(--ease-out), color 0.3s var(--ease-out); }
.deadline.is-stuck,
body[data-theme="wine"] .deadline { background-color: var(--lime); color: var(--ink); }

.deadline .wrap {
  padding-block: 20px;
  border-block: var(--hairline) solid var(--line);
  transition: border-color 0.3s var(--ease-out);
}
.deadline.is-stuck .wrap,
body[data-theme="wine"] .deadline .wrap { border-color: transparent; }

/* Line on the left, time left on the right */
.deadline-line {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 24px;
  font: 400 var(--text-label)/1.4 var(--font-mono);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: var(--fg-muted);
}
.deadline.is-stuck .deadline-line,
body[data-theme="wine"] .deadline-line { color: rgb(20 23 31 / 0.7); }

/* Live time left: the numbers in full strength */
.deadline-clock b { font-weight: 400; font-variant-numeric: tabular-nums; }
.deadline-line b { color: var(--fg); }
.deadline.is-stuck .deadline-line b,
body[data-theme="wine"] .deadline-line b { color: var(--ink); }

/* 5. Services with pricing: Edition's services grid (below the sticky
   deadline header) ---------------------------------------------------------
   Each service is a band that fades the whole page to its own colour
   (burgundy, white, navy). Text on the left four columns, sticky, holding the
   price; imagery on the right seven (a wide image over two smaller). */

/* Breathing room between the sector strip and the countdown header */
.service-grid { margin-top: var(--section-md); }

.service { scroll-margin-top: 40px; }

/* A hairline divides one service from the next */
.service + .service .service-inner { border-top: var(--hairline) solid var(--line); }

/* Each service fills at least a full screen */
.service-inner {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--grid-gap);
  align-items: start;
  min-height: 100vh;
  min-height: 100svh;
  padding-block: var(--section-md);
}

/* Intro and price, choreographed (desktop, screens at least 700px tall).
   Scrolling down: the price follows right under the intro; once it is
   fully on screen it holds at the bottom of the screen while the intro
   carries on up (a gap opens); the intro then holds near the top; at the
   end of the band the price is released and rises until the intro sits
   stacked on top of it again. The script sizes the intro's track to end
   exactly where the price finishes, and pulls the price up under the
   intro to start (--head-track, --buy-pull, --buy-h). */
.service-text { grid-column: 1 / 5; align-self: stretch; display: flex; flex-direction: column; }
/* Once the next band takes over the page colour, the text of the band
   you've just left fades back so the new band leads */
.service-text { transition: opacity var(--dur-theme) var(--ease-out); }
.service.is-past .service-text { opacity: 0.35; }
.service-head-track { flex: none; height: var(--head-track, auto); }
/* The price block is opaque (page colour, 40px band on top) and layered
   over the intro, so when it rises it slides over the list */
.service-buy {
  position: relative;
  z-index: 1;
  margin-top: var(--buy-pull, 0px);
  padding-top: 40px;
  background-color: var(--bg);
}
.motion .service-buy { transition: background-color var(--dur-theme) var(--ease-out); }
@media (min-width: 992px) and (min-height: 700px) {
  /* holds below the countdown bar, and slides down with it when the nav
     comes back on scroll-up, so the label is never tucked under the bar (5 Nov 2026) */
  .service-head { position: sticky; top: calc(100px + var(--nav-shown, 0px)); }
  .motion .service-head { transition: top 0.45s var(--ease-ui); }
  .service-buy { position: sticky; top: calc(100vh - var(--buy-h, 0px) - 40px); }
}
.service-media { grid-column: 6 / 13; align-self: center; display: grid; grid-template-columns: 1fr 1fr; gap: 30px; }

.service-title {
  margin-top: 24px;
  font-size: var(--text-h5);
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: var(--tracking-tight);
}

.service-copy {
  margin-top: 12px;
  font-size: var(--text-button);
  line-height: 1.4;
  color: var(--fg-muted);
}

/* Price: the standard price struck through, the foundation price huge.
   It counts down from the standard price once it's fully in view. */
.price {
  padding-top: 20px;
  border-top: var(--hairline) solid var(--line);
}

.price-was {
  font: 400 var(--text-label)/1.4 var(--font-mono);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: var(--fg-muted);
}

.price-now {
  margin-block: 8px 10px;
  font-family: var(--font-display);
  font-size: clamp(3.25rem, 1rem + 5vw, 5.5rem);
  line-height: 1;
  letter-spacing: var(--tracking-display);
  font-variant-numeric: tabular-nums;
}

/* "Foundation" sits a clear gap under the standard price, in the same
   mono caps but full text colour, with the big price directly under it */
.price-label {
  margin-top: 28px;
  font: 400 var(--text-label)/1.4 var(--font-mono);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: var(--fg);
}
.price-label + .price-now { margin-top: 4px; }

/* Badges under the price: small square-cornered tags, so they never read
   as buttons. The saving comes first with a full-strength outline (it
   pops in as the count lands), then the perks with hairline outlines */
.price-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}
.price-badges li {
  padding: 5px 8px;
  border: var(--hairline) solid var(--line);
  border-radius: 4px;
  font: 400 var(--text-label)/1.2 var(--font-mono);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
}
/* every badge matches the Save badge: full-strength outline in the text colour (user, 5 Nov 2026) */
.price-badges li { border-color: currentColor; color: inherit; background: none; }
/* Every badge waits until the count has landed, then they pop in one
   after another (user, 5 Nov 2026). Prices without a countdown show
   them straight away (--saved defaults to 1). */
.price-badges li {
  opacity: var(--saved, 1);
  transform: scale(calc(0.85 + 0.15 * var(--saved, 1)));
  transform-origin: left center;
  transition: opacity var(--dur-ui) var(--ease-ui), transform var(--dur-ui) var(--ease-spring);
}
/* the Brand refresh "Additional 60%" badge stays lime: solid chip, ink text, so it reads on white (user, 5 Nov 2026) */
#brand .price-badges .price-lime { background: var(--lime); border-color: var(--lime); color: var(--ink); }
[data-price] { --saved: 0; } /* hidden from first paint, so they never flash on load */
/* one after another, left to right (user, 5 Nov 2026) */
.price-badges li:nth-child(2) { transition-delay: 350ms; }
.price-badges li:nth-child(3) { transition-delay: 700ms; }
.price-badges li:nth-child(4) { transition-delay: 1050ms; }


/* The old price stays easy to read: full text colour, a touch larger,
   with a plain horizontal strike drawn left to right in the theme's
   accent (--strike: 0 → 1) */
.price-was s {
  position: relative;
  margin-left: 0.4em;
  font-size: 1.15em;
  color: var(--fg);
  text-decoration: none;
}
.price-was s::after {
  content: "";
  position: absolute;
  left: -2px;
  right: -2px;
  top: 52%;
  height: 1.5px;
  background: var(--accent);
  transform: scaleX(var(--strike, 1));
  transform-origin: left center;
}

/* What's included: a plain two-column list under the intro's copy, in
   the same muted size as the copy (Edition's services page) */
.service-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px 24px;
  margin-top: 32px;
  font-size: var(--text-button);
  line-height: 1.4;
  color: var(--fg-muted);
}

/* The section's calls to action open the price block, above its hairline:
   primary solid first, secondary outline beside it (they wrap when narrow) */
.price-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 32px; }

.service-img {
  width: 100%;
  aspect-ratio: 373 / 330;
  object-fit: cover;
  border-radius: var(--radius-image);
  background: var(--surface);
}

.service-img.is-wide { grid-column: 1 / -1; aspect-ratio: 775 / 411; }

/* 6. Capabilities: three columns of chips ------------------------------ */

.cap-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--grid-gap);
}

.cap-title {
  margin-bottom: 24px;
  font-size: var(--text-button);
  font-weight: 400;
}

.cap-list { display: flex; flex-wrap: wrap; gap: 10px; }

.cap-list li {
  padding: 6px 12px;
  border-radius: 6px;
  background: var(--surface);
  font-size: var(--text-small);
  line-height: 1.4;
}

/* 10. CTA ------------------------------------------------------------ */

.cta {
  padding: var(--section-lg) var(--gutter);
  text-align: center;
}

.cta-title {
  max-width: var(--container-cta);
  margin-inline: auto;
  font-family: var(--font-display);
  font-size: var(--text-display);
  line-height: 1.1;
  letter-spacing: var(--tracking-display);
}

.form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 28px var(--grid-gap);
  max-width: var(--container-small);
  margin: clamp(56px, 7vw, 96px) auto 0;
  text-align: left;
}

.form label {
  display: grid;
  gap: 10px;
  font: 400 var(--text-micro)/1.2 var(--font-mono);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: var(--fg-muted);
}

.form-wide { grid-column: 1 / -1; }

.form input {
  padding: 8px 0 12px;
  border: 0;
  border-bottom: var(--hairline) solid var(--line);
  border-radius: 0;
  background: transparent;
  color: var(--fg);
  font: 400 var(--text-body)/1.3 var(--font-body);
  letter-spacing: 0;
  text-transform: none;
  transition: border-color var(--dur-ui);
}

.form input::placeholder { color: var(--fg-faint); }
.form input:focus { outline: none; border-bottom-color: var(--fg); }

/* "What are you after?": a dropdown that looks like the other fields
   (text on a bottom hairline, chevron on the right) and opens a panel of
   tick boxes, so several can be chosen. The service buttons tick theirs,
   so the sign-up records which was pressed */
.interest { position: relative; border: 0; padding: 0; margin: 0; min-width: 0; }
.interest legend {
  margin-bottom: 10px;
  padding: 0;
  font: 400 var(--text-micro)/1.2 var(--font-mono);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: var(--fg-muted);
}
.interest legend span { color: var(--fg-faint); }
.interest-drop summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 8px 0 12px;
  border-bottom: var(--hairline) solid var(--line);
  font: 400 var(--text-body)/1.3 var(--font-body);
  color: var(--fg);
  cursor: pointer;
  list-style: none;
  transition: border-color var(--dur-ui);
}
.interest-drop summary::-webkit-details-marker { display: none; }
.interest-drop summary:hover,
.interest-drop[open] summary { border-bottom-color: var(--fg); }
.interest-drop summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.interest-drop .is-empty { color: var(--fg-faint); }
.interest-chevron {
  flex: none;
  width: 9px;
  height: 9px;
  margin-top: -5px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--dur-ui), margin var(--dur-ui);
}
.interest-drop[open] .interest-chevron { transform: rotate(-135deg); margin-top: 4px; }
.interest-options {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 5;
  display: grid;
  margin-top: 8px;
  padding: 0 20px;
  border: var(--hairline) solid var(--fg);
  border-radius: 4px;
  background: var(--bg);
}
/* Each choice is a plain row (no tick box): muted until chosen, then
   full colour with the burgundy dot used by the section labels */
.form .interest-options label {
  position: relative;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 0;
  border-top: var(--hairline) solid var(--line);
  font: 400 var(--text-body)/1.3 var(--font-body);
  letter-spacing: 0;
  text-transform: none;
  color: var(--fg-muted);
  cursor: pointer;
  transition: color var(--dur-ui);
}
.form .interest-options label:first-child { border-top: 0; }
.form .interest-options input { position: absolute; opacity: 0; pointer-events: none; }
.interest-options label::before {
  content: "";
  flex: none;
  width: 10px;
  height: 10px;
  border: var(--hairline) solid currentColor;
  border-radius: 50%;
  transition: background-color var(--dur-ui), border-color var(--dur-ui);
}
.form .interest-options label:hover,
.form .interest-options label:has(input:checked) { color: var(--fg); }
.interest-options label:has(input:checked)::before { background: currentColor; }
/* The headline offers always carry a solid dot: burgundy for the website
   offers, navy for brand identity */
.interest-options label[data-dot="wine"]::before { background: var(--wine); border-color: var(--wine); }
.interest-options label[data-dot="navy"]::before { background: var(--ink); border-color: var(--ink); }
.interest-options label[data-dot="fern"]::before { background: var(--fern); border-color: var(--fern); }
.interest-options label:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.interest-options label::after {
  content: "Add";
  margin-left: auto;
  font: 400 var(--text-micro)/1 var(--font-mono);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: var(--fg-faint);
}
.interest-options label:has(input:checked)::after { content: "Added"; color: var(--fg); }

.form .pill { grid-column: 1 / -1; justify-self: center; margin-top: 12px; }

.hp { position: absolute; left: -9999px; }

/* Footer -------------------------------------------------------------
   Edition's footer, measured at 1440px: 30px side margin, 80px top and
   32px bottom padding, 64px between groups, mono 12px titles, 16px links
   at 60% strength, 18px blurb, 14px grey copyright. */

.footer { font-size: var(--text-small); }

.footer-inner { padding: 80px var(--footer-gutter) 32px; }

.footer-grid {
  display: flex;
  gap: 64px;
}

/* Edition's link columns start just over a quarter of the way across */
.footer-left {
  display: flex;
  flex-direction: column;
  flex: 0 0 232px;
  margin-right: clamp(0px, 5.2vw, 75px);
}

.footer-blurb { font-size: var(--text-body); line-height: 1.4; }

.footer-info {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 32px;
}

.footer-muted {
  line-height: 1.4;
  color: var(--fg-grey);
  text-decoration: none;
}

/* Link columns sit flush to the right edge, text right-aligned */
.footer-cols {
  display: flex;
  gap: 64px;
  margin-left: auto;
  text-align: right;
}

.footer-col {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  min-width: 140px;
}

.footer-title {
  padding-bottom: 12px;
  font: 400 var(--text-micro)/1.2 var(--font-mono);
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.footer-link {
  padding-block: 8px;
  line-height: 1.45;
  text-decoration: none;
  opacity: 0.6;
  transition: opacity var(--dur-ui);
}

.footer-link:hover { opacity: 1; }

.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  margin-top: clamp(96px, 4rem + 9vw, 200px);  /* lots of air below the blurb and links (Edition uses 32px) */
  padding-block: 28px;
  border-top: var(--hairline) solid var(--line);
}

.footer-locale {
  display: flex;
  align-items: center;
  gap: 8px;
}

.footer-locale svg {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.2;
}

.footer-copyright {
  font-size: 14px;
  line-height: 1;
  color: var(--fg-grey);
}

/* Follow cursor ------------------------------------------------------
   Edition's drag pill: "← Drag →", trailing the hidden pointer. */

.cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 60;
  pointer-events: none;
  opacity: 0;
}

.cursor > span {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0.44rem 1.12rem;
  border: var(--hairline) solid var(--ink);
  border-radius: var(--radius-pill);
  background: var(--paper);
  color: var(--ink);
  font-size: var(--text-button);
  line-height: 1.4;
  transform: scale(0.6);
  transition: transform var(--dur-ui) var(--ease-ui);
}

.cursor b { font-weight: 400; }
.cursor i { font-style: normal; transition: transform var(--dur-ui) var(--ease-ui); }
.cursor.is-visible { opacity: 1; }
.cursor.is-visible > span { transform: scale(1); }
.cursor.is-pressed > span { transform: scale(0.92); }
.cursor.is-pressed i:first-child { transform: translateX(-3px); }
.cursor.is-pressed i:last-child { transform: translateX(3px); }

/* Who we design for: the strip's photos are black and white and bloom
   into colour while hovered. Everywhere else photos are in full colour. */
.photo-card img { filter: grayscale(1); transition: filter 0.6s var(--ease-ui); }
.photo-card:hover img { filter: none; }

/* Scroll reveals ----------------------------------------------------- */

.motion [data-reveal] > * {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.6s var(--ease-out) var(--delay, 0s), transform 0.6s var(--ease-out) var(--delay, 0s);
}

.motion [data-reveal].is-in > * { opacity: 1; transform: none; }

/* Responsive --------------------------------------------------------- */

@media (max-width: 991px) {
  .hero-bar { grid-template-columns: 1fr; text-align: center; }
  .hero-meta, .hero-bar-line { display: none; }
  .service-inner { display: block; }
  .service-text { margin-bottom: 40px; }
  .cap-grid { grid-template-columns: 1fr 1fr; row-gap: 48px; }
  .footer-grid { flex-direction: column; }
}

@media (max-width: 767px) {
  .nav-inner > nav { display: none; }
  .nav-inner { grid-template-columns: 1fr auto; }
  .form { grid-template-columns: 1fr; }
  .footer-cols { flex-direction: column; gap: 32px; margin-left: 0; text-align: left; }
  .footer-col { align-items: flex-start; }
  .footer-bottom { flex-direction: column; align-items: flex-start; }
  .service-media { gap: 16px; }
  .cap-grid { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* The free landing page offer and its free-hosting badge take the bright
   lime of the foundation-pricing bar, so the offer and the deadline read
   as one promotion */
.pill.is-solid.is-lime { background: var(--lime); color: var(--ink); border-color: var(--lime); }
body .pill.is-solid.is-lime:hover { background: transparent; color: var(--lime); border-color: var(--lime); }

/* Headline on burgundy blocks drawn exactly like the browser's text
   selection (1 Nov 2026): each line gets a block the height of the
   font's letter area, the same shape selecting the text gives. Two
   copies of the headline share one grid cell: the back copy is invisible
   text on burgundy, the front copy is the real text, so every block sits
   behind every letter and nothing is cut off. */
.page-title { display: grid; color: var(--accent-fg); }
.page-title-bg, .page-title-fg { grid-area: 1 / 1; display: block; }
.page-title-bg { color: transparent; user-select: none; }
.page-title-bg > span { background: var(--accent); -webkit-box-decoration-break: clone; box-decoration-break: clone; }
.page-title ::selection { background: var(--fg); color: var(--bg); }

/* Headline style on trial (1 Nov 2026), via the toolbar:
   - Blocks:        every line on burgundy (the selection look)
   - One word:      only "delivers." on a burgundy block
   - Marker:        a soft burgundy highlighter band under each line
   - Burgundy text: the words themselves in burgundy, no blocks
   - Plain:         the original dark headline */
:root[data-hl]:not([data-hl="blocks"]) .page-title-bg > span { background: none; }
:root[data-hl]:not([data-hl="blocks"]) .page-title-fg { color: var(--fg); }
:root[data-hl="word"] .page-title-bg .hl-word { background: var(--accent); -webkit-box-decoration-break: clone; box-decoration-break: clone; }
:root[data-hl="word"] .page-title-fg .hl-word { color: var(--accent-fg); }
:root[data-hl="marker"]:not([data-hl="blocks"]) .page-title-bg > span { background: linear-gradient(transparent 58%, color-mix(in srgb, var(--accent) 22%, transparent) 58% 84%, transparent 84%); -webkit-box-decoration-break: clone; box-decoration-break: clone; }
:root[data-hl="wine"] .page-title-fg { color: var(--accent); }

.hl-try { position: fixed; z-index: 200; left: 50%; bottom: 16px; transform: translateX(-50%); display: flex; align-items: center; gap: 4px; max-width: calc(100vw - 32px); overflow-x: auto; padding: 6px; background: #fff; color: #14171f; box-shadow: 0 8px 30px rgb(0 0 0 / 0.25); border-radius: 999px; font: 500 13px/1 system-ui, sans-serif; }
.hl-try-label { padding: 0 8px 0 10px; font-weight: 600; white-space: nowrap; }
.hl-try button { padding: 8px 12px; border: 0; border-radius: 999px; background: none; color: inherit; font: inherit; white-space: nowrap; cursor: pointer; }
.hl-try button[aria-pressed="true"] { background: #451b20; color: #fff; }
/* "What we do" lands at the start of the statement, as the words begin */
.scroll-text-anchor.is-start { top: 0; }
/* Bold marker: the band is full burgundy, and the part of each letter
   that sits on it turns white (the text is painted with a matching
   dark / white / dark gradient, clipped to the letters) */
:root[data-hl="marker-bold"]:not([data-hl="blocks"]) .page-title-bg > span { background: linear-gradient(transparent 58%, var(--accent) 58% 84%, transparent 84%); -webkit-box-decoration-break: clone; box-decoration-break: clone; }
:root[data-hl="marker-bold"] .page-title-fg > span { color: transparent; background: linear-gradient(var(--fg) 58%, var(--accent-fg) 58% 84%, var(--fg) 84%); -webkit-background-clip: text; background-clip: text; -webkit-box-decoration-break: clone; box-decoration-break: clone; }

/* Footer brand: the W mark tile beside the WhiteSpace wordmark */
.footer-brand { display: inline-flex; align-items: center; gap: 14px; margin-bottom: 28px; color: inherit; text-decoration: none; }
.footer-mark { width: 44px; height: 44px; flex: none; }
.footer-wordmark svg { display: block; width: clamp(150px, 12vw, 180px); height: auto; }
/* Footer brand stacked (1 Nov 2026): the W tile on top, the wordmark
   beneath it, both on the same left edge as the W */
.footer-brand { flex-direction: column; align-items: flex-start; gap: 18px; margin-bottom: 32px; }
.footer-mark { width: 64px; height: 64px; }
.footer-wordmark svg { width: 176px; margin-left: -1px; }
/* Footer brand side by side again (1 Nov 2026): the wordmark sits to the
   right of the W tile, sized and placed so its capital W is exactly as
   tall as the tile's W and level with it top and bottom. The tile's W
   runs from 49.97% to 99.14% of the tile's height; the wordmark's W is
   51.6 of its 66.4 units tall, starting 1.5 units down. */
.footer-brand { --t: 48px; flex-direction: row; align-items: flex-start; gap: calc(var(--t) * 0.3); margin-bottom: 28px; }
.footer-mark { width: var(--t); height: var(--t); }
.footer-wordmark svg { width: calc(var(--t) * 3.8517); margin: calc(var(--t) * 0.4854) 0 0; }
.footer-brand { width: max-content; } .footer-wordmark { flex: none; }

/* Footer brand on trial (1 Nov 2026), via the toolbar:
   - Logo + wordmark: the designated lockup (default)
   - Logo, large:     the W tile alone, bigger
   - Wordmark, large: the wordmark alone, bigger
   - Giant wordmark:  the wordmark set across the full footer width,
                      just above the bottom line
   - Giant logo:      the lockup kept small, plus a large W tile at the
                      bottom right */
.footer-giant { display: none; color: var(--fg); }
.footer-giant svg { display: block; width: 100%; height: auto; }
:root[data-fb="mark"] .footer-wordmark { display: none; }
:root[data-fb="mark"] .footer-brand { --t: 96px; }
:root[data-fb="word"] .footer-mark { display: none; }
:root[data-fb="word"] .footer-wordmark svg { width: 260px; margin: 0; }
:root[data-fb="giant"] .footer-brand { display: none; }
:root[data-fb="giant"] .footer-giant { display: block; margin: clamp(48px, 6vw, 96px) 0 clamp(24px, 3vw, 40px); }
:root[data-fb="giant-mark"] .footer-giant { display: block; width: clamp(120px, 16vw, 220px); margin: clamp(48px, 6vw, 96px) 0 clamp(24px, 3vw, 40px) auto; aspect-ratio: 180.05 / 179.41; background: url("assets/favicon.svg") center / contain no-repeat; }
:root[data-fb="giant-mark"] .footer-giant svg { display: none; }

.fb-try { position: fixed; z-index: 200; left: 50%; bottom: 16px; transform: translateX(-50%); display: flex; align-items: center; gap: 4px; max-width: calc(100vw - 32px); overflow-x: auto; padding: 6px; background: #fff; color: #14171f; box-shadow: 0 8px 30px rgb(0 0 0 / 0.25); border-radius: 999px; font: 500 13px/1 system-ui, sans-serif; }
.fb-try-label { padding: 0 8px 0 10px; font-weight: 600; white-space: nowrap; }
.fb-try button { padding: 8px 12px; border: 0; border-radius: 999px; background: none; color: inherit; font: inherit; white-space: nowrap; cursor: pointer; }
.fb-try button[aria-pressed="true"] { background: #451b20; color: #fff; }
/* Footer: the W tile alone, large (chosen 1 Nov 2026) */
:root[data-fb="mark"] .footer-brand { --t: 144px; margin-bottom: 36px; }
@media (max-width: 767px) { :root[data-fb="mark"] .footer-brand { --t: 112px; } }
:root[data-fb="mark"] .footer-brand { --t: 208px; margin-bottom: 40px; }
@media (max-width: 767px) { :root[data-fb="mark"] .footer-brand { --t: 152px; } }
/* The W tile is exactly as wide as the footer blurb beside it in the
   same column */
:root[data-fb="mark"] .footer-brand { display: block; width: 100%; }
:root[data-fb="mark"] .footer-mark { display: block; width: 100%; height: auto; aspect-ratio: 180.05 / 179.41; }
/* Lockup maths after the favicon's W moved down (1 Nov 2026): the tile's
   W now runs from 55.54% of the tile's height to its bottom edge */
.footer-wordmark svg { width: calc(var(--t) * 3.4827); margin-top: calc(var(--t) * 0.5425); }

/* Insights: post cards on the home page and the blog --------------------
   Edition's insight cards: a rounded 16:9 photo, a grey category chip and
   the read time in mono, then the title. Three across on desktop.
   Built into the pages by blog/_build.py. */

.insights-opener { display: flex; justify-content: space-between; align-items: center; gap: 24px; }
.insights-all { font-size: var(--text-small); color: var(--fg-muted); text-decoration: none; }
.insights-all:hover { color: var(--fg); }

.insight-list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(56px, 5.8vw, 120px) clamp(20px, 2.9vw, 60px);  /* Edition: 120px rows, 60px columns at 2056 wide */
}
@media (max-width: 960px) { .insight-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) { .insight-list { grid-template-columns: 1fr; } }

.insight-link { display: grid; align-content: start; text-decoration: none; }
.insight-link .insight-meta { margin-top: clamp(18px, 1.4vw, 28px); }
.insight-link .insight-title { margin-top: 16px; }

.insight-img {
  display: block;
  overflow: hidden;
  border-radius: 16px;
  background: var(--surface);
}
.insight-img img {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  transition: transform 0.6s var(--ease-ui);
}
.insight-link:hover .insight-img img { transform: scale(1.03); }

.insight-meta {
  display: flex;
  align-items: center;
  gap: 12px;
  font: 400 var(--text-micro)/1 var(--font-mono);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
}
.insight-meta .chip { padding: 8px 12px; border-radius: 4px; background: color-mix(in srgb, var(--fg) 7%, var(--bg)); color: var(--fg); }
.insight-meta .mins { color: var(--fg); }

.insight-title {
  font-family: var(--font-body);
  font-size: clamp(1.25rem, 1.56vw, 2rem);   /* Edition: 32px at 2056 wide */
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}
.insight-link:hover .insight-title { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 4px; }
