/* ==========================================================================
   JUST AI — Design System v3 "Editorial Monochrome"
   Growth agency for ambitious brands.

   Scope: new homepage (index.html) + shared header/footer.
   The legacy stylesheet (assets/styles.css) is untouched and still serves the
   older pages. Do not merge the two.

   Structure
     1. Tokens
     2. Reset & base
     3. Typography primitives
     4. Layout primitives
     5. Components
     6. Sections
     7. Motion
     8. Responsive
   ========================================================================== */

/* --------------------------------------------------------------------------
   FONTS — self-hosted (Satoshi, Indian Type Foundry free licence · JetBrains
   Mono, SIL OFL). Latin subset only.
   -------------------------------------------------------------------------- */
@font-face{font-family:Satoshi;src:url(fonts/satoshi-400.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:Satoshi;src:url(fonts/satoshi-500.woff2) format("woff2");font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:Satoshi;src:url(fonts/satoshi-700.woff2) format("woff2");font-weight:700;font-style:normal;font-display:swap}
@font-face{font-family:Satoshi;src:url(fonts/satoshi-900.woff2) format("woff2");font-weight:900;font-style:normal;font-display:swap}
@font-face{font-family:"JetBrains Mono";src:url(fonts/jetbrainsmono-400.woff2) format("woff2");font-weight:400 500;font-style:normal;font-display:swap}

/* ==========================================================================
   1. TOKENS
   ========================================================================== */
:root{
  /* -- Brand palette (single source of truth) -- */
  --carbon:#0A0A0A;
  --soft-white:#FAFAF7;
  --light-grey:#F1F1ED;
  --neutral-grey:#D8D8D2;
  --dark-grey:#686864;

  /* -- Accents. Flat only. Never gradients, never glows. -- */
  --signal-orange:#FF5733;
  --electric-blue:#3155FF;
  --bright-yellow:#FFD53D;
  --fresh-green:#39D98A;

  /* Accessible text-on-light variants of the accents (AA on --soft-white) */
  --orange-ink:#C2350F;
  --blue-ink:#2440CC;
  --yellow-ink:#7A5C00;
  --green-ink:#0E7A48;

  /* -- Semantic surface tokens. Overridden by .inverse for dark sections. -- */
  --bg:var(--soft-white);
  --surface:var(--light-grey);
  --fg:var(--carbon);
  --fg-muted:var(--dark-grey);
  --rule:var(--neutral-grey);
  --rule-soft:#E4E4DF;
  /* Borders of interactive controls. WCAG 1.4.11 wants 3:1, which --rule
     (a decorative divider) does not meet. */
  --control-bd:#8E8E88;
  --accent:var(--signal-orange);
  --accent-ink:var(--orange-ink);

  /* -- Typography -- */
  --font-sans:Satoshi,"Helvetica Neue",Helvetica,Arial,sans-serif;
  --font-mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace;

  --fs-display:clamp(2.55rem,7.4vw,7rem);
  --fs-h2:clamp(2rem,4.6vw,3.9rem);
  --fs-h3:clamp(1.4rem,2.4vw,2rem);
  --fs-h4:clamp(1.125rem,1.4vw,1.3rem);
  --fs-lead:clamp(1.0625rem,1.45vw,1.375rem);
  --fs-body:1rem;          /* 16px floor — never smaller for body copy */
  --fs-small:0.9375rem;
  --fs-label:0.75rem;

  --lh-display:0.94;
  --lh-heading:1.06;
  --lh-body:1.62;
  --tr-display:-0.035em;
  --tr-label:0.16em;

  /* -- Spacing -- */
  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px; --s-5:24px;
  --s-6:32px; --s-7:48px; --s-8:64px; --s-9:88px; --s-10:120px;
  --section-y:clamp(72px,9vw,140px);
  --gutter:clamp(20px,4.4vw,56px);
  --container:1360px;
  --header-h:74px;

  /* -- Borders & radii (editorial = near-square) -- */
  --bw:1px;
  --r-0:0;
  --r-1:2px;

  /* -- Motion -- */
  --dur-1:150ms; --dur-2:250ms; --dur-3:400ms;
  --ease:cubic-bezier(.2,.7,.2,1);

  /* -- Breakpoints (documentation; media queries must repeat the value) --
     --bp-xs:480px  --bp-sm:768px  --bp-md:1024px  --bp-lg:1280px  --bp-xl:1600px */
}

/* Dark inversion — applied per-section, not globally. */
.inverse{
  --bg:var(--carbon);
  --surface:#141412;
  --fg:var(--soft-white);
  --fg-muted:#A3A39D;
  --rule:#2A2A27;
  --rule-soft:#1E1E1C;
  --control-bd:#5E5E59;
  --accent-ink:var(--signal-orange);
  background:var(--bg);
  color:var(--fg);
}

/* ==========================================================================
   2. RESET & BASE
   ========================================================================== */
*,*::before,*::after{box-sizing:border-box}
*{margin:0;padding:0}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scroll-padding-top:calc(var(--header-h) + 16px)}
body{
  background:var(--bg);
  color:var(--fg);
  font-family:var(--font-sans);
  font-size:var(--fs-body);
  line-height:var(--lh-body);
  font-weight:400;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
  text-rendering:optimizeLegibility;
}
img,svg,video{display:block;max-width:100%}
img{height:auto}
ul,ol{list-style:none}
a{color:inherit;text-decoration:none}
button,input,select,textarea{font:inherit;color:inherit}
button{background:none;border:0;cursor:pointer}
::selection{background:var(--carbon);color:var(--soft-white)}
.inverse ::selection{background:var(--soft-white);color:var(--carbon)}

/* Focus — always visible, never removed. */
:focus{outline:none}
:focus-visible{
  outline:2px solid var(--signal-orange);
  outline-offset:3px;
  border-radius:var(--r-1);
}
.inverse :focus-visible{outline-color:var(--signal-orange)}

.skip-link{
  position:absolute;left:var(--s-4);top:-100px;z-index:200;
  background:var(--carbon);color:var(--soft-white);
  padding:var(--s-3) var(--s-5);font-weight:700;
  transition:top var(--dur-2) var(--ease);
}
.skip-link:focus-visible{top:var(--s-4)}

.visually-hidden{
  position:absolute!important;width:1px;height:1px;
  margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}

/* ==========================================================================
   3. TYPOGRAPHY PRIMITIVES
   ========================================================================== */
.display{
  font-size:var(--fs-display);
  line-height:var(--lh-display);
  letter-spacing:var(--tr-display);
  font-weight:900;
  text-wrap:balance;
}
h2,.h2{font-size:var(--fs-h2);line-height:var(--lh-heading);letter-spacing:-0.028em;font-weight:900;text-wrap:balance}
h3,.h3{font-size:var(--fs-h3);line-height:1.16;letter-spacing:-0.02em;font-weight:700}
h4,.h4{font-size:var(--fs-h4);line-height:1.25;letter-spacing:-0.012em;font-weight:700}
.lead{font-size:var(--fs-lead);line-height:1.5;color:var(--fg-muted);max-width:56ch;font-weight:400}
.muted{color:var(--fg-muted)}
.small{font-size:var(--fs-small)}

/* Mono label — the editorial "kicker" used throughout. */
.label{
  display:inline-flex;align-items:center;gap:var(--s-3);
  font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:var(--tr-label);text-transform:uppercase;
  color:var(--fg-muted);font-weight:500;
}
.label::before{
  content:"";flex:none;width:9px;height:9px;
  background:var(--accent);
}
.label--plain::before{display:none}

/* Section index, e.g. "01" — sits in the section header's right rail. */
.index{
  font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--fg-muted);
}

/* `.ph` / `.ph-token` — the dashed "awaiting validation" markers — were
   removed on 2026-09-11. All four company metrics are now confirmed, so the
   homepage carries no unvalidated figure and nothing was left to mark.
   If a future claim needs flagging, reinstate a marker rather than publishing
   an un-signed-off number as if it were confirmed. */

/* Development-only banner. Every instance is a piece of content the site is
   waiting on. Deleting the element is the whole removal — no other rule
   depends on it. */
.dev-flag{
  display:inline-flex;align-items:center;gap:8px;align-self:flex-start;
  padding:6px 10px;
  background:#FFEDE6;color:#8A3B12;
  border:1px dashed var(--signal-orange);
  font-family:var(--font-mono);font-size:0.6875rem;
  letter-spacing:.11em;text-transform:uppercase;line-height:1.35;
  text-align:left;
}
.dev-flag::before{content:"";flex:none;width:7px;height:7px;background:var(--signal-orange)}
.inverse .dev-flag{background:#2B1710;color:#FFC7B4}

/* ==========================================================================
   4. LAYOUT PRIMITIVES
   ========================================================================== */
.container{
  width:100%;max-width:var(--container);
  margin-inline:auto;padding-inline:var(--gutter);
}
.section{
  position:relative;
  padding-block:var(--section-y);
  background:var(--bg);
  color:var(--fg);
}
.section--tight{padding-block:clamp(48px,5.5vw,84px)}
.section--surface{background:var(--surface)}
.section + .section:not(.inverse):not(.section--surface){border-top:var(--bw) solid var(--rule-soft)}
/* Consecutive dark bands would otherwise read as one very long section. */
.section.inverse + .section.inverse{border-top:var(--bw) solid var(--rule)}

/* Blueprint column rules — a print-style grid, drawn only on wide viewports.
   Purely decorative, hidden from assistive tech, no motion. */
.section--ruled::before{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  max-width:var(--container);margin-inline:auto;
  padding-inline:var(--gutter);
  background-image:repeating-linear-gradient(to right,var(--rule-soft) 0 1px,transparent 1px calc(100% / 6));
  background-clip:content-box;
  opacity:.7;
}
.section > .container{position:relative;z-index:1}
@media (max-width:1024px){.section--ruled::before{display:none}}

/* Section header: title left, index + optional note right. */
.section-head{
  display:grid;grid-template-columns:minmax(0,1fr);
  gap:var(--s-5);
  padding-bottom:clamp(36px,4.5vw,64px);
}
/* `ch` on the wrapper would resolve against the 16px inherited size, not the
   heading's, and crush every H2 into a ~220px column. Constrain the heading. */
.section-head__title{display:flex;flex-direction:column;gap:var(--s-4);align-items:flex-start}
.section-head__title h2{max-width:14ch}
.section-head__aside{display:flex;flex-direction:column;gap:var(--s-4);align-self:end}
.section-head__aside p{color:var(--fg-muted);max-width:44ch}
@media (min-width:900px){
  .section-head{grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);gap:var(--s-8);align-items:end}
  .section-head__aside{align-items:flex-start}
}

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

/* ==========================================================================
   5. COMPONENTS
   ========================================================================== */

/* -------------------------------- Button -------------------------------- */
.btn{
  --btn-bg:transparent;--btn-fg:var(--fg);--btn-bd:var(--fg);
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s-3);
  min-height:48px;padding:14px 26px;
  background:var(--btn-bg);color:var(--btn-fg);
  border:var(--bw) solid var(--btn-bd);border-radius:var(--r-0);
  font-weight:700;font-size:var(--fs-small);letter-spacing:-0.01em;
  text-align:center;white-space:nowrap;
  transition:background var(--dur-2) var(--ease),color var(--dur-2) var(--ease),
             border-color var(--dur-2) var(--ease),transform var(--dur-1) var(--ease);
}
.btn svg{width:15px;height:15px;flex:none;transition:transform var(--dur-2) var(--ease)}
.btn:hover svg{transform:translate(2px,-2px)}
.btn:active{transform:translateY(1px)}

/* Carbon on Signal Orange is 6.28:1. White would be 3.15:1 — below AA for
   this text size, so the label stays dark and the brand orange stays exact. */
.btn--primary{--btn-bg:var(--signal-orange);--btn-fg:var(--carbon);--btn-bd:var(--signal-orange)}
.btn--primary:hover{--btn-bg:#FF7455;--btn-bd:#FF7455}

.btn--secondary{--btn-bg:transparent;--btn-fg:var(--fg);--btn-bd:var(--control-bd)}
.btn--secondary:hover{--btn-bd:var(--fg);--btn-bg:var(--fg);--btn-fg:var(--bg)}

.btn--solid{--btn-bg:var(--fg);--btn-fg:var(--bg);--btn-bd:var(--fg)}
.btn--solid:hover{--btn-bg:transparent;--btn-fg:var(--fg)}

.btn--lg{min-height:56px;padding:17px 32px;font-size:1rem}
.btn--block{width:100%}

/* Text link with an animated underline. */
.link-arrow{
  display:inline-flex;align-items:center;gap:var(--s-2);
  font-weight:700;font-size:var(--fs-small);
  padding-block:9px;
  border-bottom:2px solid var(--fg);
  transition:gap var(--dur-2) var(--ease),border-color var(--dur-2) var(--ease),color var(--dur-2) var(--ease);
}
.link-arrow:hover{gap:12px;border-color:var(--signal-orange);color:var(--accent-ink)}
.link-arrow svg{width:14px;height:14px}

/* -------------------------------- Header -------------------------------- */
.header{
  position:sticky;top:0;z-index:100;
  background:color-mix(in srgb,var(--soft-white) 88%,transparent);
  -webkit-backdrop-filter:saturate(180%) blur(10px);
  backdrop-filter:saturate(180%) blur(10px);
  border-bottom:var(--bw) solid transparent;
  transition:border-color var(--dur-2) var(--ease),background var(--dur-2) var(--ease);
}
.header.is-stuck{
  background:var(--soft-white);
  border-bottom-color:var(--rule);
}
.header__inner{
  display:flex;align-items:center;gap:var(--s-6);
  min-height:var(--header-h);
}
.brand{display:flex;align-items:center;flex:none;padding-block:6px;min-height:44px}
.brand img{width:104px;height:auto;aspect-ratio:520/159}
.brand__white{display:none}

.nav{display:none;margin-left:auto}
.nav__list{display:flex;align-items:center;gap:clamp(14px,1.8vw,30px)}
.nav__link{
  position:relative;display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-height:44px;min-width:44px;padding-inline:2px;
  font-size:var(--fs-small);font-weight:500;
  transition:color var(--dur-2) var(--ease);
}
.nav__link::after{
  content:"";position:absolute;left:0;right:0;bottom:14px;height:2px;
  background:var(--carbon);transform:scaleX(0);transform-origin:left;
  transition:transform var(--dur-2) var(--ease);
}
.nav__link:hover::after,.nav__link[aria-expanded=true]::after,.nav__link.is-current::after{transform:scaleX(1)}
.nav__link svg{width:12px;height:12px;transition:transform var(--dur-2) var(--ease)}
.nav__link[aria-expanded=true] svg{transform:rotate(180deg)}

.nav__actions{display:none;align-items:center;gap:var(--s-4);margin-left:var(--s-5)}
.nav__commerce{
  display:inline-flex;align-items:center;gap:6px;
  font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:.1em;text-transform:uppercase;color:var(--fg-muted);
  min-height:44px;
  transition:color var(--dur-2) var(--ease);
}
.nav__commerce:hover{color:var(--fg)}

/* Services dropdown */
.nav__item{position:relative}
.nav__panel{
  position:absolute;top:calc(100% + 6px);left:-20px;
  width:min(600px,90vw);
  display:grid;grid-template-columns:1fr 1fr;
  background:var(--soft-white);
  border:var(--bw) solid var(--rule);
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity var(--dur-2) var(--ease),transform var(--dur-2) var(--ease),visibility var(--dur-2);
}
.nav__item:hover .nav__panel,.nav__item:focus-within .nav__panel,.nav__panel.is-open{
  opacity:1;visibility:visible;transform:translateY(0);
}
.nav__panel a{
  display:flex;flex-direction:column;gap:4px;
  padding:var(--s-5);border-right:var(--bw) solid var(--rule-soft);border-bottom:var(--bw) solid var(--rule-soft);
  transition:background var(--dur-2) var(--ease);
}
.nav__panel a:nth-child(2n){border-right:0}
.nav__panel a:nth-last-child(-n+2){border-bottom:0}
.nav__panel a:hover{background:var(--light-grey)}
.nav__panel b{font-size:var(--fs-small);font-weight:700;display:flex;align-items:center;gap:8px}
.nav__panel b::before{content:"";width:8px;height:8px;flex:none;background:var(--dot,var(--signal-orange))}
.nav__panel span{font-size:0.8125rem;color:var(--fg-muted);line-height:1.45}

.menu-btn{
  display:inline-flex;align-items:center;justify-content:center;
  width:44px;height:44px;margin-left:auto;flex:none;
  border:var(--bw) solid var(--rule);
}
.menu-btn svg{width:20px;height:20px}

/* Mobile menu — full-screen panel, single level. */
.mobile-menu{
  position:fixed;inset:0;z-index:99;
  background:var(--soft-white);
  padding:calc(var(--header-h) + var(--s-6)) var(--gutter) var(--s-8);
  display:flex;flex-direction:column;gap:var(--s-5);
  overflow-y:auto;
  visibility:hidden;opacity:0;
  /* Visibility flips instantly on open so the panel is focusable straight
     away, and is delayed on close so the fade-out stays visible. */
  transition:opacity var(--dur-2) var(--ease),visibility 0s var(--dur-2);
}
.mobile-menu.is-open{visibility:visible;opacity:1;transition:opacity var(--dur-2) var(--ease),visibility 0s}
.mobile-menu a{font-size:1.5rem;font-weight:700;letter-spacing:-0.02em;padding-block:10px;min-height:44px}
.mobile-menu .mm-sub{font-size:1.0625rem;font-weight:500;color:var(--fg-muted);padding-left:var(--s-5);position:relative}
.mobile-menu .mm-sub::before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);width:8px;height:8px;background:var(--dot,var(--signal-orange))}
.mobile-menu .mm-group{display:flex;flex-direction:column;gap:2px;padding-block:var(--s-2)}
.mobile-menu hr{height:1px;background:var(--rule);border:0;margin-block:0}
.mobile-menu .btn{margin-top:var(--s-4)}

