/* ============================================================
   Numodev — design system
   Dark is the default theme; light is opt-in via [data-theme]
   ============================================================ */

:root{
  --orange:#ff8a34;
  --orange-deep:#e5701a;
  --orange-soft:rgba(255,138,52,.14);
  --orange-line:rgba(255,138,52,.34);
  --orange-glow:rgba(255,138,52,.32);

  --bg:#14161d;
  --bg-2:#1b1e28;
  --bg-3:#232733;
  --line:rgba(255,255,255,.10);
  --line-strong:rgba(255,255,255,.18);
  --fg:#f6f1ea;
  --fg-dim:#aaa49b;
  --fg-faint:#7d766d;
  --on-orange:#1a0d03;
  --chip:rgba(255,255,255,.06);
  --shadow:0 24px 60px -30px rgba(0,0,0,.9);
  --link-hover:#ffab6e;

  /* Display face: headings and the things set in the heading voice — buttons,
     the marquee, section numbers and metrics. Body copy stays Nunito Sans. */
  --display:"Rubik",system-ui,-apple-system,"Segoe UI",sans-serif;
  --body:"Nunito Sans",system-ui,-apple-system,"Segoe UI",sans-serif;

  --r-sm:18px; --r-md:26px; --r-lg:34px; --r-xl:44px;
  --pad:clamp(20px,5vw,80px);
  --maxw:1280px;
  --section:clamp(72px,9vw,130px);
}

[data-theme="light"]{
  --bg:#f7f3ed;
  --bg-2:#ffffff;
  --bg-3:#f0eae1;
  --line:rgba(20,22,29,.10);
  --line-strong:rgba(20,22,29,.20);
  --fg:#14161d;
  --fg-dim:#5d5850;
  --fg-faint:#8b847a;
  --chip:rgba(20,22,29,.05);
  --orange-soft:rgba(255,138,52,.16);
  --orange-glow:rgba(255,138,52,.34);
  --shadow:0 24px 60px -34px rgba(20,22,29,.30);
  --link-hover:var(--orange-deep);
}

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

html{scroll-behavior:smooth;scroll-padding-top:96px}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}

body{
  margin:0;
  background:var(--bg);
  color:var(--fg);
  font-family:var(--body);
  font-size:16px;
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}

/* 1.1 rather than the 1.06 Fredoka wanted: Rubik has a taller x-height and
   real Cyrillic descenders, and at the old leading the lines nearly touched. */
h1,h2,h3,h4{font-family:var(--display);font-weight:500;margin:0;line-height:1.1;letter-spacing:-.022em;text-wrap:balance}
p{margin:0;text-wrap:pretty}
ul,ol{margin:0;padding:0;list-style:none}
img,svg{max-width:100%}
a{color:var(--orange);text-decoration:none;transition:color .2s}
a:hover{color:var(--link-hover)}
::selection{background:var(--orange);color:var(--on-orange)}
:focus-visible{outline:2px solid var(--orange);outline-offset:3px;border-radius:10px}

.wrap{width:100%;max-width:var(--maxw);margin:0 auto;padding-left:var(--pad);padding-right:var(--pad)}
.skip{position:absolute;left:-9999px}
.skip:focus{left:16px;top:16px;z-index:200;background:var(--orange);color:var(--on-orange);padding:12px 20px;border-radius:999px}

/* ---------- shared bits ---------- */
.eyebrow{display:flex;align-items:center;gap:10px;font-size:12px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--orange)}
.eyebrow::before{content:"";width:9px;height:9px;border-radius:50%;background:var(--orange);flex:none}

.section-head{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.9fr);
  gap:clamp(24px,4vw,56px);align-items:end;margin-bottom:clamp(36px,5vw,56px)}
.section-head h2{font-size:clamp(30px,4.4vw,52px);margin-top:18px}
.section-head p{color:var(--fg-dim);font-weight:300;font-size:17px}
@media (max-width:880px){.section-head{grid-template-columns:1fr}}

.btn{display:inline-flex;align-items:center;justify-content:center;gap:9px;
  min-height:52px;padding:14px 28px;border-radius:999px;border:2px solid var(--orange);
  background:var(--orange);color:var(--on-orange);
  font-family:var(--display);font-weight:500;font-size:16px;cursor:pointer;
  transition:transform .22s cubic-bezier(.3,1.4,.5,1),background .2s,box-shadow .2s,border-color .2s}
.btn:hover{background:var(--orange-deep);border-color:var(--orange-deep);color:var(--on-orange);
  transform:translateY(-2px)}
.btn--ghost{background:transparent;color:var(--fg);border-color:var(--line-strong)}
.btn--ghost:hover{background:transparent;border-color:var(--orange);color:var(--orange)}
.btn--sm{min-height:44px;padding:11px 22px;font-size:15px}
[data-compact="true"] .header-in .btn--sm{min-height:38px;padding:8px 18px;font-size:14px}

