/* =============================================================================
   SSMS — Spear Systems Modular Solutions
   Design system. Mobile-first: base = mobile, min-width queries scale up.
   Feeling: engineered calm. See design-notes.md before changing anything here.
   ============================================================================= */

/* --- Tokens --------------------------------------------------------------- */
:root{
  /* Brand — sampled from the supplied logo, not guessed.
     ROLE RULE: teal = identity, red = action. Never a red decoration. */
  --charcoal:#231F20;
  --charcoal-soft:#4A4548;
  --charcoal-mute:#6B6568;
  /* Measured contrast, not assumed. Brand hues are kept for marks and thin
     accents; text-bearing surfaces use the darker step so they pass AA.
     The logo does white-on-#12A89D at 2.95:1 — fine for a logo (exempt),
     never for body text. That's why --teal-dark exists. */
  --teal:#12A89D;           /* identity: logo, rules, thin accents */
  --teal-dark:#0C7A73;      /* white on it 5.19:1 · on white 5.19:1 · on paper 4.84:1 */
  --teal-deep:#0A6B65;      /* hover step, white on it 6.36:1 */
  --teal-wash:rgba(18,168,157,.08);
  --red:#ED1B24;            /* the spear mark; as huge display text 4.1:1 (large ≥3) */
  --red-cta:#D4171E;        /* button fill — white on it 5.33:1 */
  --red-cta-hover:#B31219;  /* 6.96:1 */
  --red-dark:#C4141B;       /* red text on white 6.06:1 */
  --paper:#F7F7F7;
  --white:#FFFFFF;
  --line:rgba(35,31,32,.13);
  --line-soft:rgba(35,31,32,.075);

  /* Spacing — 4/8 rhythm */
  --s1:.25rem; --s2:.5rem;  --s3:.75rem; --s4:1rem;
  --s5:1.5rem; --s6:2rem;   --s7:3rem;   --s8:4rem;

  --shell:min(1180px, 100% - 2rem);
  --radius:6px;
  --radius-lg:12px;
  --shadow:0 1px 2px rgba(35,31,32,.04), 0 8px 24px rgba(35,31,32,.06);
  --shadow-lift:0 2px 4px rgba(35,31,32,.06), 0 18px 44px rgba(35,31,32,.11);

  /* Live height of the sticky header. site.js measures the real element and
     overwrites this, so anything stacking beneath the header (the chip nav,
     scroll-margin on anchors) stays correct when the header reflows. */
  --header-h:76px;

  --step:clamp(3.5rem, 9vw, 6rem);          /* section rhythm */
  --ease:cubic-bezier(.2,.9,.25,1);
  --ease-out:cubic-bezier(.16,1,.3,1);
  --dur:220ms;

  --z-header:50; --z-modal:100; --z-toast:1000;
}

@media (min-width:768px){ :root{ --shell:min(1180px, 100% - 3rem); } }

/* --- Reset ---------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box;}
html{
  -webkit-text-size-adjust:100%;
  scroll-behavior:smooth;
  color-scheme:light;
}
body{
  margin:0;
  background:var(--paper);
  color:var(--charcoal);
  font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  font-size:1rem;                 /* 16px floor — prevents iOS focus zoom */
  line-height:1.65;
  overflow-x:hidden;
  -webkit-tap-highlight-color:rgba(18,168,157,.14);
}
@media (min-width:768px){ body{font-size:1.05rem;} }

img,picture,svg{max-width:100%;display:block;}
img{height:auto;}
a{color:inherit;}
button{font:inherit;color:inherit;}

h1,h2,h3,h4{
  font-family:Archivo,Inter,sans-serif;
  letter-spacing:-.025em;
  line-height:1.1;
  margin:0;
  text-wrap:balance;
}
h1{font-weight:800;font-size:clamp(2.05rem,7.2vw,4rem);}
h2{font-weight:800;font-size:clamp(1.7rem,4.4vw,2.6rem);}
h3{font-weight:700;font-size:clamp(1.12rem,2.2vw,1.32rem);letter-spacing:-.015em;}
p{margin:0;text-wrap:pretty;}

:where(a,button,input,textarea,select,summary):focus-visible{
  outline:2px solid var(--teal-dark);
  outline-offset:3px;
  border-radius:3px;
}

/* Anchored headings clear the sticky header (and the chip nav where present) */
[id]{scroll-margin-top:calc(var(--header-h) + var(--s4));}
.has-chip-nav [id]{scroll-margin-top:calc(var(--header-h) + 56px + var(--s3));}

.skip-link{
  position:absolute;left:var(--s4);top:-4rem;z-index:var(--z-toast);
  background:var(--charcoal);color:var(--white);
  padding:var(--s3) var(--s4);border-radius:var(--radius);
  text-decoration:none;font-weight:600;font-size:.9rem;
  transition:top var(--dur) var(--ease);
}
.skip-link:focus{top:var(--s4);}

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

/* --- Layout --------------------------------------------------------------- */
.shell{width:var(--shell);margin-inline:auto;}
.section{padding-block:var(--step);}
.section--white{background:var(--white);border-block:1px solid var(--line-soft);}

.section__head{max-width:60ch;margin-bottom:var(--s6);}
.section__head p{margin-top:var(--s4);color:var(--charcoal-soft);}

/* The eyebrow's leading rule is the site's smallest recurring motion: it thrusts
   forward like the spear it borrows from. Scale from the left, so it draws
   rather than slides — GPU-only, no layout. Plays once when revealed. */
.eyebrow{
  display:inline-flex;align-items:center;gap:var(--s2);
  font-family:Archivo,Inter,sans-serif;
  font-size:.72rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--teal-dark);margin-bottom:var(--s3);
}
.eyebrow::before{
  content:"";width:18px;height:2px;background:var(--teal);flex:none;
  transform-origin:left center;
}
.js .eyebrow::before{
  transform:scaleX(0);
  animation:thrust .5s cubic-bezier(.2,.9,.25,1) .1s forwards;
}
@keyframes thrust{ to{transform:scaleX(1);} }

.lede{color:var(--charcoal-soft);max-width:60ch;}

/* --- Buttons -------------------------------------------------------------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);
  min-height:48px;                       /* touch target */
  font-family:Archivo,Inter,sans-serif;font-weight:700;font-size:.95rem;
  letter-spacing:-.01em;text-decoration:none;cursor:pointer;
  border:1px solid transparent;border-radius:var(--radius);
  padding:var(--s3) var(--s5);
  touch-action:manipulation;
  transition:background var(--dur) var(--ease),
             border-color var(--dur) var(--ease),
             transform var(--dur) var(--ease),
             box-shadow var(--dur) var(--ease);
}
.btn--primary{background:var(--red-cta);color:var(--white);}
.btn--primary:hover{background:var(--red-cta-hover);transform:translateY(-2px);box-shadow:var(--shadow);}
.btn--ghost{border-color:var(--line);color:var(--charcoal);background:var(--white);}
.btn--ghost:hover{border-color:var(--charcoal);transform:translateY(-2px);}
.btn--wa{background:var(--teal-dark);color:var(--white);}
.btn--wa:hover{background:var(--teal-deep);transform:translateY(-2px);box-shadow:var(--shadow);}
.btn--onteal{background:var(--white);color:var(--charcoal);}
.btn--onteal:hover{transform:translateY(-2px);box-shadow:var(--shadow-lift);}
.btn:active{transform:translateY(0) scale(.98);}
.btn[disabled],.btn[aria-disabled="true"]{opacity:.45;pointer-events:none;}
.btn svg{width:18px;height:18px;flex:none;}