/* ------------------------------ Logo grid ------------------------------- */
.logo-grid{
  display:grid;grid-template-columns:repeat(2,1fr);
  border-top:var(--bw) solid var(--rule);border-left:var(--bw) solid var(--rule);
}
.logo-grid__cell{
  display:grid;place-items:center;
  padding:var(--s-5) var(--s-5);min-height:126px;
  border-right:var(--bw) solid var(--rule);border-bottom:var(--bw) solid var(--rule);
}
/* Thin-stroke marks (Callebaut, Avril) disappear below ~.75 once flattened to
   a single ink, so the resting opacity carries most of the weight. */
.logo-grid__cell img{
  max-height:var(--logo-h,46px);width:auto;max-width:100%;
  object-fit:contain;
  filter:grayscale(1) contrast(0) brightness(0);
  opacity:.78;
  transition:opacity var(--dur-3) var(--ease);
}
.inverse .logo-grid__cell img{filter:grayscale(1) contrast(0) brightness(0) invert(1);opacity:.68}
.logo-grid__cell:hover img{opacity:1}

/* 15-logo variant (homepage): 2 / 3 / 5 columns, so every row stays full.
   The base .logo-grid 4-column rhythm is kept for work.html's 8 marks. */
.logo-grid--5{grid-template-columns:repeat(2,minmax(0,1fr))}
/* An odd final cell would sit alone against the left edge on mobile; widen the
   cell, not the mark, so the logo keeps its optical size. */
.logo-grid--5 .logo-grid__cell:last-child:nth-child(odd){grid-column:1/-1}

/* ----------------------------- Service row ------------------------------ */
.services{border-top:var(--bw) solid var(--rule)}
.service{
  position:relative;display:block;
  border-bottom:var(--bw) solid var(--rule);
  transition:background var(--dur-3) var(--ease);
}
.service::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:4px;
  background:var(--svc,var(--signal-orange));
  transform:scaleY(0);transform-origin:top;
  transition:transform var(--dur-3) var(--ease);
}
.service:hover,.service:focus-visible{background:var(--surface)}
.service:hover::before,.service:focus-visible::before{transform:scaleY(1)}
.service__inner{
  display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-5);
  padding:clamp(30px,3.6vw,48px) 0 clamp(30px,3.6vw,48px) clamp(16px,2vw,28px);
}
.service__num{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:var(--tr-label);
  color:var(--fg-muted);display:flex;align-items:center;gap:10px;
}
.service__num::before{content:"";width:9px;height:9px;background:var(--svc,var(--signal-orange))}
.service__title{
  font-size:clamp(1.6rem,3.4vw,2.9rem);line-height:1.04;letter-spacing:-0.03em;font-weight:900;
}
.service__meta{display:flex;flex-direction:column;gap:var(--s-4)}
.service__desc{color:var(--fg-muted);max-width:46ch;line-height:1.6}
.service__tags{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);
}
.service__go{
  display:inline-flex;align-items:center;gap:8px;
  font-weight:700;font-size:var(--fs-small);
  border-bottom:2px solid transparent;padding-bottom:2px;
  transition:border-color var(--dur-2) var(--ease);
}
.service__go svg{width:14px;height:14px;transition:transform var(--dur-2) var(--ease)}
.service:hover .service__go,.service:focus-visible .service__go{border-bottom-color:var(--svc,var(--fg))}
.service:hover .service__go svg{transform:translate(3px,-3px)}
@media (min-width:900px){
  .service__inner{
    grid-template-columns:78px minmax(0,1.1fr) minmax(0,1fr) auto;
    gap:var(--s-6);align-items:start;
  }
  /* Optical alignment: the mono number and the link sit on the title's first
     baseline rather than on its box top. */
  .service__num{padding-top:14px}
  .service__meta{padding-top:8px}
  .service__go{padding-top:12px;justify-self:end;align-self:start}
}

/* Removed 2026-09-11 together with the Featured Work section and the
   awaiting-validation proof panel:
     .case / .case__*        — case-study cards
     .work-grid              — their grid
     .proof-panel / .proof-figure / .ledger / .proof-note
                             — the single-figure + "awaiting validation" ledger,
                               replaced by the .metrics row further down
     .quote / .quote__*      — the old testimonial card, replaced by .tcard
   None of these had another consumer at the time they were removed. Note that
   this stylesheet is no longer homepage-only: index, about, contact, work,
   services, the four services/*.html pages and both legal pages all load it,
   so any edit below is a site-wide edit. Add variants; do not retune shared
   rules in place. */

/* ------------------------------ Proof list ------------------------------ */
.proofs{display:grid;grid-template-columns:minmax(0,1fr);border-top:var(--bw) solid var(--rule)}
.proof{
  display:flex;gap:var(--s-5);align-items:flex-start;
  padding-block:clamp(22px,2.6vw,34px);
  border-bottom:var(--bw) solid var(--rule);
}
.proof__body{display:flex;flex-direction:column;gap:var(--s-3)}
.proof__num{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:var(--tr-label);
  color:var(--fg-muted);flex:none;padding-top:6px;width:34px;
}
.proof p{font-size:clamp(1.125rem,2.1vw,1.55rem);line-height:1.24;letter-spacing:-0.02em;font-weight:700;max-width:24ch}
.proof p.proof__sub{
  font-size:var(--fs-small);line-height:1.5;letter-spacing:0;font-weight:400;
  color:var(--fg-muted);max-width:42ch;
}

/* Three-up variant (the contact page's process steps). The base .proofs goes
   two-up at 768px, which would leave a three-item list with an orphan on the
   second row, so this holds one column until there is room for all three.
   The responsive section repeats these selectors — see part 8. */
.proofs--3 .proof p{max-width:20ch}

/* ------------------------------ Insight card ---------------------------- */
.insight{
  display:flex;flex-direction:column;gap:var(--s-3);
  padding-top:var(--s-5);border-top:2px solid var(--fg);
  transition:opacity var(--dur-2) var(--ease);
}
.insight:hover{opacity:.62}
.insight__meta{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;text-transform:uppercase;color:var(--fg-muted)}
.insight h3{font-size:clamp(1.15rem,1.8vw,1.45rem)}

/* --------------------------- Placeholder frame -------------------------- */
/* Used wherever real photography is still missing. Never dress a placeholder
   up as delivered client work. */
.frame{
  position:relative;display:block;
  background:var(--surface);
  border:var(--bw) solid var(--rule);
  overflow:hidden;
}
.frame img{width:100%;height:100%;object-fit:cover}
.frame__cap{
  position:absolute;left:0;bottom:0;
  padding:6px 10px;background:var(--carbon);color:var(--soft-white);
  font-family:var(--font-mono);font-size:0.6875rem;letter-spacing:.12em;text-transform:uppercase;
}

/* ================================ Forms ================================= */
.form{display:grid;gap:var(--s-4)}
.form__row{display:grid;gap:var(--s-4);grid-template-columns:minmax(0,1fr)}
@media (min-width:640px){.form__row--2{grid-template-columns:1fr 1fr}}
.field{display:flex;flex-direction:column;gap:6px}
.field > span{font-size:0.8125rem;font-weight:700;letter-spacing:-0.005em}
.field > span i{font-style:normal;font-weight:400;color:var(--fg-muted)}
.field input,.field select,.field textarea{
  width:100%;min-height:48px;padding:12px 14px;
  background:var(--soft-white);color:var(--carbon);
  border:var(--bw) solid var(--control-bd);border-radius:var(--r-0);
  font-size:var(--fs-body);
  transition:border-color var(--dur-2) var(--ease);
}
.field textarea{min-height:110px;resize:vertical}
.field select{appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A0A0A' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 12px center;background-size:16px;padding-right:38px}
.field input:hover,.field select:hover,.field textarea:hover{border-color:var(--dark-grey)}
.field input:focus-visible,.field select:focus-visible,.field textarea:focus-visible{border-color:var(--carbon)}
.field__error{
  display:none;font-size:0.8125rem;font-weight:700;color:var(--orange-ink);
}
.field__error::before{content:"✕ ";font-weight:700}
.field.has-error input,.field.has-error select,.field.has-error textarea{border-color:var(--orange-ink);border-width:2px}
.field.has-error .field__error{display:block}

/* Helper row under a control: guidance on the left, live length on the right.
   Both are plain text, never a live region — see justai.js. */
.field__foot{display:flex;flex-wrap:wrap;gap:4px var(--s-4);justify-content:space-between;align-items:baseline}
.field__hint{font-size:0.8125rem;color:var(--fg-muted);line-height:1.45}
.field__count{
  font-family:var(--font-mono);font-size:0.6875rem;letter-spacing:.08em;
  color:var(--fg-muted);flex:none;white-space:nowrap;
}

.form__hp{position:absolute!important;left:-9999px;width:1px;height:1px;overflow:hidden}

/* Result region. Green while things are going well, deep orange when they are
   not — a colour swap alone would fail 1.4.1, so the message itself always
   states the outcome in words. */
.form__status{
  padding:var(--s-4);border-left:4px solid var(--fresh-green);
  background:var(--surface);font-size:var(--fs-small);
}
.form__status--error{border-left-color:var(--orange-ink)}
.form__status[hidden]{display:none}
.form__legal{font-size:0.8125rem;color:var(--fg-muted)}

/* ================================ Modal ================================= */
.modal{position:fixed;inset:0;z-index:200;display:none}
.modal.is-open{display:block}
.modal__backdrop{position:absolute;inset:0;background:rgba(10,10,10,.55)}
.modal__card{
  position:absolute;inset:auto 0 0 0;
  max-height:92vh;overflow-y:auto;
  background:var(--soft-white);
  border-top:3px solid var(--carbon);
  padding:var(--s-6) var(--gutter) var(--s-8);
}
@media (min-width:900px){
  .modal__card{
    inset:50% auto auto 50%;transform:translate(-50%,-50%);
    width:min(760px,92vw);max-height:88vh;
    border:var(--bw) solid var(--carbon);border-top-width:3px;
    padding:var(--s-7);
  }
}
.modal__close{
  position:absolute;top:14px;right:14px;
  width:44px;height:44px;display:grid;place-items:center;
  border:var(--bw) solid var(--rule);background:var(--soft-white);
}
.modal__close svg{width:18px;height:18px}
.modal__head{display:flex;flex-direction:column;gap:var(--s-3);padding-bottom:var(--s-5);padding-right:52px}

/* ================================ Footer ================================ */
/* Padding is ~30% below --section-y: the footer sits directly under a dark
   final-CTA band, and the rule is what separates them, not empty space. */
.footer{
  background:var(--carbon);color:var(--soft-white);
  border-top:var(--bw) solid #2A2A27;
  padding-block:clamp(52px,6vw,96px) var(--s-6);
}
.footer__grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-6)}
.footer__brand{display:flex;flex-direction:column;gap:var(--s-4);max-width:34ch}
.footer__brand img{width:124px}
.footer__desc{color:#A3A39D;font-size:var(--fs-small)}
.footer__cols{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s-6) var(--s-5)}
/* Headings share one baseline across all four columns and the brand block. */
.footer__col{display:flex;flex-direction:column;gap:0;align-content:start}
.footer__col h2{
  margin-bottom:var(--s-2);min-height:22px;display:flex;align-items:center;
}
.footer__col h2{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:var(--tr-label);
  text-transform:uppercase;color:#7C7C76;font-weight:500;
}
.footer__col a{font-size:var(--fs-small);color:#D6D6D0;min-height:44px;display:inline-flex;align-items:center;transition:color var(--dur-2) var(--ease)}
.footer__col a:hover{color:var(--soft-white)}
.footer__social{display:flex;gap:var(--s-3)}
.footer__social a{
  width:44px;height:44px;display:grid;place-items:center;
  border:var(--bw) solid #2A2A27;transition:border-color var(--dur-2) var(--ease),background var(--dur-2) var(--ease);
}
.footer__social a:hover{border-color:var(--soft-white);background:#141412}
.footer__social svg{width:18px;height:18px}
.footer__bottom{
  display:flex;flex-wrap:wrap;gap:var(--s-4) var(--s-6);justify-content:space-between;align-items:center;
  margin-top:var(--s-6);padding-top:var(--s-3);border-top:var(--bw) solid #2A2A27;
  font-size:0.8125rem;color:#7C7C76;
}
.footer__bottom nav{display:flex;flex-wrap:wrap;gap:0 var(--s-5)}
.footer__bottom a{display:inline-flex;align-items:center;min-height:44px}
.footer__bottom a:hover{color:var(--soft-white)}
@media (min-width:900px){
  .footer__grid{grid-template-columns:minmax(0,1.05fr) minmax(0,2.15fr);gap:var(--s-8)}
  .footer__cols{grid-template-columns:repeat(4,minmax(0,1fr))}
}

/* ==========================================================================
   6. SECTIONS
   ========================================================================== */

/* -------------------------------- Hero ---------------------------------- */
.hero{padding-top:clamp(28px,3.4vw,52px);padding-bottom:0;border-bottom:var(--bw) solid var(--rule)}
.hero__eyebrow{
  display:flex;flex-wrap:wrap;gap:var(--s-4) var(--s-6);
  align-items:center;justify-content:space-between;
  padding-bottom:clamp(24px,2.8vw,36px);
}
/* Capped below --fs-display: the headline now shares the row with the montage,
   so it is sized to the column rather than to the page. */
.hero__title{font-size:clamp(2.55rem,5.2vw,4.5rem);margin:0}
.hero__title .ln{display:block}
.hero__grid{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(36px,4.5vw,56px);padding-bottom:clamp(44px,5vw,72px)}
.hero__copy{display:flex;flex-direction:column;gap:clamp(20px,2.4vw,30px);max-width:56ch}
.hero__actions{display:flex;flex-wrap:wrap;gap:var(--s-4)}
.hero__proof{
  display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);
}
.hero__proof .sep{width:4px;height:4px;background:var(--rule)}

/* Editorial montage — asymmetric, three frames, no motion. */
/* Below 640px the asymmetric grid would crop each frame hard on a narrow
   column, so the frames stack full-width and keep their natural proportions. */
.montage{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-3)}
.montage .frame{aspect-ratio:auto}
.montage .frame img{height:auto}

/* Below 640px the three previews were stacking at full width, roughly 960px of
   image on a 390px screen — enough to push the headline out of the first view.
   A two-column mosaic with fixed ratios keeps the previews useful and keeps
   the H1 dominant. */
@media (max-width:639px){
  .montage{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s-2)}
  .montage .frame img{height:100%}
  .montage .frame:nth-child(1){grid-column:1 / -1;aspect-ratio:24/13}
  .montage .frame:nth-child(2){aspect-ratio:3/4}
  .montage .frame:nth-child(3){aspect-ratio:439/224;align-self:end}
}

@media (min-width:640px){
  .montage{grid-template-columns:repeat(6,1fr)}
  .montage .frame img{height:100%}
  /* Matches the Be Pretty capture's own 2880x1560 so the storefront is scaled,
     never cropped — at 4/3 the cover crop ate both sides of the headline. */
  .montage .frame:nth-child(1){grid-column:1 / 5;aspect-ratio:24/13}
  .montage .frame:nth-child(2){grid-column:5 / 7;aspect-ratio:3/4;align-self:end}
  /* Matches the dashboard's own 1756x896 so no column is cropped away. */
  .montage .frame:nth-child(3){grid-column:2 / 7;aspect-ratio:439/224}
}

/* A storefront reads from the top down: keep the header and hero, let any
   overflow fall off the bottom rather than slicing through the masthead. */
.frame--site img{object-position:top center}
/* The dashboard is information, not texture — never crop it. */
.frame--dash img{object-fit:contain;background:var(--soft-white)}
@media (min-width:900px){
  .hero__grid{grid-template-columns:minmax(0,1fr) minmax(0,1.04fr);align-items:center;gap:clamp(40px,4.5vw,72px)}
}

/* Marquee-free client strip lives in its own section (see .logo-grid) */

/* ------------------------------- Commerce -------------------------------- */
/* Two columns on desktop: the pitch on the left, the showcase image directly
   opposite it. Not stacked — the reader should never have to scroll past the
   copy to discover the image. */
.commerce{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(32px,4vw,56px);align-items:center}
.commerce__copy{display:flex;flex-direction:column;gap:var(--s-5);min-width:0}
/* The measure is capped on the prose only, so the capability list and the
   buttons below it can still use the full width of the column. */
.commerce__copy .lead{max-width:46ch}

/* The six things the Shopify practice actually does. auto-fit rather than a
   breakpoint: the list sits in a half-width column on desktop and a
   full-width one when stacked, so it has to react to its own container, not
   to the viewport. 260px is the width at which the longest label
   ("Checkout & payment setup") still holds one line. */