.tag{padding:7px 16px;border-radius:999px;background:var(--chip);font-size:13px;color:var(--fg)}
.pill-metric{padding:11px 22px;border-radius:999px;background:var(--orange-soft);
  color:var(--orange);font-family:var(--display);font-weight:500;font-size:16px;white-space:nowrap}

/* ---------- header ---------- */
/* Sits just below the header's resting height; once it leaves the viewport the
   header is told to compact. An observer rather than a scroll listener, so
   nothing runs on every scroll frame. */
.scroll-sentinel{position:absolute;top:80px;width:1px;height:1px;pointer-events:none}

.site-header{position:sticky;top:0;z-index:60;background:color-mix(in srgb,var(--bg) 82%,transparent);
  backdrop-filter:blur(18px);border-bottom:1px solid var(--line);
  transition:background .3s,box-shadow .3s}
.site-header[data-compact="true"]{background:color-mix(in srgb,var(--bg) 92%,transparent);
  box-shadow:0 10px 30px -24px rgba(0,0,0,.9)}
.header-in{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:24px;min-height:80px;
  transition:min-height .3s cubic-bezier(.3,.8,.4,1)}
[data-compact="true"] .header-in{min-height:62px}
/* One markup for both themes: the mark takes the link's own colour, which is
   also what gives it the hover tint, and only the lettering is pinned to the
   accent. */
.logo{display:flex;align-items:center;color:var(--fg);flex:none;transition:color .2s}
/* aspect-ratio, not width:auto — as a grid/flex item the svg would otherwise
   be squeezed horizontally wherever the row runs short of room. */
.logo svg{height:32px;width:auto;aspect-ratio:1233/266;flex:none;display:block;
  transition:height .3s cubic-bezier(.3,.8,.4,1)}
[data-compact="true"] .logo svg{height:26px}
.logo .mark{fill:currentColor}
.logo .word{fill:var(--orange)}
.logo:hover{color:var(--link-hover)}
@media (max-width:1080px){.logo svg{height:26px}}

.nav{display:flex;gap:28px;justify-content:center;font-size:15px;font-weight:600;
  transition:gap .3s,font-size .3s}
[data-compact="true"] .nav{gap:24px;font-size:14px}
.nav a{color:var(--fg-dim)}
.nav a:hover{color:var(--fg)}

.header-tools{display:flex;align-items:center;justify-content:flex-end;gap:10px}

.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;
  border-radius:999px;border:1px solid var(--line);background:transparent;color:var(--fg);
  cursor:pointer;transition:border-color .2s,color .2s,width .3s,height .3s}
[data-compact="true"] .header-tools .icon-btn{width:38px;height:38px}
.icon-btn:hover{border-color:var(--orange);color:var(--orange)}
.icon-btn svg{width:20px;height:20px}
.icon-btn .sun{display:none}
[data-theme="light"] .icon-btn .sun{display:block}
[data-theme="light"] .icon-btn .moon{display:none}

/* language switcher */
.lang{position:relative}
.lang__btn{display:inline-flex;align-items:center;gap:7px;height:44px;padding:0 16px;
  border-radius:999px;border:1px solid var(--line);background:transparent;color:var(--fg);
  font-family:var(--body);font-weight:700;font-size:13px;letter-spacing:.08em;cursor:pointer;
  transition:border-color .2s,color .2s,height .3s,padding .3s}
[data-compact="true"] .lang__btn{height:38px;padding:0 13px}
.lang__btn:hover{border-color:var(--orange);color:var(--orange)}
.lang__btn svg{width:14px;height:14px;transition:transform .2s}
.lang[data-open="true"] .lang__btn svg{transform:rotate(180deg)}
.lang__menu{position:absolute;right:0;top:calc(100% + 10px);min-width:190px;padding:8px;
  background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-md);
  box-shadow:var(--shadow);display:none;z-index:70}
.lang[data-open="true"] .lang__menu{display:block}
.lang__menu a{display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding:11px 14px;border-radius:16px;color:var(--fg);font-size:15px}
.lang__menu a:hover{background:var(--chip);color:var(--fg)}
.lang__menu a[aria-current="true"]{color:var(--orange)}
.lang__menu small{color:var(--fg-faint);font-weight:700;letter-spacing:.08em;font-size:11px}

.burger{display:none}
@media (max-width:1080px){
  .nav{display:none}
  .header-in .btn{display:none}
  .burger{display:inline-flex}

  /* Centring the nav is what the three-column grid is for; with the nav hidden
     the empty middle column just squeezes the logo, so go back to a row. */
  .header-in{display:flex;gap:14px}
  .header-tools{margin-left:auto}
}