/* --- Header --------------------------------------------------------------- */
.site-header{
  position:sticky;top:0;z-index:var(--z-header);
  background:rgba(247,247,247,.9);
  backdrop-filter:saturate(180%) blur(12px);
  border-bottom:1px solid var(--line-soft);
  padding-top:env(safe-area-inset-top);
}
.site-header .shell{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s4);
  padding-block:var(--s3);
}
.brand{display:inline-block;line-height:0;flex:none;view-transition-name:brand;}
.brand img{width:128px;}
@media (min-width:768px){ .brand img{width:156px;} }

/* Desktop nav ------------------------------------------------------------- */
.nav{display:none;}
@media (min-width:900px){
  .nav{display:flex;align-items:center;gap:var(--s5);}
  .nav a{
    font-size:.92rem;font-weight:500;text-decoration:none;color:var(--charcoal-soft);
    position:relative;padding-block:var(--s1);
    transition:color var(--dur) var(--ease);
  }
  .nav a::after{
    content:"";position:absolute;left:0;bottom:0;height:2px;width:0;
    background:var(--teal);transition:width var(--dur) var(--ease);
  }
  .nav a:hover{color:var(--charcoal);}
  .nav a:hover::after,.nav a[aria-current="page"]::after{width:100%;}
  .nav a[aria-current="page"]{color:var(--charcoal);}
}

.header-actions{display:flex;align-items:center;gap:var(--s2);flex:none;}
.header-actions .btn{padding:var(--s2) var(--s4);font-size:.88rem;min-height:44px;}
.header-actions .btn--ghost{display:none;}
@media (min-width:600px){ .header-actions .btn--ghost{display:inline-flex;} }

/* Mobile menu -------------------------------------------------------------
   A disclosure, not a modal: no focus trap, no scroll lock, no dependencies.
   Hidden with [hidden] so it is unreachable to AT and keyboard when closed. */