.commerce__capabilities{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));gap:0;
  column-gap:var(--s-6);
  list-style:none;margin:0;padding:0;
  border-top:var(--bw) solid var(--rule);
}
.commerce__capabilities li{
  padding:var(--s-4) 0;
  border-bottom:var(--bw) solid var(--rule);
  font-size:1.0625rem;font-weight:500;letter-spacing:-0.01em;
  display:flex;align-items:center;gap:var(--s-3);
}
.commerce__capabilities li::before{
  content:"";flex:none;width:7px;height:7px;background:var(--accent);
}
.commerce__actions{
  display:flex;flex-wrap:wrap;gap:var(--s-4);align-items:center;
  margin-top:var(--s-3);
}

/* Showcase panel, right-hand column. `height:auto` with the artwork's own
   1586:992 ratio means it is scaled, never cropped and never squashed — the
   calm left side and the devices both stay in frame at any column width. */
.commerce__showcase{
  margin:0;
  border:var(--bw) solid var(--rule);
  background:var(--surface);
  overflow:hidden;
}
.commerce__showcase picture{display:block}
.commerce__showcase img{
  display:block;width:100%;height:auto;
  aspect-ratio:1586/992;object-fit:contain;
}
@media (min-width:1000px){
  /* Slightly wider image column: the artwork carries more detail than the
     copy carries width, and the two blocks end up the same visual height. */
  .commerce{grid-template-columns:minmax(0,1fr) minmax(0,1.04fr);gap:clamp(40px,4.4vw,var(--s-8))}
  /* Single-column state used while no showcase image is configured. Declared
     after the two-column rule so it wins without !important. */
  .commerce--solo{grid-template-columns:minmax(0,1fr)}
}
/* Reserved slot for a future showcase image. Stays `hidden` — and carries no
   <img> at all — until a real asset is configured, so nothing is requested and
   nothing can render broken. The ratio is declared here so that dropping the
   image in later costs no layout shift. */
.commerce__media{
  margin:0;aspect-ratio:16/10;
  border:var(--bw) solid var(--rule);background:var(--surface);overflow:hidden;
}
.commerce__media[hidden]{display:none}
.commerce__media img{display:block;width:100%;height:100%;object-fit:cover}
/* Matches the supplied master's own 1536x1024, so the render is scaled whole
   rather than cropped by the default 16:10 frame. */
.commerce__media--3x2{aspect-ratio:3/2}

/* -------------------------------- Metrics -------------------------------- */
/* Four confirmed figures. Plain text in the markup, no counter, so there is no
   frame in which a visitor sees a zero. */
.metrics{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:0;margin:0;
  border-top:var(--bw) solid var(--rule);
}
.metric{
  display:flex;flex-direction:column;gap:var(--s-2);
  padding:clamp(24px,3vw,40px) var(--s-5) clamp(24px,3vw,40px) 0;
  border-bottom:var(--bw) solid var(--rule);
}
.metric__figure{
  font-size:clamp(2.4rem,5.4vw,4rem);font-weight:900;
  letter-spacing:-0.04em;line-height:.94;
}
.metric__label{
  margin:0;font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--fg-muted);
}
.metric__support{
  margin:0;font-size:0.9375rem;line-height:1.45;color:var(--fg-muted);
}
@media (min-width:900px){
  .metrics{grid-template-columns:repeat(4,minmax(0,1fr))}
  .metric{border-bottom:0;border-right:var(--bw) solid var(--rule);padding-left:var(--s-5)}
  .metric:first-child{padding-left:0}
  .metric:last-child{border-right:0}
}
/* Three-figure variant (homepage). Three items in a two-column grid would
   orphan the third, so it holds one column until all three fit in a row. */
.metrics--3{grid-template-columns:minmax(0,1fr)}
@media (min-width:900px){
  .metrics--3{grid-template-columns:repeat(3,minmax(0,1fr))}
}

/* -------------------------------- Founder -------------------------------- */
.founder{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(32px,4vw,64px);align-items:center}
.founder__portrait{position:relative;max-width:420px}
/* 4:5 container. `center top` rather than centre: a portrait cropped from the
   middle loses the head first, and the head is the point. */
.founder__portrait img{width:100%;aspect-ratio:4/5;object-fit:cover;object-position:center top}
.founder__copy{display:flex;flex-direction:column;gap:var(--s-5)}
.founder__role{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:var(--tr-label);
  text-transform:uppercase;color:var(--fg-muted);
}
@media (min-width:900px){.founder{grid-template-columns:minmax(0,.72fr) minmax(0,1.28fr);gap:var(--s-9)}}

/* ----------------------------- Testimonials ------------------------------ *
 * One testimonial in view at a time, advanced only by the user.
 *
 * The horizontal scroller IS the carousel: scroll-snap gives native swipe on
 * touch and native keyboard scrolling on the focusable viewport, so the JS in
 * justai.js only has to call scrollTo() and relabel the status line. If that
 * script never runs, the section degrades to a plain scrollable row rather
 * than a dead widget. There is no autoplay and no timer anywhere.
 * -------------------------------------------------------------------------- */
.tslider{margin-top:clamp(28px,3.4vw,48px)}
.tslider__viewport{
  overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x mandatory;scroll-behavior:smooth;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:none;
}
.tslider__viewport::-webkit-scrollbar{display:none}
.tslider__viewport:focus-visible{outline:2px solid var(--accent);outline-offset:4px}
.tslider__track{
  display:flex;gap:var(--s-5);
  margin:0;padding:0;list-style:none;
}
/* Each slide fills the viewport, so exactly one card is ever in view. The
   script marks it `.is-current` — a hook for later, not something the layout
   depends on, so the section is identical with the script removed. */
.tslide{flex:0 0 100%;min-width:0;scroll-snap-align:start}

/* ---- The card ---- *
 * Deliberately empty. No quotation, no author, no result: none has been
 * supplied. The card reserves the space those will occupy so that filling it
 * later is a content change, not a layout change.
 */
.tcard{
  display:flex;flex-direction:column;gap:var(--s-6);
  height:100%;margin:0;
  padding:clamp(28px,3.4vw,48px);
  border:var(--bw) solid var(--rule);background:var(--surface);
}
/* Reserved logo area — stays empty until the client approves logo usage. */
.tcard__logo{
  display:flex;align-items:center;
  min-height:44px;
}
/* No opacity here: fading muted grey on the light surface drops it under
   4.5:1. If this needs to read quieter, pick a lighter colour that still
   passes rather than reaching for opacity. */
.tcard__logo-note{
  font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:var(--tr-label);text-transform:uppercase;
  color:var(--fg-muted);
}
.tcard__pending{display:flex;flex-direction:column;gap:var(--s-5);flex:1 1 auto}
/* --accent-ink, not --accent: pure Signal Orange only reaches 2.78:1 on this
   light surface, which fails AA for 12px text. The ink token is the deeper
   orange on light fields and the pure accent on .inverse ones. */
.tcard__status{
  margin:0;
  font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:var(--tr-label);text-transform:uppercase;
  color:var(--accent-ink);
}
/* Decorative stand-in for the future quotation. Three bars, not lorem ipsum:
   nothing here can ever be mistaken for something a client said.
   aria-hidden in the markup, so screen readers hear only the status line. */
.tcard__lines{display:flex;flex-direction:column;gap:var(--s-3)}
.tcard__lines span{
  display:block;height:12px;border-radius:2px;
  background:var(--neutral-grey);opacity:.55;
}
.tcard__lines span:nth-child(1){width:100%}
.tcard__lines span:nth-child(2){width:92%}
.tcard__lines span:nth-child(3){width:64%}
.tcard__foot{
  padding-top:var(--s-5);border-top:var(--bw) solid var(--rule);
}
.tcard__company{
  font-size:1.0625rem;font-weight:700;letter-spacing:-0.01em;color:var(--fg);
}

/* ---- Controls ---- */
.tslider__controls{
  display:flex;align-items:center;gap:var(--s-4);
  margin-top:var(--s-5);
}
.tslider__btn{
  display:inline-flex;align-items:center;justify-content:center;
  width:44px;height:44px;flex:none;
  border:var(--bw) solid var(--rule);background:transparent;color:var(--fg);
  cursor:pointer;
  transition:background var(--dur-2) var(--ease),border-color var(--dur-2) var(--ease),color var(--dur-2) var(--ease);
}
.tslider__btn svg{width:18px;height:18px}
.tslider__btn:hover:not(:disabled){background:var(--fg);border-color:var(--fg);color:var(--bg)}
.tslider__btn:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.tslider__btn:disabled{opacity:.32;cursor:not-allowed}
.tslider__status{
  margin:0;
  font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--fg-muted);
}

/* ---- The published state ---- *
 * Written ahead of time so that filling a card is a CONTENT change and not a
 * design job. Nothing below matches anything on the page today: there is no
 * .tcard__quote, .tcard__name or .tcard__role in the markup, because there is
 * no approved quotation to put in one.
 *
 * When a quote arrives, swap that card's .tcard__pending block for:
 *   <blockquote class="tcard__quote">…</blockquote>
 * and add to .tcard__foot:
 *   <b class="tcard__name">…</b><span class="tcard__role">…</span>
 * The card keeps its height and rhythm — nothing else has to move.
 */
.tcard__quote{
  flex:1 1 auto;margin:0;
  font-size:clamp(1.0625rem,1.6vw,1.3rem);line-height:1.45;
  letter-spacing:-0.015em;font-weight:500;
}
.tcard__quote::before{content:"“"}
.tcard__quote::after{content:"”"}
.tcard__name{display:block;font-size:var(--fs-small);font-weight:700}
.tcard__role{display:block;font-size:0.8125rem;color:var(--fg-muted)}
/* Once a logo is approved it goes in .tcard__logo. Capped so a wide wordmark
   and a square mark occupy the same optical weight. */
.tcard__logo img{max-height:34px;max-width:150px;width:auto;height:auto;object-fit:contain}

@media (min-width:900px){
  /* One featured testimonial, centred and capped so a wide viewport does not
     stretch an empty card across 1400px. */
  .tslide{flex-basis:100%}
  .tcard{max-width:760px}
  .tcard__logo{min-height:56px}
  .tcard__logo img{max-height:40px;max-width:180px}
}
@media (prefers-reduced-motion:reduce){
  .tslider__viewport{scroll-behavior:auto}
}

/* ============================= Contact page ============================== *
 * Everything below is used by contact.html only. It adds no new colours, no
 * new type sizes and no new motion — it arranges existing tokens.
 * -------------------------------------------------------------------------- */

/* The contact hero reuses .hero / .hero__grid. The homepage centres its two
   columns against a montage; here the right column is a tall form, so both
   columns hang from the top instead. */
.hero--form .hero__copy{gap:clamp(20px,2.2vw,28px)}
@media (min-width:900px){
  .hero--form .hero__grid{grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);align-items:start}
}

/* Compact facts under the hero copy. Bordered rows rather than a bullet list:
   same editorial rhythm as .commerce__capabilities, one line each. */
.factlist{border-top:var(--bw) solid var(--rule)}
.factlist li{
  display:flex;align-items:center;gap:var(--s-3);
  padding:11px 0;border-bottom:var(--bw) solid var(--rule);
  font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:.1em;text-transform:uppercase;color:var(--fg-muted);
  line-height:1.5;
}
.factlist li::before{content:"";flex:none;width:7px;height:7px;background:var(--accent)}

/* Direct contact pair in the hero. Stacked so each is a full-width 44px
   target on a phone. */
.contact-direct{display:flex;flex-direction:column;gap:var(--s-3);align-items:flex-start}
.contact-direct__link{
  display:inline-flex;align-items:center;gap:var(--s-3);
  min-height:44px;font-size:1.0625rem;font-weight:700;letter-spacing:-0.015em;
  border-bottom:2px solid var(--fg);padding-bottom:2px;
  transition:border-color var(--dur-2) var(--ease),color var(--dur-2) var(--ease);
}
.contact-direct__link:hover{border-color:var(--signal-orange);color:var(--accent-ink)}
.contact-direct__link svg{width:16px;height:16px;flex:none}

/* The form card. A framed panel so the hero reads as "message | form" rather
   than as one long column of controls. */
.form-panel{
  background:var(--surface);
  border:var(--bw) solid var(--rule);
  border-top:3px solid var(--carbon);
  padding:clamp(24px,3vw,40px);
}
.form-panel__head{display:flex;flex-direction:column;gap:var(--s-3);padding-bottom:var(--s-5)}
.form-panel__head h2{font-size:var(--fs-h3);line-height:1.16;letter-spacing:-0.02em;font-weight:700;max-width:none}
/* Inputs sit on --surface here, so they need to stay lighter than their field
   to read as controls. */
.form-panel .field input,.form-panel .field select,.form-panel .field textarea{background:var(--soft-white)}

/* Dark direct-contact band. Copy left, the three details right. */
.contact-band{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(28px,3.5vw,56px)}
.contact-band__copy{display:flex;flex-direction:column;gap:var(--s-4);max-width:46ch}
.contact-band__details{
  display:flex;flex-direction:column;gap:0;
  border-top:var(--bw) solid var(--rule);
}
.contact-band__row{
  display:flex;flex-direction:column;gap:2px;
  padding:var(--s-4) 0;border-bottom:var(--bw) solid var(--rule);
}
.contact-band__row dt{
  font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--fg-muted);
}
.contact-band__row dd{
  margin:0;font-size:1.0625rem;font-weight:700;letter-spacing:-0.015em;
}
.contact-band__row dd a{
  display:inline-flex;align-items:center;min-height:44px;
  border-bottom:2px solid transparent;
  transition:border-color var(--dur-2) var(--ease)}
.contact-band__row dd a:hover{border-bottom-color:var(--signal-orange)}
@media (min-width:900px){
  .contact-band{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--s-8);align-items:start}
}

/* --------------------------------- FAQ ----------------------------------- *
 * Button + panel, wired with aria-expanded / aria-controls in justai.js.
 * The markup ships expanded so the answers are readable with the script
 * absent; the script collapses them on init. Height is not animated: a
 * transition on auto height either janks or needs a fixed max-height that
 * clips longer answers.
 * -------------------------------------------------------------------------- */
.faq{border-top:var(--bw) solid var(--rule);max-width:78ch}
.faq__item{border-bottom:var(--bw) solid var(--rule)}
.faq__q{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s-5);
  width:100%;min-height:64px;padding:var(--s-4) 0;
  text-align:left;font-size:1.0625rem;font-weight:700;letter-spacing:-0.015em;
  color:var(--fg);cursor:pointer;
  transition:color var(--dur-2) var(--ease);
}
.faq__q:hover{color:var(--accent-ink)}
/* Plus/minus drawn from two rules, so there is no icon file and no font
   dependency. The vertical bar collapses when the panel opens. */
.faq__icon{
  position:relative;flex:none;width:20px;height:20px;
  border:var(--bw) solid var(--control-bd);
}
.faq__icon::before,.faq__icon::after{
  content:"";position:absolute;top:50%;left:50%;
  width:9px;height:var(--bw);background:currentColor;
  transform:translate(-50%,-50%);
}
.faq__icon::after{transform:translate(-50%,-50%) rotate(90deg);transition:opacity var(--dur-2) var(--ease)}
.faq__q[aria-expanded="true"] .faq__icon::after{opacity:0}
.faq__a{padding:0 0 var(--s-5)}
.faq__a p{color:var(--fg-muted);max-width:64ch;line-height:1.6}
.faq__a[hidden]{display:none}

/* ------------------------------- Final CTA -------------------------------- */
.final-cta{display:flex;flex-direction:column;gap:var(--s-6);align-items:flex-start;max-width:60ch}
.final-cta__actions{display:flex;flex-wrap:wrap;gap:var(--s-4);align-items:center}

/* ---------------------------- Generic grids ------------------------------ */
.grid-3{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-6)}
@media (min-width:768px){.grid-3{grid-template-columns:repeat(3,minmax(0,1fr))}}

/* ==========================================================================
   GROWTH STRATEGY PAGE (services/growth-strategy.html)
   Everything below is scoped to .page-growth or to a class only that page
   uses, so adding it cannot alter the homepage or the contact page.
   ========================================================================== */

/* Page accent. The brief specifies #FF5A36 for Growth Strategy; the design
   system's --signal-orange is #FF5733. The two are three hex points apart and
   indistinguishable on screen, so rather than run both on one page we remap
   the token for this page only. Result: exactly one orange here, and
   consolidating the site onto a single value later is a one-line edit.
   --accent-ink is deliberately NOT remapped: #FF5A36 on the off-white
   background is 2.98:1, below AA for text, so orange *text* keeps the
   accessible ink variant while fills, rules and nodes use the brand orange. */