/* mobile drawer */
.drawer{position:fixed;inset:0;z-index:80;background:var(--bg);padding:24px var(--pad) 40px;
  display:none;flex-direction:column;gap:8px;overflow-y:auto}
.drawer[data-open="true"]{display:flex}
.drawer__top{display:flex;align-items:center;justify-content:space-between;min-height:56px;margin-bottom:16px}
.drawer nav{display:flex;flex-direction:column}
.drawer nav a{padding:18px 0;border-bottom:1px solid var(--line);color:var(--fg);
  font-family:var(--display);font-weight:500;font-size:26px}
.drawer .btn{margin-top:24px;width:100%}
.drawer__langs{display:flex;gap:10px;margin-top:24px}
.drawer__langs a{flex:1;text-align:center;padding:13px 0;border:1px solid var(--line);
  border-radius:999px;color:var(--fg);font-weight:700;font-size:13px;letter-spacing:.08em}
.drawer__langs a[aria-current="true"]{border-color:var(--orange);color:var(--orange)}

/* ---------- hero ---------- */
.hero{position:relative;padding:clamp(48px,7vw,80px) 0 clamp(64px,8vw,100px);overflow:hidden;
  /* The wave and anything riding it read their frame from here, so the two can
     never drift apart. It keeps growing with the viewport so the line always
     sweeps across the composition and bleeds off the right edge instead of
     floating as an isolated squiggle; the stroke stays a constant thickness
     regardless, through vector-effect below. */
  --wave-right:min(-5%,-72px);
  --wave-top:22%;
  --wave-w:max(920px,62%)}
.hero__glow{position:absolute;border-radius:50%;pointer-events:none;filter:blur(70px)}
.hero__glow--a{width:min(760px,90vw);aspect-ratio:1;left:-14vw;top:-16vh;
  background:radial-gradient(circle,var(--orange-glow),transparent 66%);animation:drift-a 26s ease-in-out infinite}
.hero__glow--b{width:min(620px,74vw);aspect-ratio:1;right:-12vw;top:-26vh;
  background:radial-gradient(circle,rgba(255,171,110,.22),transparent 68%);animation:drift-b 31s ease-in-out infinite}
@keyframes drift-a{50%{transform:translate(5vw,4vh) scale(1.12)}}
@keyframes drift-b{50%{transform:translate(-4vw,5vh) scale(.92)}}

/* Wider than the viewport on both sides and anchored to the bottom of the hero,
   so the hero's own overflow clip hides every end of the stroke. */
/* Sits entirely inside the hero vertically — nothing is cut off at the top or
   bottom. The right tail bleeds off the screen; the left one is faded out by a
   mask, so neither end of the stroke is ever visible. */
/* The wave keeps its size as the window narrows and simply runs further off the
   edges; it only grows again past ~1440px, where 64% is the larger value. */