.nav-toggle{
  display:inline-flex;align-items:center;justify-content:center;
  width:44px;height:44px;flex:none;
  background:none;border:1px solid var(--line);border-radius:var(--radius);
  cursor:pointer;touch-action:manipulation;
  transition:border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.nav-toggle:hover{border-color:var(--charcoal-mute);}
@media (min-width:900px){ .nav-toggle{display:none;} }

/* Three bars morph to an X. Transform only — no layout thrash. */
.nav-toggle .bars{position:relative;width:18px;height:12px;display:block;}
.nav-toggle .bars i{
  position:absolute;left:0;height:2px;width:100%;
  background:var(--charcoal);border-radius:1px;
  transition:transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.nav-toggle .bars i:nth-child(1){top:0;}
.nav-toggle .bars i:nth-child(2){top:5px;}
.nav-toggle .bars i:nth-child(3){top:10px;}
.nav-toggle[aria-expanded="true"] .bars i:nth-child(1){transform:translateY(5px) rotate(45deg);}
.nav-toggle[aria-expanded="true"] .bars i:nth-child(2){opacity:0;}
.nav-toggle[aria-expanded="true"] .bars i:nth-child(3){transform:translateY(-5px) rotate(-45deg);}

.mobile-nav{
  border-top:1px solid var(--line-soft);
  background:var(--paper);
}
.mobile-nav[hidden]{display:none;}
@media (min-width:900px){ .mobile-nav{display:none;} }
.mobile-nav ul{list-style:none;margin:0;padding:var(--s2) 0 var(--s4);display:grid;}
.mobile-nav a{
  display:flex;align-items:center;min-height:52px;
  padding:0 var(--s1);
  font-family:Archivo,Inter,sans-serif;font-weight:700;font-size:1.02rem;
  color:var(--charcoal);text-decoration:none;
  border-bottom:1px solid var(--line-soft);
}
.mobile-nav li:last-child a{border-bottom:0;}
.mobile-nav a[aria-current="page"]{color:var(--teal-dark);}
.mobile-nav a[aria-current="page"]::before{
  content:"";width:3px;height:18px;background:var(--teal);
  margin-right:var(--s3);border-radius:2px;
}
.mobile-nav .btn{margin-top:var(--s4);width:100%;}
.js .mobile-nav:not([hidden]) li{
  opacity:0;transform:translateY(-6px);
  animation:navIn .26s var(--ease-out) forwards;
}
.js .mobile-nav:not([hidden]) li:nth-child(1){animation-delay:.02s}
.js .mobile-nav:not([hidden]) li:nth-child(2){animation-delay:.05s}
.js .mobile-nav:not([hidden]) li:nth-child(3){animation-delay:.08s}
.js .mobile-nav:not([hidden]) li:nth-child(4){animation-delay:.11s}
.js .mobile-nav:not([hidden]) li:nth-child(5){animation-delay:.14s}
.js .mobile-nav:not([hidden]) li:nth-child(6){animation-delay:.17s}
@keyframes navIn{ to{opacity:1;transform:none;} }

/* --- Hero ----------------------------------------------------------------- */
.hero{position:relative;padding-top:var(--s6);padding-bottom:var(--step);}
.hero::before{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background-image:
    linear-gradient(var(--line-soft) 1px, transparent 1px),
    linear-gradient(90deg, var(--line-soft) 1px, transparent 1px);
  background-size:56px 56px;
  -webkit-mask-image:radial-gradient(ellipse 90% 60% at 20% 15%, #000 15%, transparent 72%);
          mask-image:radial-gradient(ellipse 90% 60% at 20% 15%, #000 15%, transparent 72%);
}
.hero .shell{position:relative;z-index:1;}
.hero__copy{max-width:58ch;}
.hero h1 .accent{color:var(--red);}
.hero__lede{margin-top:var(--s4);font-size:1.05rem;}
@media (min-width:768px){ .hero__lede{font-size:1.2rem;} }
.hero__actions{display:flex;flex-wrap:wrap;gap:var(--s3);margin-top:var(--s6);}
.hero__actions .btn{flex:1 1 auto;}
@media (min-width:600px){ .hero__actions .btn{flex:0 0 auto;} }
.hero__note{margin-top:var(--s4);font-size:.86rem;color:var(--charcoal-mute);}

.hero__figure{
  position:relative;margin-top:var(--s7);
  border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-lift);
}
.hero__figure img{width:100%;object-fit:cover;}

/* --- Hero slider ---------------------------------------------------------- */
/* Slides share one grid cell, so the container is sized by the slides
   themselves and nothing is absolutely positioned. No fixed height, no CLS. */
.hero__slider{
  position:relative;
  display:grid;
  margin-top:var(--s7);
  border-radius:var(--radius-lg);
  overflow:hidden;
  box-shadow:var(--shadow-lift);
  background:var(--charcoal);
}
.hero__slide{
  grid-area:1 / 1;
  position:relative;   /* anchors this slide's own chip */
  margin:0;
  min-width:0;
  opacity:0;
  visibility:hidden;
  transform:scale(1.04);
  /* visibility flips only after the fade finishes, so an outgoing slide stays
     painted while it fades but leaves the a11y tree once it's gone. */
  transition:opacity .9s var(--ease), transform 1.3s var(--ease), visibility 0s .9s;
}
/* Slide 1 carries .is-active in the markup, so with JS disabled the hero shows
   a real image instead of going blank. The rule is deliberately not scoped to
   .js for that reason. */
.hero__slide.is-active{
  opacity:1;
  visibility:visible;
  transform:scale(1);
  transition:opacity .9s var(--ease), transform 1.3s var(--ease), visibility 0s 0s;
}
.hero__slide img{display:block;width:100%;height:100%;object-fit:cover;}

/* Controls are an enhancement — without JS they do nothing, so they aren't shown. */
.slider__ui{display:none;}
.js .slider__ui{display:block;}

.slider__arrow{
  position:absolute;top:50%;transform:translateY(-50%);
  z-index:2;
  display:grid;place-items:center;
  width:44px;height:44px;              /* full tap target, not a decorative dot */
  border:1px solid rgba(255,255,255,.28);
  border-radius:999px;
  background:rgba(35,31,32,.5);
  backdrop-filter:blur(6px);
  color:var(--white);
  cursor:pointer;
  opacity:0;
  transition:opacity var(--dur) var(--ease), background var(--dur) var(--ease);
}
.slider__arrow svg{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;}
.slider__arrow--prev{left:var(--s3);}
.slider__arrow--next{right:var(--s3);}
.hero__slider:hover .slider__arrow,
.hero__slider:focus-within .slider__arrow{opacity:1;}
.slider__arrow:hover{background:rgba(35,31,32,.75);}
.slider__arrow:focus-visible{opacity:1;outline:2px solid var(--white);outline-offset:2px;}
/* Touch has no hover, so the arrows would never appear. Dots and swipe carry
   navigation there instead. */
@media (hover:none){ .slider__arrow{display:none;} }

.slider__dots{
  position:absolute;left:var(--s3);bottom:var(--s3);z-index:2;
  display:flex;gap:var(--s2);
}
.slider__dots button{
  /* 8px of ink, 24px of target — the padding does the reaching. */
  width:24px;height:24px;padding:8px;
  border:0;background:none;cursor:pointer;
  display:grid;place-items:center;
}
.slider__dots button::before{
  content:"";display:block;width:8px;height:8px;
  border-radius:999px;
  background:rgba(255,255,255,.45);
  box-shadow:0 0 0 1px rgba(35,31,32,.25);
  transition:background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.slider__dots button.is-on::before{background:var(--white);transform:scale(1.25);}
.slider__dots button:focus-visible{outline:2px solid var(--white);outline-offset:0;border-radius:999px;}

/* Reduced motion: swap instantly, and site.js never starts the autoplay timer. */
@media (prefers-reduced-motion:reduce){
  .hero__slide{transition:opacity .01s, visibility 0s .01s;transform:none;}
  .hero__slide.is-active{transition:opacity .01s, visibility 0s 0s;transform:none;}
}

/* Delivered work. The overlay counterpart to .status-tag--live, which is a
   body tag rather than a chip. Teal = identity, per the brand rule. */
.live-chip{
  position:absolute;right:var(--s3);bottom:var(--s3);
  font-family:Archivo,Inter,sans-serif;
  font-size:.62rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--white);background:var(--teal-dark);
  border:1px solid rgba(255,255,255,.24);
  border-radius:999px;padding:.28rem .62rem;
}

/* Honesty chip — visualisation, not delivered work */
.concept-chip{
  position:absolute;right:var(--s3);bottom:var(--s3);
  font-family:Archivo,Inter,sans-serif;
  font-size:.62rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--white);background:rgba(35,31,32,.66);
  backdrop-filter:blur(6px);
  border:1px solid rgba(255,255,255,.24);
  border-radius:999px;padding:.28rem .62rem;
}

/* module assembly strip — the motion through-line: things lock into place */
.modules{display:flex;gap:5px;margin:0;padding:0;list-style:none;}
.modules li{
  height:8px;width:clamp(24px,6vw,44px);
  background:var(--charcoal);border-radius:2px;
  opacity:0;transform:translateY(-10px);
  animation:drop .5s var(--ease-out) forwards;
}
.modules li:nth-child(1){animation-delay:.08s}
.modules li:nth-child(2){animation-delay:.18s}
.modules li:nth-child(3){animation-delay:.28s}
.modules li:nth-child(4){animation-delay:.38s;background:var(--teal)}
.modules li:nth-child(5){animation-delay:.48s}
.modules li:nth-child(6){animation-delay:.58s;background:var(--red);width:clamp(12px,2.6vw,18px)}
@keyframes drop{to{opacity:1;transform:translateY(0);}}

/* --- Page hero (inner pages) ---------------------------------------------- */
.page-hero{
  position:relative;
  padding-block:var(--s7) var(--s6);
  border-bottom:1px solid var(--line-soft);
  /* The grid below starts translated to the right of its box. Without this it
     would widen the document and add a horizontal scrollbar for one second. */
  overflow:hidden;
}
/* The blueprint grid sits in the dead space to the RIGHT of the heading, not
   underneath it: h1 is capped at 18ch, so the right half of every inner hero
   was empty. Masked from 85%, it fills that space without ever running under
   the text, where it competed with the words for the same pixels. */
.page-hero::before{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background-image:
    linear-gradient(var(--line-soft) 1px, transparent 1px),
    linear-gradient(90deg, var(--line-soft) 1px, transparent 1px);
  background-size:56px 56px;
  -webkit-mask-image:radial-gradient(ellipse 62% 92% at 85% 45%, #000 12%, transparent 72%);
          mask-image:radial-gradient(ellipse 62% 92% at 85% 45%, #000 12%, transparent 72%);
  /* Settles in from the right, echoing the spear's forward thrust and the
     module strip. Compositor-only (transform + opacity), so it costs nothing
     on the main thread. */
  transform-origin:100% 50%;
  animation:grid-settle 1.1s var(--ease) both;
}
@keyframes grid-settle{
  from{opacity:0;transform:translate3d(44px,0,0) scale(1.05);}
  to  {opacity:1;transform:none;}
}
/* Below 768px the heading wraps wide and there is no dead space to fill, so the
   grid would sit under the text. Pull it back toward the corner instead. */
@media (max-width:767px){
  .page-hero::before{
    -webkit-mask-image:radial-gradient(ellipse 80% 70% at 88% 8%, #000 10%, transparent 70%);
            mask-image:radial-gradient(ellipse 80% 70% at 88% 8%, #000 10%, transparent 70%);
  }
}
@media (prefers-reduced-motion:reduce){
  .page-hero::before{animation:none;}
}
.page-hero .shell{position:relative;z-index:1;}
.page-hero h1{font-size:clamp(1.9rem,5.4vw,3.2rem);max-width:18ch;}
.page-hero .lede{margin-top:var(--s4);font-size:1.05rem;}
@media (min-width:768px){ .page-hero .lede{font-size:1.15rem;} }

/* Breadcrumb */
.crumbs{margin-bottom:var(--s3);font-size:.82rem;color:var(--charcoal-mute);}
.crumbs ol{list-style:none;display:flex;flex-wrap:wrap;align-items:center;gap:var(--s2);margin:0;padding:0;}
.crumbs li{display:flex;align-items:center;}
.crumbs li:not(:last-child)::after{content:"/";margin-left:var(--s2);color:var(--line);}
/* 44px tap target without pushing the crumb visually off the grid */
.crumbs a{
  color:var(--charcoal-soft);text-decoration:none;
  display:inline-flex;align-items:center;min-height:44px;
  transition:color var(--dur) var(--ease);
}
.crumbs a:hover{color:var(--teal-dark);}

/* --- Anchor chip nav ------------------------------------------------------ */
.chip-nav{
  /* Stacks BELOW the sticky header, not underneath it. Both are sticky, so
     top:0 here would park the chips invisibly behind the header. */
  position:sticky;top:var(--header-h);z-index:40;
  background:rgba(247,247,247,.92);
  backdrop-filter:saturate(180%) blur(10px);
  border-bottom:1px solid var(--line-soft);
  position:sticky;
}
/* A chip cut off at the edge is fine ONLY if it reads as "there's more this
   way". Bare, it just looks broken. The mask fades the trailing chip out
   instead of guillotining it, and scroll-snap makes the swipe land cleanly.
   The fade is dropped once everything fits. */
.chip-nav .shell{
  display:flex;gap:var(--s2);
  overflow-x:auto;
  padding-block:var(--s3);
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;
  scroll-padding-inline:1rem;
  -webkit-mask-image:linear-gradient(90deg, #000 calc(100% - 48px), transparent);
          mask-image:linear-gradient(90deg, #000 calc(100% - 48px), transparent);
}
.chip-nav .shell::-webkit-scrollbar{display:none;}
.chip-nav a{scroll-snap-align:start;}
/* No overflow, no fade: .is-end is set by site.js when scrolled to the end,
   and .no-scroll when everything already fits. */
.chip-nav .shell.is-end,
.chip-nav .shell.no-scroll{
  -webkit-mask-image:none;mask-image:none;
}
.chip-nav a{
  flex:none;display:inline-flex;align-items:center;min-height:44px;
  padding:0 var(--s4);
  font-family:Archivo,Inter,sans-serif;font-weight:700;font-size:.82rem;
  color:var(--charcoal-soft);text-decoration:none;white-space:nowrap;
  border:1px solid var(--line);border-radius:999px;background:var(--white);
  transition:border-color var(--dur) var(--ease), color var(--dur) var(--ease),
             background var(--dur) var(--ease);
}
.chip-nav a:hover{border-color:var(--charcoal-mute);color:var(--charcoal);}
.chip-nav a.is-active{
  background:var(--teal-wash);border-color:var(--teal-dark);color:var(--teal-dark);
}

/* --- Sector blocks (alternating) ------------------------------------------ */
.sector{padding-block:var(--step);border-bottom:1px solid var(--line-soft);}
.sector:nth-child(even){background:var(--white);}
.sector__grid{display:grid;gap:var(--s6);align-items:center;}
@media (min-width:900px){
  .sector__grid{grid-template-columns:1fr 1fr;gap:var(--s8);}
  /* Alternate which side the image sits on, without reordering the DOM */
  .sector:nth-child(even) .sector__media{order:2;}
}
.sector__media{border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow);position:relative;}
.sector__media img{width:100%;object-fit:cover;}
.sector h2{margin-bottom:var(--s3);}
.sector__body > p{color:var(--charcoal-soft);}

.spec-list{list-style:none;margin:var(--s5) 0 0;padding:0;display:grid;gap:var(--s2);}
.spec-list li{display:flex;gap:var(--s3);align-items:flex-start;font-size:.94rem;}
.spec-list li::before{
  content:"";flex:none;width:7px;height:7px;margin-top:.55rem;
  background:var(--teal);border-radius:1px;
}
/* Mobile-first: one full-width button per row, so the two CTAs read as a pair
   rather than two ragged widths. They shrink to content once there's room. */
.sector__cta{margin-top:var(--s6);display:grid;gap:var(--s3);}
@media (min-width:520px){
  .sector__cta{display:flex;flex-wrap:wrap;}
  .sector__cta .btn{flex:0 0 auto;}
}

/* --- FAQ ------------------------------------------------------------------ */
.faq{display:grid;gap:var(--s2);margin-top:var(--s6);}
.faq details{
  background:var(--white);border:1px solid var(--line-soft);
  border-radius:var(--radius);overflow:hidden;
  transition:border-color var(--dur) var(--ease);
}
.faq details[open]{border-color:var(--line);}
.faq summary{
  cursor:pointer;list-style:none;
  display:flex;align-items:center;justify-content:space-between;gap:var(--s4);
  padding:var(--s4);min-height:56px;
  font-family:Archivo,Inter,sans-serif;font-weight:700;font-size:1rem;
  touch-action:manipulation;
}
.faq summary::-webkit-details-marker{display:none;}
.faq summary::after{
  content:"";flex:none;width:10px;height:10px;
  border-right:2px solid var(--teal-dark);border-bottom:2px solid var(--teal-dark);
  transform:rotate(45deg) translateY(-2px);
  transition:transform var(--dur) var(--ease);
}
.faq details[open] summary::after{transform:rotate(-135deg) translateY(-2px);}
.faq summary:hover{color:var(--teal-dark);}
.faq .answer{padding:0 var(--s4) var(--s5);color:var(--charcoal-soft);font-size:.95rem;}
.faq .answer p + p{margin-top:var(--s3);}

/* --- Project cards -------------------------------------------------------- */
.project{
  background:var(--white);border:1px solid var(--line-soft);
  border-radius:var(--radius-lg);overflow:hidden;
}
.project__grid{display:grid;}
@media (min-width:820px){ .project__grid{grid-template-columns:1.1fr .9fr;align-items:center;} }
.project__media{position:relative;background:var(--paper);}
.project__media img{width:100%;object-fit:cover;aspect-ratio:4/3;}
@media (min-width:820px){ .project__media img{height:100%;aspect-ratio:auto;min-height:360px;} }
/* Drawings and product renders are letterboxed at build time onto the paper
   colour — contain here too so nothing gets sliced by the card's aspect. */
.project__media--contain img{object-fit:contain;}

/* Design chip — the counterpart to .concept-chip, for SSMS's own drawings. */
.design-chip{
  position:absolute;right:var(--s3);bottom:var(--s3);
  font-family:Archivo,Inter,sans-serif;
  font-size:.62rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--charcoal);background:rgba(255,255,255,.9);
  backdrop-filter:blur(6px);
  border:1px solid var(--line);
  border-radius:999px;padding:.28rem .62rem;
}
.project__body{padding:var(--s5) var(--s4);}
@media (min-width:600px){ .project__body{padding:var(--s6);} }

.status-tag{
  display:inline-flex;align-items:center;gap:var(--s2);
  font-family:Archivo,Inter,sans-serif;font-size:.66rem;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;
  border-radius:999px;padding:.3rem .7rem;margin-bottom:var(--s3);
}
.status-tag--live{background:var(--teal-dark);color:var(--white);}
.status-tag--wip{background:var(--charcoal);color:var(--white);}
/* SSMS's own design work — drawings and 3D. Distinct from both a delivered
   photo and an AI concept image. */
.status-tag--design{
  background:var(--white);color:var(--charcoal-soft);
  border:1px solid var(--line);
}
.status-tag--design::before{
  content:"";width:7px;height:7px;flex:none;
  border:2px solid var(--teal);border-radius:1px;
}
.status-tag--wip .pulse{
  width:6px;height:6px;border-radius:50%;background:var(--red);
  animation:pulse 2s ease-in-out infinite;
}
@keyframes pulse{ 0%,100%{opacity:1} 50%{opacity:.3} }

/* --- Gallery -------------------------------------------------------------- */
.gallery{display:grid;gap:var(--s3);margin-top:var(--s6);}
@media (min-width:600px){ .gallery{grid-template-columns:repeat(2,1fr);} }
@media (min-width:1000px){ .gallery{grid-template-columns:repeat(3,1fr);} }
.gallery figure{
  margin:0;position:relative;border-radius:var(--radius);overflow:hidden;
  background:var(--paper);border:1px solid var(--line-soft);
}
.gallery img{width:100%;aspect-ratio:3/2;object-fit:cover;transition:transform .5s var(--ease);}
.gallery figure:hover img{transform:scale(1.04);}

/* Per-image captions. A single caption saying "left and centre... right..."
   is only true in a 3-column grid; on a phone the grid is one column and the
   words describe a layout that isn't there. Caption each image instead and it
   reads correctly at every width. */
.gallery figcaption.shot{
  position:static;
  padding:var(--s3) var(--s4) var(--s4);
  font-size:.84rem;
  color:var(--charcoal-soft);
  line-height:1.45;
  background:var(--white);
  border-top:1px solid var(--line-soft);
}
.gallery figure:has(> figcaption.shot){display:flex;flex-direction:column;}
.gallery figure:has(> figcaption.shot) picture{display:block;}

/* --- Timeline (process) ---------------------------------------------------
   The rail draws downward and each dot lands as its step arrives: the process
   advancing, step by step. The rail is a pseudo-element so it can scaleY
   without touching layout. */
.timeline{list-style:none;margin:var(--s6) 0 0;padding:0;display:grid;gap:0;}
.timeline li{
  position:relative;
  padding:0 0 var(--s7) var(--s6);
}
.timeline li::before{
  content:"";position:absolute;left:0;top:0;bottom:0;
  width:2px;background:var(--line);
  transform-origin:top center;
}
.timeline li:last-child{padding-bottom:0;}
.timeline li:last-child::before{display:none;}
.timeline .dot{
  position:absolute;left:-7px;top:2px;
  width:16px;height:16px;border-radius:50%;
  background:var(--paper);border:2px solid var(--teal);
  z-index:1;
}
.timeline li:first-child .dot{background:var(--teal);}

.js .timeline.is-in li::before{
  transform:scaleY(0);
  animation:rail .5s linear forwards;
}
.js .timeline.is-in .dot{
  transform:scale(0);
  animation:land .34s cubic-bezier(.2,1.5,.4,1) forwards;
}
@keyframes rail{ to{transform:scaleY(1);} }
@keyframes land{ to{transform:scale(1);} }
/* Stagger so the rail reaches a dot just before the dot lands. */
.js .timeline.is-in li:nth-child(1)::before{animation-delay:.10s}
.js .timeline.is-in li:nth-child(1) .dot{animation-delay:.05s}
.js .timeline.is-in li:nth-child(2)::before{animation-delay:.55s}
.js .timeline.is-in li:nth-child(2) .dot{animation-delay:.50s}
.js .timeline.is-in li:nth-child(3)::before{animation-delay:1.00s}
.js .timeline.is-in li:nth-child(3) .dot{animation-delay:.95s}
.js .timeline.is-in li:nth-child(4)::before{animation-delay:1.45s}
.js .timeline.is-in li:nth-child(4) .dot{animation-delay:1.40s}
.js .timeline.is-in li:nth-child(5)::before{animation-delay:1.90s}
.js .timeline.is-in li:nth-child(5) .dot{animation-delay:1.85s}
.js .timeline.is-in li:nth-child(6) .dot{animation-delay:2.30s}
.timeline .n{
  font-family:Archivo,Inter,sans-serif;font-weight:800;font-size:.72rem;
  letter-spacing:.12em;color:var(--teal-dark);
  display:block;margin-bottom:var(--s1);font-variant-numeric:tabular-nums;
}
.timeline h3{margin-bottom:var(--s2);}
.timeline p{color:var(--charcoal-soft);font-size:.95rem;}
.timeline .who{
  margin-top:var(--s3);font-size:.82rem;color:var(--charcoal-mute);
  display:flex;align-items:center;gap:var(--s2);
}
.timeline .who::before{
  content:"";width:14px;height:2px;background:var(--line);flex:none;
}

/* --- Prose (about / long copy) -------------------------------------------- */
.prose{max-width:66ch;}
.prose p + p{margin-top:var(--s4);}
.prose h2{margin-top:var(--s7);margin-bottom:var(--s3);}
.prose h3{margin-top:var(--s5);margin-bottom:var(--s2);}
.prose ul{margin:var(--s4) 0 0;padding-left:var(--s5);color:var(--charcoal-soft);}
.prose li{margin-bottom:var(--s2);}
.pull{
  margin:var(--s6) 0;padding-left:var(--s5);
  border-left:3px solid var(--teal);
  font-family:Archivo,Inter,sans-serif;font-weight:700;
  font-size:clamp(1.15rem,2.4vw,1.5rem);letter-spacing:-.02em;line-height:1.35;
}

/* --- Capability strip -----------------------------------------------------
   Four plain boxes read as filler. Each cell now carries an index, a rule that
   grows on hover, and a blueprint grid that surfaces behind it — the same
   language as the hero, so it belongs to the page rather than sitting on it. */
.strip{
  display:grid;gap:1px;margin:0;
  grid-template-columns:1fr 1fr;
  background:var(--line-soft);
  border:1px solid var(--line);border-radius:var(--radius-lg);overflow:hidden;
  box-shadow:var(--shadow);
}
@media (min-width:900px){ .strip{grid-template-columns:repeat(4,1fr);} }

.strip > div{
  position:relative;
  background:var(--white);
  padding:var(--s6) var(--s5) var(--s5);
  overflow:hidden;
  isolation:isolate;
  transition:background var(--dur) var(--ease);
}
.strip > div::before{           /* blueprint grid, hidden until hover */
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:
    linear-gradient(var(--line-soft) 1px, transparent 1px),
    linear-gradient(90deg, var(--line-soft) 1px, transparent 1px);
  background-size:28px 28px;
  opacity:0;transition:opacity .35s var(--ease);
}
.strip > div:hover::before{opacity:1;}

/* index number, engineering-annotation style */
.strip > div::after{
  content:counter(strip-i, decimal-leading-zero);
  position:absolute;top:var(--s3);right:var(--s4);
  font-family:Archivo,Inter,sans-serif;font-weight:700;
  font-size:.62rem;letter-spacing:.14em;
  color:var(--charcoal-mute);opacity:.45;
  font-variant-numeric:tabular-nums;
}
.strip{counter-reset:strip-i;}
.strip > div{counter-increment:strip-i;}

.strip dt{
  font-family:Archivo,Inter,sans-serif;font-weight:800;
  font-size:clamp(1.7rem,3.2vw,2.15rem);
  line-height:1;letter-spacing:-.03em;
  font-variant-numeric:tabular-nums;
  color:var(--charcoal);
}
/* the rule under each number is the accent — it extends on hover */
.strip dt::after{
  content:"";display:block;
  width:22px;height:3px;border-radius:2px;
  background:var(--teal);
  margin-top:var(--s3);
  transition:width .35s var(--ease), background .35s var(--ease);
}
.strip > div:hover dt::after{width:44px;}
.strip > div:last-child dt::after{background:var(--red);}

.strip dd{
  margin:var(--s3) 0 0;
  font-size:.88rem;color:var(--charcoal-soft);line-height:1.5;
  max-width:22ch;
}

/* --- Cards ---------------------------------------------------------------- */
.grid-sectors{display:grid;gap:var(--s4);}
@media (min-width:640px){ .grid-sectors{grid-template-columns:repeat(2,1fr);gap:var(--s5);} }
@media (min-width:1000px){ .grid-sectors{grid-template-columns:repeat(3,1fr);} }

.card{
  display:flex;flex-direction:column;
  background:var(--white);border:1px solid var(--line-soft);
  border-radius:var(--radius);overflow:hidden;
  text-decoration:none;color:inherit;
  transition:transform var(--dur) var(--ease),
             box-shadow var(--dur) var(--ease),
             border-color var(--dur) var(--ease);
}
.card:hover{transform:translateY(-4px);box-shadow:var(--shadow-lift);border-color:var(--line);}
.card:active{transform:translateY(-1px);}

.card__media{position:relative;overflow:hidden;background:var(--paper);}
/* Fixed ratio on every card, so a 4:3 source and a 16:9 source still line up
   across the grid. Without this the intrinsic ratio wins and the row goes ragged. */
.card__media img{
  width:100%;aspect-ratio:16/9;object-fit:cover;
  transition:transform .55s var(--ease);
}
/* Real kiosk photos are square and bottom-weighted (the unit sits low in frame),
   so trim from the top rather than centring and beheading it. */
.card__media img.crop-low{object-position:center 72%;}
.card:hover .card__media img{transform:scale(1.045);}

.card__body{padding:var(--s5) var(--s4);display:flex;flex-direction:column;flex:1;}
.card__body h3{margin-bottom:var(--s2);}
.card__kicker{
  font-family:Archivo,Inter,sans-serif;font-size:.68rem;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--teal-dark);
  margin-bottom:var(--s2);display:block;
}
.card__body p{font-size:.93rem;color:var(--charcoal-soft);}
.card__list{margin:var(--s4) 0 0;padding:0;list-style:none;display:flex;flex-wrap:wrap;gap:var(--s1);}
.card__list li{
  font-size:.74rem;color:var(--charcoal-mute);
  border:1px solid var(--line-soft);border-radius:3px;padding:.22rem .48rem;
}
.card__more{
  margin-top:auto;padding-top:var(--s4);
  font-family:Archivo,Inter,sans-serif;font-weight:700;font-size:.85rem;
  color:var(--teal-dark);display:inline-flex;align-items:center;gap:var(--s1);
}
.card__more::after{content:"→";transition:transform var(--dur) var(--ease);}
.card:hover .card__more::after{transform:translateX(4px);}

/* --- Split / reasons ------------------------------------------------------ */
.split{display:grid;gap:var(--s6);align-items:center;}
@media (min-width:900px){ .split{grid-template-columns:1fr 1fr;gap:var(--s8);} }
.split__media{border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow);position:relative;}
.split__media img{width:100%;object-fit:cover;}

.reasons{margin:var(--s6) 0 0;padding:0;list-style:none;display:grid;gap:var(--s5);}
.reasons li{padding-left:var(--s4);border-left:2px solid var(--teal);}
.reasons h3{margin-bottom:var(--s1);}
.reasons p{font-size:.93rem;color:var(--charcoal-soft);}

/* --- Feature (real project) ----------------------------------------------- */
.feature{display:grid;gap:var(--s6);align-items:center;}
@media (min-width:900px){ .feature{grid-template-columns:1.05fr .95fr;gap:var(--s7);} }
.feature__media{border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow);}
.feature__media img{width:100%;object-fit:cover;}
.badge-real{
  display:inline-flex;align-items:center;gap:var(--s2);
  font-family:Archivo,Inter,sans-serif;font-size:.68rem;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;
  color:var(--white);background:var(--teal-dark);
  border-radius:999px;padding:.3rem .7rem;margin-bottom:var(--s3);
}
.feature__meta{
  margin:var(--s6) 0 0;padding:var(--s5) 0 0;
  border-top:1px solid var(--line);
  display:grid;grid-template-columns:repeat(2,1fr);gap:var(--s4);
}
@media (min-width:600px){ .feature__meta{grid-template-columns:repeat(3,1fr);} }
.feature__meta dt{font-size:.68rem;letter-spacing:.12em;text-transform:uppercase;color:var(--charcoal-mute);}
.feature__meta dd{
  margin:var(--s1) 0 0;font-family:Archivo,Inter,sans-serif;
  font-weight:700;font-size:.95rem;
}

/* --- Process -------------------------------------------------------------- */
.steps{
  display:grid;gap:1px;margin:0;padding:0;
  background:var(--line-soft);
  border:1px solid var(--line-soft);border-radius:var(--radius);overflow:hidden;
}
@media (min-width:640px){ .steps{grid-template-columns:repeat(2,1fr);} }
@media (min-width:1000px){ .steps{grid-template-columns:repeat(3,1fr);} }
.steps li{background:var(--white);padding:var(--s5) var(--s4);list-style:none;}
.steps .n{
  font-family:Archivo,Inter,sans-serif;font-weight:800;font-size:.74rem;
  color:var(--teal-dark);letter-spacing:.1em;display:block;margin-bottom:var(--s2);
  font-variant-numeric:tabular-nums;
}
.steps h3{font-size:1rem;margin-bottom:var(--s1);}
.steps p{font-size:.86rem;color:var(--charcoal-soft);}

/* --- CTA band ------------------------------------------------------------- */
/* Deeper teal than the logo band so white body text clears AA (5.19:1).
   Hierarchy comes from size/weight, never opacity — faded white would fail. */
.cta-band{
  position:relative;
  background:var(--teal-dark);
  color:var(--white);
  overflow:hidden;
  isolation:isolate;
}
/* The module motif again, at architectural scale: a blueprint grid plus one
   red module locking in. Same idea as the hero strip, so the site's last
   screen rhymes with its first. */
.cta-band::before{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:
    linear-gradient(rgba(255,255,255,.09) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.09) 1px, transparent 1px);
  background-size:64px 64px;
  -webkit-mask-image:radial-gradient(ellipse 70% 120% at 88% 50%, #000 10%, transparent 70%);
          mask-image:radial-gradient(ellipse 70% 120% at 88% 50%, #000 10%, transparent 70%);
}
/* The spear mark itself, traced to an outline from the real logo (see
   tools/build-images.py) rather than approximated by hand. Decorative only —
   the mark already appears properly in the header and footer. */
/* The spear is now an inlined <svg class="cta-spear"> (traced from the logo by
   tools/trace-spear.py) rather than a background image, because a background
   can't be stroke-animated. Sized by HEIGHT: the mark is 425:856, so a
   width-driven box overflows the band and clips the tip. */
.cta-spear{
  position:absolute;z-index:-1;pointer-events:none;
  right:3%;top:50%;
  /* 88% keeps the tip and tail inside the band. Anything over 100% clips them,
     which reads as a mistake rather than a bleed. */
  height:min(88%, 420px);
  width:auto;
  transform:translateY(-50%);
  overflow:visible;
  stroke:#fff;
  stroke-width:5;
  stroke-linejoin:round;
  stroke-linecap:round;
  fill:none;
  opacity:.24;
}
@media (max-width:899px){
  .cta-spear{right:-8%;opacity:.15;height:min(78%, 300px);stroke-width:8;}
}

/* Draw-on: pathLength="1" normalises the dash maths, so this is two lines of
   CSS and no JS measurement. The mark draws itself once, when the band arrives. */
.js .cta-spear path{
  stroke-dasharray:1;
  stroke-dashoffset:1;
}
.js .cta-spear.is-in path{
  stroke-dashoffset:0;
  transition:stroke-dashoffset 1.6s cubic-bezier(.65,0,.35,1) .15s;
}
.cta-band .shell{
  display:grid;gap:var(--s5);
  padding-block:var(--step);
}
@media (min-width:900px){
  .cta-band .shell{grid-template-columns:1.25fr auto;align-items:center;gap:var(--s8);}
}
.cta-band .eyebrow{color:var(--white);}
.cta-band .eyebrow::before{background:var(--white);opacity:.55;}
.cta-band h2{max-width:18ch;}
.cta-band p{margin-top:var(--s4);color:var(--white);max-width:46ch;}

.cta-band__actions{display:flex;flex-direction:column;gap:var(--s3);}
@media (min-width:600px) and (max-width:899px){
  .cta-band__actions{flex-direction:row;flex-wrap:wrap;}
  .cta-band__actions .btn{flex:1 1 auto;}
}
@media (min-width:900px){
  .cta-band__actions{min-width:252px;}
}
/* Centre the labels. Left-aligning them inside a full-width button left the
   text stranded against one edge on mobile, which read as broken rather than
   deliberate. The icon still sits with its label. */
.cta-band__actions .btn{padding-inline:var(--s5);}

/* Secondary action reads as secondary — outline on the teal, not a second slab
   of white competing with the primary.

   The background is the band's own colour rather than `transparent`, which
   looks identical on a plain surface but is not: the spear watermark is drawn
   behind this button, and a transparent fill let its strokes read straight
   through the label. The WhatsApp button never had the problem only because
   its white fill is opaque. A control owns its own pixels. */
.btn--onteal-ghost{
  background:var(--teal-dark);color:var(--white);
  border-color:rgba(255,255,255,.5);
}
/* Same lift as before, but opaque for the same reason as the base rule — a
   translucent hover would let the spear back through. #248781 is white 10%
   composited over --teal-dark, so it looks identical to the old rgba fill. */
.btn--onteal-ghost:hover{
  background:#248781;
  background:color-mix(in srgb, #fff 10%, var(--teal-dark));
  border-color:var(--white);
  transform:translateY(-2px);
}

.cta-band__note{
  margin-top:var(--s4);
  font-size:.84rem;
  color:var(--white);
  display:flex;align-items:center;gap:var(--s2);
}
.cta-band__note::before{
  content:"";width:6px;height:6px;border-radius:50%;
  background:var(--white);flex:none;
  animation:pulse 2.4s ease-in-out infinite;
}

/* --- Contact rows --------------------------------------------------------- */
.contact-list{list-style:none;margin:var(--s5) 0 0;padding:0;display:grid;gap:var(--s2);}
.contact-list a{
  display:flex;align-items:center;gap:var(--s3);min-height:48px;
  text-decoration:none;font-weight:500;
  padding:var(--s2) 0;
  transition:color var(--dur) var(--ease);
}
.contact-list a:hover{color:var(--teal-dark);}
.contact-list svg{width:20px;height:20px;flex:none;color:var(--teal-dark);}
.contact-list .label{
  display:block;font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--charcoal-mute);font-weight:600;
}
.contact-list .value{font-variant-numeric:tabular-nums;}

/* --- Footer --------------------------------------------------------------- */
.site-footer{background:var(--white);border-top:1px solid var(--line-soft);}
.site-footer .shell{display:grid;gap:var(--s6);padding-block:var(--s7) var(--s6);}
/* Four columns for four blocks. Three columns left Contact wrapping onto a
   second row under the logo, which read as a hole in the footer. */
@media (min-width:700px){ .site-footer .shell{grid-template-columns:1fr 1fr;gap:var(--s6) var(--s5);} }
@media (min-width:1000px){ .site-footer .shell{grid-template-columns:1.5fr 1fr 1fr 1.2fr;} }
.site-footer img{width:150px;margin-bottom:var(--s4);}
.site-footer h2{
  font-family:Archivo,Inter,sans-serif;font-size:.74rem;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--charcoal-mute);
  margin:0 0 var(--s3);
}

/* --- Footer accordion -----------------------------------------------------
   Eleven stacked links pushed the phone numbers off the bottom of a phone.
   <details> collapses them there. Ships with [open] so a JS failure leaves
   every link reachable; site.js closes them below 700px. Desktop keeps them
   open and strips the affordance so it reads as a plain column. */
.foot-group{margin:0;}
.foot-group summary{
  list-style:none;cursor:pointer;
  display:flex;align-items:center;justify-content:space-between;
  min-height:44px;
  touch-action:manipulation;
}
.foot-group summary::-webkit-details-marker{display:none;}
.foot-group summary h2{margin:0;}
.foot-group summary::after{
  content:"";flex:none;
  width:8px;height:8px;margin-right:2px;
  border-right:2px solid var(--charcoal-mute);
  border-bottom:2px solid var(--charcoal-mute);
  transform:rotate(45deg) translateY(-2px);
  transition:transform var(--dur) var(--ease);
}
.foot-group[open] summary::after{transform:rotate(-135deg) translateY(-2px);}
.foot-group summary:hover::after{border-color:var(--charcoal);}
.foot-group > ul{padding-bottom:var(--s3);}

@media (min-width:700px){
  /* Not interactive on desktop: no pointer, no chevron, always open. */
  .foot-group summary{cursor:default;min-height:0;pointer-events:none;}
  .foot-group summary::after{display:none;}
  .foot-group summary h2{margin:0 0 var(--s3);}
  .foot-group > ul{padding-bottom:0;}
}
.site-footer ul{list-style:none;margin:0;padding:0;display:grid;}
.site-footer a{
  font-size:.92rem;color:var(--charcoal-soft);text-decoration:none;
  /* 44px touch target without visually spacing the list out */
  display:inline-flex;align-items:center;min-height:44px;
  transition:color var(--dur) var(--ease);
}
.site-footer a:hover{color:var(--teal-dark);}
.site-footer .muted{font-size:.92rem;color:var(--charcoal-soft);}
.footer-base{border-top:1px solid var(--line-soft);}
.footer-base .shell{
  display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;
  gap:var(--s2) var(--s5);
  padding-block:var(--s4);font-size:.8rem;color:var(--charcoal-mute);
  padding-bottom:calc(var(--s4) + env(safe-area-inset-bottom));
}
/* Legal and credit travel together as ONE group on the right, so the row reads
   as two things (whose site | the small print) instead of three loose items.
   Under space-between a third item gets stranded in the middle, next to
   nothing it relates to. */
.footer-base__meta{
  display:flex;flex-wrap:wrap;align-items:center;
  gap:var(--s2) var(--s5);
}
/* .footer-base sits INSIDE .site-footer, so `.site-footer a` was already giving
   these links .92rem type in an .8rem row and a 44px inline-flex box. Both had
   to be undone here: the oversized type made the links louder than the line
   they sit in, and the 44px box is why a border-bottom underline floated ~15px
   under the baseline instead of hugging the text. These are inline links in a
   sentence, which WCAG 2.2 exempts from the target-size minimum (SC 2.5.8,
   "Inline" exception), so the 44px box bought nothing here. */
.footer-base a{
  font-size:inherit;
  display:inline;
  min-height:0;
  color:var(--charcoal-soft);
  /* Underlined at rest, unlike the footer's link lists above. Those sit in an
     obvious column of links; these are inline in a sentence ("Built by
     AxionCoreTech"), where colour is the only thing marking the link - and
     #4A4548 on #6B6568 is 1.65:1, far under the 3:1 that WCAG 1.4.1 wants
     before colour may carry that job alone. The underline is the non-colour
     cue. text-decoration, not border-bottom: it hugs the baseline and skips
     descenders, where a border draws at the bottom of the box. */
  text-decoration:underline;
  text-decoration-color:var(--line);
  text-decoration-thickness:1px;
  text-underline-offset:.22em;
  transition:color var(--dur) var(--ease), text-decoration-color var(--dur) var(--ease);
}
.footer-base a:hover,
.footer-base a:focus-visible{
  color:var(--teal-dark);
  text-decoration-color:currentColor;
}

/* --- Floating WhatsApp ---------------------------------------------------- */
.wa-float{
  position:fixed;z-index:var(--z-header);
  right:var(--s4);
  bottom:calc(var(--s4) + env(safe-area-inset-bottom));
  width:56px;height:56px;border-radius:50%;
  display:grid;place-items:center;
  /* WhatsApp's darker brand green. Their #25D366 gives a white glyph only
     1.98:1 — under the 3:1 minimum for meaningful icons. This still reads
     unmistakably as WhatsApp at 3.1:1. */
  background:#1DA851;color:#fff;
  box-shadow:0 6px 20px rgba(0,0,0,.22);
  touch-action:manipulation;
  transition:transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.wa-float:hover{transform:scale(1.07);box-shadow:0 10px 28px rgba(0,0,0,.28);}
.wa-float:active{transform:scale(.96);}
.wa-float svg{width:30px;height:30px;}

/* --- Scroll reveal --------------------------------------------------------
   FAILS OPEN. Content is visible by default; only the `.js` class (set by an
   inline script in <head>) opts into hiding. If site.js never loads, or JS is
   off, every section still renders — motion is decoration and must never be
   able to hide the product. */
.js .reveal{opacity:0;transform:translateY(16px);}
.js .reveal.is-in{
  opacity:1;transform:none;
  transition:opacity .55s var(--ease-out), transform .55s var(--ease-out);
}
.js .reveal-group > *{opacity:0;transform:translateY(16px);}
.js .reveal-group.is-in > *{
  opacity:1;transform:none;
  transition:opacity .5s var(--ease-out), transform .5s var(--ease-out);
}
.reveal-group.is-in > *:nth-child(1){transition-delay:0ms}
.reveal-group.is-in > *:nth-child(2){transition-delay:40ms}
.reveal-group.is-in > *:nth-child(3){transition-delay:80ms}
.reveal-group.is-in > *:nth-child(4){transition-delay:120ms}
.reveal-group.is-in > *:nth-child(5){transition-delay:160ms}
.reveal-group.is-in > *:nth-child(6){transition-delay:200ms}

/* --- View transitions (cross-document, MPA) ------------------------------- */
@view-transition{ navigation:auto; }
::view-transition-old(root){ animation:vt-out .18s var(--ease) both; }
::view-transition-new(root){ animation:vt-in .28s var(--ease-out) both; }
@keyframes vt-out{ to{opacity:0;} }
@keyframes vt-in{ from{opacity:0;transform:translateY(8px);} }

/* --- Reduced motion ------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto;}
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
  .modules li{opacity:1;transform:none;}
  .js .reveal,.js .reveal-group > *{opacity:1;transform:none;}
  /* Every signature motion collapses to its finished state. */
  .js .eyebrow::before{transform:none;animation:none;}
  .js .cta-spear path{stroke-dashoffset:0;}
  .js .timeline.is-in li::before,
  .js .timeline.is-in .dot{transform:none;animation:none;}
  @view-transition{ navigation:none; }
}