.page-growth{--signal-orange:#FF5A36;--accent:#FF5A36}

/* Breadcrumb — small, quiet, above the H1. */
.crumbs{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;text-transform:uppercase;color:var(--fg-muted)}
.crumbs ol{display:flex;flex-wrap:wrap;align-items:center;gap:0 var(--s-2)}
.crumbs li{display:flex;align-items:center;gap:var(--s-2)}
.crumbs li + li::before{content:"/";color:var(--rule)}
/* Crumb type stays small, but the tap area must still clear 44px. Vertical
   padding grows the hit box; the matching negative margin keeps the crumb line
   visually as tight as the type size implies, so nothing moves on screen. */
.crumbs a{display:inline-block;padding:12px 0;margin:-12px 0;border-bottom:var(--bw) solid transparent;transition:border-color var(--dur-2) var(--ease)}
.crumbs a:hover{border-bottom-color:var(--accent)}
.crumbs [aria-current]{color:var(--fg)}

/* ------------------- Hero: copy left, diagram right --------------------- */
.hero--diagram .hero__copy{gap:clamp(20px,2.2vw,28px);max-width:52ch}
/* The shared hero splits into two columns well before 1100px. That is right
   for a hero whose second column is an image, but the roadmap here is a
   three-column table: in a half-width column at 1024px every cell wraps onto
   two lines. Below 1100px the document takes the full width instead. */
@media (max-width:1099px){
  .hero--diagram .hero__grid{grid-template-columns:minmax(0,1fr)}
}
@media (min-width:1100px){
  /* Centred, not top-aligned: the hero copy is taller than the document, and
     hanging the document off the top leaves a visible void under it. */
  .hero--diagram .hero__grid{grid-template-columns:minmax(0,.95fr) minmax(0,1.05fr);gap:clamp(40px,4vw,72px);align-items:center}
}

/* ====================== Growth Strategy components ======================
   Everything prefixed .gs- is used only by services/growth-strategy.html.
   The prefix exists because the four service pages share .situations,
   .dlist, .chain, .fitlist, .roadmap and .wcard — changing any of those to
   suit this page would silently retune three other pages.

   The visuals below are documents, not pictures: real text in real elements,
   so they are selectable, translatable, readable by a screen reader and they
   scale with the user's font size. No information is carried by colour or by
   hover alone — the accent only ever emphasises something the text already
   says (WCAG 1.4.1). Nothing here animates.
   ======================================================================== */

/* The shared shell. One frame, one head, then whatever shape the document
   actually is. Used full-size in the hero and denser in the deliverables. */
.gs-doc{border:var(--bw) solid var(--rule);background:var(--bg)}
.gs-doc__head{
  display:flex;flex-wrap:wrap;gap:var(--s-2) var(--s-4);
  justify-content:space-between;align-items:baseline;
  padding:var(--s-4) var(--s-5);border-bottom:var(--bw) solid var(--rule);
}
.gs-doc__title{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.14em;text-transform:uppercase;color:var(--fg)}
.gs-doc__flag{font-family:var(--font-mono);font-size:0.6875rem;letter-spacing:.1em;text-transform:uppercase;color:var(--fg-muted)}
.gs-doc--preview .gs-doc__head{padding:var(--s-3) var(--s-4)}

/* ------------------------------- Tables --------------------------------- */
.gs-table{width:100%;border-collapse:collapse;text-align:left}
.gs-table th{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.12em;
  text-transform:uppercase;color:var(--fg-muted);font-weight:400;
  padding:var(--s-3) var(--s-3);border-bottom:var(--bw) solid var(--rule);
}
.gs-table td{padding:var(--s-5) var(--s-4);border-bottom:var(--bw) solid var(--rule-soft);font-size:var(--fs-small);line-height:1.45;vertical-align:top}
.gs-table tbody tr:last-child td{border-bottom:0}
.gs-table th:first-child,.gs-table td:first-child{padding-left:var(--s-5)}
.gs-table th:last-child,.gs-table td:last-child{padding-right:var(--s-5)}
.gs-table b{font-weight:700}
/* First column carries the row's subject, so it gets the rail. */
.gs-table tbody td:first-child{box-shadow:inset 2px 0 0 0 var(--rule)}
.gs-table tbody tr:first-child td:first-child{box-shadow:inset 2px 0 0 0 var(--accent)}

.gs-table--compact th{padding:var(--s-2) var(--s-2);font-size:0.6875rem}
.gs-table--compact td{padding:var(--s-3) var(--s-2);font-size:0.8125rem}
.gs-table--compact th:first-child,.gs-table--compact td:first-child{padding-left:var(--s-4)}
.gs-table--compact th:last-child,.gs-table--compact td:last-child{padding-right:var(--s-4)}

/* Priority token. The word is the information; the border is emphasis. */
.gs-pri{
  display:inline-block;font-family:var(--font-mono);font-size:0.625rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--fg-muted);
  border:var(--bw) solid var(--control-bd);padding:4px 7px;white-space:nowrap;
}
.gs-pri--high{color:var(--accent-ink);border-color:var(--accent)}

/* Below 720px a three-column table cannot hold its columns without either
   scrolling sideways or shrinking the type, so each row becomes a stacked
   group and the column name is reprinted from data-col. The head is hidden
   because it would then be a heading for nothing. Only applied to the full
   table: the compact one is short enough to stay a table at 390px. */
@media (max-width:719px){
  .gs-table:not(.gs-table--compact),
  .gs-table:not(.gs-table--compact) tbody,
  .gs-table:not(.gs-table--compact) tr,
  .gs-table:not(.gs-table--compact) td{display:block;width:100%}
  .gs-table:not(.gs-table--compact) thead{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
  .gs-table:not(.gs-table--compact) tbody tr{padding:var(--s-4) var(--s-5);border-bottom:var(--bw) solid var(--rule)}
  .gs-table:not(.gs-table--compact) tbody tr:last-child{border-bottom:0}
  .gs-table:not(.gs-table--compact) tbody tr:first-child{box-shadow:inset 2px 0 0 0 var(--accent)}
  .gs-table:not(.gs-table--compact) td{padding:4px 0;border-bottom:0;box-shadow:none}
  .gs-table:not(.gs-table--compact) tbody td:first-child{box-shadow:none}
  .gs-table:not(.gs-table--compact) td::before{
    content:attr(data-col);display:block;
    font-family:var(--font-mono);font-size:0.625rem;letter-spacing:.12em;
    text-transform:uppercase;color:var(--fg-muted);margin-bottom:2px;
  }
}

/* ------------------------- Client situations ---------------------------- */
.gs-cases{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-6)}
.gs-case{display:flex;flex-direction:column;gap:var(--s-3);border-top:3px solid var(--rule);padding-top:var(--s-4)}
.gs-case__num{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.16em;color:var(--accent-ink)}
.gs-case h3{font-size:var(--fs-h4);letter-spacing:-0.02em;line-height:1.2}
.gs-case p{color:var(--fg-muted);line-height:1.6;max-width:42ch}
@media (min-width:768px){
  .gs-cases{grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-7)}
}

/* ---------------------------- Deliverables ------------------------------ */
.gs-deliverables{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-7)}
.gs-deliverable{display:flex;flex-direction:column;gap:var(--s-4)}
/* The four previews are different shapes and so different heights. Letting
   the frame absorb the slack keeps two side-by-side frames the same height,
   which keeps the headings under them on one line. */
.gs-deliverable .gs-doc--preview{flex:1}
.gs-deliverable h3{font-size:var(--fs-h4);letter-spacing:-0.02em;display:flex;flex-wrap:wrap;align-items:baseline;gap:10px;line-height:1.2}
.gs-deliverable__num{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.16em;color:var(--fg-muted)}
.gs-deliverable p{color:var(--fg-muted);line-height:1.6;max-width:44ch}
@media (min-width:900px){
  .gs-deliverables{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s-8) var(--s-7)}
}

/* Preview 01 — priority matrix. The two axis words are aria-hidden because
   the four quadrant labels already name the decision in full text. */
.gs-matrix{
  display:grid;grid-template-columns:auto minmax(0,1fr);
  gap:var(--s-2) var(--s-3);padding:var(--s-4) var(--s-4) var(--s-4);
}
.gs-matrix__y,.gs-matrix__x{font-family:var(--font-mono);font-size:0.625rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg-muted)}
.gs-matrix__y{grid-column:1;grid-row:1;writing-mode:vertical-rl;transform:rotate(180deg);align-self:center}
.gs-matrix__x{grid-column:2;grid-row:2;text-align:center}
/* 1px gaps drawn by the parent background, so the four cells read as one
   grid without eight overlapping borders. */
.gs-matrix__grid{
  grid-column:2;grid-row:1;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--bw);background:var(--rule);border:var(--bw) solid var(--rule);
}
.gs-quad{display:flex;flex-direction:column;gap:3px;padding:var(--s-3);background:var(--bg);min-height:72px}
.gs-quad--first{background:var(--surface)}
.gs-quad__tag{font-family:var(--font-mono);font-size:0.625rem;letter-spacing:.1em;text-transform:uppercase;color:var(--fg)}
.gs-quad--first .gs-quad__tag{color:var(--accent-ink)}
.gs-quad__ex{font-size:0.75rem;line-height:1.35;color:var(--fg-muted)}

/* Preview 02 — positioning brief. */
.gs-brief{padding:var(--s-2) var(--s-4) var(--s-4)}
.gs-brief__row{display:flex;flex-direction:column;gap:2px;padding:var(--s-3) 0;border-bottom:var(--bw) solid var(--rule-soft)}
.gs-brief__row:last-child{border-bottom:0;padding-bottom:0}
.gs-brief dt{font-family:var(--font-mono);font-size:0.625rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg-muted)}
.gs-brief dd{font-size:0.8125rem;line-height:1.45}

/* Preview 04 — 90-day phases on a single rail. */
.gs-phases{display:flex;flex-direction:column;gap:var(--s-4);padding:var(--s-4)}
.gs-phase{position:relative;display:flex;flex-direction:column;gap:3px;padding-left:var(--s-5)}
.gs-phase::before{content:"";position:absolute;left:0;top:.35em;width:9px;height:9px;background:var(--rule)}
.gs-phase:first-child::before{background:var(--accent)}
/* The rail segment between one marker and the next. */
.gs-phase::after{content:"";position:absolute;left:4px;top:calc(.35em + 9px);bottom:calc(-1 * var(--s-4));width:var(--bw);background:var(--rule)}
.gs-phase:last-child::after{display:none}
.gs-phase__days{font-family:var(--font-mono);font-size:0.625rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg-muted)}
.gs-phase__what{font-size:0.8125rem;line-height:1.45}

.gs-note{
  margin-top:var(--s-6);padding-left:var(--s-4);border-left:2px solid var(--rule);
  font-size:var(--fs-small);color:var(--fg-muted);max-width:56ch;
}

/* ------------------------------- Process -------------------------------- */
.gs-steps{display:grid;grid-template-columns:minmax(0,1fr);border-top:var(--bw) solid var(--rule)}
.gs-step{padding:var(--s-6) 0;border-bottom:var(--bw) solid var(--rule);display:flex;flex-direction:column;gap:var(--s-3)}
.gs-step__num{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.16em;color:var(--accent-ink)}
.gs-step p{color:var(--fg-muted);line-height:1.6;max-width:40ch}
@media (min-width:900px){
  .gs-steps{grid-template-columns:repeat(3,minmax(0,1fr));column-gap:var(--s-7);border-top:0}
  .gs-step{border-bottom:0;border-top:3px solid var(--rule);padding:var(--s-5) 0 0}
  .gs-step:first-child{border-top-color:var(--accent)}
}

/* Handoff to the other three services. Three links, not a second section. */
.gs-handoff{margin-top:var(--s-8);padding-top:var(--s-6);border-top:var(--bw) solid var(--rule);display:flex;flex-direction:column;gap:var(--s-3);max-width:62ch}
.gs-handoff > p{color:var(--fg-muted);line-height:1.6}
.gs-handoff__links{display:flex;flex-wrap:wrap;gap:var(--s-2) var(--s-5)}
/* Padding grows the tap target past 44px; the matching negative margin keeps
   the row visually tight. The underline is drawn by text-decoration rather
   than a border, so it stays against the text and not at the padding edge. */
.gs-handoff__links a{
  display:inline-block;padding:12px 0;margin:-12px 0;color:var(--fg);
  text-decoration:underline;text-decoration-thickness:var(--bw);
  text-underline-offset:5px;text-decoration-color:var(--control-bd);
  transition:text-decoration-color var(--dur-2) var(--ease);
}
.gs-handoff__links a:hover{text-decoration-color:var(--accent)}

/* ---------------------- Situations (4, bordered 2x2) --------------------- */
.situations{display:grid;grid-template-columns:minmax(0,1fr);border-top:var(--bw) solid var(--rule)}
.situation{padding:var(--s-6) 0;border-bottom:var(--bw) solid var(--rule);display:flex;flex-direction:column;gap:var(--s-3)}
.situation h3{font-size:var(--fs-h4);letter-spacing:-0.02em;display:flex;align-items:center;gap:10px}
.situation h3::before{content:"";width:8px;height:8px;flex:none;background:var(--accent)}
.situation p{color:var(--fg-muted);max-width:46ch;line-height:1.6}
@media (min-width:768px){
  .situations{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--s-8)}
}

/* ---------------- Numbered steps (dark section, 4 stages) ---------------- */
.steps{display:grid;grid-template-columns:minmax(0,1fr);border-top:var(--bw) solid var(--rule)}
.step{padding:var(--s-6) 0;border-bottom:var(--bw) solid var(--rule);display:flex;flex-direction:column;gap:var(--s-4)}
.step__num{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.16em;color:var(--accent-ink)}
.step h3{font-size:var(--fs-h4);letter-spacing:-0.02em}
.step p{color:var(--fg-muted);line-height:1.6}
.step__tags{display:flex;flex-wrap:wrap;gap:6px}
.step__tags li{
  font-family:var(--font-mono);font-size:0.6875rem;letter-spacing:.08em;text-transform:uppercase;
  color:var(--fg-muted);border:var(--bw) solid var(--rule);padding:5px 9px;
}
@media (min-width:900px){
  .steps{grid-template-columns:repeat(4,minmax(0,1fr));column-gap:var(--s-6)}
  .step{border-bottom:0;border-top:3px solid var(--rule);padding-top:var(--s-5)}
  /* The active rail: stage 01 is where the engagement begins. */
  .step:first-child{border-top-color:var(--accent)}
}

/* ------------------------- Deliverables (6 rows) ------------------------- */
.dlist{display:grid;grid-template-columns:minmax(0,1fr);border-top:var(--bw) solid var(--rule)}
.dlist__item{
  position:relative;padding:var(--s-5) 0 var(--s-5) var(--s-5);
  border-bottom:var(--bw) solid var(--rule);
  display:flex;flex-direction:column;gap:var(--s-2);
}
.dlist__item::before{
  content:"";position:absolute;left:0;top:var(--s-5);bottom:var(--s-5);width:2px;
  background:var(--rule);transition:background var(--dur-2) var(--ease);
}
.dlist__item:hover::before,.dlist__item:focus-within::before{background:var(--accent)}
.dlist__num{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.16em;color:var(--fg-muted)}
.dlist__item h3{font-size:1.0625rem;letter-spacing:-0.015em}
.dlist__item p{color:var(--fg-muted);font-size:var(--fs-small);line-height:1.55;max-width:44ch}
@media (min-width:900px){
  .dlist{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--s-8)}
}

/* ------------------ Diagram 2 — 90-day illustrative roadmap -------------- */
.roadmap{border:var(--bw) solid var(--rule);padding:var(--s-5)}
.roadmap__head{display:flex;flex-direction:column;gap:var(--s-3);padding-bottom:var(--s-6)}
.roadmap__flag{
  align-self:flex-start;font-family:var(--font-mono);font-size:0.6875rem;letter-spacing:.12em;
  text-transform:uppercase;border:var(--bw) solid var(--control-bd);padding:6px 10px;color:var(--fg-muted);
}
.roadmap__grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-5)}
.phase{display:flex;flex-direction:column;gap:var(--s-3);border-top:3px solid var(--rule);padding-top:var(--s-4)}
.phase:first-child{border-top-color:var(--accent)}
.phase__days{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.14em;color:var(--fg-muted)}
.phase h4{font-size:var(--fs-h4);letter-spacing:-0.02em}
.phase ul{display:flex;flex-direction:column;gap:10px}
.phase li{position:relative;padding-left:18px;font-size:var(--fs-small);color:var(--fg-muted);line-height:1.5}
.phase li::before{content:"";position:absolute;left:0;top:.55em;width:7px;height:var(--bw);background:var(--control-bd)}
@media (min-width:900px){
  .roadmap{padding:var(--s-7)}
  .roadmap__grid{grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-7)}
}

/* ------------- Diagram 3 — Strategy to execution (4 linked blocks) ------- */
.chain{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-3)}
.chain__link{
  position:relative;display:flex;flex-direction:column;gap:var(--s-2);
  padding:var(--s-5);border:var(--bw) solid var(--rule);background:var(--bg);
  transition:border-color var(--dur-2) var(--ease),background var(--dur-2) var(--ease);
}
a.chain__link:hover{border-color:var(--accent);background:var(--surface)}
.chain__step{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.14em;color:var(--fg-muted)}
.chain__name{font-weight:700;font-size:1.0625rem;letter-spacing:-0.015em;line-height:1.2}
.chain__role{font-size:0.8125rem;color:var(--fg-muted);line-height:1.5}
/* The current page is a block, not a link: marked in text as well as in
   colour so the state is not carried by the accent alone. */
.chain__link--current{border-color:var(--accent);border-top:3px solid var(--accent)}
.chain__here{font-family:var(--font-mono);font-size:0.6875rem;letter-spacing:.1em;text-transform:uppercase;color:var(--accent-ink)}
@media (min-width:768px){.chain{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s-4)}}
@media (min-width:1100px){
  .chain{grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--s-6)}
  /* Arrow connectors sit in the gap. Decorative only — the reading order of
     the blocks already states the sequence. */
  .chain__link:not(:last-child)::after{
    content:"";position:absolute;top:50%;right:calc(-1 * var(--s-6));
    width:var(--s-6);height:var(--bw);background:var(--rule);
  }
}