.hero__wave{position:absolute;right:var(--wave-right);top:var(--wave-top);width:var(--wave-w);
  max-width:none;height:auto;
  opacity:.08;pointer-events:none;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 24%);
  mask-image:linear-gradient(90deg,transparent 0,#000 24%)}
.hero__wave path{fill:none;stroke:var(--orange);stroke-width:15;stroke-linecap:round;stroke-linejoin:round;
  /* Without this the stroke scales with the box, so the line grew fat on a wide
     monitor. Now the width is in screen pixels and the same everywhere. */
  vector-effect:non-scaling-stroke}
/* Visible by default; the animation only replays the stroke being drawn,
   so the wave never stays blank if the animation does not run. */
.hero__wave .draw{stroke-dasharray:4200;stroke-dashoffset:0;animation:draw 2.6s cubic-bezier(.4,0,.2,1) forwards}
@keyframes draw{from{stroke-dashoffset:4200}to{stroke-dashoffset:0}}

@media (max-width:760px){.hero__wave{display:none}}

/* A firefly running the hero wave.
   Head and halo are the same path drawn three times, each showing a single
   dash; a round line cap turns a near-zero dash into a dot. It shares the
   wave's frame variables, so the light always sits on the curve.

   There is no comet tail: it was built from stacked dashes of growing length,
   and each layer's round cap left a visible step, so the fade read as bands
   rather than as a trail. A smooth falloff along a path needs far more layers
   than is reasonable to animate, so the tail is gone rather than approximated. */
.hero__firefly{position:absolute;right:var(--wave-right);top:var(--wave-top);width:var(--wave-w);
  max-width:none;height:auto;pointer-events:none;z-index:0}
.hero__firefly .ride{fill:none;stroke:var(--orange);stroke-linecap:round;
  vector-effect:non-scaling-stroke;animation:ride-dot 14s linear infinite}
@keyframes ride-dot{from{stroke-dashoffset:0.1} to{stroke-dashoffset:-2102.9}}
.hero__firefly .halo2{stroke-width:24;opacity:.10;stroke-dasharray:0.1 2103}
.hero__firefly .halo1{stroke-width:12;opacity:.18;stroke-dasharray:0.1 2103}
.hero__firefly .core{stroke:#ffc79a;stroke-width:4.6;opacity:.95;stroke-dasharray:0.1 2103;
  filter:drop-shadow(0 0 5px rgba(255,181,120,.85))}
.hero__firefly .hit{stroke:transparent;stroke-width:33;stroke-dasharray:0.1 2103;
  pointer-events:stroke}

/* Hovering the spark holds it. The target is the invisible dot travelling with
   it, so only the light itself stops the animation — not the whole strip it
   crosses. The rule hangs off .hero because the target and the visible layers
   live in two different SVGs. Where :has() is unsupported it simply never
   pauses. */
.hero__firefly--hit{z-index:3}
.hero:has(.hit:hover) .ride{animation-play-state:paused}

[data-theme="light"] .hero__firefly .core{stroke:var(--orange-deep);
  filter:drop-shadow(0 0 4px rgba(229,112,26,.5))}
[data-theme="light"] .hero__firefly .halo1{opacity:.24}
[data-theme="light"] .hero__firefly .halo2{opacity:.14}
[data-theme="light"] .hero__firefly .core{stroke-width:5.5}

/* Free-floating specks over the whole hero. They sit below the copy in the
   stacking order and stay faint, so behind text they read as dust rather than
   as something to look at. */
.motes{position:absolute;inset:0;pointer-events:none;z-index:0}
.mote{position:absolute;border-radius:50%;background:#ffb578;
  box-shadow:0 0 10px 3px rgba(255,138,52,.35);opacity:.46}
[data-theme="light"] .mote{background:var(--orange-deep);
  box-shadow:0 0 10px 3px rgba(229,112,26,.22);opacity:.4}
.m1{width:6px;height:6px;left:5%;top:18%;animation:mote-b 23s ease-in-out infinite reverse}
.m2{width:8px;height:8px;left:11%;top:55%;animation:mote-c 28s ease-in-out infinite}
.m3{width:6px;height:6px;left:16%;top:80%;animation:mote-a 33s ease-in-out infinite reverse}
.m4{width:8px;height:8px;left:22%;top:33%;animation:mote-b 20s ease-in-out infinite}
.m5{width:8px;height:8px;left:28%;top:64%;animation:mote-c 25s ease-in-out infinite reverse}
.m6{width:6px;height:6px;left:33%;top:10%;animation:mote-a 30s ease-in-out infinite}
.m7{width:6px;height:6px;left:38%;top:45%;animation:mote-b 35s ease-in-out infinite reverse}
.m8{width:6px;height:6px;left:43%;top:74%;animation:mote-c 22s ease-in-out infinite}
.m9{width:8px;height:8px;left:48%;top:25%;animation:mote-a 27s ease-in-out infinite reverse}
.m10{width:6px;height:6px;left:53%;top:58%;animation:mote-b 32s ease-in-out infinite}
.m11{width:5px;height:5px;left:58%;top:86%;animation:mote-c 19s ease-in-out infinite reverse}
.m12{width:5px;height:5px;left:63%;top:15%;animation:mote-a 24s ease-in-out infinite}
.m13{width:8px;height:8px;left:67%;top:50%;animation:mote-b 29s ease-in-out infinite reverse}
.m14{width:6px;height:6px;left:71%;top:72%;animation:mote-c 34s ease-in-out infinite}
.m15{width:6px;height:6px;left:76%;top:30%;animation:mote-a 21s ease-in-out infinite reverse}
.m16{width:7px;height:7px;left:80%;top:60%;animation:mote-b 26s ease-in-out infinite}
.m17{width:6px;height:6px;left:84%;top:12%;animation:mote-c 31s ease-in-out infinite reverse}
.m18{width:8px;height:8px;left:88%;top:44%;animation:mote-a 18s ease-in-out infinite}
.m19{width:5px;height:5px;left:91%;top:78%;animation:mote-b 23s ease-in-out infinite reverse}
.m20{width:4px;height:4px;left:94%;top:28%;animation:mote-c 28s ease-in-out infinite}
.m21{width:6px;height:6px;left:97%;top:58%;animation:mote-a 33s ease-in-out infinite reverse}
.m22{width:5px;height:5px;left:99%;top:68%;animation:mote-b 20s ease-in-out infinite}
@keyframes mote-a{50%{transform:translate(30px,-38px)}}
@keyframes mote-b{50%{transform:translate(-40px,-26px)}}
@keyframes mote-c{50%{transform:translate(22px,-52px)}}

/* No wave below this width, so nothing to ride and no empty band to fill. */
@media (max-width:760px){.hero__firefly,.motes{display:none}}


.hero__in{position:relative;z-index:1}
.hero h1{font-size:clamp(40px,6.2vw,84px);font-weight:400;letter-spacing:-.028em;
  margin:26px 0 0;max-width:17ch}
.hero h1 .accent{color:var(--orange)}
/* The name leads the sentence at the same size and weight as the rest, in the
   accent — so the line opens and closes on brand colour. The dash between stays
   muted, or the three would read as one orange run. */
/* The name holds a line of its own, so the headline reads in three beats:
   the name, the claim, the payoff. A touch of space under it because the
   headline's own line-height is too tight for two separate thoughts.
   The dash sits at the head of the second line, where it reads as the sentence
   resuming rather than as something left hanging off the name. */
/* Heavier than the rest of the headline, and with nearly neutral tracking:
   caps do not need the tightening the lowercase lines get. */
.hero__brand{display:block;font-weight:500;
  color:var(--orange);letter-spacing:-.005em;white-space:nowrap;margin-bottom:.06em}
.hero__dash{color:var(--fg-faint)}
.hero__lede{margin-top:28px;max-width:54ch;font-size:clamp(16px,1.5vw,19px);font-weight:300;color:var(--fg-dim)}
.hero__cta{display:flex;flex-wrap:wrap;gap:14px;margin-top:38px}

/* ---------- marquee ---------- */
.marquee{margin:0 clamp(12px,3vw,24px);background:var(--orange);border-radius:999px;
  padding:16px 0;overflow:hidden;position:relative}
.marquee__track{display:flex;width:max-content;animation:slide 42s linear infinite}
/* four copies + a -25% shift: the track is always at least three groups wider
   than the viewport, so the loop point never comes into view */
.marquee__group{display:flex;align-items:center;gap:44px;padding-right:44px;color:var(--on-orange);
  font-family:var(--display);font-weight:500;font-size:15px;white-space:nowrap}
.marquee__group span::after{content:"";display:inline-block;vertical-align:middle;
  width:7px;height:7px;border-radius:50%;background:var(--on-orange);margin-left:44px}
@keyframes slide{to{transform:translateX(-25%)}}
@media (prefers-reduced-motion:reduce){.marquee__track{animation:none}.hero__glow{animation:none}
  .hero__wave .draw{animation:none}
  .hero__firefly,.motes{display:none}
  .site-header,.header-in,.logo svg,.nav,.icon-btn,.lang__btn,.btn{transition:none}}

/* ---------- services bento ---------- */
.section{padding:var(--section) 0 0}
.bento{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:18px}
.cell{background:var(--bg-2);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:clamp(26px,2.6vw,34px);display:flex;flex-direction:column;gap:14px;
  transition:transform .25s,border-color .25s}
.cell:hover{transform:translateY(-3px);border-color:var(--line-strong)}
.cell h3{font-size:clamp(22px,2vw,25px)}
.cell p{color:var(--fg-dim);font-weight:300;font-size:15px}
.cell__icon{width:30px;height:30px;stroke:var(--orange);fill:none;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round}
.cell__tags{display:flex;flex-wrap:wrap;gap:8px;margin-top:auto;padding-top:8px}
.cell--wide{grid-column:span 4;padding:clamp(30px,3vw,40px);
  background:radial-gradient(120% 140% at 0% 0%,var(--orange-soft),transparent 58%),var(--bg-2);
  border-color:var(--orange-line)}
.cell--wide h3{font-size:clamp(26px,3vw,34px)}
.cell--wide p{font-size:16px;max-width:46ch}
.cell--wide .cell__icon{width:34px;height:34px}
.cell--half{grid-column:span 2}
.cell--third{grid-column:span 3}
.cell--cta{grid-column:span 3;background:transparent;border:2px dashed var(--orange-line);
  justify-content:center}
.cell--cta h3{color:var(--orange)}
.cell--cta .btn{align-self:flex-start;background:var(--orange-soft);color:var(--orange);border-color:transparent}
.cell--cta .btn:hover{background:var(--orange);color:var(--on-orange)}
@media (max-width:980px){
  .bento{grid-template-columns:repeat(4,minmax(0,1fr))}
  .cell--wide{grid-column:span 4}
  .cell--half{grid-column:span 2}
  .cell--third,.cell--cta{grid-column:span 2}
}
@media (max-width:640px){
  .bento{grid-template-columns:1fr}
  .cell--wide,.cell--half,.cell--third,.cell--cta{grid-column:span 1}
}

/* ---------- process ---------- */
.panel{margin:var(--section) clamp(12px,3vw,24px) 0;background:var(--bg-2);
  border-radius:var(--r-xl);padding:clamp(56px,7vw,100px) 0}
.panel .wrap{max-width:calc(var(--maxw) - 8px)}

/* The wave is texture here, not a diagram: it runs behind the whole row at low
   opacity, and the order is carried by the dashed arrows between the numbers.
   Its old node circles are gone — they sat on the crests and pointed at
   nothing in particular. */
.timeline{position:relative;padding-top:26px}
.timeline__wave{position:absolute;left:-6%;top:50%;width:112%;height:250px;
  transform:translateY(-50%);opacity:.08;pointer-events:none;z-index:0;
  /* Same fade the hero wave uses, mirrored to both ends: the stroke should
     arrive and leave rather than being sliced off at the panel edge. */
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 16%,#000 84%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 16%,#000 84%,transparent 100%)}
/* Same treatment as the hero wave: a stroke width in screen pixels, so the
   non-uniform stretch of preserveAspectRatio="none" cannot thicken the line —
   and the same 15px, since it is the same wave doing the same job. */
.timeline__wave path{fill:none;stroke:var(--orange);stroke-width:15;stroke-linecap:round;
  vector-effect:non-scaling-stroke}

.steps{--step-pad:clamp(8px,1.6vw,26px);
  position:relative;z-index:1;
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px}
.step{position:relative;padding:0 var(--step-pad)}
.step__n{font-family:var(--display);font-size:15px;font-weight:600;letter-spacing:.1em;color:var(--orange)}

/* A short stub after each number rather than a bridge all the way to the next
   one: it should suggest that the sequence continues, not draw the join. The
   dash pattern is a repeating gradient because `border-style: dashed` leaves
   the dash size to the browser, and at this length that difference shows.
   It must be `repeating-`: a plain linear-gradient paints one dash stretched
   across the whole box, which is what made the run all but invisible. */
.step:not(:last-child)::before{
  content:"";position:absolute;top:12px;
  left:calc(var(--step-pad) + 40px);width:96px;height:2px;
  background-image:repeating-linear-gradient(90deg,rgba(255,138,52,.55) 0 5px,transparent 5px 12px)}
.step:not(:last-child)::after{
  content:"";position:absolute;top:13px;
  left:calc(var(--step-pad) + 142px);
  width:7px;height:7px;
  border-top:2px solid rgba(255,138,52,.7);border-right:2px solid rgba(255,138,52,.7);
  transform:translateY(-50%) rotate(45deg)}
.step h3{font-size:clamp(20px,1.9vw,24px);margin-top:10px}
.step p{margin-top:12px;color:var(--fg-dim);font-weight:300;font-size:15px}
.step__out{margin-top:16px;font-size:12px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--fg-faint)}
@media (max-width:900px){
  .timeline{padding-top:8px}
  /* Stacked steps read top to bottom on their own; a horizontal arrow between
     them would point the wrong way. The wave stays as texture. */
  .step:not(:last-child)::before,
  .step:not(:last-child)::after{display:none}
  .steps{grid-template-columns:1fr;gap:0;margin-top:24px}
  .step{padding:26px 0;border-top:1px solid var(--line)}
  .timeline__wave{height:180px}
}

/* ---------- work ---------- */
.cases{display:flex;flex-direction:column}
.case{display:grid;grid-template-columns:110px minmax(0,1fr) minmax(0,.8fr) auto;
  gap:clamp(16px,2.4vw,32px);align-items:center;padding:clamp(24px,3vw,34px) 0;
  border-top:1px solid var(--line);color:var(--fg);transition:padding-left .25s}
.case:last-child{border-bottom:1px solid var(--line)}
.case:hover{color:var(--fg);padding-left:10px}
.case:hover .case__n{color:var(--orange)}
.case__n{font-family:var(--display);font-size:clamp(34px,4vw,52px);font-weight:600;
  line-height:1;color:var(--orange-line);transition:color .25s}
.case h3{font-size:clamp(22px,2.4vw,32px)}
.case__meta{color:var(--fg-dim);font-weight:300;font-size:15px}
.case .pill-metric{justify-self:end}
@media (max-width:900px){
  .case{grid-template-columns:64px minmax(0,1fr);row-gap:10px}
  .case__n{font-size:34px}
  .case__meta{grid-column:2}
  .case .pill-metric{grid-column:2;justify-self:start}
}

/* ---------- engagement ---------- */
.plans{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:22px;align-items:start}
.plan{background:var(--bg);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:clamp(28px,3vw,36px);display:flex;flex-direction:column;gap:18px}
.plan--hot{border-color:var(--orange);
  background:radial-gradient(120% 90% at 50% 0%,var(--orange-soft),transparent 62%),var(--bg)}
.plan h3{font-size:26px}
.plan__who{color:var(--fg-dim);font-weight:300;font-size:15px}
.plan__badge{align-self:flex-start;padding:5px 16px;border-radius:999px;background:var(--orange);
  color:var(--on-orange);font-family:var(--display);font-weight:500;font-size:13px}
.plan__badge--ghost{visibility:hidden}
.plan dl{margin:6px 0 0;display:flex;flex-direction:column;gap:14px}
.plan dt{font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--fg-faint)}
.plan dd{margin:4px 0 0;font-size:15px}
@media (max-width:920px){.plans{grid-template-columns:1fr}}