/* ----------------------------- Good fit list ---------------------------- */
.fitlist{display:grid;grid-template-columns:minmax(0,1fr);border-top:var(--bw) solid var(--rule)}
.fitlist li{padding:var(--s-4) 0;border-bottom:var(--bw) solid var(--rule);display:flex;gap:var(--s-3);align-items:flex-start;line-height:1.5}
.fitlist li::before{content:"";flex:none;width:7px;height:7px;margin-top:.5em;background:var(--accent)}
@media (min-width:900px){.fitlist{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--s-8)}}
.note{
  margin-top:var(--s-6);padding:var(--s-5);background:var(--surface);
  border-left:3px solid var(--accent);max-width:62ch;
}
.note p{color:var(--fg-muted)}

/* --------------------------- Engagement formats -------------------------- */
.wcard{display:flex;flex-direction:column;gap:var(--s-3);padding-top:var(--s-5);border-top:3px solid var(--rule)}
.wcard h3{font-size:var(--fs-h4);letter-spacing:-0.02em}
.wcard p{color:var(--fg-muted);line-height:1.6}

/* --------------------- Conversion band (dark, with form) ----------------- */
.formband{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(32px,4vw,64px);align-items:start}
.formband__copy{display:flex;flex-direction:column;gap:var(--s-5);max-width:46ch}
@media (min-width:1000px){
  .formband{grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr)}
}

/* Dark-section form corrections. The control fills stay light on purpose, so
   only the parts that inherit dark tokens need fixing:
     - the select chevron is a hard-coded black SVG; on a light control inside
       a dark section it still reads, so it is left alone;
     - --orange-ink (#C2350F) is an on-light colour: 2.6:1 on carbon. Error
       text and the status rule switch to the brand orange, 5.8:1 on carbon. */
.inverse .field__error{color:var(--signal-orange)}
.inverse .form__status--error{border-left-color:var(--signal-orange)}

/* ==========================================================================
   PERFORMANCE MARKETING PAGE (services/performance-marketing.html)

   Additive. Every rule below is scoped to .page-perf or to a class that only
   this page uses, so the homepage, contact page and Growth Strategy page are
   untouched.

   Page accent — the brief specifies #3157FF. The global token
   --electric-blue is #3155FF, two hex digits away. Rather than edit a global
   that four pages already use, the brief's blue is scoped here. Consolidating
   later is a one-line edit.

   Contrast, measured rather than assumed:
     #3157FF on --soft-white  5.10:1  → passes AA for text
     #3157FF on --carbon      3.71:1  → fails AA text, passes 3:1 for UI
     #6F8CFF on --carbon      6.48:1  → passes AA for text
     --carbon on #3157FF      3.71:1  → fails AA, so the CTA label is NOT black
     --soft-white on #3157FF  5.10:1  → passes AA, so the CTA label is off-white
     --soft-white on #2445D8  6.88:1  → passes AA, the CTA hover
   So unlike the orange page, blue text IS allowed on the light background and
   --accent-ink can be the brand blue itself. On dark sections the brand blue
   is kept for fills, rules and borders, and text switches to the light blue.

   NOTE: --signal-orange, not --accent, is the primitive the components
   actually read (.btn--primary, focus outlines, dot markers, hover rules all
   reference it directly). Overriding --accent alone left every CTA orange on a
   blue page. The Growth Strategy page sets --signal-orange for the same
   reason; this page follows it, so a single accent governs the whole page.
   ========================================================================== */
.page-perf{
  --electric-blue:#3157FF;--blue-light:#6F8CFF;
  --signal-orange:#3157FF;--accent:#3157FF;--accent-ink:#3157FF;
}
/* The primary CTA inverts against blue: black on #3157FF is 3.71:1 and fails.
   The hover darkens rather than lightens — a lighter blue would drop the label
   below AA (off-white on #6F8CFF is only 2.88:1). */
.page-perf .btn--primary{--btn-fg:var(--soft-white)}
.page-perf .btn--primary:hover{--btn-bg:#2445D8;--btn-bd:#2445D8}
.page-perf .inverse{--accent-ink:var(--blue-light)}
/* On dark, the brand blue focus ring is only 3.71:1. It clears the 3:1 asked of
   a non-text indicator, but the lighter blue at 6.48:1 is unmistakable, and a
   focus ring is the one thing that must never be subtle. */
.page-perf .inverse :focus-visible{outline-color:var(--blue-light)}
.page-perf .inverse .field__error{color:var(--blue-light)}
.page-perf .inverse .form__status--error{border-left-color:var(--blue-light)}

/* ----------------- Hero: copy beside one account capture ------------------ */
/* Single column until there is room for the capture to stay legible beside the
   headline. Below that the figure drops under the copy at full width, which is
   the only place a 1756px table reads on a narrow screen. */
.hero--proof .hero__copy{gap:clamp(20px,2.2vw,28px);max-width:54ch}
@media (min-width:1000px){
  .hero--proof .hero__grid{
    grid-template-columns:minmax(0,.95fr) minmax(0,1.05fr);
    gap:clamp(40px,4vw,64px);align-items:center;
  }
}

/* -------------------------- Account capture ------------------------------- */
/* The capture in an editorial window: a rule, a label bar and the image. No
   perspective, no shadow, no browser chrome pretending to be a browser. */
.acct{border:var(--bw) solid var(--rule);background:var(--surface);display:flex;flex-direction:column}
.acct__bar{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s-4);
  padding:var(--s-3) var(--s-4);border-bottom:var(--bw) solid var(--rule);
}
.acct__dots{display:flex;align-items:center;gap:6px}
.acct__dots i{width:9px;height:9px;border:var(--bw) solid var(--control-bd)}
.acct__dots i:first-child{background:var(--accent);border-color:var(--accent)}
.acct__src{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);
}

/* Full aspect ratio, never cropped: the intrinsic width/height on the <img>
   reserve the space, and a height cap is deliberately absent so no row is
   sliced off. #FFF because the capture is white-backed and any other colour
   shows as a seam at the edges. */
.acct__shot{display:block;margin:var(--s-4) var(--s-4) 0;background:#FFF;border:var(--bw) solid var(--rule-soft)}
.acct__shot img{display:block;width:100%;height:auto}

.acct__foot{
  display:flex;flex-direction:column;align-items:flex-start;
  gap:var(--s-4);padding:var(--s-4);
}
/* The masking legend is a permanent part of the component, never a caption
   that an editor might remove as decoration. */
.acct__legend{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);
}
.acct__zoom{
  display:inline-flex;align-items:center;gap:var(--s-2);
  min-height:44px;padding:0 var(--s-4);
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg);
  border:var(--bw) solid var(--control-bd);background:transparent;
  transition:border-color var(--dur-2) var(--ease),color var(--dur-2) var(--ease);
}
.acct__zoom svg{width:14px;height:14px}
.acct__zoom:hover{border-color:var(--accent);color:var(--accent-ink)}

/* The capture is 1756px wide. The shared lightbox floors an image at 880px,
   which on a phone shrinks this table's text to half its size — enlarging it
   into something still unreadable. Here the capture
   renders at its own size instead and the figure scrolls to it. The scroll is
   inside the dialog, the figure is tabindex="0", so it is reachable by
   keyboard, and the page itself never gains a horizontal scrollbar. */
@media (max-width:900px){
  .page-perf .lightbox__figure img{width:auto;max-width:none;min-width:0}
}

/* --------------------------------- Lightbox ------------------------------ */
.lightbox{position:fixed;inset:0;z-index:210;display:none}
.lightbox.is-open{display:block}
.lightbox__backdrop{position:absolute;inset:0;background:rgba(10,10,10,.82)}
.lightbox__card{
  position:absolute;inset:50% auto auto 50%;transform:translate(-50%,-50%);
  width:min(1600px,94vw);max-height:92vh;overflow:auto;
  background:var(--soft-white);border:var(--bw) solid var(--carbon);
  border-top:3px solid var(--carbon);padding:var(--s-5);
  display:flex;flex-direction:column;gap:var(--s-4);
}
/* Sticky so the close control stays on screen once a tall capture makes the
   card scroll. On a short viewport the button would otherwise scroll away and
   leave Escape as the only exit. */
.lightbox__head{
  position:sticky;top:calc(var(--s-5) * -1);z-index:1;
  display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s-4);
  padding:var(--s-5) 0 var(--s-3);margin:calc(var(--s-5) * -1) 0 0;
  background:var(--soft-white);
}
.lightbox__title{font-size:var(--fs-h4);letter-spacing:-0.02em}
.lightbox__close{
  flex:0 0 auto;width:44px;height:44px;display:grid;place-items:center;
  border:var(--bw) solid var(--rule);background:var(--soft-white);
}
.lightbox__close svg{width:18px;height:18px}
/* Below 900px the capture cannot be legible at page width, so the lightbox
   scrolls it horizontally at a readable size rather than shrinking it to
   nothing. This is the controlled horizontal container the brief asks for —
   it is inside the dialog and never affects the page itself. */
.lightbox__figure{margin:0;overflow:auto;border:var(--bw) solid var(--rule);background:#FFF}
.lightbox__figure img{display:block;width:100%;height:auto;min-width:880px}
.lightbox__cap{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--dark-grey);
}
.lightbox__note{font-size:var(--fs-small);color:var(--dark-grey);max-width:70ch}

/* ------------------------- The Performance Loop -------------------------- */
/* Six stages that close back on themselves. Built as a grid rather than a
   circle: a real circle needs absolute positioning and breaks the moment the
   text length changes or the viewport narrows. The loop is made explicit by
   the return bar underneath, which is a labelled element and not decoration. */
.loop{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-4)}
@media (min-width:700px){.loop{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (min-width:1100px){.loop{grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-5)}}

.loop__node{
  position:relative;display:flex;flex-direction:column;gap:var(--s-2);
  padding:var(--s-5);background:var(--surface);
  border:var(--bw) solid var(--rule);border-top:3px solid var(--rule);
  transition:border-color var(--dur-2) var(--ease),background var(--dur-2) var(--ease);
}
/* Hover AND focus, because the brief asks for an active state and a keyboard
   user must get the same one. Plain :focus is listed alongside :focus-visible
   on purpose — these are non-text blocks, so there is no reason to withhold the
   state from a programmatic or pointer focus. The description is always
   rendered, so the colour change is emphasis only — never the carrier of
   information. */
.loop__node:hover,.loop__node:focus,.loop__node:focus-visible,.loop__node:focus-within{
  border-color:var(--accent);border-top-color:var(--accent);background:var(--bg);
}
.loop__idx{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.14em;color:var(--fg-muted)}
.loop__name{font-size:var(--fs-h4);font-weight:700;letter-spacing:-0.02em}
.loop__desc{font-size:var(--fs-small);color:var(--fg-muted);line-height:1.55}

.loop__return{
  display:flex;align-items:center;gap:var(--s-4);
  margin-top:var(--s-5);padding-top:var(--s-5);
  border-top:var(--bw) solid var(--rule);
}
.loop__arrow{flex:0 0 auto;width:34px;height:34px;display:grid;place-items:center;border:var(--bw) solid var(--accent);color:var(--accent-ink)}
.loop__arrow svg{width:16px;height:16px}
.loop__return p{font-size:var(--fs-small);color:var(--fg-muted);max-width:70ch}

/* --------------------- Creative testing matrix (3 x 3) ------------------- */
.matrix{border:var(--bw) solid var(--rule);background:var(--bg);padding:var(--s-5)}
@media (min-width:900px){.matrix{padding:var(--s-7)}}
.matrix__head{display:flex;flex-direction:column;gap:var(--s-3);padding-bottom:var(--s-6)}
.matrix__flag{
  align-self:flex-start;font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:.1em;text-transform:uppercase;color:var(--fg-muted);
  border:var(--bw) solid var(--rule);padding:6px 10px;
}
/* Row label column + three angle columns. Below 760px the row labels become
   headings inside each group, so the table collapses to one column and never
   needs a horizontal scroll. */
.matrix__grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-4)}
.matrix__colhead{display:none}
/* Mobile first: the row label is a block heading above its three cells, so it
   needs top spacing to separate it from the previous group. That padding must
   be dropped again on desktop, where the label becomes a vertically centred
   left-hand cell — hence the explicit reset in the media query below. Keep the
   base rule before the query; swapping the order makes the padding leak. */
.matrix__rowhead{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.12em;
  text-transform:uppercase;color:var(--fg);padding-top:var(--s-4);
}
@media (min-width:760px){
  .matrix__grid{grid-template-columns:minmax(90px,.55fr) repeat(3,minmax(0,1fr));gap:var(--s-3)}
  .matrix__colhead{
    display:block;font-family:var(--font-mono);font-size:var(--fs-label);
    letter-spacing:.12em;text-transform:uppercase;color:var(--fg-muted);
    padding-bottom:var(--s-2);border-bottom:var(--bw) solid var(--rule);
  }
  .matrix__rowhead{display:flex;align-items:center;padding-top:0}
}

.matrix__note{margin-top:var(--s-6);padding-top:var(--s-5);border-top:var(--bw) solid var(--rule);font-size:var(--fs-small);color:var(--fg-muted);max-width:78ch}

/* ----------------------- Creative flow (3 stages) ------------------------ */
/* An <ol>, because the order is the point. Three columns from 800px, stacked
   below it. Numbered by a real element rather than a list marker so the
   number can sit beside the icon. */
.cflow{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-4);list-style:none}
@media (min-width:800px){.cflow{grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-5)}}
.cflow__step{
  display:flex;flex-direction:column;gap:var(--s-3);
  padding:var(--s-5);background:var(--bg);
  border:var(--bw) solid var(--rule);border-top:3px solid var(--accent);
}
.cflow__num{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.14em;color:var(--fg-muted)}
.cflow__icon{
  width:44px;height:44px;display:grid;place-items:center;
  border:var(--bw) solid var(--rule);color:var(--accent-ink);
}
.cflow__icon svg{width:22px;height:22px}
.cflow__step h3{font-size:var(--fs-h4);letter-spacing:-0.02em}
.cflow__step p{font-size:var(--fs-small);color:var(--fg-muted);line-height:1.55}

/* --------------------------- Platform grid ------------------------------- */
/* Flex rather than grid on purpose: seven items in four columns leave three on
   the second row, and justify-content:center centres that row. CSS grid would
   strand them against the left edge.
   The marks are inlined SVG recoloured to a single ink — see the section
   comment in performance-marketing.html for why they are not brand-coloured. */
.pgrid{
  display:flex;flex-wrap:wrap;justify-content:center;
  gap:var(--s-3);list-style:none;
}
.pgrid__item{
  flex:0 0 calc(50% - var(--s-3) / 2);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:var(--s-3);min-height:132px;padding:var(--s-5) var(--s-3);
  background:var(--bg);border:var(--bw) solid var(--rule);
  transition:border-color var(--dur-2) var(--ease),color var(--dur-2) var(--ease);
}
.pgrid__item:hover{border-color:var(--accent);color:var(--accent-ink)}
/* One box for every mark, so a wide logo and a square logo read as the same
   size rather than the same width. */
.pgrid__mark{width:32px;height:32px;display:grid;place-items:center}
.pgrid__mark svg{width:100%;height:100%;display:block}
.pgrid__name{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;text-align:center;
}
@media (min-width:640px){
  .pgrid__item{flex-basis:calc(33.3333% - var(--s-3) * 2 / 3)}
}
@media (min-width:1000px){
  .pgrid__item{flex-basis:calc(25% - var(--s-3) * 3 / 4)}
}

/* ---------------------------- Measurement funnel ------------------------- */
/* Horizontal on desktop, vertical on mobile. The width step-down is a visual
   metaphor only; no stage carries a number, because no number here would be
   anything other than invented. */
.funnel{display:flex;flex-direction:column;gap:var(--s-3)}
@media (min-width:900px){
  .funnel{flex-direction:row;align-items:stretch;gap:var(--s-2)}
}
.fstage{
  position:relative;flex:1 1 0;display:flex;flex-direction:column;gap:var(--s-2);
  padding:var(--s-5);background:var(--surface);
  border:var(--bw) solid var(--rule);border-left:3px solid var(--rule);
  transition:border-color var(--dur-2) var(--ease);
}
@media (min-width:900px){
  .fstage{border-left:var(--bw) solid var(--rule);border-top:3px solid var(--rule)}
}
.fstage:hover,.fstage:focus-visible{border-color:var(--accent)}
@media (min-width:900px){
  .fstage:hover,.fstage:focus-visible{border-top-color:var(--accent)}
}
/* Progressive activation on scroll: each stage's top rule fills in turn. The
   reveal class already respects prefers-reduced-motion, and the stage is fully
   readable at every point of the transition. */
.js .funnel.reveal .fstage{border-top-color:var(--rule)}
.js .funnel.reveal.is-in .fstage{border-top-color:var(--accent);transition:border-color var(--dur-3) var(--ease)}
.js .funnel.reveal.is-in .fstage:nth-child(2){transition-delay:90ms}
.js .funnel.reveal.is-in .fstage:nth-child(3){transition-delay:180ms}
.js .funnel.reveal.is-in .fstage:nth-child(4){transition-delay:270ms}
.js .funnel.reveal.is-in .fstage:nth-child(5){transition-delay:360ms}
@media (prefers-reduced-motion:reduce){
  .js .funnel.reveal.is-in .fstage{transition-delay:0ms!important}
}
.fstage__idx{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.14em;color:var(--fg-muted)}
.fstage__name{font-size:var(--fs-h4);font-weight:700;letter-spacing:-0.02em}
.fstage__desc{font-size:var(--fs-small);color:var(--fg-muted);line-height:1.5}

/* Checkbox group — the only multi-select control on the site. Built from real
   checkboxes rather than a <select multiple>, which is close to unusable on
   touch and invisible to most visitors as a multi-choice control. */
.checks{display:flex;flex-wrap:wrap;gap:var(--s-3)}
.check{
  display:inline-flex;align-items:center;gap:var(--s-3);
  min-height:44px;padding:0 var(--s-4);
  border:var(--bw) solid var(--control-bd);background:var(--bg);
  font-size:var(--fs-small);cursor:pointer;
  transition:border-color var(--dur-2) var(--ease);
}
.check:hover{border-color:var(--accent)}
.check input{width:18px;height:18px;accent-color:var(--electric-blue);margin:0}
.check:has(input:checked){border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
.fieldset{display:flex;flex-direction:column;gap:var(--s-3);border:0;padding:0;margin:0}
.fieldset__legend{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.12em;text-transform:uppercase;color:var(--fg-muted)}

/* ==========================================================================
   CREATIVE & CONTENT PAGE (services/creative-content.html)

   Additive. Every rule below is scoped to .page-creative or to a class only
   this page uses, so the homepage, contact, Growth Strategy and Performance
   Marketing pages are untouched.

   Contrast, measured rather than assumed:
     #7C3AED on --soft-white  5.45:1  → passes AA for text
     #7C3AED on --carbon      3.47:1  → fails AA text, passes 3:1 for UI
     #A78BFA on --carbon      7.27:1  → passes AA for text
     --carbon on #7C3AED      3.47:1  → fails AA, so the CTA label is NOT black
     --soft-white on #7C3AED  5.45:1  → passes AA, so the CTA label is off-white
     --soft-white on #6D28D9  6.80:1  → passes AA, the CTA hover
   Same shape as the Performance page: the brand violet is readable as text on
   the light background, but not on the dark one, so dark sections switch text
   and focus rings to the light violet.

   --signal-orange is overridden, not just --accent: it is the primitive the
   components actually read. --electric-blue is overridden too, because
   .check input{accent-color:var(--electric-blue)} would otherwise paint the
   multi-select ticks blue on a violet page.
   ========================================================================== */
.page-creative{
  --violet:#7C3AED;--violet-light:#A78BFA;
  --signal-orange:#7C3AED;--electric-blue:#7C3AED;
  --accent:#7C3AED;--accent-ink:#7C3AED;
}
.page-creative .btn--primary{--btn-fg:var(--soft-white)}
.page-creative .btn--primary:hover{--btn-bg:#6D28D9;--btn-bd:#6D28D9}
.page-creative .inverse{--accent-ink:var(--violet-light)}
/* A focus ring is the one thing that must never be subtle: on dark the brand
   violet is 3.47:1, the light violet 7.27:1. */
.page-creative .inverse :focus-visible{outline-color:var(--violet-light)}
.page-creative .inverse .field__error{color:var(--violet-light)}
.page-creative .inverse .form__status--error{border-left-color:var(--violet-light)}

/* ---------------------------- Hero composition --------------------------- *
   Three client creatives, shown straight and whole. The grid is 1fr / 2fr so
   the single large asset and the two stacked small ones end up the same
   height: two 4:5 images in a 1fr column stack to 0.833W, and one 4:5 image
   in a 2fr column is 0.833W tall. No rotation, no overlap, no mockup.

   The same two columns hold at every width, which is what keeps the hero
   compact on a phone instead of turning into a 3-image vertical scroll.
   -------------------------------------------------------------------------- */
.hero--creative .hero__copy{gap:clamp(20px,2.2vw,28px);max-width:52ch}
@media (min-width:1000px){
  .hero--creative .hero__grid{
    grid-template-columns:minmax(0,1fr) minmax(0,.92fr);
    gap:clamp(40px,4.5vw,72px);align-items:center;
  }
}
.chero__art{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,2fr);
  gap:var(--s-3);align-items:start;
}
@media (min-width:768px){.chero__art{gap:var(--s-4)}}
/* The large asset leads in the DOM because it leads visually. */
.chero__art > :first-child{grid-column:2;grid-row:1 / span 2}
.chero__shot{border:var(--bw) solid var(--rule);background:var(--surface);display:block}
.chero__shot img{display:block;width:100%;height:auto}

/* --------------------------- What we create (4) -------------------------- *
   Number, title, one sentence. Two columns on desktop, one on mobile. The
   rule above each item is the only graphic.
   -------------------------------------------------------------------------- */
.cmake{display:grid;grid-template-columns:minmax(0,1fr);gap:0}
.cmake__item{
  display:flex;flex-direction:column;gap:var(--s-3);
  padding:var(--s-6) 0;border-top:var(--bw) solid var(--rule);
}
.cmake__item:first-child{border-top-color:var(--accent);border-top-width:3px}
.cmake__num{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.16em;
  color:var(--accent-ink);
}
.cmake__item h3{font-size:var(--fs-h4);letter-spacing:-0.02em}
.cmake__item p{color:var(--fg-muted);line-height:1.6;max-width:46ch}
@media (min-width:860px){
  .cmake{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:clamp(32px,5vw,72px)}
  .cmake__item{border-top-width:3px;border-top-color:var(--rule)}
  .cmake__item:nth-child(-n+2){border-top-color:var(--accent)}
}

/* ------------------------------ How we work ------------------------------ *
   Horizontal on desktop, vertical on mobile. The connector is a rule drawn
   with a border, so it is present in high-contrast mode and costs nothing
   when the step wraps.
   -------------------------------------------------------------------------- */
.csteps{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-5)}
.cstep{
  display:flex;flex-direction:column;gap:var(--s-3);
  padding:var(--s-5);border:var(--bw) solid var(--rule);
  border-top:3px solid var(--accent);background:var(--bg);
}
.cstep__num{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.16em;
  color:var(--fg-muted);
}
.cstep h3{font-size:var(--fs-h4);letter-spacing:-0.02em}
.cstep p{color:var(--fg-muted);font-size:var(--fs-small);line-height:1.6}
@media (min-width:860px){
  .csteps{grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-4)}
}

/* ------------------------------ Work gallery ----------------------------- *
   A grid, not CSS columns. Real masonry via `columns` reorders the cards down
   each column, so the DOM order and the reading order stop matching — which
   also breaks keyboard order. align-items:start gives the staggered look
   without that cost, and handles 1:1, 4:5, 9:16 and 16:9 side by side.

   The card is capped at 560px so the single approved project today renders as
   a deliberate feature rather than a lonely tile stretched across the page.
   Nothing needs changing when the second one lands.
   -------------------------------------------------------------------------- */
.gallery__grid{
  display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-6);
  align-items:start;justify-items:start;
}
@media (min-width:768px){.gallery__grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (min-width:1100px){.gallery__grid{grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-7)}}

.wcard-work{width:100%;max-width:560px;display:flex;flex-direction:column;gap:var(--s-4)}
.wcard-work[hidden]{display:none}
/* One approved project today. Dropped into a three-column grid it would sit in
   a 384px column with two empty columns beside it, which reads as two missing
   projects rather than one presented one. Letting the only card span the row
   gives it the full 560px cap instead. This unsets itself the moment a second
   approved project appears — :only-child stops matching, and both cards fall
   back into the normal column rhythm with no CSS to remember to remove. */
.gallery__grid .wcard-work:only-child{grid-column:1/-1}
.wcard-work__open{
  position:relative;display:block;background:var(--surface);
  border:var(--bw) solid var(--rule);
  transition:border-color var(--dur-2) var(--ease);
}
/* object-fit is deliberately absent: the creative is shown whole, never
   cropped to fit a tile. */
.wcard-work__open img{display:block;width:100%;height:auto}
.wcard-work__open:hover{border-color:var(--accent)}
.wcard-work__zoom{
  position:absolute;right:0;bottom:0;
  padding:10px var(--s-4);background:var(--carbon);color:var(--soft-white);
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;
  opacity:0;transform:translateY(4px);
  transition:opacity var(--dur-2) var(--ease),transform var(--dur-2) var(--ease);
}
/* Revealed on focus as well as hover, and aria-hidden either way: the link's
   own text already says what it does, so this is decoration. */
.wcard-work__open:hover .wcard-work__zoom,
.wcard-work__open:focus-visible .wcard-work__zoom{opacity:1;transform:none}
.wcard-work__cap{display:flex;flex-direction:column;gap:4px}
.wcard-work__client{font-size:var(--fs-h4);font-weight:700;letter-spacing:-0.02em}
.wcard-work__cat{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);
}
/* Built by justai.js only when there is enough work to filter. Never authored
   in the HTML, so a dead control cannot ship. */
.gfilters{display:flex;flex-wrap:wrap;gap:var(--s-3);margin-bottom:var(--s-6)}
.gfilter{
  min-height:44px;padding:0 var(--s-5);
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg);
  background:transparent;border:var(--bw) solid var(--control-bd);cursor:pointer;
  transition:border-color var(--dur-2) var(--ease),background var(--dur-2) var(--ease);
}
.gfilter:hover{border-color:var(--accent)}
/* The active filter is marked by the fill AND by aria-pressed, so the state is
   not carried by colour alone. */
.gfilter.is-on{background:var(--accent);border-color:var(--accent);color:var(--soft-white)}

/* ------------------ Selected creative work: composed grid ---------------- *
   The shared .gallery__grid is a plain tile grid. Here the work is seven
   portrait creatives at the same 4:5 ratio, and a straight grid of those
   reads as a contact sheet. Two columns, a vertical offset on the right-hand
   one and two inset widths break the lockstep without reordering anything, so
   reading order and tab order still follow the markup.
   -------------------------------------------------------------------------- */
.page-creative .wcard-work{gap:var(--s-3)}
.page-creative .wcard-work__open{border-color:var(--rule-soft)}
.page-creative .wcard-work__client{font-size:1rem;letter-spacing:-0.01em}
@media (min-width:860px){
  .page-creative .gallery__grid{
    grid-template-columns:repeat(2,minmax(0,1fr));
    column-gap:clamp(32px,5vw,80px);
    row-gap:clamp(48px,6vw,96px);
  }
  .page-creative .gallery__grid .wcard-work{max-width:none}
  .page-creative .gallery__grid .wcard-work:nth-child(even){margin-top:clamp(40px,7vw,104px)}
  .page-creative .gallery__grid .wcard-work:nth-child(4n+3){width:86%}
  .page-creative .gallery__grid .wcard-work:nth-child(4n){width:86%;margin-left:auto}
}

/* ------------------------ Content system (4 layers) ---------------------- */
.layers{display:grid;grid-template-columns:minmax(0,1fr);border-top:var(--bw) solid var(--rule)}
.layer{
  display:flex;flex-direction:column;gap:var(--s-3);
  padding:var(--s-6) 0;border-bottom:var(--bw) solid var(--rule);
}
.layer__num{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.16em;color:var(--accent-ink)}
.layer h3{font-size:var(--fs-h4);letter-spacing:-0.02em}
.layer p{color:var(--fg-muted);line-height:1.6;max-width:46ch}
@media (min-width:900px){
  .layers{grid-template-columns:repeat(4,minmax(0,1fr));column-gap:var(--s-6)}
  .layer{border-bottom:0;border-top:3px solid var(--rule);padding-top:var(--s-5)}
  .layer:first-child{border-top-color:var(--accent)}
}

/* --------------------- Lightbox: whole-image variant --------------------- *
   The Performance lightbox forces a min-width so a wide dashboard stays
   legible and scrolls sideways. A creative asset is the opposite case: it
   must be shown whole, so the height is capped to the viewport and the width
   follows.
   -------------------------------------------------------------------------- */
.lightbox--media .lightbox__figure{display:grid;place-items:center;padding:var(--s-4)}
.lightbox--media .lightbox__figure img{
  width:auto;min-width:0;max-width:100%;max-height:min(72vh,860px);height:auto;
}

/* ==========================================================================
   WEB DESIGN & DEVELOPMENT PAGE (services/web-development.html)

   Additive. Every rule below is scoped to .page-web or to a class only this
   page uses, so the homepage, contact, Growth Strategy, Performance Marketing
   and Creative & Content pages are untouched.

   Contrast, measured rather than assumed:
     #00A878 on --soft-white  2.92:1  → fails AA text AND the 3:1 asked of a
                                        non-text indicator, so the brand green
                                        is NEVER text or a focus ring on light
     #00A878 on --carbon      6.48:1  → passes AA for text
     --carbon on #00A878      6.48:1  → passes AA, so the CTA label is BLACK
     --carbon on #00C48C      8.74:1  → passes AA, the CTA hover
     #007956 on --soft-white  5.19:1  → passes AA: the on-light ink and the
                                        on-light focus ring
   Same shape as the Growth Strategy page: the brand colour is too light to be
   text on off-white, so fills, rules, nodes and markers use #00A878 while
   anything that has to be *read* on the light background uses the darker
   #007956. On dark sections both roles collapse back to #00A878.

   --signal-orange and --electric-blue are overridden, not just --accent: they
   are the primitives the shared components actually read (:focus-visible,
   .btn--primary, .link-arrow:hover, .check input{accent-color}).

   The 10–15% budget the brief sets for green is held by using it only for:
   CTAs, the .label squares, active process stages, the active wireframe zone,
   list bullets, note borders and hover/focus edges. No green backgrounds, no
   green headings, no green body copy.
   ========================================================================== */
.page-web{
  --web-green:#00A878;--web-green-ink:#007956;
  --signal-orange:#00A878;--electric-blue:#00A878;
  --accent:#00A878;--accent-ink:#007956;
}
/* Black on the brand green is 6.48:1, so unlike the blue and violet pages the
   label stays dark and the green stays exact. The hover LIGHTENS (8.74:1);
   darkening would eventually push the black label down instead of up. */
.page-web .btn--primary:hover{--btn-bg:#00C48C;--btn-bd:#00C48C}
/* A focus ring is the one thing that must never be subtle. The brand green is
   2.92:1 on off-white — under the 3:1 floor for a non-text indicator — so the
   ring on light uses the ink. On dark the brand green is 6.48:1 and is kept. */
.page-web :focus-visible{outline-color:var(--web-green-ink)}
.page-web .inverse :focus-visible{outline-color:var(--web-green)}
.page-web .inverse{--accent-ink:var(--web-green)}
.page-web .inverse .field__error{color:var(--web-green)}
.page-web .inverse .form__status--error{border-left-color:var(--web-green)}

/* ---------------- Hero: copy left, real capture right -------------------- */
.hero--site .hero__copy{gap:clamp(20px,2.2vw,28px);max-width:52ch}
@media (min-width:1100px){
  .hero--site .hero__grid{
    grid-template-columns:minmax(0,.94fr) minmax(0,1.06fr);
    gap:clamp(40px,4vw,72px);align-items:start;
  }
}

/* ------------------------- The site window ------------------------------- *
   The Bambidou capture in an editorial window. Deliberately NOT a 3D mockup:
   no perspective, no rotation, no drop shadow, no laptop or phone shell drawn
   around a screenshot. A rule, a bar carrying the real host, the capture, and
   a caption. Everything inside the frame is a real file — there is no invented
   screen, no placeholder content and no fake dashboard anywhere in it.
   -------------------------------------------------------------------------- */
.sitewin{border:var(--bw) solid var(--rule);background:var(--bg);display:flex;flex-direction:column}
.sitewin__bar{
  display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap;
  padding:var(--s-2) var(--s-4);border-bottom:var(--bw) solid var(--rule);
  background:var(--surface);
}
.sitewin__dots{display:flex;gap:6px;flex:none}
.sitewin__dots i{width:8px;height:8px;border:var(--bw) solid var(--control-bd);display:block}
.sitewin__dots i:first-child{background:var(--accent);border-color:var(--accent)}
.sitewin__host{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);margin-right:auto;
}
.sitewin__visit{
  display:inline-flex;align-items:center;gap:var(--s-2);
  min-height:44px;padding:0 var(--s-2);
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg);
  border-bottom:2px solid transparent;
  transition:border-color var(--dur-2) var(--ease),color var(--dur-2) var(--ease);
}
.sitewin__visit:hover{border-bottom-color:var(--accent);color:var(--accent-ink)}
.sitewin__visit svg{width:12px;height:12px;flex:none}

/* Desktop capture and the phone capture side by side. Both are real files;
   the phone is a separate capture of the same live site, not a squeezed crop
   of the desktop one pretending to be responsive output. */
.sitewin__body{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--bw);background:var(--rule)}
.sitewin__shot,.sitewin__mob{margin:0;overflow:hidden;background:#FFF}
/* 16:10 is close to the 2880x2000 capture's own ratio, so the crop only takes
   a sliver off the bottom; object-position keeps the header, navigation and
   hero — the part that shows the design decisions — in view at every width. */
.sitewin__shot img{width:100%;height:100%;aspect-ratio:16/10;object-fit:cover;object-position:top center}
.sitewin__mob{aspect-ratio:4/3}
.sitewin__mob img{width:100%;height:100%;object-fit:cover;object-position:top center}
@media (min-width:760px){
  .sitewin__body{grid-template-columns:minmax(0,1fr) minmax(0,.3fr)}
  /* In two columns the phone stretches to the desktop capture's height rather
     than setting its own, so the frame stays a clean rectangle. */
  .sitewin__mob{aspect-ratio:auto}
}
.sitewin__foot{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:var(--s-3);padding:var(--s-4);border-top:var(--bw) solid var(--rule);
}
.sitewin__cap{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);
}
/* ----------------- Website gallery — browser-framed cards ---------------- *
   Extends the .wcard-work component the Creative page uses. A website is a
   landscape artefact, so the card keeps a landscape crop instead of the 4:5
   the creative grid uses, and gains a chrome bar carrying the REAL host plus
   a link out to the live site.
   -------------------------------------------------------------------------- */