/* ---------- contact ---------- */
.contact-card{position:relative;background:var(--bg-2);border-radius:var(--r-xl);
  padding:clamp(32px,5vw,64px);display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.9fr);
  gap:clamp(32px,5vw,64px);align-items:start;overflow:hidden}
.contact-card::before{content:"";position:absolute;left:-120px;bottom:-240px;width:560px;height:560px;
  border-radius:50%;background:radial-gradient(circle,var(--orange-soft),transparent 66%);
  filter:blur(60px);pointer-events:none}
.contact-card > *{position:relative}
.contact-card h2{font-size:clamp(30px,4.4vw,52px);margin-top:18px}
.contact__lede{margin-top:20px;color:var(--fg-dim);font-weight:300;font-size:17px;max-width:42ch}
.direct{display:flex;flex-direction:column;gap:20px;margin-top:34px}
.direct li{display:flex;align-items:center;gap:14px}
.direct li::before{content:"";width:10px;height:10px;border-radius:50%;background:var(--orange);flex:none}
.direct b{display:block;font-size:12px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--fg-faint)}
.direct a,.direct span{font-size:17px;color:var(--fg)}
@media (max-width:880px){.contact-card{grid-template-columns:1fr}}

form{display:flex;flex-direction:column;gap:16px}
.field label{display:block;margin-bottom:8px;font-size:12px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;color:var(--fg-faint)}
.field input,.field textarea,.field select{
  width:100%;background:var(--bg);border:1px solid var(--line);color:var(--fg);
  font-family:var(--body);font-size:15px;padding:15px 18px;border-radius:var(--r-sm);
  transition:border-color .2s}