.gallery--sites .gallery__grid{grid-template-columns:minmax(0,1fr)}
.gallery--sites .wcard-work{border:var(--bw) solid var(--rule);background:var(--bg)}
.wcard-work__chrome{
  display:flex;align-items:center;gap:var(--s-3);
  padding:var(--s-2) var(--s-4);border-bottom:var(--bw) solid var(--rule);
  background:var(--surface);
}
.wcard-work__dots{display:flex;gap:6px;flex:none}
.wcard-work__dots i{width:8px;height:8px;border:var(--bw) solid var(--control-bd);display:block}
.wcard-work__dots i:first-child{background:var(--accent);border-color:var(--accent)}
.wcard-work__host{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);
}
/* The card shows the top of the page — header, navigation and hero — and the
   lightbox shows the capture whole, so nothing is hidden by the crop. */
.gallery--sites .wcard-work__open img{aspect-ratio:16/10;object-fit:cover;object-position:top center}
.gallery--sites .wcard-work__cap{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--s-2) var(--s-4);
  padding:var(--s-4);border-top:var(--bw) solid var(--rule);
}
.wcard-work__visit{
  margin-left:auto;display:inline-flex;align-items:center;gap:var(--s-2);
  min-height:44px;padding-block:10px;
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg);
  border-bottom:2px solid var(--control-bd);
  transition:border-color var(--dur-2) var(--ease),color var(--dur-2) var(--ease);
}
.wcard-work__visit:hover{border-bottom-color:var(--accent);color:var(--accent-ink)}
/* One approved project today. The grid is authored for more and the renderer
   appends them, so a second card needs no CSS change. */
@media (min-width:1000px){
  .gallery--sites .gallery__grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .gallery--sites .gallery__grid .wcard-work:only-child{grid-column:1 / -1;max-width:none}
}
.gallery__legend{margin-top:var(--s-5);font-size:var(--fs-small);color:var(--fg-muted);max-width:70ch}

/* Full-page capture in the lightbox. 1440x10329 cannot be shown whole on a
   screen, so the figure scrolls rather than the image being shrunk to an
   unreadable strip. tabindex="0" makes the scroller reachable and operable
   from the keyboard, and the lightbox focus trap includes it. */
.lightbox--page .lightbox__figure{
  overflow:auto;max-height:min(66vh,720px);background:#FFF;
  border:var(--bw) solid var(--rule);
}
.lightbox--page .lightbox__figure img{width:100%;height:auto;max-height:none}
.lightbox--page .lightbox__figure:focus-visible{outline-offset:-3px}
.lightbox__hint{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--dark-grey);
}

/* ------------------- Non-blocking routing notice ------------------------- *
   Shown under the project-type select when "Shopify store" is chosen. It is a
   STATUS, not a validation error: it never blocks submission, never clears a
   field and never changes the answer. Styled apart from .field__error so it
   cannot be mistaken for one, and it ships hidden with the same [hidden]
   contract as .form__status.
   -------------------------------------------------------------------------- */
.form__note{
  padding:var(--s-4);border-left:4px solid var(--accent-ink);
  background:rgba(255,255,255,0.06);font-size:var(--fs-small);line-height:1.55;
}
.form__note[hidden]{display:none}
.form__note a{border-bottom:var(--bw) solid currentColor}

/* ------------------------- Engagements (four) ---------------------------- */
.grid-4{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-6)}
@media (min-width:700px){.grid-4{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s-7)}}
@media (min-width:1100px){.grid-4{grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--s-6)}}

/* ==========================================================================
   ABOUT / SERVICES / WORK  ·  rebuilt 2026-09-20
   Three pages share one block because they share one problem: presenting
   structure (a story, a system, a portfolio) without photography, icon sets
   or invented numbers. Everything below is additive and scoped to a page
   class or to a class that exists on no other page.
   ========================================================================== */

/* ---------------------- Per-page accent remapping ------------------------ *
   Shared components read the PRIMITIVES (--signal-orange, --electric-blue),
   not just --accent, so a page tint has to remap the primitives too. About
   and Work keep the house orange; Services stays neutral because it shows
   all four discipline colours at once and must not favour one.
   -------------------------------------------------------------------------- */
.page-about,.page-work{--accent:#FF5A36;--signal-orange:#FF5A36}

/* Discipline swatches. Used as --svc / --dot / local --accent inside the
   four-discipline blocks, never as body text colour. */
.svc-strategy{--svc:#FF5A36}
.svc-performance{--svc:#3157FF}
.svc-creative{--svc:#7C3AED}
.svc-web{--svc:#00A878}

/* ------------------------- Image placeholder ---------------------------- *
   Injected by justai.js when an <img data-fallback> fails. It is visibly a
   placeholder — a hairline box with the alt text — so a missing asset never
   reads as delivered work and never renders as a broken-image glyph.
   -------------------------------------------------------------------------- */
.imgph{
  display:flex;flex-direction:column;justify-content:flex-end;gap:var(--s-3);
  min-height:220px;padding:var(--s-5);
  border:var(--bw) dashed var(--control-bd);background:var(--surface);
}
.imgph__mark{display:block;width:22px;height:22px;border:2px solid var(--control-bd)}
.imgph__text{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--dark-grey);
}

/* =============================== ABOUT ================================== */

/* ============================== SERVICES ================================ */

/* ----------------------------- Service block ---------------------------- *
   A full section per discipline, not a card: heading, prose, capability
   list and its own CTA. The discipline colour appears as a top edge and a
   9px square only — never as text, because none of the four passes AA as
   body copy on off-white.
   -------------------------------------------------------------------------- */
.svcblock{
  display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-6);
  padding-top:clamp(32px,3.6vw,52px);
  border-top:3px solid var(--svc,var(--fg));
}
.svcblock + .svcblock{margin-top:clamp(48px,6vw,96px)}
@media (min-width:960px){
  .svcblock{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--s-8) var(--s-9)}
}
.svcblock__head{display:flex;flex-direction:column;gap:var(--s-4);min-width:0}
.svcblock__num{
  display:flex;align-items:center;gap:10px;
  font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--fg-muted);
}
.svcblock__num::before{content:"";width:9px;height:9px;flex:none;background:var(--svc,var(--fg))}
.svcblock__title{font-size:clamp(1.7rem,3.4vw,2.7rem);line-height:1.06;letter-spacing:-0.03em;font-weight:900}
.svcblock__desc{color:var(--fg-muted);max-width:52ch;line-height:1.6}
.svcblock__body{display:flex;flex-direction:column;gap:var(--s-5);min-width:0}
.svcblock__caps{
  list-style:none;margin:0;padding:0;
  border-top:var(--bw) solid var(--rule);
}
.svcblock__caps li{
  display:flex;align-items:flex-start;gap:var(--s-3);
  padding-block:var(--s-4);border-bottom:var(--bw) solid var(--rule);
  font-size:1.0625rem;font-weight:500;letter-spacing:-0.01em;line-height:1.4;
}
.svcblock__caps li::before{content:"";flex:none;width:7px;height:7px;margin-top:.45em;background:var(--svc,var(--fg))}
.svcblock__actions{display:flex;flex-wrap:wrap;gap:var(--s-4)}

/* ------------------------------ Hero diagram ---------------------------- *
   The four disciplines as a connected sequence with a labelled return leg.
   A grid, not a circle: a circle needs absolute positioning and collapses
   the moment a label wraps. The return leg is real text, so the loop is
   stated for a screen reader and not implied by an arc.
   -------------------------------------------------------------------------- */
.sysdia{display:flex;flex-direction:column;gap:var(--s-3)}
.sysdia__row{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-3)}
@media (min-width:560px){.sysdia__row{grid-template-columns:repeat(2,minmax(0,1fr))}}
.sysdia__node{
  display:flex;flex-direction:column;gap:var(--s-2);
  padding:var(--s-5);background:var(--surface);
  border:var(--bw) solid var(--rule);border-top:3px solid var(--svc,var(--fg));
}
.sysdia__idx{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.14em;color:var(--fg-muted)}
.sysdia__name{font-size:1.0625rem;font-weight:700;letter-spacing:-0.01em}
.sysdia__desc{font-size:var(--fs-small);color:var(--fg-muted);line-height:1.5}
.sysdia__return{
  display:flex;align-items:center;gap:var(--s-4);
  margin-top:var(--s-2);padding-top:var(--s-5);
  border-top:var(--bw) solid var(--rule);
}
.sysdia__arrow{flex:0 0 auto;width:34px;height:34px;display:grid;place-items:center;border:var(--bw) solid var(--control-bd);color:var(--fg)}
.sysdia__arrow svg{width:16px;height:16px}
.sysdia__return p{font-size:var(--fs-small);color:var(--fg-muted);max-width:44ch}

/* ------------------------------- Picker --------------------------------- *
   "Not sure where to start?" Four plain links, each stating a situation in
   the visitor's words and routing to the discipline that answers it. Links,
   not a quiz: a four-option quiz with a deterministic answer is just four
   links with extra steps and extra ways to fail.
   -------------------------------------------------------------------------- */
.picker{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-4)}
@media (min-width:760px){.picker{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s-5)}}
.picker__opt{
  display:flex;flex-direction:column;gap:var(--s-3);
  padding:var(--s-6);background:var(--bg);
  border:var(--bw) solid var(--rule);border-left:4px solid var(--svc,var(--fg));
  transition:background var(--dur-2) var(--ease),border-color var(--dur-2) var(--ease);
}
.picker__opt:hover,.picker__opt:focus-visible{background:var(--surface)}
.picker__said{font-size:1.125rem;font-weight:700;letter-spacing:-0.02em;line-height:1.3}
.picker__then{font-size:var(--fs-small);color:var(--fg-muted);line-height:1.5}
.picker__go{
  display:inline-flex;align-items:center;gap:8px;margin-top:auto;
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--accent-ink);
}
.picker__go svg{width:12px;height:12px;transition:transform var(--dur-2) var(--ease)}
.picker__opt:hover .picker__go svg{transform:translateX(3px)}

/* ==========================================================================
   WORK PAGE  ·  work.html
   A portfolio, so the images are the layout. Everything is scoped under
   .page-work except .acct-pair, .logo-grid--compact, .section-head--tight and
   .lightbox--wide, which are generic modifiers of components that already
   exist and are safe for another page to reuse.
   ========================================================================== */

/* ------------------------------ Page opening ---------------------------- *
   The introduction and the gallery share ONE section on purpose. Two sections
   would stack two sets of section padding between the headline and the first
   project, and the first project is meant to be on screen at 1440x900 without
   scrolling. Hence the tight padding and the two-column head.
   -------------------------------------------------------------------------- */
.work-lead{padding-block:var(--s-6) var(--s-9)}
.work-lead__top{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:var(--s-4);padding-bottom:var(--s-5);
  border-bottom:var(--bw) solid var(--rule);
}
.work-lead__head{
  display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-4);
  padding-block:var(--s-6) var(--s-5);
}
.work-lead__title{
  font-size:clamp(2.6rem,7vw,4.6rem);line-height:.96;
  letter-spacing:-0.045em;font-weight:900;
}
.work-lead__aside{display:flex;flex-direction:column;align-items:flex-start;gap:var(--s-4)}
.work-lead__aside .lead{max-width:44ch}
/* From 900px the description sits beside the headline rather than under it,
   which is what actually buys the vertical space the brief asks for. */
@media (min-width:900px){
  .work-lead__head{
    grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr);
    gap:var(--s-7);align-items:end;
  }
}
/* The filter bar is appended here by script. Until then the row is empty and
   collapses, so no space is reserved for a control that may never be built. */
.work-lead__bar:not(:empty){padding-bottom:var(--s-5)}

/* ------------------------------ Mixed grid ------------------------------ *
   Two kinds of image in one grid: website captures at 16:10 and creatives at
   4:5. align-items:start (inherited from .gallery__grid) lets each row size to
   its own content instead of stretching every card to the tallest, and the
   websites are ordered ahead of the creatives so the two shapes do not
   interleave. Two columns, never three: the brief asks for generous image
   sizes, and a third column here would shrink a capture below legibility.
   -------------------------------------------------------------------------- */
/* The shared grid pairs up at 768px. A website capture in a 334px column is
   the tiny shrunken page the brief rules out, so this page stays single until
   a column is wide enough to read. */
@media (max-width:899px){
  .page-work .gallery__grid{grid-template-columns:minmax(0,1fr)}
}
@media (min-width:1100px){
  .page-work .gallery__grid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
/* The shared 560px card cap is sized for a three-column grid. In a two-column
   one it would leave a dead strip beside every card, so here the card fills
   its column and the images get the size the brief asks for. */
.page-work .gallery__grid .wcard-work{max-width:none}
/* A website card shows a readable portion of the page, anchored to the top,
   rather than a whole long page squeezed into a thumbnail. The full capture is
   one click away in the lightbox, so the crop hides nothing. */
.page-work .wcard-work[data-work-tags="Websites"] .wcard-work__open img{
  aspect-ratio:16/10;width:100%;height:auto;
  object-fit:cover;object-position:top center;
}
/* A creative keeps its own proportions and is never cropped or stretched: the
   headline, the product and the client's mark all have to survive. */
.page-work .wcard-work[data-work-tags="Creative"] .wcard-work__open img{
  aspect-ratio:auto;width:100%;height:auto;
  object-fit:contain;background:var(--surface);
}

/* --------------------------- Account view pair -------------------------- *
   Side by side from 1000px, stacked below it. .acct already supplies the
   frame, the bar and the caption; only the pairing is new.
   -------------------------------------------------------------------------- */
.acct-pair{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-6)}
@media (min-width:1000px){
  .acct-pair{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s-5);align-items:start}
}

/* ---------------------- Compact head and logo rows ---------------------- */
.section-head--tight{margin-bottom:var(--s-5)}
/* Four across from 720px, so eight marks land as two tidy rows rather than a
   wall. Cells keep .logo-grid's own sizing, so no mark is stretched. */
@media (min-width:720px){
  .logo-grid--compact{grid-template-columns:repeat(4,minmax(0,1fr))}
}

/* ------------------------------ Client wall ----------------------------- *
   Forty-five marks, ten across on desktop. Each --logo-h is computed for the
   narrow desktop cell; --logo-scale grows every mark by the same factor on the
   wider cells lower down, so the optical balance between marks is set once and
   holds at every breakpoint.
   -------------------------------------------------------------------------- */
.logo-grid.logo-grid--wall{grid-template-columns:repeat(3,minmax(0,1fr));--logo-scale:2}
.logo-grid.logo-grid--wall .logo-grid__cell{padding:var(--s-4) var(--s-3);min-height:96px}
.logo-grid.logo-grid--wall .logo-grid__cell img{max-height:calc(var(--logo-h) * var(--logo-scale))}
/* The shared mark treatment flattens every opaque pixel to solid black, which
   suits the wordmarks on the homepage but turns a badge logo into a black
   blob. Across forty-five mixed marks, plain greyscale keeps the page
   monochrome while leaving the inside of a badge readable. The cost is that a
   near-white source mark stays near-white, so the brightness step gives those
   marks enough body to hold their own beside the dark ones. */
.logo-grid.logo-grid--wall .logo-grid__cell img{filter:grayscale(1) brightness(.82) contrast(1.05);opacity:.82}
.logo-grid.logo-grid--wall .logo-grid__cell:hover img{opacity:1}
@media (min-width:600px){
  .logo-grid.logo-grid--wall{grid-template-columns:repeat(5,minmax(0,1fr));--logo-scale:1.7}
}
@media (min-width:900px){
  .logo-grid.logo-grid--wall{grid-template-columns:repeat(9,minmax(0,1fr));--logo-scale:1.2}
  .logo-grid.logo-grid--wall .logo-grid__cell{min-height:84px}
}
@media (min-width:1200px){
  .logo-grid.logo-grid--wall{grid-template-columns:repeat(10,minmax(0,1fr));--logo-scale:1}
  /* 45 marks leave five over on the last row of ten. Widening those five cells
     fills the row without resizing the marks inside them. */
  .logo-grid.logo-grid--wall .logo-grid__cell:nth-last-child(-n+5){grid-column:span 2}
}

/* ------------------------- Lightbox: wide variant ----------------------- *
   An account table is wide, not tall. Shrunk to fit it becomes unreadable, so
   below 900px it renders at its own size and the FIGURE scrolls sideways. That
   scroll is inside the dialog; the page never gains a horizontal scrollbar.
   tabindex="0" on the figure puts the scroller in the keyboard order and
   inside the dialog's focus trap.
   -------------------------------------------------------------------------- */
.lightbox--wide .lightbox__figure{max-height:min(74vh,760px);overflow:auto}
.lightbox--wide .lightbox__figure img{max-height:none}
@media (max-width:900px){
  .lightbox--wide .lightbox__figure img{width:auto;max-width:none;min-width:0}
}

/* ==========================================================================
   LEGAL PAGES  ·  legal-notice.html / privacy-policy.html
   Long-form documents, not sales pages. Three rules govern the treatment:
     1. The measure is capped at 68ch. Legal text is the only place on this
        site where anyone reads more than four consecutive sentences, so it
        gets the narrowest column in the system.
     2. The contents list is a real list of real links, sticky on desktop only
        (position:sticky is simply not applied in the single-column layout,
        where a pinned index would cover the text it indexes).
     3. No accent fills, no cards, no reveal animation. Rules and numerals do
        the structural work — the same way the rest of the site indexes
        things, and legible even if the CSS only half-loads.
   -------------------------------------------------------------------------- */
.legal{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-7);align-items:start}
.legal__toc{min-width:0}
.legal__toc h2{
  font-family:var(--font-mono);font-size:var(--fs-label);font-weight:400;
  letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--fg-muted);
  padding-bottom:var(--s-3);border-bottom:var(--bw) solid var(--rule);
}
.legal__toc ol{counter-reset:toc}
.legal__toc li{counter-increment:toc;border-bottom:var(--bw) solid var(--rule-soft)}
.legal__toc a{
  display:flex;gap:var(--s-3);align-items:baseline;
  padding:var(--s-3) 0;font-size:var(--fs-small);
  transition:color var(--dur-2) var(--ease);
}
.legal__toc a::before{
  content:counter(toc,decimal-leading-zero);
  flex:none;font-family:var(--font-mono);font-size:var(--fs-label);color:var(--fg-muted);
}
.legal__toc a:hover{color:var(--accent-ink)}
.legal__body{min-width:0;max-width:68ch}

/* scroll-margin keeps an in-page jump from landing under the sticky header */
.lsec{
  border-top:var(--bw) solid var(--rule);padding-top:var(--s-5);margin-top:var(--s-7);
  scroll-margin-top:calc(var(--header-h) + var(--s-5));
}
.lsec:first-child{margin-top:0;border-top:0;padding-top:0}
.lsec__num{
  display:block;font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--fg-muted);
  margin-bottom:var(--s-3);
}
.lsec h2{font-size:var(--fs-h3);line-height:var(--lh-heading);margin-bottom:var(--s-4)}
.lsec h3{font-size:var(--fs-h4);margin:var(--s-5) 0 var(--s-2)}
.lsec p,.lsec li{line-height:var(--lh-body)}
.lsec p + p{margin-top:var(--s-4)}
.lsec > ul{margin-top:var(--s-4);display:flex;flex-direction:column;gap:var(--s-2)}
.lsec > ul > li{padding-left:var(--s-5);position:relative}
.lsec > ul > li::before{
  content:"";position:absolute;left:0;top:.72em;
  width:7px;height:var(--bw);background:var(--accent);
}
.lsec__body a{border-bottom:var(--bw) solid var(--rule);transition:border-color var(--dur-2) var(--ease)}
.lsec__body a:hover{border-bottom-color:var(--accent)}

/* Identity block: a description list, because that is what it is. Label left,
   value right on wide screens; stacked below 560px so nothing is squeezed. */
.facts{margin-top:var(--s-5);border-top:var(--bw) solid var(--rule)}
.facts > div{
  display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-1);
  padding:var(--s-4) 0;border-bottom:var(--bw) solid var(--rule-soft);
}
.facts dt{
  font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:.1em;text-transform:uppercase;color:var(--fg-muted);
}
.facts dd{font-size:var(--fs-small)}
@media (min-width:560px){
  .facts > div{grid-template-columns:minmax(0,180px) minmax(0,1fr);gap:var(--s-5);align-items:baseline}
}
@media (min-width:900px){
  .legal{grid-template-columns:minmax(0,220px) minmax(0,1fr);gap:var(--s-9)}
  .legal__toc{position:sticky;top:calc(var(--header-h) + var(--s-5))}
}

/* ==========================================================================
   7. MOTION
   Reveals are opt-in via the `js` class so that content is fully visible when
   JavaScript is unavailable or fails.
   ========================================================================== */
.js .reveal{opacity:0;transform:translateY(14px);transition:opacity var(--dur-3) var(--ease),transform var(--dur-3) var(--ease)}
.js .reveal.is-in{opacity:1;transform:none}
.js .reveal[data-delay="1"]{transition-delay:70ms}
.js .reveal[data-delay="2"]{transition-delay:140ms}
.js .reveal[data-delay="3"]{transition-delay:210ms}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important;
  }
  .js .reveal{opacity:1!important;transform:none!important}
}

/* ==========================================================================
   8. RESPONSIVE
   Verified at 360 / 390 / 768 / 1024 / 1440 / 1920.
   ========================================================================== */
@media (min-width:768px){
  .logo-grid{grid-template-columns:repeat(4,1fr)}
  /* Tablet: three across, five rows of three. */
  .logo-grid--5{grid-template-columns:repeat(3,minmax(0,1fr))}
  .logo-grid--5 .logo-grid__cell:last-child:nth-child(odd){grid-column:auto}
  .proofs{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--s-8)}
  .proofs .proof:nth-last-child(-n+2){border-bottom:0}
  /* Three items in two columns would orphan the third and strip the border
     from the second. Hold one column until all three fit side by side. */
  .proofs--3{grid-template-columns:minmax(0,1fr)}
  .proofs--3 .proof:nth-last-child(-n+2){border-bottom:var(--bw) solid var(--rule)}
}
@media (min-width:900px){
  .proofs--3{grid-template-columns:repeat(3,minmax(0,1fr));column-gap:var(--s-7)}
  .proofs--3 .proof{border-bottom:0}
}
@media (min-width:1024px){
  :root{--header-h:82px}
  .logo-grid{grid-template-columns:repeat(4,1fr)}
  /* Desktop: the intended 5 x 3. Cells tighten horizontally so the marks keep
     breathing room without the row growing taller. */
  .logo-grid--5{grid-template-columns:repeat(5,minmax(0,1fr))}
  .logo-grid--5 .logo-grid__cell{padding:var(--s-5) var(--s-4);min-height:118px}
  .menu-btn{display:none}
  .nav,.nav__actions{display:flex}
  .brand img{width:124px}
}
@media (min-width:1600px){
  :root{--container:1480px}
}

/* Dark-section swaps for the shared header/brand assets */
.inverse .brand__black{display:none}
.inverse .brand__white{display:block}

/* ==========================================================================
   WEB DESIGN & DEVELOPMENT  ·  rebuilt 2026-09-20
   Additive. Every rule below is scoped to .page-web or to a class that exists
   on no other page, so nothing here can reach another template.
   ========================================================================== */

/* The Shopify routing line inside the E-commerce entry. A qualifier, not a
   fourth category, so it is set smaller and muted rather than as body copy. */
.dlist__aside{
  font-size:var(--fs-small);color:var(--fg-muted);line-height:1.55;
  padding-left:var(--s-3);border-left:2px solid var(--accent);
}

/* ---------------- What goes in — four items ------------------------------ *
   .layers is authored for a single column. Four needs its own track counts or
   the last two orphan onto a second row with the rules misaligned. */
@media (min-width:700px){
  .layers--4{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--s-7)}
  .layers--4 .layer{border-bottom:0;border-top:3px solid var(--rule);padding-top:var(--s-5)}
}
@media (min-width:1100px){
  .layers--4{grid-template-columns:repeat(4,minmax(0,1fr));column-gap:var(--s-6)}
}

/* ---------------- Gallery card — Desktop / Mobile preview ---------------- *
   Both captures are REAL and separate: the phone view is a 390px capture, not
   the desktop file squeezed into a narrow box.

   With JavaScript off, both images render and both are labelled — honest, and
   nothing is hidden behind a control that cannot work. The toggle itself is
   BUILT BY SCRIPT (see the page-scoped script at the end of the document), so
   no dead control ever ships.
   -------------------------------------------------------------------------- */

/* The desktop capture is 1440x900 — exactly the 16/10 the card crops to, so
   this frame never distorts it. */
.page-web .wshot--desktop{aspect-ratio:16/10}

/* The base sheet sets `img{display:block}`, which outranks the UA rule behind
   the `hidden` attribute. Without this the toggle flips `hidden` and nothing
   changes on screen. */
.page-web .gallery--sites .wcard-work__open img[hidden]{display:none}

/* The phone capture is 780x1688. Cropping that to 16/10 would show the top
   inch of a phone screen, so it keeps its own ratio, is contained rather than
   cropped, and is centred in the frame instead of being stretched across it. */
.page-web .gallery--sites .wcard-work__open img.wshot--mobile{
  aspect-ratio:auto;object-fit:contain;
  width:auto;max-width:100%;
  height:clamp(300px,30vw,420px);
  margin:var(--s-5) auto;
}

/* Sits at the right-hand end of the browser chrome bar. */
.page-web .wtoggle{display:inline-flex;margin-left:auto;flex:none;border:var(--bw) solid var(--rule)}
.page-web .wtoggle__btn{
  font-family:var(--font-mono);font-size:0.6875rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);
  background:none;border:0;padding:5px 10px;cursor:pointer;
  transition:background var(--dur-2) var(--ease),color var(--dur-2) var(--ease);
}
.page-web .wtoggle__btn+.wtoggle__btn{border-left:var(--bw) solid var(--rule)}
.page-web .wtoggle__btn:hover{color:var(--accent-ink)}
/* Black on the brand green is 6.48:1, so the active state keeps the exact
   brand green and a dark label rather than inverting to white. */
.page-web .wtoggle__btn[aria-pressed="true"]{background:var(--accent);color:#0B0B0B}

/* ==========================================================================
   ABOUT — page-scoped
   Everything below is prefixed .page-about so the rebuilt About page cannot
   reach the homepage or the service pages. The page otherwise reuses shared
   components (.founder, .metrics--3, .proofs--3, .final-cta) unchanged.
   ========================================================================== */

/* The hero is a single readable column: the old two-column version existed to
   hold a decorative word stack that the brief removed. */
.page-about .about-hero{
  display:flex;flex-direction:column;gap:clamp(20px,2.4vw,30px);max-width:56ch;
  padding-bottom:clamp(44px,5vw,72px);
}
.page-about .about-hero .hero__title{max-width:none;text-wrap:balance}
.page-about .about-hero .hero__title .ln{white-space:nowrap}
@media (max-width:420px){.page-about .about-hero .hero__title .ln{white-space:normal}}
.page-about .about-hero .lead{max-width:52ch}

/* Stacked section header. The shared .section-head reserves a second column
   for an editorial note, and those notes are exactly what was removed here. */
.page-about .about-head{
  display:flex;flex-direction:column;gap:var(--s-4);align-items:flex-start;
  padding-bottom:clamp(32px,4vw,56px);
}
.page-about .about-head h2{max-width:24ch}

/* Caption under the portrait. Two lines, no quotation, no biography. */
.page-about .founder__caption{
  display:flex;flex-direction:column;gap:2px;padding-top:var(--s-4);
}
.page-about .founder__name{font-size:1.0625rem;font-weight:700;letter-spacing:-0.01em}
.page-about .founder__role{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--fg-muted)}

.page-about .about-geo{
  padding-top:var(--s-5);
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);
}

/* Expertise rows. Rules rather than cards: four bordered boxes would be the
   "excessive cards" the brief rules out, and the accent already distinguishes
   one discipline from the next. */
.page-about .xrows{list-style:none;margin:0;padding:0;border-top:var(--bw) solid var(--rule)}
.page-about .xrow{border-bottom:var(--bw) solid var(--rule)}
.page-about .xrow__link{
  display:grid;grid-template-columns:auto minmax(0,1fr) auto;
  align-items:baseline;gap:var(--s-4);
  padding-block:var(--s-5);color:inherit;text-decoration:none;
  transition:background-color var(--dur-2) var(--ease),padding-inline var(--dur-2) var(--ease);
}
/* The accent is a square, not coloured text. #00A878 and #FF5A36 both fall
   below 4.5:1 on the off-white background, and this is the treatment the
   service rows already use everywhere else on the site. */
.page-about .xrow__num{
  display:flex;align-items:center;gap:10px;
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:var(--tr-label);
  color:var(--fg-muted);
}
.page-about .xrow__num::before{content:"";width:9px;height:9px;flex:none;background:var(--svc)}
.page-about .xrow__body{display:flex;flex-direction:column;gap:6px;min-width:0}
.page-about .xrow__title{font-size:var(--fs-h3);font-weight:900;letter-spacing:-0.03em}
.page-about .xrow__desc{font-size:var(--fs-small);color:var(--fg-muted);line-height:1.55}
.page-about .xrow__go{width:20px;height:20px;flex:none;align-self:center;color:var(--fg-muted)}
.page-about .xrow__link:hover,
.page-about .xrow__link:focus-visible{background:var(--surface)}
.page-about .xrow__link:hover .xrow__go{color:var(--fg)}
@media (min-width:700px){
  .page-about .xrow__link:hover,
  .page-about .xrow__link:focus-visible{padding-inline:var(--s-5)}
}

.page-about .about-commerce{
  padding-top:var(--s-6);font-size:var(--fs-small);color:var(--fg-muted);
}

/* Text labels, not logos — no licensed Shopify or Meta mark exists here. */
.page-about .pstrip{
  list-style:none;margin:0;padding:0;
  display:flex;flex-wrap:wrap;gap:var(--s-4);
}
.page-about .pstrip__item{
  padding:var(--s-4) var(--s-6);
  border:var(--bw) solid var(--rule);background:var(--bg);
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.12em;
  text-transform:uppercase;
}

@media (prefers-reduced-motion:reduce){
  .page-about .xrow__link{transition:none}
}

/* ==========================================================================
   CONTACT — page-scoped
   Prefixed .page-contact so nothing here reaches the homepage modal or the
   four service-page briefs, which share the same .form / .field components.
   ========================================================================== */
.page-contact{--signal-orange:#FF5A36;--accent:#FF5A36}

/* The form has to be visible without scrolling, so this hero gives up the
   generous top padding every other page uses. */
.page-contact .hero--compact{padding-top:clamp(20px,2.4vw,32px)}
.page-contact .hero--compact .hero__grid{padding-bottom:clamp(36px,4vw,56px)}
.page-contact .hero__title{font-size:clamp(2.1rem,3.8vw,3.25rem);max-width:16ch}
.page-contact .hero__copy .lead{max-width:44ch}

.page-contact .reply-note{
  display:flex;align-items:center;gap:10px;
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);
}
.page-contact .reply-note::before{content:"";flex:none;width:7px;height:7px;background:var(--accent)}

/* Direct contacts as a definition list: the label is the term, the link is
   the value, so "Email" and "Phone" are announced with their destinations. */
.page-contact .contact-direct{
  display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-3);
  border-top:var(--bw) solid var(--rule);padding-top:var(--s-5);
}
.page-contact .contact-direct__row{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px var(--s-4)}
.page-contact .contact-direct__row dt{
  flex:none;min-width:5.5em;
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);
}
.page-contact .contact-direct__row dd{margin:0}

.page-contact .contact-wa{align-self:flex-start}
.page-contact .contact-wa svg{width:18px;height:18px}
/* The shared .btn:hover nudges the arrow icon diagonally; a speech bubble
   sliding off the button is just noise. */
.page-contact .contact-wa:hover svg{transform:none}

.page-contact .contact-place{
  font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.1em;
  text-transform:uppercase;color:var(--fg-muted);
}

/* Native <details>. No JavaScript, so it works on a failed script load. */
.page-contact .disclosure{border:var(--bw) solid var(--rule);background:var(--soft-white)}
.page-contact .disclosure__summary{
  display:flex;align-items:center;gap:10px;cursor:pointer;
  min-height:48px;padding:12px var(--s-4);
  font-size:0.8125rem;font-weight:700;letter-spacing:-0.005em;
  list-style:none;
}
.page-contact .disclosure__summary::-webkit-details-marker{display:none}
.page-contact .disclosure__summary i{font-style:normal;font-weight:400;color:var(--fg-muted)}
/* Own marker, so the control reads the same in every browser. */
.page-contact .disclosure__summary::before{
  content:"";flex:none;width:9px;height:9px;
  border-right:2px solid var(--accent);border-bottom:2px solid var(--accent);
  transform:rotate(45deg) translate(-2px,-2px);
  transition:transform var(--dur-2) var(--ease);
}
.page-contact .disclosure[open] > .disclosure__summary::before{transform:rotate(-135deg) translate(-3px,-3px)}
.page-contact .disclosure__summary:focus-visible{outline:2px solid var(--carbon);outline-offset:-2px}
.page-contact .disclosure__body{
  display:grid;gap:var(--s-4);
  padding:0 var(--s-4) var(--s-4);
  border-top:var(--bw) solid var(--rule);padding-top:var(--s-4);
}

/* Error states must not move the fields below them. The message box is always
   in the layout and the invalid border is drawn with an inset shadow rather
   than a thicker border, so nothing reflows when a message appears. */
.page-contact .field__error{display:block;min-height:1.2em}
.page-contact .field__error:empty::before{content:none}
.page-contact .field.has-error input,
.page-contact .field.has-error select,
.page-contact .field.has-error textarea{
  border-width:var(--bw);box-shadow:inset 0 0 0 1px var(--orange-ink);
}

.page-contact .form__fallback{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px var(--s-4);
  font-size:var(--fs-small);
}
.page-contact .form__fallback[hidden]{display:none}
.page-contact .form__fallback .sep{width:4px;height:4px;background:var(--rule)}

@media (prefers-reduced-motion:reduce){
  .page-contact .disclosure__summary::before{transition:none}
}