.field textarea{min-height:120px;resize:vertical}
.field input:focus,.field textarea:focus,.field select:focus{border-color:var(--orange);outline:none}
.field select{appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23aaa49b' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 18px center;background-size:12px;padding-right:44px}
.f2{display:grid;grid-template-columns:1fr 1fr;gap:16px}
@media (max-width:540px){.f2{grid-template-columns:1fr}}
.form-note{font-size:13px;color:var(--fg-faint)}

/* Honeypot. Off-screen rather than display:none, because a bot that renders
   CSS skips hidden fields but still fills a field it can "see". */
.field--trap{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

.form-status{font-size:14px;font-weight:600}
.form-status[hidden]{display:none}
.form-status[data-state="sent"]{color:var(--orange)}
.form-status[data-state="failed"],
.form-status[data-state="invalid"]{color:#ff6b5e}
[data-theme="light"] .form-status[data-state="failed"],
[data-theme="light"] .form-status[data-state="invalid"]{color:#c0392b}
form[data-busy="true"] .btn{opacity:.6;pointer-events:none}

/* ---------- footer ---------- */
.site-footer{margin-top:var(--section);border-top:1px solid var(--line);padding:clamp(48px,6vw,72px) 0 40px}
.footer-grid{display:grid;grid-template-columns:minmax(0,1.4fr) repeat(3,minmax(0,1fr));
  gap:clamp(28px,4vw,48px)}
.footer-brand .logo{margin-bottom:18px}
.footer-brand .logo svg{height:30px}
.footer-brand p{color:var(--fg-dim);font-weight:300;font-size:15px;max-width:32ch}
.footer-col h4{font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--fg-faint);font-family:var(--body);margin-bottom:16px}
.footer-col li+li{margin-top:11px}
.footer-col a,.footer-col span{color:var(--fg-dim);font-size:15px}
.footer-col a:hover{color:var(--orange)}
.footer-col button{background:none;border:0;padding:0;color:var(--fg-dim);font:inherit;
  font-size:15px;cursor:pointer;text-align:left}
.footer-col button:hover{color:var(--orange)}
.footer-bottom{display:flex;flex-wrap:wrap;gap:12px 28px;align-items:center;
  margin-top:clamp(36px,5vw,56px);padding-top:28px;border-top:1px solid var(--line);
  font-size:13px;color:var(--fg-faint)}
.footer-bottom .sep{margin-left:auto}
@media (max-width:880px){.footer-grid{grid-template-columns:1fr 1fr}}
@media (max-width:560px){.footer-grid{grid-template-columns:1fr}}

/* ---------- cookie banner ---------- */
.cookie{position:fixed;left:16px;right:16px;bottom:16px;z-index:120;
  max-width:560px;margin:0 auto;background:var(--bg-2);border:1px solid var(--line);
  border-radius:var(--r-lg);padding:26px 28px;box-shadow:var(--shadow);
  max-height:calc(100dvh - 32px);overflow-y:auto;
  transform:translateY(140%);transition:transform .45s cubic-bezier(.2,.9,.3,1)}
.cookie[data-open="true"]{transform:none}
.cookie h2{font-size:22px}
.cookie p{margin-top:12px;color:var(--fg-dim);font-weight:300;font-size:15px}
.cookie__actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:20px}
.cookie__actions .btn{flex:1 1 auto;min-width:150px}
.cookie__link{background:none;border:0;padding:0;margin-top:14px;color:var(--fg-faint);
  font:inherit;font-size:13px;cursor:pointer;text-decoration:underline}
.cookie__link:hover{color:var(--orange)}
.cookie__cats{display:none;flex-direction:column;gap:14px;margin-top:20px;
  padding-top:20px;border-top:1px solid var(--line)}
.cookie[data-detail="true"] .cookie__cats{display:flex}
.cookie[data-detail="true"] .cookie__actions{order:3}
.cookie__cat{display:flex;gap:14px;align-items:flex-start}
.cookie__cat div{flex:1}
.cookie__cat b{display:block;font-size:15px}
.cookie__cat small{display:block;margin-top:4px;color:var(--fg-dim);font-size:13px;font-weight:300}
.switch{position:relative;flex:none;width:46px;height:27px;margin-top:2px}
.switch input{position:absolute;opacity:0;width:100%;height:100%;margin:0;cursor:pointer}
.switch span{position:absolute;inset:0;border-radius:999px;background:var(--chip);
  border:1px solid var(--line);transition:background .2s,border-color .2s;pointer-events:none}
.switch span::after{content:"";position:absolute;top:3px;left:3px;width:19px;height:19px;
  border-radius:50%;background:var(--fg-faint);transition:transform .2s,background .2s}
.switch input:checked + span{background:var(--orange);border-color:var(--orange)}
.switch input:checked + span::after{transform:translateX(19px);background:var(--on-orange)}
.switch input:disabled + span{opacity:.55}
.switch input:focus-visible + span{outline:2px solid var(--orange);outline-offset:3px}
@media (max-width:560px){.cookie{padding:22px 20px}}

/* ---------- legal pages ---------- */
.legal{padding:clamp(48px,6vw,80px) 0 0}
.legal__head{max-width:none}
.legal__head h1{font-size:clamp(34px,5vw,60px)}
.legal__updated{margin-top:16px;font-size:12px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--fg-faint)}
.legal__intro{margin-top:26px;font-size:17px;font-weight:300;color:var(--fg-dim);line-height:1.8}
.legal__body{margin-top:clamp(40px,5vw,64px)}
/* Full width, as asked. A line this long is past the measure text is usually
   set to, so the leading below is opened up to compensate — at a wide measure
   tight leading is what makes the eye lose the next line. */
.legal__section{max-width:none}
.legal__section+.legal__section{margin-top:44px}
.legal__section h2{font-size:clamp(20px,2.2vw,26px)}
.legal__section p{margin-top:14px;color:var(--fg-dim);font-weight:300;line-height:1.8}
.legal__section ul{margin-top:14px;display:flex;flex-direction:column;gap:10px}
.legal__section ul li{position:relative;padding-left:22px;color:var(--fg-dim);font-weight:300;line-height:1.8}
.legal__section ul li::before{content:"";position:absolute;left:0;top:11px;width:8px;height:8px;
  border-radius:50%;background:var(--orange)}
.legal__table-wrap{overflow-x:auto;margin-top:18px;border:1px solid var(--line);border-radius:var(--r-md)}
.legal__table{width:100%;border-collapse:collapse;min-width:620px;font-size:14px}
.legal__table th{text-align:left;padding:14px 18px;background:var(--bg-2);
  font-size:12px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--fg-faint)}
.legal__table td{padding:14px 18px;border-top:1px solid var(--line);color:var(--fg-dim);font-weight:300;vertical-align:top}
.legal__table td:first-child{color:var(--fg);font-weight:600;white-space:nowrap}


/* ---------- reveal ---------- */
.rv{opacity:0;transform:translateY(18px);transition:opacity .7s ease,transform .7s ease}
.rv.is-in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){.rv{opacity:1;transform:none;transition:none}}
