/* ============================================================
   Kairos Systemics — continuous cinematic reel
   Palette: #57676B slate · #74847C moss · #9DABA8 sage · #B4C4BE mist
   ============================================================ */

:root{
  --ink:#0d1010;
  --paper:#eef1ec;
  --slate:#57676B;
  --moss:#74847C;
  --sage:#9DABA8;
  --mist:#B4C4BE;
  --bone:#d6dcd5;
  --gold:#c9a96b;

  --serif:"Fraunces", "Times New Roman", serif;
  --sans:"Inter", system-ui, sans-serif;
  --mono:"JetBrains Mono", ui-monospace, monospace;

  --gutter:clamp(1.25rem, 4vw, 4rem);
  --maxw:1480px;
}

*,*::before,*::after{box-sizing:border-box}
html,body{margin:0;padding:0;background:#0a0c0c;color:var(--paper);font-family:var(--sans);-webkit-font-smoothing:antialiased}
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth{scroll-behavior:auto!important}
.lenis.lenis-smooth [data-lenis-prevent]{overscroll-behavior:contain}

img,video{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
button{font:inherit;cursor:pointer;border:0;background:none;color:inherit}
::selection{background:var(--mist);color:var(--ink)}

/* Accessibility helpers — visually-hidden + skip link */
.screen-reader-text{position:absolute!important;clip:rect(1px,1px,1px,1px);clip-path:inset(50%);width:1px;height:1px;overflow:hidden;word-wrap:normal!important;padding:0;margin:-1px;border:0}
.screen-reader-text:focus,.skip-link:focus{
  position:fixed!important;top:1rem;left:1rem;width:auto;height:auto;clip:auto;clip-path:none;
  z-index:9999;
  background:var(--mist);color:var(--ink);
  padding:.75rem 1rem;font-family:var(--mono);font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;
  border:1px solid var(--paper);
}
/* Global keyboard focus ring */
:focus-visible{outline:2px solid var(--mist);outline-offset:3px}
/* Admin bar offset for fixed nav */
.admin-bar .nav{top:32px}
@media (max-width:782px){.admin-bar .nav{top:46px}}

/* film grain */
.grain{position:fixed;inset:0;z-index:200;pointer-events:none;opacity:.07;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)' opacity='.55'/></svg>");
  animation:grainShift 1.4s steps(6) infinite;
}
@keyframes grainShift{
  0%{transform:translate(0,0)}20%{transform:translate(-3%,2%)}40%{transform:translate(2%,-3%)}
  60%{transform:translate(-2%,1%)}80%{transform:translate(3%,3%)}100%{transform:translate(0,0)}
}

/* subtle global vignette */
.vignette{position:fixed;inset:0;z-index:85;pointer-events:none;
  background:radial-gradient(ellipse at center, transparent 50%, rgba(0,0,0,.40) 100%)}

/* Story→pricing transition: a black curtain that draws across the stage */
.curtain{
  position:fixed;inset:0;z-index:88;pointer-events:none;
  background:#0a0c0c;
  opacity:0;
  will-change:opacity;
}

/* ----------------------------------------------------------------
   PERSISTENT STAGE — one fixed reel of 9 videos that crossfade
---------------------------------------------------------------- */
.stage{position:fixed;inset:0;z-index:0;overflow:hidden;background:#0a0c0c}
.stage__v{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;
  transform:scale(1.16);
  transform-origin:center 55%;
  filter:saturate(.95) contrast(1.05);
  transition:opacity 1.4s cubic-bezier(.55,0,.25,1), filter 1.6s ease;
  will-change:opacity,transform,filter;
  background:#0a0c0c;
}
.stage__v.active{opacity:1;filter:saturate(1) contrast(1.06)}

/* WebCodecs canvas — mirrors .stage__v positioning. Hidden by default;
   shown only when body.webcodecs-scrub is set (feature detect passed). */
.stage__c{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;
  transform:scale(1.16);
  transform-origin:center 55%;
  filter:saturate(.95) contrast(1.05);
  transition:opacity 1.4s cubic-bezier(.55,0,.25,1), filter 1.6s ease;
  will-change:opacity,transform,filter;
  background:#0a0c0c;
  display:none;
}
body.webcodecs-scrub .stage__c{display:block}
body.webcodecs-scrub .stage__v{display:none}
.stage__c.active{opacity:1;filter:saturate(1) contrast(1.06)}

/* veils — three flavours faded in by JS based on current scene's data-veil */
.stage__veil{
  position:absolute;inset:0;z-index:2;pointer-events:none;
  opacity:0;
  transition:opacity 1.4s cubic-bezier(.55,0,.25,1);
  background:
    radial-gradient(130% 90% at 0% 55%, rgba(8,10,11,.92), rgba(8,10,11,.30) 55%, rgba(8,10,11,0) 78%),
    linear-gradient(to top, rgba(8,10,11,.75), rgba(8,10,11,.10) 38%, rgba(8,10,11,.55));
  mix-blend-mode:multiply;
}
.stage__veil--right{
  background:
    radial-gradient(130% 90% at 100% 55%, rgba(8,10,11,.94), rgba(8,10,11,.30) 55%, rgba(8,10,11,0) 78%),
    linear-gradient(to top, rgba(8,10,11,.7), rgba(8,10,11,.05) 38%, rgba(8,10,11,.45));
}
.stage__veil--center{
  background:
    radial-gradient(45% 35% at 50% 50%, rgba(8,10,11,.72), rgba(8,10,11,.35) 65%, rgba(8,10,11,.55) 100%),
    radial-gradient(120% 90% at 50% 50%, rgba(8,10,11,.25), rgba(8,10,11,.75));
}
.stage[data-veil="left"]   .stage__veil:not(.stage__veil--right):not(.stage__veil--center){opacity:1}
.stage[data-veil="right"]  .stage__veil--right{opacity:1}
.stage[data-veil="center"] .stage__veil--center{opacity:1}

/* grade pass for cinematic split-tone */
.stage::after{
  content:"";position:absolute;inset:0;z-index:3;pointer-events:none;
  background:
    radial-gradient(60% 40% at 50% 30%, rgba(180,196,190,.05), transparent 70%),
    radial-gradient(80% 60% at 50% 100%, rgba(201,169,107,.04), transparent 70%);
  mix-blend-mode:screen;
}

/* ----------------------------------------------------------------
   Nav
---------------------------------------------------------------- */
.nav{
  position:fixed; top:0; left:0; right:0; z-index:100;
  display:grid; grid-template-columns:auto 1fr auto; align-items:center; gap:2rem;
  padding:1.1rem var(--gutter);
  background:linear-gradient(to bottom, rgba(8,10,10,.55), rgba(8,10,10,0));
  font-family:var(--mono); font-size:.72rem; letter-spacing:.14em; text-transform:uppercase;
  color:var(--bone);
}
.nav__mark{display:inline-flex;align-items:center;color:var(--paper);line-height:0}

/* Horizontal lockup logo (mathematical flower + wordmark + tagline baked in) */
.nav__lockup{
  display:block;
  width:auto;
  height:80px;
  max-width:none;
  /* Source PNG has near-black background — screen blend drops the black so
     only the silver linework + wordmark + tagline render against the nav. */
  mix-blend-mode:screen;
  filter:brightness(1.18) contrast(1.08);
  transition:filter .5s ease;
}
.nav__mark:hover .nav__lockup{filter:brightness(1.32) contrast(1.10)}

/* Hamburger trigger — only visible on mobile */
.nav__hamburger{
  display:none;
  align-items:center;justify-content:center;
  width:38px;height:38px;
  padding:0;border:1px solid rgba(180,196,190,.25);background:transparent;color:var(--bone);cursor:pointer;
  transition:background .3s,color .3s,border-color .3s;
}
.nav__hamburger:hover{background:rgba(180,196,190,.08);color:var(--paper);border-color:var(--mist)}
.nav__hamburger-bars{display:inline-flex;flex-direction:column;justify-content:center;gap:5px;width:18px;height:14px}
.nav__hamburger-bars span{display:block;height:1px;width:100%;background:currentColor}
.nav__hamburger-bars span:nth-child(2){width:70%;align-self:flex-end}

@media(max-width:1024px){
  /* Mobile/tablet nav: flex layout pins lockup left, hamburger right */
  .nav{
    display:flex;
    justify-content:space-between;
    align-items:center;
    gap:.6rem;
    padding:.85rem var(--gutter);
  }
  .nav__lockup{height:clamp(48px,12vw,72px)}
  .nav__links{display:none !important}
  .nav__hamburger{display:inline-flex;width:46px;height:46px}
  .nav__hamburger-bars{width:22px}
  .nav__progress{display:none}
}
@media(max-width:480px){
}

/* ─── Mobile fade-modal menu ─── */
.mobile-menu{
  position:fixed;inset:0;z-index:300;
  background:rgba(8,10,11,.92);
  backdrop-filter:blur(10px);
  -webkit-backdrop-filter:blur(10px);
  opacity:0;visibility:hidden;
  transition:opacity .45s cubic-bezier(.2,.7,.2,1), visibility 0s linear .45s;
}
.mobile-menu.is-open{
  opacity:1;visibility:visible;
  transition:opacity .45s cubic-bezier(.2,.7,.2,1), visibility 0s linear 0s;
}
.mobile-menu__inner{
  position:relative;min-height:100svh;height:100%;
  display:flex;flex-direction:column;
  padding:1.4rem var(--gutter) 2rem;
  max-width:48rem;margin:0 auto;
}
.mobile-menu__head{
  display:flex;justify-content:space-between;align-items:center;gap:1rem;
  padding-bottom:1.4rem;border-bottom:1px solid rgba(180,196,190,.16);
}
.mobile-menu__eyebrow{font-family:var(--mono);font-size:.66rem;letter-spacing:.22em;text-transform:uppercase;color:var(--sage)}
.mobile-menu__close{
  width:38px;height:38px;display:inline-flex;align-items:center;justify-content:center;
  border:1px solid rgba(180,196,190,.25);background:transparent;color:var(--bone);cursor:pointer;
  transition:background .3s,color .3s,border-color .3s;
}
.mobile-menu__close:hover{background:var(--mist);color:var(--ink);border-color:var(--mist)}

.mobile-menu__nav{
  flex:1;
  display:flex;flex-direction:column;gap:.4rem;
  padding-top:3.5rem;
  opacity:0;transform:translateY(20px);
  transition:opacity .55s ease .1s,transform .55s cubic-bezier(.2,.7,.2,1) .1s;
}
.mobile-menu.is-open .mobile-menu__nav{opacity:1;transform:translateY(0)}
.mobile-menu__link{
  display:block;padding:.65rem 0;
  font-family:var(--serif);font-weight:400;
  font-size:clamp(2rem,7vw,3rem);line-height:1.1;letter-spacing:-.015em;
  color:var(--paper);
  font-variation-settings:"opsz" 32;
  border-bottom:1px solid rgba(180,196,190,.08);
  transition:color .3s,padding-left .3s;
}
.mobile-menu__link:hover{color:var(--mist);padding-left:.3rem}
.mobile-menu__link:last-child{border-bottom:0}

.mobile-menu__foot{
  padding-top:2rem;
  display:flex;flex-direction:column;gap:1.5rem;align-items:flex-start;
  border-top:1px solid rgba(180,196,190,.16);
  opacity:0;transform:translateY(20px);
  transition:opacity .55s ease .25s,transform .55s cubic-bezier(.2,.7,.2,1) .25s;
}
.mobile-menu.is-open .mobile-menu__foot{opacity:1;transform:translateY(0)}
/* Controls row: language + motion side by side */
.mobile-menu__controls{display:flex;gap:2.5rem;align-items:flex-start;flex-wrap:wrap}
.mobile-menu__controls .eyebrow{display:block;margin-bottom:.7rem;font-family:var(--mono);font-size:.62rem;letter-spacing:.22em;text-transform:uppercase;color:var(--sage)}

.mobile-menu__lang-row{display:flex;align-items:center;gap:0}
.mobile-menu__lang-item{
  position:relative;
  padding:.3rem .7rem;
  font-family:var(--mono);font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;
  color:rgba(214,220,213,.55);
  transition:color .3s;
}
.mobile-menu__lang-item:first-child{padding-left:0}
.mobile-menu__lang-item + .mobile-menu__lang-item{border-left:1px solid rgba(180,196,190,.22)}
.mobile-menu__lang-item:hover{color:var(--paper)}
.mobile-menu__lang-item.is-active{color:var(--paper)}
.mobile-menu__lang-item.is-active::after{content:"";position:absolute;left:.7rem;right:.7rem;bottom:.1em;height:1px;background:var(--mist)}
.mobile-menu__lang-item:first-child.is-active::after{left:0}

/* Motion button — wider, no wrap, inside menu */
.mobile-menu__motion-btn{
  display:inline-flex !important;align-items:center;gap:.7rem;
  width:auto !important;height:auto !important;
  padding:.55rem 1rem !important;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.2em;text-transform:uppercase;
  white-space:nowrap;
}

.mobile-menu__cta{margin-top:1rem;align-self:flex-start}

/* Belt-and-suspenders: hide the fixed nav entirely while the modal is open
   so nothing from the header bleeds through behind the modal blur */
body.mobile-menu-open .nav,
body.mobile-menu-open .vignette,
body.mobile-menu-open .grain{visibility:hidden}

body.mobile-menu-open{overflow:hidden}

.nav__links{display:flex;justify-content:flex-end;gap:1.6rem;align-items:center}
.nav__links a{position:relative;color:var(--bone);transition:color .3s}
.nav__links a:hover{color:var(--paper)}
.nav__links a:not(.nav__cta):not(.lang-switcher__item)::after{content:"";position:absolute;left:0;right:0;bottom:-.4em;height:1px;background:currentColor;transform:scaleX(0);transform-origin:left;transition:transform .4s}
.nav__links a:not(.nav__cta):not(.lang-switcher__item):hover::after{transform:scaleX(1)}
.nav__links a.nav__cta{
  padding:.7rem 1.1rem;
  border:1px solid var(--mist);
  border-radius:0;
  color:var(--paper);
  font-family:var(--mono);
  font-size:.68rem;
  letter-spacing:.22em;
  text-transform:uppercase;
  transition:background .35s ease,color .35s ease,letter-spacing .35s ease;
}
.nav__links a.nav__cta:hover{background:var(--mist);color:var(--ink);letter-spacing:.28em}
.nav__links a.nav__cta:hover::after{display:none}
/* Default: show full label, hide short label. Mobile media query inverts these. */
.nav__cta-full{display:inline}
.nav__cta-short{display:none}
/* ─── Motion toggle (WCAG 2.2.2 Pause/Stop/Hide for autoplaying content) ─── */
.nav__motion-toggle{
  display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;
  padding:0;
  background:transparent;
  border:1px solid rgba(180,196,190,.25);
  color:var(--bone);cursor:pointer;
  transition:background .3s,color .3s,border-color .3s;
}
.nav__motion-toggle:hover{background:rgba(180,196,190,.08);color:var(--paper);border-color:var(--mist)}
.nav__motion-toggle[aria-pressed="true"]{background:var(--mist);color:var(--ink);border-color:var(--mist)}
.nav__motion-toggle[aria-pressed="true"] .nav__motion-pause{display:none}
.nav__motion-toggle[aria-pressed="true"] .nav__motion-play{display:inline!important}
@media(max-width:780px){.nav__motion-toggle{width:26px;height:26px}}

/* ─── Language switcher ─── */
.lang-switcher{display:inline-flex;align-items:center;gap:0;font-family:var(--mono);font-size:.65rem;letter-spacing:.18em;text-transform:uppercase;color:var(--bone)}
.lang-switcher__item{
  position:relative;
  padding:.35rem .6rem;
  color:rgba(214,220,213,.5);
  transition:color .25s ease;
}
.lang-switcher__item:hover{color:var(--paper)}
.lang-switcher__item.is-active{color:var(--paper)}
.lang-switcher__item.is-active::after{
  content:"";position:absolute;left:.6rem;right:.6rem;bottom:.05em;
  height:1px;background:var(--mist);
}
.lang-switcher__item + .lang-switcher__item{border-left:1px solid rgba(180,196,190,.18)}
@media(max-width:900px){
  .lang-switcher{font-size:.62rem;letter-spacing:.16em}
  .lang-switcher__item{padding:.3rem .5rem}
}

.nav__progress{grid-column:1/-1;height:1px;background:rgba(180,196,190,.15);position:relative;margin-top:.5rem}
.nav__progress span{position:absolute;left:0;top:0;bottom:0;background:linear-gradient(90deg,var(--sage),var(--mist));width:0%}
@media (max-width:780px){ .nav__links a:not(.nav__cta):not(.lang-switcher__item){display:none} }

/* ----------------------------------------------------------------
   Scene primitive — pure scroll runway holding copy only
---------------------------------------------------------------- */
.scene{position:relative;height:var(--scene-h, 240vh);z-index:2}
.scene__pin{position:sticky;top:0;height:100vh;display:grid;align-items:center}
.scene__copy{
  position:relative;z-index:6;
  width:100%; max-width:var(--maxw); margin:0 auto;
  padding:7rem var(--gutter) 5rem;
  display:flex; flex-direction:column; gap:1.6rem;
  max-inline-size:min(46rem, 100%);
}
.scene--right .scene__copy{margin-left:auto;margin-right:0;align-items:flex-end;text-align:right}
.scene--right .scene__copy > *{max-width:46rem}
.scene__copy--center{margin-left:auto;margin-right:auto;align-items:center;text-align:center;max-inline-size:62rem;isolation:isolate}
/* soft scrim behind centered title cards for legibility over busy videos */
.scene__copy--center::before{
  content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(110%,80rem);height:min(120%,28rem);
  z-index:-1;pointer-events:none;
  background:radial-gradient(50% 50% at 50% 50%, rgba(8,10,11,.62), rgba(8,10,11,.25) 60%, rgba(8,10,11,0) 78%);
  filter:blur(4px);
}
.scene__copy--center.manifesto::before{height:min(120%,46rem)}
.scene__copy--center h2,.scene__copy--center .display{text-shadow:0 1px 22px rgba(0,0,0,.55)}
.scene__copy--hero{padding-top:9rem;padding-bottom:7rem;max-inline-size:min(72rem,100%)}
/* wide editorial scenes — let the layout breathe across the viewport */
#s5 .scene__copy,#s7 .scene__copy{max-inline-size:min(104rem,100%)}
#s5 .title,#s5 .body,#s7 .title{max-width:none}
#s7 .method article{padding:1.6rem 1.6rem 2rem;min-height:16rem;gap:.75rem}
#s7 .method article h3{font-size:1.5rem;line-height:1.1}
#s7 .method article p{font-size:.95rem;line-height:1.55}
.scene__copy--hero .display{max-width:none;white-space:nowrap}
@media(max-width:900px){.scene__copy--hero .display{white-space:normal}}

/* HUD label */
.hud{display:inline-flex;align-items:center;gap:.85rem;font-family:var(--mono);font-size:.7rem;letter-spacing:.22em;text-transform:uppercase;color:var(--mist)}
.hud__num{color:var(--gold)}
.hud__line{flex:0 0 3rem;height:1px;background:currentColor;opacity:.5}
.hud--center{justify-content:center}

/* Typography */
.display{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(2.8rem, 7.2vw, 7.5rem);
  line-height:.96; letter-spacing:-.02em; margin:0;
  /* opsz 32 = text optical size: lowercase 'e' crossbar stays thick and
     horizontal even when displayed at large pixel sizes. Decouples Fraunces'
     internal "display" voice from the visible size on screen. */
  font-variation-settings:"opsz" 32;
}
.display span{display:block}
.display__em{font-style:italic;color:var(--mist);font-weight:300}
.display--quiet{font-size:clamp(2rem, 4.2vw, 4rem); line-height:1.1; font-weight:400; max-width:36ch; margin:0 auto;
  font-variation-settings:"opsz" 32;
}
.display--quiet em{font-style:italic;color:var(--sage)}

.title{font-family:var(--serif);font-weight:400;font-size:clamp(2.1rem, 5vw, 4.4rem);line-height:1;letter-spacing:-.015em;margin:0;
  font-variation-settings:"opsz" 32;
}
.title em{font-style:italic;color:var(--sage)}

.lede{font-family:var(--serif);font-style:italic;font-weight:300;font-size:clamp(1.05rem,1.4vw,1.35rem);line-height:1.5;color:var(--bone);max-width:34ch;margin:0}
.body{font-size:1rem;line-height:1.65;color:var(--bone);max-width:38ch;margin:0;font-weight:300}
.body--narrow{max-width:30ch}

.scroll-hint{display:inline-flex;flex-direction:column;align-items:flex-start;gap:.4rem;margin-top:auto;font-family:var(--mono);font-size:.65rem;letter-spacing:.3em;text-transform:uppercase;color:var(--sage);opacity:.75}
.scroll-hint svg{animation:drop 1.8s ease-in-out infinite}
@keyframes drop{0%,100%{transform:translateY(0);opacity:.7}50%{transform:translateY(8px);opacity:1}}

.marker{list-style:none;padding:0;margin:.5rem 0 0;display:flex;flex-direction:column;gap:.5rem;font-family:var(--mono);font-size:.78rem;letter-spacing:.04em;color:var(--sage);text-transform:uppercase}
.scene--right .marker{align-items:flex-end}
.marker li{position:relative;padding-left:1.2em}
.scene--right .marker li{padding-left:0;padding-right:1.2em}
.marker li::before{content:"›";position:absolute;left:0;color:var(--gold)}
.scene--right .marker li::before{left:auto;right:0}

.diptych{display:grid;grid-template-columns:1fr 1fr;gap:0;border-top:1px solid rgba(180,196,190,.2);border-bottom:1px solid rgba(180,196,190,.2);margin-top:1.5rem;max-width:34rem;margin-left:auto}
.diptych > div{padding:1.1rem 1.2rem;display:flex;flex-direction:column;gap:.25rem;text-align:left}
.diptych > div + div{border-left:1px solid rgba(180,196,190,.2)}
.diptych__k{font-family:var(--serif);font-style:italic;font-size:1.4rem;color:var(--paper)}
.diptych__v{font-family:var(--mono);font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;color:var(--sage)}

/* ───────────────────────── Districts (Scene 5) ─────────────────────────
   The 8 districts are a scroll-driven 3D STACKED CAROUSEL: every card is
   absolutely stacked in one spot inside a perspective stage; main.js maps
   scroll progress → a continuous active index and writes a transform/opacity
   per card (front card sharp at z:0, upcoming cards recede in depth behind it,
   the exited card flies toward the viewer and fades). The background video
   scrubs in lockstep with the same scroll. Pure transform+opacity = 60fps.
   Mobile uses the identical deck (sticky-pinned) driven by a scroll listener;
   reduced-motion falls back to a clean static list. */
.scene--districts .scene__pin{
  display:flex;flex-direction:column;justify-content:center;align-items:center;
  gap:clamp(1.4rem,3vh,2.4rem);
  box-sizing:border-box;padding:clamp(4.5rem,8vh,6rem) var(--gutter) clamp(3rem,6vh,4.5rem);
}
/* heading block — KILL the inherited `.scene__copy{padding:7rem .. 5rem}` (that
   bottom padding was the visible "gap") and the `#s5 .scene__copy` 104rem width.
   The #s5 prefix is needed to beat those higher-specificity rules above. Result:
   a tight, centered section anchor sitting close to the card. */
#s5 .scene__copy--districts{
  padding:0;margin-inline:auto;text-align:center;flex:0 0 auto;gap:1rem;
  max-inline-size:min(52rem,92vw);
}
#s5 .scene__copy--districts .hud{justify-content:center}
#s5 .title--districts{margin-bottom:.5rem}
#s5 .scene__copy--districts .body{margin-inline:auto;max-width:60ch}

/* the perspective stage — sized to the card (NOT flex:1, which created the gap);
   the heading + deck now sit together as one vertically-centered group. */
.deck{
  position:relative;flex:0 0 auto;width:100%;
  min-height:clamp(296px,40vh,392px);
  perspective:1900px;perspective-origin:50% 48%;
  transform-style:preserve-3d;
}

/* wide, SHORT editorial card — a numeral rail on the left, content spanning the
   full width on the right (uses the section's width, keeps the height low).
   Numeral watermark sits behind for depth. */
.district{
  position:absolute;top:50%;left:50%;
  width:min(860px,92%);box-sizing:border-box;
  min-height:clamp(238px,30vh,308px);
  display:grid;grid-template-columns:minmax(0,auto) 1fr;align-items:center;
  gap:clamp(1.5rem,3.2vw,3.2rem);
  padding:clamp(2.1rem,2.8vw,2.9rem) clamp(1.9rem,3vw,2.8rem);
  overflow:hidden;
  border:1px solid rgba(180,196,190,.22);
  border-radius:7px;
  background:
    radial-gradient(120% 140% at 0% 50%, rgba(116,132,124,.16), rgba(116,132,124,0) 55%),
    linear-gradient(162deg, rgba(17,20,21,.9), rgba(8,10,11,.82));
  backdrop-filter:blur(11px) saturate(.92);-webkit-backdrop-filter:blur(11px) saturate(.92);
  box-shadow:
    0 40px 90px -34px rgba(0,0,0,.86),
    inset 0 1px 0 rgba(238,241,236,.07),
    inset 0 0 0 1px rgba(0,0,0,.2);
  /* JS owns transform/opacity; baseline centers the card before paint. */
  transform:translate(-50%,-50%);
  transform-style:preserve-3d;backface-visibility:hidden;
  will-change:transform,opacity;
}
/* gold cap along the top edge */
.district::before{
  content:"";position:absolute;top:0;left:0;right:0;height:2px;z-index:2;
  background:linear-gradient(90deg, var(--gold), rgba(201,169,107,.12));
}
/* giant faint numeral watermark behind the left rail */
.district__ghost{
  position:absolute;left:-.6rem;top:50%;transform:translateY(-52%);z-index:0;pointer-events:none;
  font-family:var(--serif);font-style:italic;font-weight:300;line-height:1;
  font-size:clamp(7rem,15vw,11rem);letter-spacing:-.05em;color:rgba(201,169,107,.06);
}
.district > :not(.district__ghost){position:relative;z-index:1}

/* left rail — kicker + big numeral, divided from the content */
.district__aside{
  display:flex;flex-direction:column;justify-content:center;gap:.7rem;
  padding-right:clamp(1.4rem,3vw,3rem);
  border-right:1px solid rgba(180,196,190,.16);
}
.district__kicker{
  font-family:var(--mono);font-size:.6rem;letter-spacing:.26em;text-transform:uppercase;color:var(--sage);line-height:1.8;
}
.district__numeral{
  font-family:var(--serif);font-style:italic;font-weight:300;line-height:.9;color:var(--gold);
  font-size:clamp(3rem,5.4vw,4.8rem);text-shadow:0 2px 22px rgba(0,0,0,.45);
}

/* right column — content using the width */
.district__main{min-width:0}
.district__name{
  margin:0;font-family:var(--serif);font-weight:400;font-size:clamp(1.6rem,2.7vw,2.3rem);
  letter-spacing:-.02em;line-height:1.04;color:var(--paper);
}
.district__rule{
  display:block;width:2.4rem;height:2px;margin:.95rem 0;background:var(--gold);
  box-shadow:0 0 16px rgba(201,169,107,.5);
}
.district__services{
  margin:0;font-family:var(--mono);font-size:.76rem;line-height:1.7;letter-spacing:.02em;color:var(--bone);
}
.district__outcome{
  margin:.85rem 0 0;font-family:var(--serif);font-style:italic;
  font-size:clamp(1rem,1.5vw,1.15rem);line-height:1.4;color:var(--mist);
}

/* progress dots (one per district) */
.districts__nav{
  position:absolute;left:50%;transform:translateX(-50%);bottom:-2rem;z-index:50;
  display:flex;gap:.5rem;list-style:none;margin:0;padding:0;
}
.districts__dot{
  width:16px;height:2px;background:rgba(180,196,190,.22);
  transition:background .4s ease, width .4s ease;
}
.districts__dot.is-active{background:var(--gold);width:28px}

/* ── Mobile: a self-contained SWIPE carousel (NOT scroll-pinned) ──────────────
   The section is a normal one-viewport scene, so it can't hijack the page scroll
   or overlap the next scene. The deck stays the 3D stack; main.js advances it on
   horizontal swipe (touch-action:pan-y lets vertical page-scroll through). The
   background video keeps autoplaying behind it. */
body.is-mobile .scene.scene--districts{min-height:100svh}
body.is-mobile .scene--districts .scene__pin{
  justify-content:center;padding-top:clamp(4.5rem,11vh,6.5rem);
  touch-action:pan-y;  /* horizontal gestures → JS swipe; vertical → page scroll */
}
body.is-mobile .deck{perspective:1300px;min-height:clamp(300px,44svh,420px);margin-top:1.2rem}
body.is-mobile .district{width:min(460px,92%);grid-template-columns:1fr;gap:1rem;padding:1.6rem 1.5rem}
body.is-mobile .district__aside{flex-direction:row;align-items:baseline;gap:1rem;border-right:0;border-bottom:1px solid rgba(180,196,190,.16);padding-right:0;padding-bottom:.9rem}
body.is-mobile .district__numeral{font-size:2.6rem}
body.is-mobile .district__ghost{font-size:8rem}
/* compact heading on mobile so the deck + swipe indicator stay above the fold */
body.is-mobile #s5 .title--districts{font-size:clamp(1.85rem,7.6vw,2.5rem);line-height:1.06;margin-bottom:.5rem}
body.is-mobile #s5 .scene__copy--districts .body{font-size:.92rem;line-height:1.55;max-width:34ch}
body.is-mobile .scene--districts .scene__pin{gap:1rem}

/* bigger, tappable progress dots */
body.is-mobile .districts__nav{bottom:-1.3rem;gap:.6rem}
body.is-mobile .districts__dot{height:3px;width:22px}
body.is-mobile .districts__dot.is-active{width:34px}

/* animated SWIPE indicator — a gold dot tracking left↔right under the deck, with
   a label. Injected by main.js on the mobile carousel; fades out on first swipe. */
.deck-swipe{
  position:absolute;left:50%;bottom:-3.7rem;transform:translateX(-50%);
  display:flex;flex-direction:column;align-items:center;gap:.4rem;
  pointer-events:none;opacity:.9;transition:opacity .45s ease;
}
.deck-swipe.is-hidden{opacity:0}
.deck-swipe__track{position:relative;width:54px;height:2px;border-radius:2px;background:rgba(180,196,190,.22)}
.deck-swipe__dot{position:absolute;top:50%;left:0;width:9px;height:9px;border-radius:50%;
  background:var(--gold);box-shadow:0 0 10px rgba(201,169,107,.6);
  transform:translate(-50%,-50%);animation:deckSwipeDot 1.9s cubic-bezier(.45,0,.55,1) infinite}
.deck-swipe__label{font-family:var(--mono);font-size:.56rem;letter-spacing:.32em;text-transform:uppercase;color:var(--sage)}
@keyframes deckSwipeDot{0%,100%{left:16%}50%{left:84%}}
@media (prefers-reduced-motion: reduce){ .deck-swipe__dot{animation:none;left:50%} }

/* ── Reduced-motion: no 3D, no scroll dependency — a clean static list ─────── */
body.reduced-motion .scene--districts{min-height:0}
body.reduced-motion .scene--districts .scene__pin{position:relative;height:auto;min-height:0;display:block;padding-block:clamp(4rem,9vh,6rem)}
body.reduced-motion .deck{display:flex;flex-direction:column;gap:1rem;perspective:none;min-height:0;margin-top:1.6rem}
body.reduced-motion .district{
  position:relative;top:auto;left:auto;width:100%;min-height:auto;overflow:visible;
  transform:none!important;opacity:1!important;filter:none!important;
  will-change:auto;box-shadow:none;backdrop-filter:none;
}
body.reduced-motion .district__ghost{display:none}
body.reduced-motion .districts__nav{display:none}

.defs{margin:.6rem 0 0;display:flex;flex-direction:column;gap:1.1rem;text-align:right}
.defs > div{padding:1rem 0;border-top:1px solid rgba(180,196,190,.18);display:flex;flex-direction:column;gap:.35rem}
.defs > div:last-child{border-bottom:1px solid rgba(180,196,190,.18)}
.defs dt{font-family:var(--serif);font-size:1.35rem;font-weight:400}
.defs dd{margin:0;font-size:.92rem;line-height:1.5;color:var(--bone);max-width:36ch;margin-left:auto}

.method{display:grid;grid-template-columns:repeat(4,1fr);gap:0;border-top:1px solid rgba(180,196,190,.2);margin-top:1.4rem}
.method article{padding:1.4rem 1.2rem 1.6rem;border-right:1px solid rgba(180,196,190,.15);display:flex;flex-direction:column;gap:.55rem;min-height:14rem;position:relative}
.method article:last-child{border-right:0}
.method article > span{font-family:var(--mono);font-size:.7rem;letter-spacing:.22em;color:var(--gold)}
.method article h3{margin:0;font-family:var(--serif);font-weight:400;font-size:1.25rem}
.method article p{margin:0;color:var(--bone);font-size:.86rem;line-height:1.5}
.method article::before{content:"";position:absolute;top:-1px;left:0;width:0;height:2px;background:var(--mist);transition:width .9s ease}
.method article.in::before{width:100%}
@media(max-width:880px){.method{grid-template-columns:1fr 1fr}.method article{border-bottom:1px solid rgba(180,196,190,.15)}}
@media(max-width:520px){.method{grid-template-columns:1fr}}

.manifesto{gap:1rem;max-inline-size:64rem}
.manifesto p{font-family:var(--serif);font-weight:300;font-size:clamp(1.4rem,3.4vw,2.6rem);line-height:1.25;margin:0;color:var(--bone)}
.manifesto p[data-align="l"]{align-self:flex-start;text-align:left}
.manifesto p[data-align="r"]{align-self:flex-end;text-align:right}
.manifesto p em{font-style:italic;color:var(--mist)}

.cta{display:inline-flex;align-items:center;gap:.6rem;padding:1rem 1.6rem;margin-top:1rem;border:1px solid var(--mist);font-family:var(--mono);font-size:.75rem;letter-spacing:.22em;text-transform:uppercase;color:var(--paper);transition:.3s}
.cta:hover{background:var(--mist);color:var(--ink);letter-spacing:.28em}

/* ----------------------------------------------------------------
   Pricing / Contact / Footer (light dressed sections)
---------------------------------------------------------------- */
/* :not(body) is load-bearing — WordPress body_class() puts `page` on <body>
   for every Page, so this rule was matching the body element itself and
   boxing the whole site to 1480px with 9rem of vertical padding. That is
   where the dead space on every section came from. Cannot be section.page:
   page.php puts the class on a <main>. */
.page:not(body){position:relative;z-index:10;padding:9rem var(--gutter);max-width:var(--maxw);margin:0 auto;color:var(--paper);background:#0a0c0c}
.page__hdr{display:grid;grid-template-columns:1fr;gap:1rem;margin-bottom:3.5rem;max-width:48rem}
.eyebrow{font-family:var(--mono);font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;color:var(--sage)}
.page h2{font-family:var(--serif);font-weight:400;font-size:clamp(2rem,4.4vw,3.8rem);line-height:1.05;letter-spacing:-.015em;margin:0;max-width:24ch}

.plans{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:rgba(180,196,190,.18);border:1px solid rgba(180,196,190,.18)}
.plan{background:#0a0c0c;padding:2.4rem 2rem 2.2rem;display:flex;flex-direction:column;gap:1rem;position:relative}
.plan header{display:flex;flex-direction:column;gap:.6rem;padding-bottom:1rem;border-bottom:1px solid rgba(180,196,190,.15)}
.plan h3{margin:0;font-family:var(--serif);font-weight:400;font-size:1.7rem}
.plan__price{font-family:var(--mono);font-size:.8rem;letter-spacing:.12em;color:var(--sage)}
.plan__price b{color:var(--paper);font-weight:500;font-size:1rem}
.plan > p{margin:0;color:var(--bone);font-size:.95rem;font-style:italic;font-family:var(--serif)}
.plan ul{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.55rem;font-size:.9rem;color:var(--bone);font-weight:300}
.plan ul li{padding-left:1.1em;position:relative}
.plan ul li::before{content:"+";position:absolute;left:0;color:var(--sage)}
.plan__cta{
  margin-top:auto;align-self:flex-start;
  padding:.95rem 1.4rem;
  border:1px solid var(--mist);
  font-family:var(--mono);font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;
  color:var(--paper);
  transition:background .35s ease,color .35s ease,letter-spacing .35s ease;
}
.plan__cta:hover{background:var(--mist);color:var(--ink);letter-spacing:.28em}
.plan--featured{background:linear-gradient(180deg, rgba(157,171,168,.07), rgba(10,12,12,1) 60%)}
.plan--featured::before{content:"Featured";position:absolute;top:1rem;right:1.2rem;font-family:var(--mono);font-size:.62rem;letter-spacing:.22em;text-transform:uppercase;color:var(--gold)}
@media(max-width:920px){.plans{grid-template-columns:1fr}}

.extras{margin-top:2.5rem;display:grid;grid-template-columns:1fr 1fr;gap:1.4rem}
.extras article{padding:1.6rem 1.4rem;border:1px solid rgba(180,196,190,.18);display:flex;flex-direction:column;gap:.4rem}
.extras h4{margin:0;font-family:var(--serif);font-size:1.25rem;font-weight:400}
.extras span{font-family:var(--mono);font-size:.72rem;letter-spacing:.18em;color:var(--gold)}
.extras p{margin:0;color:var(--bone);font-size:.9rem;line-height:1.5}
@media(max-width:720px){.extras{grid-template-columns:1fr}}

.page--contact{padding-top:6rem;padding-bottom:6rem}
.contact{display:grid;grid-template-columns:1.1fr 1fr;gap:5rem;align-items:start}
.contact h2{font-family:var(--serif);font-weight:400;font-size:clamp(2.2rem,4.8vw,4rem);line-height:1.02;margin:.4rem 0 1rem}
.contact p{color:var(--bone);max-width:32ch;line-height:1.6}
.form{display:flex;flex-direction:column;gap:1.2rem}
.form label{display:flex;flex-direction:column;gap:.35rem;font-family:var(--mono);font-size:.7rem;letter-spacing:.2em;text-transform:uppercase;color:var(--sage)}
.form input,.form textarea{background:transparent;border:0;border-bottom:1px solid rgba(180,196,190,.3);padding:.6rem 0;color:var(--paper);font:inherit;font-family:var(--serif);font-size:1.05rem;transition:border-color .3s}
.form input:focus,.form textarea:focus{outline:0;border-color:var(--mist)}
.form button{
  margin-top:1rem;align-self:flex-start;
  padding:1rem 1.5rem;
  border:1px solid var(--mist);
  color:var(--paper);
  font-family:var(--mono);font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;
  transition:background .35s ease,color .35s ease,letter-spacing .35s ease;
}
.form button:hover{background:var(--mist);color:var(--ink);letter-spacing:.28em}
.form__ok{font-family:var(--mono);font-size:.72rem;letter-spacing:.18em;color:var(--gold)}

/* ─── CF7 integration — mirror the .form treatment onto CF7's markup ─── */
.wpcf7-form{display:flex;flex-direction:column;gap:1.2rem}
.wpcf7-form p{margin:0}
.wpcf7-form label{display:flex;flex-direction:column;gap:.35rem;font-family:var(--mono);font-size:.7rem;letter-spacing:.2em;text-transform:uppercase;color:var(--sage)}
.wpcf7-form label > span:first-child{display:block}
.wpcf7-form .wpcf7-form-control-wrap{display:block}
.wpcf7-form input[type="text"],
.wpcf7-form input[type="email"],
.wpcf7-form input[type="tel"],
.wpcf7-form input[type="url"],
.wpcf7-form textarea{
  width:100%;
  background:transparent;
  border:0;
  border-bottom:1px solid rgba(180,196,190,.3);
  padding:.6rem 0;
  color:var(--paper);
  font:inherit;
  font-family:var(--serif);
  font-size:1.05rem;
  transition:border-color .3s;
  border-radius:0;
  box-shadow:none;
}
.wpcf7-form textarea{resize:vertical;min-height:6rem}
.wpcf7-form input:focus,.wpcf7-form textarea:focus{outline:0;border-color:var(--mist)}
.wpcf7-form input::placeholder,.wpcf7-form textarea::placeholder{color:rgba(214,220,213,.35)}

.wpcf7-form .wpcf7-submit{
  margin-top:1rem;align-self:flex-start;
  padding:1rem 1.5rem;
  background:transparent;
  border:1px solid var(--mist);
  border-radius:0;
  color:var(--paper);
  font-family:var(--mono);font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;
  cursor:pointer;
  transition:background .35s ease,color .35s ease,letter-spacing .35s ease;
}
.wpcf7-form .wpcf7-submit:hover{background:var(--mist);color:var(--ink);letter-spacing:.28em}

/* CF7 response messages — brand-aligned */
.wpcf7-response-output,
.wpcf7 form.sent .wpcf7-response-output,
.wpcf7 form.failed .wpcf7-response-output,
.wpcf7 form.invalid .wpcf7-response-output,
.wpcf7 form.spam .wpcf7-response-output{
  margin:1.4rem 0 0 !important;
  padding:1rem 1.2rem !important;
  border:1px solid !important;
  border-radius:0 !important;
  font-family:var(--mono);
  font-size:.7rem;
  letter-spacing:.14em;
  text-transform:uppercase;
  line-height:1.5;
}
.wpcf7 form.sent .wpcf7-response-output{
  border-color:var(--gold) !important;
  color:var(--gold);
  background:rgba(201,169,107,.06);
}
.wpcf7 form.failed .wpcf7-response-output,
.wpcf7 form.aborted .wpcf7-response-output,
.wpcf7 form.invalid .wpcf7-response-output,
.wpcf7 form.spam .wpcf7-response-output{
  border-color:rgba(214,90,90,.55) !important;
  color:#e89090;
  background:rgba(180,60,60,.08);
}

/* CF7 inline field validation tip */
.wpcf7-not-valid-tip{
  display:block !important;
  margin-top:.4rem !important;
  font-family:var(--mono);
  font-size:.62rem;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:#e89090 !important;
  background:transparent !important;
  padding:0 !important;
  border:0 !important;
}
.wpcf7-not-valid{border-bottom-color:rgba(214,90,90,.55) !important}

/* CF7 loading spinner — re-style to match palette */
.wpcf7-spinner{
  background-color:rgba(180,196,190,.5) !important;
  margin-left:.8rem;
}

@media(max-width:820px){.contact{grid-template-columns:1fr;gap:2.5rem}}

.foot{position:relative;z-index:10;padding:4rem var(--gutter) 2.5rem;border-top:1px solid rgba(180,196,190,.12);background:#0a0c0c;color:var(--bone);font-family:var(--sans);font-size:.95rem}
.foot__top{
  display:grid;
  grid-template-columns:1.4fr 1fr 1fr auto;
  gap:3rem;
  align-items:start;
  max-width:var(--maxw);
  margin:0 auto 3rem;
}
.foot__top .eyebrow{display:block;margin-bottom:1rem;font-family:var(--mono);font-size:.65rem;letter-spacing:.22em;text-transform:uppercase;color:var(--sage)}

.foot__contact{display:flex;flex-direction:column;gap:.55rem}
.foot__contact-link{color:var(--bone);font-family:var(--serif);font-size:1rem;line-height:1.3;transition:color .3s}
.foot__contact-link:hover{color:var(--paper)}
.foot__contact-address{margin:0;color:var(--bone);font-family:var(--serif);font-size:.92rem;line-height:1.5;font-style:italic}
.foot__contact-address a{color:inherit;border-bottom:1px solid rgba(180,196,190,.3);transition:border-color .3s}
.foot__contact-address a:hover{border-color:var(--mist)}

.foot__links{display:flex;flex-direction:column;gap:.55rem;font-family:var(--serif);font-size:1rem;letter-spacing:0;text-transform:none}
.foot__links a{color:var(--bone);transition:color .3s}
.foot__links a:hover{color:var(--paper)}

.foot__social-list{list-style:none;padding:0;margin:0;display:flex;gap:.8rem;align-items:center}
.foot__social-list a{
  display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;
  border:1px solid rgba(180,196,190,.22);
  color:var(--bone);
  transition:background .35s ease,color .35s ease,border-color .35s ease,transform .35s ease;
}
.foot__social-list a:hover{background:var(--mist);color:var(--ink);border-color:var(--mist);transform:translateY(-2px)}

.foot__bottom{
  max-width:var(--maxw);margin:0 auto;
  padding-top:2rem;border-top:1px solid rgba(180,196,190,.12);
  display:flex;justify-content:space-between;align-items:center;gap:1.5rem;flex-wrap:wrap;
  font-family:var(--mono);font-size:.66rem;letter-spacing:.18em;text-transform:uppercase;color:var(--sage);
}
.foot__copy{margin:0}
.foot__tagline{margin:0;color:var(--bone)}
.foot__designer{margin:0;color:var(--sage);opacity:.7}
.foot__designer a{color:var(--bone);border-bottom:1px solid rgba(180,196,190,.3);transition:.3s}
.foot__designer a:hover{color:var(--paper);border-color:var(--mist)}

@media(max-width:920px){
  .foot__top{grid-template-columns:1fr 1fr;gap:2.5rem}
  .foot__lockup{grid-column:1/-1}
}
@media(max-width:600px){
  .foot{padding:3rem var(--gutter) 2rem}
  .foot__top{grid-template-columns:1fr;gap:2rem;margin-bottom:2rem}
  .foot__bottom{flex-direction:column;align-items:flex-start;gap:.5rem}
}

/* Contact section — direct-contact block under the intro paragraph */
.contact__direct{
  margin-top:2rem;
  display:flex;flex-direction:column;gap:1.2rem;
}
.contact__direct > div{display:flex;flex-direction:column;gap:.25rem}
.contact__direct dt{font-family:var(--mono);font-size:.65rem;letter-spacing:.22em;color:var(--sage);text-transform:uppercase}
.contact__direct dd{margin:0;font-family:var(--serif);font-size:1.05rem;line-height:1.45;color:var(--paper)}
.contact__direct a{color:inherit;border-bottom:1px solid rgba(180,196,190,.25);transition:border-color .3s,color .3s}
.contact__direct a:hover{color:var(--mist);border-color:var(--mist)}

/* Footer lockup — wide horizontal logo with mathematical mark + wordmark */
.foot__lockup{
  display:block;
  line-height:0;
  flex:0 0 auto;
}
.foot__lockup-img{
  display:block;
  width:auto;
  height:clamp(56px, 6.5vw, 84px);
  max-width:100%;
  /* Source PNG is on a near-black background — screen blend drops the black
     and lets only the silver linework + wordmark render against the footer. */
  mix-blend-mode:screen;
  filter:brightness(1.18) contrast(1.08);
  transition:filter .5s ease,opacity .4s ease;
}
.foot__lockup:hover .foot__lockup-img{filter:brightness(1.32) contrast(1.1)}

@media(max-width:600px){
  .foot{flex-direction:column;align-items:flex-start;gap:1.4rem;padding:2.4rem var(--gutter)}
  .foot__meta{align-items:flex-start;text-align:left}
  .foot__lockup-img{height:48px}
}

/* Stage fade — opacity transitions over 1.2s; then visibility:hidden kicks in
   AT END of the transition (delayed) so the layer is fully detached from the
   compositor. This stops subpixel paint cascade onto adjacent borders. */
body.no-stage .stage{
  opacity:0;
  visibility:hidden;
  pointer-events:none;
  transition:opacity 1.2s ease, visibility 0s linear 1.2s;
}
/* Same trick for the curtain — once stage is gone, curtain has no purpose */
body.no-stage .curtain{
  opacity:0!important;
  visibility:hidden;
  pointer-events:none;
  transition:opacity .3s ease, visibility 0s linear .3s;
}
/* Also force the grain animation to stop in no-stage areas — its repaint
   cycle was the second source of the subpixel cascade */
body.no-stage .grain{animation:none!important;opacity:0;transition:opacity .8s ease}
/* hide the scroll progress bar once the cinematic story is done */
body.no-stage .nav__progress{opacity:0;transition:opacity .6s ease;pointer-events:none}

/* pricing enters as a slow fade up out of the black */
#pricing > *{opacity:0;transform:translateY(28px);transition:opacity 1.4s cubic-bezier(.2,.7,.2,1),transform 1.5s cubic-bezier(.2,.7,.2,1)}
#pricing > *:nth-child(2){transition-delay:.18s}
#pricing > *:nth-child(3){transition-delay:.32s}
#pricing.in > *{opacity:1;transform:translateY(0)}

/* ----------------------------------------------------------------
   Cinematic copy reveal — blur-in, slow, staggered
---------------------------------------------------------------- */
.scene__copy > *{
  opacity:0;
  transform:translateY(22px);
  filter:blur(8px);
  transition:opacity 1.3s cubic-bezier(.2,.65,.15,1), transform 1.4s cubic-bezier(.2,.65,.15,1), filter 1.3s ease;
}
.scene__copy > *:nth-child(2){transition-delay:.18s}
.scene__copy > *:nth-child(3){transition-delay:.34s}
.scene__copy > *:nth-child(4){transition-delay:.5s}
.scene__copy > *:nth-child(5){transition-delay:.64s}
.scene.in .scene__copy > *{opacity:1;transform:translateY(0);filter:blur(0)}
.scene.out .scene__copy > *{opacity:0;transform:translateY(-16px);filter:blur(6px);transition-duration:1s;transition-delay:0s}

/* ================================================================
   IN THE FIELD — homepage feature section (3 interventions)
   ================================================================ */
.page--field{padding-block:8rem;max-width:var(--maxw);margin:0 auto;background:#0a0c0c;position:relative;z-index:10}
.field__hdr{max-width:48rem;margin-bottom:4rem}
.field__title{font-family:var(--serif);font-weight:400;font-size:clamp(2.4rem,4.8vw,4rem);line-height:1.02;letter-spacing:-.015em;margin:.4rem 0 1.4rem;font-variation-settings:"opsz" 32}
.field__title em{font-style:italic;color:var(--sage)}
.field__intro{color:var(--bone);max-width:32ch;line-height:1.6}

.field__cases{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:0;border-top:1px solid rgba(180,196,190,.16)}
.field__case{
  display:grid;grid-template-columns:1fr 1fr;gap:3rem;align-items:center;
  padding:4.5rem 0;
  border-bottom:1px solid rgba(180,196,190,.16);
}
.field__case--right .field__media{order:2}
.field__case--right .field__copy{order:1}
.field__media{
  position:relative;display:flex;align-items:center;justify-content:center;
  aspect-ratio:16/10;
  background:#11141414;
  overflow:hidden;
  border:1px solid rgba(180,196,190,.10);
  transition:border-color .4s ease,transform .8s cubic-bezier(.2,.7,.2,1);
}
.field__media:empty::before{
  content:"Upload media via Interventions admin";
  font-family:var(--mono);font-size:.62rem;letter-spacing:.18em;text-transform:uppercase;color:rgba(180,196,190,.4);
  padding:1rem;text-align:center;
}
.field__media:hover{border-color:rgba(180,196,190,.25);transform:translateY(-3px)}
.field__loop,.field__still{
  width:100%;height:100%;object-fit:cover;display:block;
  filter:saturate(.92) contrast(1.04);
  transition:filter .6s ease;
}
.field__media:hover .field__loop,.field__media:hover .field__still{filter:saturate(1) contrast(1.06)}
/* soft vignette over each piece of media */
.field__media::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(80% 65% at 50% 50%, transparent 55%, rgba(8,10,11,.45) 100%);
}
.field__copy{display:flex;flex-direction:column;gap:1.1rem;align-items:flex-start}
.field__case-title{
  font-family:var(--serif);font-weight:400;
  font-size:clamp(1.6rem,2.6vw,2.4rem);line-height:1.1;letter-spacing:-.01em;
  margin:.2rem 0 0;
  font-variation-settings:"opsz" 32;
}
.field__case-title em{font-style:italic;color:var(--mist)}
.field__case-story{margin:0;color:var(--bone);font-size:1rem;line-height:1.6;max-width:42ch}
.field__case-tags{margin:.2rem 0 0;font-family:var(--mono);font-size:.7rem;letter-spacing:.18em;color:var(--sage);text-transform:uppercase}
.field__case-more{
  margin-top:.4rem;
  font-family:var(--mono);font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;color:var(--paper);
  border-bottom:1px solid rgba(180,196,190,.4);padding-bottom:.25rem;
  transition:border-color .3s,color .3s,letter-spacing .3s;
}
.field__case-more:hover{color:var(--mist);border-color:var(--mist);letter-spacing:.28em}
.field__cta-wrap{margin-top:3.5rem;text-align:center}

@media (max-width:820px){
  .page--field{padding-block:5rem}
  .field__hdr{margin-bottom:2.5rem}
  .field__case{grid-template-columns:1fr;gap:1.6rem;padding:3rem 0}
  .field__case--right .field__media,.field__case--right .field__copy{order:initial}
  .field__media{aspect-ratio:4/3}
}

/* ================================================================
   /interventions/ archive page
   ================================================================ */
.iv-archive{position:relative;z-index:10;padding:9rem var(--gutter) 6rem;max-width:var(--maxw);margin:0 auto;background:#0a0c0c}
.iv-archive__hdr{margin-bottom:4rem;max-width:52rem}
.iv-archive__title{font-family:var(--serif);font-weight:400;font-size:clamp(2.4rem,5.2vw,4.6rem);line-height:1.02;letter-spacing:-.015em;margin:.6rem 0 1.6rem;font-variation-settings:"opsz" 32}
.iv-archive__title em{font-style:italic;color:var(--sage)}
.iv-archive__intro{color:var(--bone);max-width:38ch;line-height:1.6}

.iv-filter{display:flex;flex-wrap:wrap;gap:.6rem;margin-top:2rem}
.iv-filter__chip{
  display:inline-flex;align-items:center;
  padding:.5rem .9rem;border:1px solid rgba(180,196,190,.25);
  font-family:var(--mono);font-size:.66rem;letter-spacing:.18em;text-transform:uppercase;color:var(--bone);
  transition:background .3s,color .3s,border-color .3s;
}
.iv-filter__chip:hover{background:rgba(180,196,190,.08);border-color:var(--mist);color:var(--paper)}
.iv-filter__chip.is-active{background:var(--mist);color:var(--ink);border-color:var(--mist)}

.iv-list{list-style:none;padding:0;margin:0;border-top:1px solid rgba(180,196,190,.16)}
.iv-row{
  display:grid;grid-template-columns:1fr 1fr;gap:3rem;align-items:center;
  padding:5rem 0;border-bottom:1px solid rgba(180,196,190,.16);
}
.iv-row--right .iv-row__media{order:2}
.iv-row--right .iv-row__copy{order:1}
.iv-row__media{position:relative;display:block;aspect-ratio:16/10;background:#111314;overflow:hidden;border:1px solid rgba(180,196,190,.10);transition:border-color .4s ease,transform .8s cubic-bezier(.2,.7,.2,1)}
.iv-row__media:hover{border-color:rgba(180,196,190,.25);transform:translateY(-3px)}
.iv-row__loop,.iv-row__still{width:100%;height:100%;object-fit:cover;display:block;filter:saturate(.92) contrast(1.04);transition:filter .6s ease}
.iv-row__media::after{content:"";position:absolute;inset:0;pointer-events:none;background:radial-gradient(80% 65% at 50% 50%, transparent 55%, rgba(8,10,11,.45) 100%)}
.iv-row__copy{display:flex;flex-direction:column;gap:1.1rem;align-items:flex-start}
.iv-row__title{margin:.2rem 0 0;font-family:var(--serif);font-weight:400;font-size:clamp(1.8rem,3vw,2.8rem);line-height:1.05;letter-spacing:-.015em;font-variation-settings:"opsz" 32}
.iv-row__title a{color:inherit;transition:color .3s}
.iv-row__title a:hover{color:var(--mist)}
.iv-row__title em{font-style:italic;color:var(--mist)}
.iv-row__story{margin:0;color:var(--bone);font-size:1.02rem;line-height:1.6;max-width:42ch}
.iv-row__tags{margin:.2rem 0 0;font-family:var(--mono);font-size:.7rem;letter-spacing:.18em;color:var(--sage);text-transform:uppercase}
.iv-row__more{margin-top:.4rem;font-family:var(--mono);font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;color:var(--paper);border-bottom:1px solid rgba(180,196,190,.4);padding-bottom:.25rem;transition:.3s}
.iv-row__more:hover{color:var(--mist);border-color:var(--mist);letter-spacing:.28em}
.iv-empty{padding:5rem 0;color:var(--sage);font-style:italic;font-family:var(--serif)}
.iv-archive__footcta{margin-top:4rem;text-align:center}

@media (max-width:820px){
  .iv-archive{padding-top:7rem}
  .iv-row{grid-template-columns:1fr;gap:1.6rem;padding:3rem 0}
  .iv-row--right .iv-row__media,.iv-row--right .iv-row__copy{order:initial}
  .iv-row__media{aspect-ratio:4/3}
}

/* ================================================================
   Single intervention
   ================================================================ */
.iv-single{position:relative;z-index:10;background:#0a0c0c}
.iv-single__hero{position:relative;width:100%;height:80vh;min-height:520px;overflow:hidden}
.iv-single__media{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.iv-single__scrim{position:absolute;inset:0;background:linear-gradient(180deg, rgba(8,10,11,.25) 0%, rgba(8,10,11,.15) 45%, rgba(8,10,11,.9) 100%)}
.iv-single__hero-copy{position:absolute;left:0;right:0;bottom:0;padding:0 var(--gutter) 4rem;max-width:var(--maxw);margin:0 auto}
.iv-single__title{font-family:var(--serif);font-weight:400;font-size:clamp(2.4rem,6vw,5rem);line-height:1.02;letter-spacing:-.02em;margin:.6rem 0 0;font-variation-settings:"opsz" 32;max-width:22ch}
.iv-single__title em{font-style:italic;color:var(--mist)}

.iv-single__body{padding:6rem var(--gutter);max-width:var(--maxw);margin:0 auto;display:grid;grid-template-columns:1fr 22rem;gap:5rem;align-items:start}
.iv-single__chips{grid-column:1/-1;list-style:none;padding:0;margin:0 0 2.5rem;display:flex;flex-wrap:wrap;gap:.6rem}
.iv-single__chips li{padding:.45rem .85rem;border:1px solid rgba(180,196,190,.22);font-family:var(--mono);font-size:.65rem;letter-spacing:.18em;color:var(--bone);text-transform:uppercase}
.iv-single__chips a{color:inherit}
.iv-single__story{font-size:1.08rem;line-height:1.75;color:var(--bone);max-width:36rem}
.iv-single__story p{margin:0 0 1.2rem}
.iv-single__story em{font-style:italic;color:var(--mist)}
.iv-single__outcome{border-left:1px solid rgba(180,196,190,.2);padding-left:1.6rem}
.iv-single__outcome .eyebrow{display:block;margin-bottom:1rem}
.iv-single__outcome ul{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:1rem}
.iv-single__outcome li{font-family:var(--serif);font-size:1.05rem;line-height:1.4;color:var(--paper)}
.iv-single__outcome li::before{content:"+";color:var(--gold);margin-right:.6rem;font-family:var(--mono);font-size:.85rem}

.iv-single__nav{
  padding:3.5rem var(--gutter);max-width:var(--maxw);margin:0 auto;
  display:flex;justify-content:space-between;align-items:center;gap:1.5rem;
  border-top:1px solid rgba(180,196,190,.16);
  font-family:var(--mono);font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;
}
.iv-single__nav > a:first-child{color:var(--bone);transition:color .3s}
.iv-single__nav > a:first-child:hover{color:var(--paper)}

@media(max-width:820px){
  .iv-single__hero{height:70vh;min-height:420px}
  .iv-single__body{grid-template-columns:1fr;gap:2.5rem;padding:4rem var(--gutter)}
  .iv-single__outcome{border-left:0;border-top:1px solid rgba(180,196,190,.2);padding-left:0;padding-top:1.6rem}
  .iv-single__nav{flex-direction:column;align-items:flex-start;gap:1rem}
}

/* ================================================================
   404 — cinematic missing-thread page
   ================================================================ */
.not-found{
  position:relative;
  min-height:100svh;
  display:flex;align-items:center;
  padding:8rem var(--gutter) 6rem;
  isolation:isolate;
  overflow:hidden;
}
.not-found__stage{position:absolute;inset:0;z-index:0;overflow:hidden;background:#0a0c0c}
.not-found__video{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:saturate(.7) contrast(1.08) brightness(.55);
  transform:scale(1.08);
  will-change:transform,filter;
  animation:notfoundDrift 24s ease-in-out infinite;
}
@keyframes notfoundDrift{
  0%,100%{transform:scale(1.08) translate3d(0,0,0)}
  50%{transform:scale(1.12) translate3d(-1.2%,1.5%,0)}
}
.not-found__veil{
  position:absolute;inset:0;
  background:
    radial-gradient(100% 80% at 30% 50%, rgba(8,10,11,.45), rgba(8,10,11,.85) 75%),
    linear-gradient(180deg, rgba(8,10,11,.4) 0%, rgba(8,10,11,.15) 30%, rgba(8,10,11,.55) 100%);
}

.not-found__copy{
  position:relative;z-index:1;
  max-width:var(--maxw);margin:0 auto;width:100%;
  display:flex;flex-direction:column;gap:1.8rem;
  max-inline-size:48rem;
}

.not-found__title{
  font-family:var(--serif);font-weight:400;
  font-size:clamp(3rem,8.5vw,7.5rem);
  line-height:.95;letter-spacing:-.025em;
  margin:.4rem 0 0;
  font-variation-settings:"opsz" 32;
}
.not-found__title em{font-style:italic;color:var(--mist)}

.not-found__story{
  font-family:var(--serif);font-style:italic;font-weight:300;
  font-size:clamp(1.05rem,1.5vw,1.35rem);line-height:1.55;color:var(--bone);
  max-width:36ch;margin:0;
}

.not-found__meta{
  margin:.5rem 0 0;
  font-family:var(--mono);font-size:.65rem;letter-spacing:.18em;color:var(--sage);text-transform:uppercase;
  display:inline-flex;align-items:center;gap:.6rem;
}
.not-found__meta::before{content:"⟶"; color:var(--gold)}
.not-found__url{
  display:inline-block;
  max-width:60vw;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:var(--bone);opacity:.65;text-transform:none;letter-spacing:.05em;
}

.not-found__nav{
  margin-top:1.8rem;
  display:flex;align-items:center;flex-wrap:wrap;gap:1.6rem 2.2rem;
}
.not-found__alt{
  font-family:var(--mono);font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;color:var(--bone);
  border-bottom:1px solid rgba(180,196,190,.3);padding-bottom:.25rem;
  transition:color .3s,border-color .3s,letter-spacing .3s;
}
.not-found__alt:hover{color:var(--paper);border-color:var(--mist);letter-spacing:.28em}

@media (max-width:780px){
  .not-found{padding:7rem var(--gutter) 4rem;align-items:flex-end;min-height:100svh}
  .not-found__copy{gap:1.4rem}
  .not-found__nav{flex-direction:column;align-items:flex-start;gap:1rem}
  .not-found__alt{font-size:.66rem}
}

/* Reduced-motion: stop the drift animation */
@media (prefers-reduced-motion: reduce){
  .not-found__video{animation:none}
}

/* ================================================================
   LEGAL PAGES — Privacy, Terms, etc.
   Editorial single column. Wide reading measure, hairline dividers,
   mono micro-labels, serif headings.
   ================================================================ */
.legal{
  position:relative;z-index:10;background:#0a0c0c;color:var(--paper);
  padding:9rem var(--gutter) 6rem;
  max-width:62rem;margin:0 auto;
}
.legal__hdr{margin-bottom:4rem;padding-bottom:3rem;border-bottom:1px solid rgba(180,196,190,.18)}
.legal__title{
  font-family:var(--serif);font-weight:400;
  font-size:clamp(2.4rem,5vw,4.2rem);line-height:1.02;letter-spacing:-.015em;margin:.5rem 0 1.6rem;
  font-variation-settings:"opsz" 32;
}
.legal__meta{
  display:inline-flex;align-items:center;gap:.6rem;
  margin:0;
  font-family:var(--mono);font-size:.66rem;letter-spacing:.18em;color:var(--sage);text-transform:uppercase;
}
.legal__meta span{opacity:.7}

/* Body — typographic reset for the_content() output */
.legal__body{font-family:var(--sans);font-weight:300;font-size:1.05rem;line-height:1.75;color:var(--bone);max-width:40rem}
.legal__body h2{
  font-family:var(--serif);font-weight:400;
  font-size:clamp(1.5rem,2.4vw,2rem);line-height:1.1;letter-spacing:-.01em;
  margin:3.2rem 0 1.2rem;color:var(--paper);
  font-variation-settings:"opsz" 32;
  position:relative;padding-top:1.8rem;
}
.legal__body h2::before{
  content:"";display:block;
  width:3rem;height:1px;background:var(--sage);
  margin:0 0 1.4rem;opacity:.5;
}
.legal__body h3{
  font-family:var(--serif);font-weight:400;font-style:italic;
  font-size:1.25rem;color:var(--mist);
  margin:2rem 0 .8rem;
}
.legal__body p{margin:0 0 1.2rem}
.legal__body em{font-style:italic;color:var(--mist)}
.legal__body strong{font-weight:500;color:var(--paper)}
.legal__body a{color:var(--mist);text-decoration:underline;text-underline-offset:.2em;text-decoration-thickness:1px;text-decoration-color:rgba(180,196,190,.4);transition:text-decoration-color .3s}
.legal__body a:hover{text-decoration-color:var(--mist)}
.legal__body ul,.legal__body ol{padding-left:1.4em;margin:0 0 1.4rem}
.legal__body li{margin-bottom:.5rem}
.legal__body li::marker{color:var(--sage);font-family:var(--mono);font-size:.8em}
.legal__body blockquote{
  margin:2rem 0;padding:.6rem 0 .6rem 1.4rem;
  border-left:1px solid var(--sage);
  font-family:var(--serif);font-style:italic;color:var(--bone);font-size:1.12rem;
}
.legal__body hr{border:0;border-top:1px solid rgba(180,196,190,.16);margin:3rem 0}
.legal__body code{font-family:var(--mono);font-size:.85em;background:rgba(180,196,190,.08);padding:.1em .4em;border-radius:0;color:var(--mist)}

.legal__foot{
  margin-top:4rem;padding-top:3rem;border-top:1px solid rgba(180,196,190,.18);
  display:flex;justify-content:space-between;align-items:center;gap:1.5rem;flex-wrap:wrap;
}
.legal__back{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.22em;color:var(--bone);text-transform:uppercase;
  transition:color .3s;
}
.legal__back:hover{color:var(--paper)}

@media(max-width:780px){
  .legal{padding-top:7rem;padding-bottom:4rem}
  .legal__hdr{margin-bottom:2.5rem;padding-bottom:2rem}
  .legal__body h2{margin:2.5rem 0 1rem}
  .legal__foot{flex-direction:column;align-items:flex-start;gap:1.2rem}
}

/* ================================================================
   MOBILE — autoplay-loop story, native scroll, single-viewport scenes
   ================================================================ */
body.is-mobile{}
body.is-mobile .scene{height:auto;min-height:100svh}
body.is-mobile .scene__pin{position:relative;top:auto;height:auto;min-height:100svh;padding:0}
body.is-mobile .scene__copy{
  padding:6rem var(--gutter) 5rem;
  gap:1.6rem;
  min-height:100svh;
  justify-content:flex-end;
  position:relative;
}
/* landing scenes (home hero + first About scene): center the copy vertically
   instead of pushing it to the bottom on mobile */
body.is-mobile .scene__copy--hero,
body.is-mobile #about-endure .scene__copy{justify-content:center;padding-top:6rem;padding-bottom:6rem}
body.is-mobile .scene__copy--center{justify-content:center;text-align:center;padding-top:7rem;padding-bottom:7rem}

/* Mobile: no per-copy scrim — the full-viewport stage veil handles legibility */
body.is-mobile .scene__copy::before,
body.is-mobile .scene__copy--center::before{display:none!important}

/* Disable the radial corner vignette on mobile portrait — its dark corners
   read as side bars on tall narrow viewports */
body.is-mobile .vignette{display:none!important}
body.is-mobile .scene__copy > *{position:relative;z-index:1}

/* mobile copy: simpler, faster reveal — no blur (cheap on GPU), shorter duration */
body.is-mobile .scene__copy > *{
  filter:none;
  transform:translateY(14px);
  transition:opacity .7s ease, transform .8s cubic-bezier(.2,.7,.2,1);
}
body.is-mobile .scene__copy > *:nth-child(2){transition-delay:.08s}
body.is-mobile .scene__copy > *:nth-child(3){transition-delay:.16s}
body.is-mobile .scene__copy > *:nth-child(4){transition-delay:.24s}
body.is-mobile .scene__copy > *:nth-child(5){transition-delay:.32s}
body.is-mobile .scene.in .scene__copy > *{opacity:1;transform:translateY(0)}
body.is-mobile .scene.out .scene__copy > *{opacity:1;transform:translateY(0);transition-duration:.5s}

/* Stage MUST fill the entire viewport on mobile — including under the WP admin bar */
body.is-mobile .stage{
  position:fixed!important;
  top:0!important; left:0!important; right:0!important; bottom:0!important;
  width:100vw!important; height:100vh!important;
  margin:0!important;
}
/* portrait videos cover full viewport. transform:translateZ(0) (NOT none) is REQUIRED
   on iOS: a <video> inside a position:fixed container (our .stage) plays but paints only
   its poster/black unless it's promoted to its own GPU compositing layer. translateZ(0)
   is visually a no-op (no scale/translate → never clips the portrait crop) but forces
   that layer so WebKit actually paints the decoded frames. Pairing backface-visibility
   keeps the layer stable across the opacity crossfade.
   filter:none is also REQUIRED on iOS: Safari renders a <video> black when a CSS filter
   (saturate/contrast) is applied to it. The grade isn't needed on mobile (veil handles it). */
body.is-mobile .stage__v,
body.is-mobile .stage__v.active{transform:translateZ(0)!important;transform-origin:center;backface-visibility:hidden;width:100%;height:100%;object-fit:cover;filter:none!important}

/* mobile veils — covers the ENTIRE stage area (not a side band), reads as a
   soft cinematic atmosphere over the whole portrait video */
body.is-mobile .stage__veil{
  position:absolute;inset:0;
  background:linear-gradient(to bottom,
    rgba(8,10,11,.40) 0%,
    rgba(8,10,11,.10) 25%,
    rgba(8,10,11,.10) 45%,
    rgba(8,10,11,.55) 80%,
    rgba(8,10,11,.85) 100%)!important;
  opacity:1!important;
  mix-blend-mode:normal!important;
}
body.is-mobile .stage::after{display:none!important} /* split-tone grade off on mobile */

/* mobile typography compaction */
@media(max-width:820px){
  :root{--gutter:1.5rem}
  .scene__copy--hero{max-inline-size:100%}
  .scene__copy--hero .display{
    white-space:normal;
    font-size:clamp(3.2rem,13vw,5.5rem);
    line-height:.95;
    letter-spacing:-.025em;
  }
  .display--quiet{font-size:clamp(2rem,7.5vw,3rem);line-height:1.15}
  .title{font-size:clamp(2.4rem,10vw,3.8rem);line-height:1.0}
  .body{font-size:1.02rem;line-height:1.55;max-width:36ch}
  .lede{font-size:clamp(1.05rem,4vw,1.25rem);line-height:1.5}
  .hud{font-size:.68rem}

  .scene--right .scene__copy{align-items:flex-start;text-align:left;margin:0}
  .scene--right .scene__copy > *{max-width:none}
  .scene--right .marker{align-items:flex-start}
  .scene--right .marker li{padding-left:1.2em;padding-right:0}
  .scene--right .marker li::before{left:0;right:auto}

  .defs{text-align:left}
  .defs dd{margin-left:0}
  .diptych{margin-left:0;max-width:100%;grid-template-columns:1fr;border-left:0}
  .diptych > div + div{border-left:0;border-top:1px solid rgba(180,196,190,.2)}
  /* Manifesto on mobile — vertical statement stack with rhythm */
  .manifesto{gap:0;width:100%;max-inline-size:100%;padding-block:1rem}
  .manifesto p{
    font-size:clamp(1.35rem,5.6vw,1.9rem);
    line-height:1.2;
    margin:0;
    padding:1.4rem 0;
    border-top:1px solid rgba(180,196,190,.16);
    width:100%;
    text-align:left;
    position:relative;
    counter-increment:manifesto;
  }
  .manifesto p:last-of-type{border-bottom:1px solid rgba(180,196,190,.16)}
  .manifesto p[data-align="r"]{align-self:stretch;text-align:left;padding-left:1.6rem}
  .manifesto p[data-align="l"]{align-self:stretch;text-align:left}
  .manifesto p[data-align="r"]::before{
    content:counter(manifesto,decimal-leading-zero);
    position:absolute;left:0;top:1.55rem;
    font-family:var(--mono);font-size:.65rem;letter-spacing:.22em;color:var(--gold);
  }
  .manifesto p[data-align="l"]{padding-left:1.6rem}
  .manifesto p[data-align="l"]::before{
    content:counter(manifesto,decimal-leading-zero);
    position:absolute;left:0;top:1.55rem;
    font-family:var(--mono);font-size:.65rem;letter-spacing:.22em;color:var(--sage);
  }
  .manifesto p em{font-style:italic;color:var(--mist);display:inline-block;border-bottom:1px solid var(--gold);padding-bottom:.1em}
  .manifesto{counter-reset:manifesto}

  #s5 .scene__copy,#s7 .scene__copy{max-inline-size:100%}
  .levels{grid-template-columns:1fr}
  .levels li{border-right:0;border-bottom:1px solid rgba(180,196,190,.15);padding:1rem 0}
  .method{grid-template-columns:1fr;border-top:0}
  .method article{border-right:0;border-top:1px solid rgba(180,196,190,.15);min-height:auto;padding:1.2rem 0}

  /* Mobile nav: compact, no wrap, keep both brand words */
  .nav{padding:.85rem var(--gutter);gap:.8rem;background:linear-gradient(to bottom, rgba(8,10,10,.7), rgba(8,10,10,0) 120%)}
  .nav__mark span{font-size:.9rem}
  .nav__links a.nav__cta{
    padding:.55rem .85rem;
    font-size:.6rem;
    letter-spacing:.18em;
    white-space:nowrap;
  }
  /* Swap full label for short label via two spans in HTML */
  .nav__cta-full{display:none}
  .nav__cta-short{display:inline}
  .nav__progress{display:none}
  .scroll-hint{display:none}

  /* pricing/contact mobile rhythm */
  .page{padding:6rem var(--gutter)}
  .plans{grid-template-columns:1fr}
  .extras{grid-template-columns:1fr}
  .page--contact{padding-top:4rem}
}

/* prefers-reduced-motion — kill expensive animations everywhere */
@media(prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;
    animation-iteration-count:1!important;
    transition-duration:.15s!important;
    transition-delay:0s!important;
  }
  .scene__copy > *{filter:none!important;transform:none!important;opacity:1!important}
  .stage__v{transform:none!important;transition:opacity .3s ease!important}
  .grain{animation:none!important}
}

/* ============================================================================
   CITY PLANS — KINETIC FILM TITLES. Oversized centered typography directly
   over each scene's video (no box; video + motion stay fully visible). Legible
   via a soft feathered radial scrim + text-shadow. Districts reveal line-by-
   line in sync with scroll (main.js toggles .is-revealed). Brand: serif display,
   mono meta, single gold accent. See page-city-plans.php.
   ========================================================================= */

/* giant ghost index behind the title — depth + editorial poster feel */
.plan-scene .scene__pin{position:sticky;top:0;height:100dvh;display:grid;place-items:center;
  box-sizing:border-box;padding:clamp(6rem,10vh,8.5rem) var(--gutter) clamp(2rem,5vh,3.2rem)}
.plan-ghost{position:absolute;top:50%;left:50%;transform:translate(-50%,-54%);z-index:1;pointer-events:none;
  font-family:var(--serif);font-weight:400;line-height:1;font-size:clamp(13rem,34vw,30rem);
  color:rgba(238,241,236,.045);font-variation-settings:"opsz" 144;letter-spacing:-.02em}

/* the centered kinetic copy — no panel, just a feathered scrim for legibility.
   Wide + short: title block on top, districts laid out in a horizontal row. */
.plan-kinetic{position:relative;z-index:6;isolation:isolate;
  width:100%;max-inline-size:min(82rem,94vw);margin:0 auto;padding:0;
  display:flex;flex-direction:column;align-items:center;text-align:center;gap:0}
.plan-kinetic::before{content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(128%,92rem);height:min(150%,44rem);z-index:-1;pointer-events:none;
  background:radial-gradient(58% 50% at 50% 50%, rgba(7,9,10,.74), rgba(7,9,10,.4) 56%, rgba(7,9,10,0) 80%);
  filter:blur(6px)}

.plan-kinetic__kicker{font-family:var(--mono);font-size:.72rem;letter-spacing:.34em;text-transform:uppercase;color:var(--mist);
  text-shadow:0 1px 10px rgba(0,0,0,.7)}
.plan-scene--featured .plan-kinetic__kicker{color:var(--gold)}

.plan-kinetic__name{margin:.7rem 0 0;font-family:var(--serif);font-weight:400;
  font-size:clamp(2.9rem,6.6vw,6rem);line-height:.94;letter-spacing:-.025em;color:var(--paper);
  font-variation-settings:"opsz" 144;text-shadow:0 2px 34px rgba(0,0,0,.72),0 1px 5px rgba(0,0,0,.5)}
.plan-kinetic__name--sm{font-size:clamp(2.5rem,5vw,4.4rem)}
.plan-kinetic__name--display{font-size:clamp(2.5rem,5.2vw,4.8rem);line-height:1.26}
/* About-page display titles: extra separation between the two stacked lines.
   (Weight unchanged — the title may stay bold; only the leading is opened up.)
   Scoped to .about-scene so the City Plans s6 display title keeps its own leading. */
.about-scene .plan-kinetic__name--display{line-height:1.46}
.plan-kinetic__name em{font-style:italic;color:var(--mist)}

/* animated gold hairline under the title */
.plan-kinetic__rule{display:block;height:1px;width:0;margin:1.1rem auto 0;background:var(--gold);
  box-shadow:0 0 18px rgba(201,169,107,.5);transition:width 1.1s cubic-bezier(.16,1,.3,1) .25s}
.scene.in .plan-kinetic__rule{width:clamp(3rem,7vw,6rem)}

.plan-kinetic__tagline{margin:1.1rem 0 0;font-family:var(--serif);font-style:italic;
  font-size:clamp(1.3rem,2.1vw,1.95rem);line-height:1.18;color:var(--mist);text-shadow:0 1px 18px rgba(0,0,0,.7)}
.plan-kinetic__lede{margin:1rem auto 0;max-width:52ch;font-size:1.05rem;line-height:1.6;color:#e3e8e2;
  text-shadow:0 1px 14px rgba(0,0,0,.7)}

/* districts — a horizontal row of columns, each revealed in turn on scroll */
.plan-lines{list-style:none;margin:2rem 0 0;padding:0;width:100%;
  display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:0;align-items:start}
.plan-line{opacity:0;transform:translateY(24px);filter:blur(7px);
  transition:opacity .8s cubic-bezier(.16,1,.3,1),transform .8s cubic-bezier(.16,1,.3,1),filter .8s ease}
.plan-line.is-revealed{opacity:1;transform:none;filter:blur(0)}
.plan-lines .plan-line{display:flex;flex-direction:column;align-items:center;gap:.45rem;
  padding:.2rem clamp(1rem,2vw,2.2rem);text-shadow:0 1px 16px rgba(0,0,0,.72)}
.plan-lines .plan-line:not(:first-child){border-left:1px solid rgba(180,196,190,.16)}
.plan-line__head{display:inline-flex;align-items:baseline;gap:.6rem;justify-content:center}
.plan-line__num{font-family:var(--mono);font-size:.78rem;letter-spacing:.04em;color:var(--gold)}
.plan-line__name{font-family:var(--serif);font-size:clamp(1.4rem,2vw,2rem);line-height:1.04;color:var(--paper)}
.plan-line__say{font-family:var(--serif);font-style:italic;font-size:clamp(1rem,1.35vw,1.18rem);color:var(--mist);line-height:1.25}
.plan-line__svc{font-family:var(--mono);font-size:.64rem;letter-spacing:.13em;text-transform:uppercase;color:var(--sage);line-height:1.6}

/* program highlight chips + closing defs (also .plan-line for the scroll reveal) */
.plan-chips{list-style:none;margin:2rem auto 0;padding:0;display:flex;flex-wrap:wrap;justify-content:center;gap:.6rem;max-width:46rem}
.plan-chips .plan-line{font-family:var(--mono);font-size:.66rem;letter-spacing:.12em;text-transform:uppercase;color:var(--mist);
  border:1px solid rgba(180,196,190,.34);border-radius:2px;padding:.5em .85em;background:rgba(10,12,12,.35)}
.plan-chips--defs{flex-wrap:nowrap;align-items:stretch;gap:0;max-width:64rem}
.plan-chips--defs .plan-line{flex:1;display:flex;flex-direction:column;gap:.3rem;border:0;background:none;padding:.2rem clamp(1rem,2vw,2rem);text-transform:none;letter-spacing:0;text-align:center}
.plan-chips--defs .plan-line:not(:first-child){border-left:1px solid rgba(180,196,190,.16)}
.plan-chips--defs .plan-line strong{font-family:var(--serif);font-weight:400;font-size:1.35rem;color:var(--paper);text-shadow:0 1px 16px rgba(0,0,0,.7)}
.plan-chips--defs .plan-line span{font-family:var(--sans);font-size:.92rem;line-height:1.5;color:#dbe1da;text-shadow:0 1px 14px rgba(0,0,0,.7)}

/* outcome */
.plan-kinetic__outcome{margin:1.6rem auto 0;max-width:62ch;font-size:1rem;line-height:1.55;color:var(--paper);text-shadow:0 1px 16px rgba(0,0,0,.72)}
.plan-kinetic__outcome-lbl{font-family:var(--mono);font-size:.6rem;letter-spacing:.22em;text-transform:uppercase;color:var(--gold);margin-right:.55em}

/* price + CTA */
.plan-kinetic__foot{margin-top:1.8rem;display:flex;align-items:center;justify-content:center;gap:1.6rem;flex-wrap:wrap}
.plan-price{margin:0;display:inline-flex;align-items:baseline;gap:.5rem;flex-wrap:wrap;justify-content:center;
  font-variant-numeric:tabular-nums;text-shadow:0 2px 20px rgba(0,0,0,.7)}
.plan-price__label{font-family:var(--mono);font-size:.6rem;letter-spacing:.2em;text-transform:uppercase;color:var(--sage);align-self:center;margin-right:.2rem}
.plan-price__prefix{font-family:var(--mono);font-size:.66rem;letter-spacing:.18em;text-transform:uppercase;color:var(--sage)}
.plan-price__amount{font-family:var(--serif);font-size:clamp(2.6rem,4vw,4rem);color:var(--paper);line-height:.9;letter-spacing:-.015em}
.plan-price__period{font-family:var(--mono);font-size:.78rem;letter-spacing:.06em;color:var(--bone)}
.plan-cta{display:inline-flex;align-items:center;gap:.6rem;padding:1rem 2rem;border:1px solid rgba(238,241,236,.6);border-radius:2px;
  color:var(--paper);font-family:var(--mono);font-size:.72rem;letter-spacing:.2em;text-transform:uppercase;text-decoration:none;white-space:nowrap;
  transition:background .28s ease,color .28s ease,letter-spacing .28s ease,transform .2s ease}
.plan-cta:hover{background:var(--paper);color:var(--ink);letter-spacing:.27em}
.plan-cta:active{transform:scale(.985)}
.plan-cta--gold{border-color:var(--gold);color:var(--gold)}
.plan-cta--gold:hover{background:var(--gold);color:var(--ink)}

/* recommended badge — floats above the title block */
.plan-tag{align-self:center;margin-bottom:1.1rem;font-family:var(--mono);font-size:.6rem;letter-spacing:.22em;text-transform:uppercase;
  color:var(--gold);border:1px solid rgba(201,169,107,.5);border-radius:999px;padding:.45em 1em;background:rgba(201,169,107,.12);
  text-shadow:none}

/* neutralise the generic per-child blur-in on the line containers — the lines
   manage their own reveal (scroll-synced), so don't double-animate the <ul>. */
.plan-kinetic > .plan-lines,
.plan-kinetic > .plan-chips,
.plan-kinetic > .about-lines,
.plan-kinetic > .guide-grid{opacity:1 !important;transform:none !important;filter:none !important}

/* ── About Us kinetic sections ──────────────────────────────────────────────
   Reuse the City Plans kinetic shell (.plan-scene / .plan-kinetic / .plan-line
   reveal) but present the copy two ways: a centered stack of statements (Why We
   Build, Designed For What Comes Next) and a width-spanning grid of principles
   (What Guides Us). Each line carries .plan-line so main.js reveals it on scroll. */

/* statements — a centered vertical stack, each line fading up in turn */
.about-lines{list-style:none;margin:1.9rem auto 0;padding:0;width:100%;max-width:56rem;
  display:flex;flex-direction:column;align-items:center;gap:clamp(.85rem,1.7vh,1.25rem)}
.about-lines .about-stmt{font-family:var(--serif);font-weight:300;text-align:center;
  font-size:clamp(1rem,1.7vw,1.5rem);line-height:1.3;color:var(--paper);letter-spacing:-.01em;
  text-shadow:0 1px 22px rgba(0,0,0,.74)}
/* the closing statement reads as the resolution — italic mist, a touch larger */
.about-lines .about-stmt:last-child{font-style:italic;font-weight:300;color:var(--mist);
  font-size:clamp(1.06rem,1.85vw,1.6rem);margin-top:.3rem}

/* principles — a width-spanning grid, each cell hung off a thin gold rule */
.guide-grid{list-style:none;margin:2.4rem auto 0;padding:0;width:100%;max-width:74rem;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:clamp(1.9rem,3.4vh,2.7rem) clamp(1.6rem,2.4vw,2.6rem)}
.guide-grid .guide{display:flex;flex-direction:column;align-items:flex-start;gap:.5rem;text-align:left;
  padding:.35rem 0 .5rem 1.15rem;border-left:1px solid rgba(201,169,107,.5);
  text-shadow:0 1px 16px rgba(0,0,0,.72)}
.guide__num{font-family:var(--mono);font-size:.62rem;letter-spacing:.2em;color:var(--gold)}
.guide__name{font-family:var(--serif);font-weight:400;font-size:clamp(1.2rem,1.8vw,1.7rem);line-height:1.18;color:var(--paper)}
.guide__desc{font-family:var(--sans);font-size:.92rem;line-height:1.55;color:#dbe1da;max-width:34ch}
/* extra breathing room between the principles grid and the diagnostic CTA
   (base value — also the mobile gap, since margin:auto collapses to 0 in block flow) */
.about-scene--guides .plan-kinetic__foot{margin-top:clamp(2.8rem,5.5vh,4rem)}
/* on desktop, keep the title + principles grid vertically CENTERED (their original
   position) but drop the CTA to the bottom edge of the section. The copy stretches to
   the full pinned height and centers its in-flow content; the foot is taken out of flow
   (absolute) so it pins to the bottom without dragging the centered group upward. */
@media(min-width:901px){
  .plan-scene.about-scene--guides .scene__pin{align-items:stretch}
  .about-scene--guides .plan-kinetic{height:100%;justify-content:center}
  .about-scene--guides .plan-kinetic__foot{position:absolute;left:0;right:0;bottom:0;margin-top:0}
}

@media(max-width:900px){
  .about-lines{max-width:94vw}
  .about-lines .about-stmt{font-size:clamp(1rem,3.5vw,1.35rem)}
  .about-lines .about-stmt:last-child{font-size:clamp(1.06rem,3.8vw,1.44rem)}
  .guide-grid{grid-template-columns:1fr;max-width:36rem;gap:0;text-align:left}
  .guide-grid .guide{padding:1.05rem 0 1.05rem 1.05rem;border-left:1px solid rgba(201,169,107,.45)}
}

/* ── reduced motion / mobile — show every line, no scroll dependency ──────── */
body.is-mobile .plan-line,
body.reduced-motion .plan-line,
body.motion-paused .plan-line{opacity:1;transform:none;filter:blur(0);transition:none}
body.is-mobile .plan-kinetic__rule,
body.reduced-motion .plan-kinetic__rule{width:clamp(3rem,7vw,6rem)}

@media(max-width:900px){
  .plan-kinetic{max-inline-size:94vw}
  .plan-ghost{font-size:38vw;opacity:.7}
  /* stack the district columns vertically on narrow screens */
  .plan-lines,.plan-chips--defs{grid-auto-flow:row;grid-auto-columns:auto;display:grid}
  .plan-lines .plan-line,.plan-chips--defs .plan-line{padding:1.1rem 0}
  .plan-lines .plan-line:not(:first-child),
  .plan-chips--defs .plan-line:not(:first-child){border-left:0;border-top:1px solid rgba(180,196,190,.16)}
  .plan-line__svc{display:none}
}
/* protect the pinned viewport from overflow on short screens (row layout is
   already short — only the title needs trimming) */
@media(max-height:780px) and (min-width:901px){
  .plan-kinetic__name{font-size:clamp(2.8rem,5vw,4.6rem)}
  .plan-kinetic__tagline{font-size:1.25rem;margin-top:.9rem}
  .plan-lines{margin-top:1.5rem}
}

/* ============================================================================
   UNIFIED CTA BUTTONS — every call-to-action matches the contact form button
   (transparent, 1px var(--mist) border, var(--paper) text, mono, sharp corners;
   hover fills with var(--mist)). The nav__cta keeps its compact navbar size but
   already shares this colour treatment.
   ========================================================================= */
.cta,
.plan__cta,
.plan-cta,
.plan-cta--gold,
.not-found__alt{
  display:inline-flex;align-items:center;gap:.6rem;
  padding:1rem 1.5rem;border:1px solid var(--mist);border-radius:0;
  background:transparent;color:var(--paper);
  font-family:var(--mono);font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;text-decoration:none;
  transition:background .35s ease,color .35s ease,letter-spacing .35s ease;
}
.cta:hover,
.plan__cta:hover,
.plan-cta:hover,
.plan-cta--gold:hover,
.not-found__alt:hover{
  background:var(--mist);color:var(--ink);letter-spacing:.28em;
}

/* Anchor offset — keep the diagnostic form clear of the fixed header when an
   anchor link (#contact / #kairos-diagnostic) scrolls to it (native/mobile path;
   the Lenis desktop path applies the same offset in main.js via navOffset()). */
.page--contact,
.anchor-alias{scroll-margin-top:clamp(5.5rem,13vh,8rem)}
.anchor-alias{display:block;width:0;height:0}

/* ════════════════════════════════════════════════════════════════════════
   TWO UNIVERSES — software (dark, original) ⇄ design (light, new)
   Same engine, same grid, same type. What inverts is the light.
   ════════════════════════════════════════════════════════════════════════ */

/* ─── Nav toggle: the divided circle ─── */
.nav__universe{
  display:inline-flex;align-items:center;gap:.5rem;
  padding:.3rem .6rem .3rem .38rem;
  border:1px solid rgba(180,196,190,.25);
  color:var(--bone);
  font-family:var(--mono);font-size:.62rem;letter-spacing:.2em;text-transform:uppercase;
  transition:border-color .3s,color .3s,background .3s;
}
.nav__universe:hover,.nav__universe:focus-visible{
  border-color:var(--mist);color:var(--paper);background:rgba(180,196,190,.08);
}
.nav__universe-mark{display:inline-flex;flex:none}
.nav__universe-mark svg{
  display:block;
  transition:transform .6s cubic-bezier(.55,0,.25,1);
}
.nav__universe:hover .nav__universe-mark svg{transform:rotate(180deg)}
.nav__universe-half--sw{fill:var(--slate)}
.nav__universe-half--ds{fill:var(--bone)}
.nav__universe-ring{stroke:currentColor;stroke-width:1;opacity:.45}
.nav__universe-label{white-space:nowrap}
/* The desktop nav runs down to 1024px, where the hamburger takes over. That
   1025–1180px band was already tight before the toggle joined the row; with it
   the grid overflowed its own container and the page gained a horizontal
   scrollbar. Drop the toggle to its bare mark and pull the gaps in — the
   divided circle carries the meaning without the word. */
@media(max-width:1180px){
  .nav__universe-label{display:none}
  .nav__universe{padding:.3rem;gap:0}
  .nav__links{gap:1.05rem}
  .nav__cta{padding-left:.9rem;padding-right:.9rem}
}

/* Mobile menu crossing */
.mobile-menu__universe{
  display:flex;align-items:center;gap:.9rem;
  margin:1.25rem 0 0;padding:1rem 0;
  border-top:1px solid rgba(180,196,190,.16);
  border-bottom:1px solid rgba(180,196,190,.16);
  color:var(--bone);
}
.mobile-menu__universe-mark{display:inline-flex;flex:none}
.mobile-menu__universe-text{display:flex;flex-direction:column;gap:.2rem}
.mobile-menu__universe-name{
  font-family:var(--serif);font-size:1.15rem;font-weight:300;color:var(--paper);
}

/* ─── Ecosystem section: the toggle, full width ─── */
.ecosystem{
  position:relative;z-index:2;
  padding:clamp(4rem,10vw,7rem) 0 0;
  background:#0a0c0c;
}
.ecosystem__head{
  max-width:var(--maxw);margin:0 auto;
  padding:0 var(--gutter) clamp(2.5rem,6vw,4rem);
  display:flex;flex-direction:column;gap:1rem;
}
.ecosystem__eyebrow{
  font-family:var(--mono);font-size:.66rem;letter-spacing:.28em;text-transform:uppercase;
  color:var(--sage);
}
.ecosystem__title{
  font-family:var(--serif);font-weight:300;line-height:1.06;margin:0;
  font-size:clamp(2rem,5.5vw,3.4rem);
  color:var(--paper);text-wrap:balance;
}
.ecosystem__title em{font-style:italic;color:var(--mist)}

.ecosystem__split{
  position:relative;
  /* Was relying on the body being capped at 1480px — which it no longer is,
     since `.page` used to match <body> via WordPress's body_class and boxed the
     whole document. With that fixed, the split needs its own measure or it runs
     edge to edge. It matches .ecosystem__head above it. */
  max-width:var(--maxw);
  margin-inline:auto;
  display:grid;
  grid-template-columns:repeat(var(--eco-cols,2),1fr);
  border-top:1px solid rgba(180,196,190,.18);
}
/* Four-way ready: when the client adds Energía + Marketing, the count
   attribute is all that changes. ponytail: no JS, no new rule per universe. */
.ecosystem__split[data-count="3"]{--eco-cols:3}
.ecosystem__split[data-count="4"]{--eco-cols:4}

.ecosystem__half{
  position:relative;
  display:flex;flex-direction:column;gap:.85rem;
  min-height:clamp(300px,42vw,420px);
  padding:clamp(3.5rem,6vw,5rem) clamp(1.5rem,3vw,2.5rem) clamp(2.5rem,5vw,3.5rem);
  justify-content:flex-end;
  transition:background .5s;
}
.ecosystem__half + .ecosystem__half{border-left:1px solid rgba(180,196,190,.18)}
.ecosystem__half--software{background:linear-gradient(to bottom,#0d1111,#131a19)}
.ecosystem__half--software:hover{background:linear-gradient(to bottom,#0f1414,#18201e)}
.ecosystem__half--design{background:linear-gradient(to bottom,var(--bone),var(--paper));color:var(--ink)}
.ecosystem__half--design:hover{background:linear-gradient(to bottom,#e2e7e0,#f4f6f2)}
.ecosystem__icon{display:block;opacity:.75}
.ecosystem__half--software .ecosystem__icon{color:var(--mist)}
.ecosystem__half--design .ecosystem__icon{color:#57676B}
.ecosystem__name{
  font-family:var(--mono);font-size:.78rem;letter-spacing:.3em;text-transform:uppercase;
}
.ecosystem__half--software .ecosystem__name{color:var(--paper)}
.ecosystem__half--design .ecosystem__name{color:#0d1010}
.ecosystem__line{
  font-size:.95rem;line-height:1.6;max-width:34ch;
}
.ecosystem__half--software .ecosystem__line{color:var(--mist)}
.ecosystem__half--design .ecosystem__line{color:#57676B}
.ecosystem__enter{
  font-family:var(--mono);font-size:.68rem;letter-spacing:.24em;text-transform:uppercase;
  margin-top:.4rem;
  transition:letter-spacing .4s;
}
.ecosystem__half--software .ecosystem__enter{color:var(--paper)}
.ecosystem__half--design .ecosystem__enter{color:#3c4644}
.ecosystem__half:hover .ecosystem__enter{letter-spacing:.34em}
.ecosystem__half.is-current{cursor:default}
.ecosystem__half.is-current .ecosystem__enter{opacity:.62}
.ecosystem__half.is-current:hover .ecosystem__enter{letter-spacing:.24em}

/* The disc where the halves meet */
.ecosystem__core{
  /* Dead centre on the seam — this is the toggle itself now, not an ornament.
     The halves carry extra inner padding so their copy clears it. */
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;
  transition:transform .6s cubic-bezier(.34,1.4,.5,1),box-shadow .4s,border-color .4s;
  width:clamp(112px,15vw,152px);height:clamp(112px,15vw,152px);
  border-radius:50%;
  background:#0a0c0c;
  border:1px solid rgba(180,196,190,.35);
  display:flex;align-items:center;justify-content:center;gap:.1rem;
  z-index:6;
}
.ecosystem__core-mark{
  font-family:var(--serif);font-size:clamp(.78rem,1.5vw,.95rem);font-weight:300;
  letter-spacing:.12em;color:var(--paper);line-height:1;
}
.ecosystem__core-sub{
  font-family:var(--mono);font-size:.42rem;letter-spacing:.28em;text-transform:uppercase;color:var(--sage);line-height:1;
}
/* Odd counts have no seam at 50% — hide the disc rather than float it. */
.ecosystem__split[data-count="3"] .ecosystem__core{display:none}

@media(max-width:780px){
  /* The halves stack, so the seam runs horizontally and the disc has to
     straddle it exactly as it does on desktop. Making the disc a flex ITEM
     between them gave it a row of its own and pushed the panels apart — the
     gap of paper showing between the two cards. It is absolutely positioned on
     the seam instead, and the panels stay touching. */
  .ecosystem__split{
    display:flex;flex-direction:column;
    grid-template-columns:1fr;
    position:relative;
  }
  .ecosystem__half{min-height:0}
  .ecosystem__half + .ecosystem__half{border-left:0;border-top:0}
  .ecosystem__half--software{order:0}
  .ecosystem__half--design{order:1}

  .ecosystem__core{
    position:absolute;
    left:50%;top:50%;
    transform:translate(-50%,-50%);
    margin:0;
    width:clamp(104px,26vw,124px);height:clamp(104px,26vw,124px);
  }
  /* The drag axis is vertical here, so the chevrons have to point up and down —
     left/right arrows would be telling the thumb the wrong thing. */
  /* Copy no longer needs to clear a disc sitting on a vertical seam; it needs
     to clear one sitting on a horizontal seam. Pad the facing edges instead. */
  .ecosystem__half--software{padding-bottom:clamp(4rem,15vw,5.5rem)}
  .ecosystem__half--design{padding-top:clamp(4rem,15vw,5.5rem)}
}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE — the inversion.
   Tokens only. The footage is lit bright in camera; never add a filter to
   <video> here — that is what rendered black on iOS WebKit.
   ════════════════════════════════════════════════════════════════════════ */
body.universe--design{
  --ink:#eef1ec;
  --paper:#0d1010;
  --bone:#3c4644;
  --sage:#57676B;
  --mist:#57676B;
  background:#f4f6f2;
  color:#0d1010;
}

/* Veils invert: multiply over dark becomes screen over light. */
body.universe--design .stage__veil{
  mix-blend-mode:screen;
  background:
    radial-gradient(130% 90% at 0% 55%, rgba(244,246,242,.94), rgba(244,246,242,.34) 55%, rgba(244,246,242,0) 78%),
    linear-gradient(to top, rgba(244,246,242,.78), rgba(244,246,242,.10) 38%, rgba(244,246,242,.58));
}
body.universe--design .stage__veil--right{
  background:
    radial-gradient(130% 90% at 100% 55%, rgba(244,246,242,.94), rgba(244,246,242,.34) 55%, rgba(244,246,242,0) 78%),
    linear-gradient(to top, rgba(244,246,242,.74), rgba(244,246,242,.06) 38%, rgba(244,246,242,.48));
}
body.universe--design .stage__veil--center{
  background:
    radial-gradient(45% 35% at 50% 50%, rgba(244,246,242,.74), rgba(244,246,242,.38) 65%, rgba(244,246,242,.58) 100%),
    radial-gradient(120% 90% at 50% 50%, rgba(244,246,242,.28), rgba(244,246,242,.78));
}

/* Grain reads as dirt on a light ground — halve it, and drop the vignette. */
body.universe--design .grain{opacity:.035;mix-blend-mode:multiply}
body.universe--design .vignette{display:none}
body.universe--design .curtain{background:#f4f6f2}

/* Nav chrome flips to ink-on-paper. */
body.universe--design .nav__link,
body.universe--design .lang-switcher,
body.universe--design .nav__universe,
body.universe--design .nav__motion-toggle{color:#3c4644}
body.universe--design .nav__link:hover,
body.universe--design .lang-switcher__item:hover,
body.universe--design .lang-switcher__item.is-active,
body.universe--design .nav__universe:hover{color:#0d1010}
body.universe--design .nav__universe,
body.universe--design .nav__motion-toggle{border-color:rgba(13,16,16,.22)}
body.universe--design .nav__universe:hover,
body.universe--design .nav__motion-toggle:hover{background:rgba(13,16,16,.05);border-color:rgba(13,16,16,.4)}
body.universe--design .lang-switcher__item + .lang-switcher__item{border-left-color:rgba(13,16,16,.18)}
body.universe--design .nav__universe-half--sw{fill:#3c4644}
body.universe--design .nav__universe-half--ds{fill:#d6dcd5}

/* ─── Mobile menu, design half ────────────────────────────────────────────
   The panel is one dark sheet with type coloured from --paper and --bone.
   The design universe inverts exactly those tokens, so every label was
   near-black on a near-black ground — the menu rendered as an empty box.

   Literal colours, not tokens, for the same reason the ecosystem uses them:
   this panel has to be light on the design half and dark on the software
   half, so it cannot inherit either side's inversion.                       */
body.universe--design .mobile-menu{
  /* Opaque, unlike the software half. Frosting works over dark footage;
     over a pale page it just leaves the reel showing through as smudges
     behind the type. With no translucency the blur only costs a layer. */
  background:#f4f6f2;
  backdrop-filter:none;-webkit-backdrop-filter:none;
}
body.universe--design .mobile-menu__head{border-bottom-color:rgba(20,24,26,.16)}
body.universe--design .mobile-menu__eyebrow,
body.universe--design .mobile-menu__controls .eyebrow,
body.universe--design .mobile-menu__universe .eyebrow{color:#5a655f}
body.universe--design .mobile-menu__close{
  border-color:rgba(20,24,26,.28);color:#14181a;
}
body.universe--design .mobile-menu__close:hover{
  background:#14181a;color:#f4f6f2;border-color:#14181a;
}
body.universe--design .mobile-menu__link{
  color:#14181a;border-bottom-color:rgba(20,24,26,.12);
}
body.universe--design .mobile-menu__link:hover{color:#8a6f36}
body.universe--design .mobile-menu__foot{border-top-color:rgba(20,24,26,.16)}

body.universe--design .mobile-menu__universe{
  border-top-color:rgba(20,24,26,.16);
  border-bottom-color:rgba(20,24,26,.16);
  color:#48524e;
}
body.universe--design .mobile-menu__universe-name{color:#14181a}
/* On paper the pale half of the mark would vanish; the ring is its edge. */
body.universe--design .mobile-menu__universe-mark .nav__universe-half--sw{fill:#14181a}
body.universe--design .mobile-menu__universe-mark .nav__universe-half--ds{fill:#cdd3ca}
body.universe--design .mobile-menu__universe-mark .nav__universe-ring{
  stroke:#14181a;opacity:.5;
}

body.universe--design .mobile-menu__lang-item{color:rgba(20,24,26,.52)}
body.universe--design .mobile-menu__lang-item:hover,
body.universe--design .mobile-menu__lang-item.is-active{color:#14181a}
body.universe--design .mobile-menu__lang-item + .mobile-menu__lang-item{
  border-left-color:rgba(20,24,26,.2);
}
body.universe--design .mobile-menu__lang-item.is-active::after{background:#8a6f36}

body.universe--design .mobile-menu__motion-btn{
  color:#14181a;border-color:rgba(20,24,26,.28);background:transparent;
}
body.universe--design .mobile-menu__motion-btn:hover{
  background:rgba(20,24,26,.06);border-color:rgba(20,24,26,.45);
}
body.universe--design .mobile-menu__cta{
  background:#14181a;border-color:#14181a;color:#f4f6f2;
}
body.universe--design .mobile-menu__cta:hover{
  background:#000;border-color:#000;color:#f4f6f2;
}
body.universe--design ::selection{background:#57676B;color:#eef1ec}
body.universe--design :focus-visible{outline-color:#57676B}

/* Crossing: lift the curtain above the nav (z-100) and grain (z-200). */
.curtain.is-crossing{z-index:300}

/* Design-universe nav chrome that the token swap alone doesn't reach. */
body.universe--design .nav__cta{border-color:rgba(13,16,16,.35);color:#0d1010}
body.universe--design .nav__links a.nav__cta:hover{background:#0d1010;color:#eef1ec;border-color:#0d1010}
body.universe--design .nav__motion-toggle[aria-pressed="true"]{background:#0d1010;color:#eef1ec;border-color:#0d1010}
body.universe--design .nav__hamburger-bars span{background:#0d1010}
body.universe--design .nav__progress{background:rgba(13,16,16,.12)}
body.universe--design .nav__progress span{background:#0d1010}
/* The design half now serves real -ink- lockup assets (see header.php), so no
   filter is applied — brightness(0) crushed the mark into a black blob. */

/* ─── Ecosystem card motifs ───
   Each half carries a drawn line language: right-angle traces + square
   junctions on the software side, construction geometry + round nodes on the
   design side. Idle they sit faint behind the copy; on hover they re-draw.
   Pure CSS — stroke-dashoffset keyframes, no JS, no library. */
.ecosystem__lines{
  position:absolute;inset:0;z-index:0;
  pointer-events:none;overflow:hidden;
  opacity:.16;
  transition:opacity 1.4s cubic-bezier(.55,0,.25,1);
  /* Copy is bottom-aligned, so fade the drawing out of the lower third —
     the lines stay an atmosphere instead of competing with the text. */
  -webkit-mask-image:linear-gradient(to top, transparent 6%, #000 46%);
  mask-image:linear-gradient(to top, transparent 6%, #000 46%);
}
.ecosystem__lines svg{width:100%;height:100%;display:block}
.ecosystem__half > *:not(.ecosystem__lines){position:relative;z-index:1}
.ecosystem__half:hover .ecosystem__lines,
.ecosystem__half:focus-visible .ecosystem__lines{opacity:.42}
.ecosystem__half.is-current:hover .ecosystem__lines{opacity:.26}

.eco-line{
  fill:none;
  stroke:currentColor;
  stroke-width:1;
  stroke-linecap:square;
  /* One length for every path — generous enough to cover the longest, and
     the overshoot is invisible because the dash starts fully retracted.
     ponytail: avoids measuring getTotalLength() in JS for six static paths. */
  stroke-dasharray:1400;
  stroke-dashoffset:0;
}
.ecosystem__half--design .eco-line{stroke-linecap:round;stroke-width:.9}
.eco-nodes{fill:currentColor;opacity:.85}
.eco-nodes rect,.eco-nodes circle{transform-box:fill-box;transform-origin:center}

.ecosystem__half--software .ecosystem__lines{color:var(--mist)}
.ecosystem__half--design .ecosystem__lines{color:var(--slate)}

/* Re-draw on hover. The idle state is offset:0 (fully drawn), so the keyframe
   snapping back to 1400 is what reads as the line redrawing itself. */
@keyframes ecoDraw{from{stroke-dashoffset:1400}to{stroke-dashoffset:0}}
@keyframes ecoNode{0%{opacity:0;transform:scale(.4)}60%{opacity:1;transform:scale(1.25)}100%{opacity:.85;transform:scale(1)}}
.ecosystem__half:hover .eco-line{
  /* --d holds the per-path stagger; doubling it here keeps the tuning in
     one place instead of thirteen inline styles. */
  animation:ecoDraw 2.6s cubic-bezier(.32,.72,.28,1) calc(var(--d,0s) * 2.2) both;
}
.ecosystem__half:hover .eco-nodes rect,
.ecosystem__half:hover .eco-nodes circle{
  animation:ecoNode .9s ease-out 1.5s both;
}

@media(prefers-reduced-motion:reduce){
  .ecosystem__half:hover .eco-line,
  .ecosystem__half:hover .eco-nodes rect,
  .ecosystem__half:hover .eco-nodes circle{animation:none}
  .ecosystem__lines{transition:none}
}

/* ─── The disc as a drag handle ───
   Clicking a half still navigates (that is the accessible path, and what most
   people will do). The drag is the delightful path on top of it: pull the
   Kairos disc into a half and that universe opens. */
.ecosystem__split{overflow:hidden}
/* Copy clears the disc on the seam-facing edge. Halves are <a>, the disc is a
   trailing <span>, so :last-child would match the disc — of-type is what
   actually addresses the outer two halves. Stays correct at four universes,
   where the middle seams carry no disc. */
.ecosystem__half:first-of-type{padding-right:clamp(4.5rem,9vw,7rem)}
.ecosystem__half:last-of-type{padding-left:clamp(4.5rem,9vw,7rem)}
@media(max-width:780px){
  .ecosystem__half:first-of-type,
  .ecosystem__half:last-of-type{padding-right:clamp(1.5rem,3vw,2.5rem);padding-left:clamp(1.5rem,3vw,2.5rem)}
}

.ecosystem__core:hover{box-shadow:0 0 0 6px rgba(180,196,190,.07);border-color:rgba(180,196,190,.6)}
.ecosystem__core.is-dragging{
  cursor:grabbing;
  transition:none;
  box-shadow:0 0 0 10px rgba(180,196,190,.10),0 18px 50px rgba(0,0,0,.5);
  border-color:var(--mist);
}
.ecosystem__core-body{
  display:flex;flex-direction:column;align-items:center;gap:.28rem;
  min-width:0;
}
.ecosystem__core-rule{
  display:block;width:26px;height:1px;background:var(--mist);opacity:.5;
}
.ecosystem__core-hint{
  font-family:var(--mono);font-size:.44rem;letter-spacing:.3em;text-transform:uppercase;
  color:var(--mist);opacity:.8;line-height:1;
  transition:opacity .4s;
}
.ecosystem__core.is-dragging .ecosystem__core-hint{opacity:.35}

/* Flanking chevrons — the affordance. They drift outward on a slow loop so
   the disc reads as draggable without a tooltip. */
.ecosystem__core-arrow{
  /* Pinned to the inner edge of the ring rather than sitting in the text
     flow — they read as "pull me sideways" only when they hug the rim. */
  position:absolute;top:50%;margin-top:-7px;
  display:inline-flex;
  color:var(--mist);opacity:.55;
  transition:opacity .35s,color .35s;
}
.ecosystem__core-arrow--l{left:11px}
.ecosystem__core-arrow--r{right:11px}
.ecosystem__core-arrow--l{animation:coreNudgeL 2.6s ease-in-out infinite}
.ecosystem__core-arrow--r{animation:coreNudgeR 2.6s ease-in-out infinite}
@keyframes coreNudgeL{0%,100%{transform:translateX(0)}50%{transform:translateX(-3px)}}
@keyframes coreNudgeR{0%,100%{transform:translateX(0)}50%{transform:translateX(3px)}}
.ecosystem__core:hover .ecosystem__core-arrow{opacity:1;color:var(--paper)}
.ecosystem__core.is-dragging .ecosystem__core-arrow{animation-play-state:paused;opacity:.3}
@media(prefers-reduced-motion:reduce){
  .ecosystem__core-arrow--l,.ecosystem__core-arrow--r{animation:none}
}

/* The half the disc is currently over, and willing to accept it. */
.ecosystem__half.is-armed{background:linear-gradient(to bottom,#131a19,#1c2523)}
.ecosystem__half--design.is-armed{background:linear-gradient(to bottom,#f2f5f0,#fff)}
.ecosystem__half.is-armed .ecosystem__lines{opacity:.5}
.ecosystem__half.is-armed .ecosystem__enter{letter-spacing:.36em}

/* ─── Warp-through: the chosen half swallows the viewport ─── */
.eco-warp{
  position:fixed;z-index:400;pointer-events:none;
  border-radius:0;
  will-change:transform,opacity;
}
body.is-warping{overflow:hidden}

/* The pre-paint cover. Set by a blocking inline script in <head> so the
   destination is never visible for even one frame; main.js swaps the animated
   aperture in underneath and clears the attribute in the same frame. */
html[data-ks-arrive]::before{
  content:"";
  position:fixed;inset:0;z-index:499;
  background:var(--ks-arrive-ground,#0a0c0c);
}

/* ─── Arrival: the world opens as a circle ───
   You dragged a disc into a universe; on the far side that disc becomes the
   aperture the page arrives through. The radius rides on the SVG <circle>'s
   own `r` property, which is a real animatable CSS property — an earlier
   version drove a radial-gradient mask through @property and that snapped
   instead of interpolating. Its own element, never .curtain, which the scrub
   controller rewrites every frame. */
.eco-arrive{
  position:fixed;inset:0;z-index:500;pointer-events:none;
  opacity:1;
  transition:opacity .35s ease .95s;
}
.eco-arrive svg{width:100%;height:100%;display:block}
.eco-arrive__hole{
  r:0;
  transition:r 1.25s cubic-bezier(.62,0,.15,1);
}
.eco-arrive__ring{
  r:0;opacity:.75;
  transition:r 1.25s cubic-bezier(.62,0,.15,1),opacity .5s ease .75s;
}
.eco-arrive.is-opening{opacity:0}
.eco-arrive.is-opening .eco-arrive__hole,
.eco-arrive.is-opening .eco-arrive__ring{r:var(--eco-r,1200px)}
.eco-arrive.is-opening .eco-arrive__ring{opacity:0}

@media(prefers-reduced-motion:reduce){
  .ecosystem__core{transition:none}
  .ecosystem__core-hint{display:none}
}

/* ─── Design · add-ons + optional services ───
   The one block on the design side with no stage video behind it: a plain
   price list that sits on the paper ground after the four package scenes. */
.design-addons{
  position:relative;z-index:2;
  background:#f4f6f2;
  padding:clamp(4rem,9vw,7rem) 0;
}
.design-addons__inner{
  max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter);
  display:flex;flex-direction:column;gap:clamp(1.5rem,3vw,2.25rem);
}
.design-addons__head{display:flex;flex-direction:column;gap:.7rem;margin-top:1rem}
.design-addons__head .hud__tag{color:var(--moss)}
.design-addons__head .title{color:var(--paper)}

.design-addons__list{
  list-style:none;margin:0;padding:0;
  display:flex;flex-direction:column;
  border-top:1px solid rgba(13,16,16,.14);
}
.design-addon{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1.4fr) auto;
  gap:1rem clamp(1rem,3vw,2.5rem);
  align-items:baseline;
  padding:1.15rem 0;
  border-bottom:1px solid rgba(13,16,16,.14);
}
.design-addon--compact{grid-template-columns:minmax(0,1fr) auto}
.design-addon__name{
  font-family:var(--serif);font-size:clamp(1rem,1.9vw,1.2rem);font-weight:300;
  color:var(--paper);line-height:1.25;
}
.design-addon__body{font-size:.94rem;line-height:1.6;color:var(--slate)}
.design-addon__price{
  font-family:var(--mono);font-size:.74rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--paper);white-space:nowrap;font-variant-numeric:tabular-nums;
}
.design-addons__note{
  font-size:.88rem;line-height:1.65;color:var(--moss);max-width:62ch;margin:0;
}
.design-addons__cta{align-self:flex-start;margin-top:1rem}

@media(max-width:780px){
  .design-addon,
  .design-addon--compact{grid-template-columns:1fr;gap:.4rem}
  .design-addon__price{justify-self:start}
}

/* ─── Design universe · plan-lines ───
   City Plans authors 3–4 districts per scene, so .plan-lines lays them out as
   a single row (grid-auto-flow:column). The design half runs 6 services, 4
   process steps and 9 industries through the same component, and nine columns
   in one row overflows the viewport. Wrap into a responsive grid instead —
   the reveal, the stagger and the type all still come from the shared rules. */
body.universe--design .plan-lines{
  grid-auto-flow:row;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,15rem),1fr));
  gap:1.6rem 0;
  margin-top:2.2rem;
}
body.universe--design .plan-line__head{justify-content:flex-start}
body.universe--design .plan-line__name{color:var(--paper)}
body.universe--design .plan-line__say{color:#4a5654;font-style:normal;font-family:var(--sans);font-size:.92rem;line-height:1.55}
body.universe--design .plan-line__num{color:var(--moss)}
body.universe--design .plan-kinetic__name,
body.universe--design .plan-kinetic__tagline,
body.universe--design .plan-kinetic__outcome{text-shadow:0 1px 14px rgba(244,246,242,.9)}
body.universe--design .plan-ghost{color:rgba(13,16,16,.06)}


/* ─── Decorative overflow must not widen the page ───
   .plan-kinetic::before is a legibility scrim sized min(128%,92rem) on a
   container already min(82rem,94vw) wide — inherently wider than the viewport,
   so it gave every kinetic scene a horizontal scrollbar. Pre-existing on City
   Plans; the design reel uses the same component and surfaced it.
   overflow-x:clip (NOT hidden) is the right tool: it clips without creating a
   scroll container, so .scene__pin's position:sticky keeps working. */
.scene{overflow-x:clip}

/* The scrim paints a dark radial glow to hold type over night footage. Over
   paper that reads as a bruise — invert it to a light halo. */
body.universe--design .plan-kinetic::before{
  background:radial-gradient(58% 50% at 50% 50%, rgba(244,246,242,.82), rgba(244,246,242,.45) 56%, rgba(244,246,242,0) 80%);
}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · layout + surfaces pass
   Three shared components hardcode #0a0c0c (.page, .foot, .ecosystem) and
   several others assume light-on-dark. On the paper half they have to invert.
   ════════════════════════════════════════════════════════════════════════ */

/* ── Surfaces ─────────────────────────────────────────────────────────── */
body.universe--design .page,
body.universe--design .ecosystem,
body.universe--design .foot{background:#f4f6f2}
body.universe--design .page{color:#0d1010}

body.universe--design .foot{
  color:#3c4644;
  border-top:1px solid rgba(13,16,16,.14);
}
body.universe--design .foot__top .eyebrow,
body.universe--design .foot__bottom,
body.universe--design .foot__designer{color:#5c6a66}
body.universe--design .foot__contact-link,
body.universe--design .foot__links a,
body.universe--design .foot__contact-address,
body.universe--design .foot__tagline{color:#2b3536}
body.universe--design .foot__contact-link:hover,
body.universe--design .foot__links a:hover{color:#0d1010}
body.universe--design .foot__bottom{border-top:1px solid rgba(13,16,16,.14)}
body.universe--design .foot__social-list a{
  border-color:rgba(13,16,16,.2);color:#3c4644;
}
body.universe--design .foot__social-list a:hover{background:#0d1010;color:#f4f6f2;border-color:#0d1010}
body.universe--design .foot__contact-address a{border-bottom-color:rgba(13,16,16,.3)}

/* The ecosystem head sits on paper here, not on the dark ground. */
body.universe--design .ecosystem__title{color:#0d1010}
body.universe--design .ecosystem__title em{color:#57676B}
body.universe--design .ecosystem__eyebrow{color:#5c6a66}
body.universe--design .ecosystem__split{border-top-color:rgba(13,16,16,.16)}
body.universe--design .ecosystem__half + .ecosystem__half{border-left-color:rgba(13,16,16,.16)}
body.universe--design .ecosystem__core{
  background:#f4f6f2;border-color:rgba(13,16,16,.3);
}
body.universe--design .ecosystem__core-mark{color:#0d1010}
body.universe--design .ecosystem__core-sub,
body.universe--design .ecosystem__core-hint{color:#5c6a66}
body.universe--design .ecosystem__core-rule{background:#57676B}
body.universe--design .ecosystem__core-arrow{color:#57676B}
body.universe--design .ecosystem__core:hover .ecosystem__core-arrow{color:#0d1010}

/* ── Copy contrast over high-key footage ──────────────────────────────
   The film is almost white, so mid-grey body text disappears into it. Darken
   the text and lay a soft paper scrim behind the column — the same trick the
   dark half uses with .plan-kinetic::before, inverted. */
body.universe--design .lede{color:#2b3536}
body.universe--design .body{color:#39443f;font-size:1.06rem}
body.universe--design .title em,
body.universe--design .display em{color:#57676B}
body.universe--design .hud__tag{color:#5c6a66}
body.universe--design .hud__line{background:#57676B;opacity:.5}
body.universe--design .scroll-hint{color:#5c6a66;opacity:1}
body.universe--design .marker li{color:#39443f}

/* Leftover from an earlier pass: this pinned kinetic scenes to 64rem, which is
   why the package scenes measured 1024px while the rest of the page sat at
   1320/1480. Container width is now owned solely by the block below. */
body.universe--design .plan-kinetic__foot{justify-content:flex-start}
body.universe--design .plan-kinetic__outcome{text-align:left}

@media(max-width:780px){
  body.universe--design .scene__copy{padding:3rem var(--gutter) 3rem}
}

/* ─── Ecosystem is a DUAL-UNIVERSE component ───
   It renders on both homepages, so every colour inside it must be a literal.
   Tokens are swapped between the halves of the site — var(--paper) means light
   ink on the software side and near-black on the design side — so a token here
   paints correctly on one page and invisibly on the other. That is exactly what
   made the Diseño panel render dark-on-dark. */
.ecosystem__half--software{background:linear-gradient(to bottom,#0d1111,#131a19)}
.ecosystem__half--software:hover{background:linear-gradient(to bottom,#0f1414,#18201e)}
.ecosystem__half--design{background:linear-gradient(to bottom,#d6dcd5,#eef1ec)}
.ecosystem__half--design:hover{background:linear-gradient(to bottom,#e2e7e0,#f7f9f5)}

.ecosystem__half--software .ecosystem__icon{color:#B4C4BE}
.ecosystem__half--software .ecosystem__name{color:#eef1ec}
.ecosystem__half--software .ecosystem__line{color:#B4C4BE}
.ecosystem__half--software .ecosystem__enter{color:#eef1ec}

.ecosystem__half--design .ecosystem__icon{color:#57676B}
.ecosystem__half--design .ecosystem__name{color:#0d1010}
.ecosystem__half--design .ecosystem__line{color:#4a5654}
.ecosystem__half--design .ecosystem__enter{color:#2b3536}

.ecosystem__half--software .ecosystem__lines{color:#B4C4BE}
.ecosystem__half--design .ecosystem__lines{color:#57676B}

/* The disc straddles both grounds, so it keeps one identity on either page. */
.ecosystem__core{background:#0a0c0c;border-color:rgba(180,196,190,.35)}
.ecosystem__core-mark{color:#eef1ec}
.ecosystem__core-sub,.ecosystem__core-hint{color:#9daba8}
.ecosystem__core-rule{background:#B4C4BE}
.ecosystem__core-arrow{color:#B4C4BE}
.ecosystem__core:hover .ecosystem__core-arrow{color:#eef1ec}
body.universe--design .ecosystem__core{background:#0a0c0c;border-color:rgba(180,196,190,.35)}
body.universe--design .ecosystem__core-mark{color:#eef1ec}
body.universe--design .ecosystem__core-sub,
body.universe--design .ecosystem__core-hint{color:#9daba8}
body.universe--design .ecosystem__core-rule{background:#B4C4BE}
body.universe--design .ecosystem__core-arrow{color:#B4C4BE}
body.universe--design .ecosystem__core:hover .ecosystem__core-arrow{color:#eef1ec}

/* The ghost numeral was sized for a centred title card. */
body.universe--design .plan-ghost{left:auto;right:4%}


/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · type + layout system
   Built against the client's reference board, which is a different language
   from the software half: a quiet sans page, not a cinematic serif one.
     · headline  — Inter 300, ~56px, tight leading, near-black
     · rule      — a 48px hairline under the headline, not a decorative flourish
     · body      — Inter 300 at 1rem/1.75 in a soft grey, three lines at most
     · actions   — one solid dark button + one text link with an arrow
     · strip     — capability columns along the bottom, hairline dividers
   Content sits in a centred container with a genuine left margin; the footage
   reads on the right. Edge-to-edge was the wrong correction.
   ════════════════════════════════════════════════════════════════════════ */
body.universe--design{
  --d-container:min(1320px, 88vw);
  --d-ink:#14181a;
  --d-body:#5f6b68;
  --d-rule:rgba(20,24,26,.16);
}

/* ── Scene shell ──────────────────────────────────────────────────────── */
body.universe--design .scene__pin{align-items:stretch}
body.universe--design .scene__copy{
  display:flex;flex-direction:column;
  width:var(--d-container);
  max-width:var(--d-container);
  max-inline-size:var(--d-container);
  margin:0 auto;
  padding:clamp(6rem,11vh,8rem) 0 clamp(2.5rem,5vh,4rem);
  gap:0;
  justify-content:center;
  align-items:stretch;text-align:left;
}

/* ── Headline group: label, headline, rule, copy, actions ─────────────── */
body.universe--design .hud{margin:0 0 1.6rem;gap:.9rem}
body.universe--design .hud__tag{
  font-family:var(--mono);font-size:.63rem;letter-spacing:.26em;
  text-transform:uppercase;color:#8a938f;
}
body.universe--design .hud__line{width:42px;height:1px;background:var(--d-rule);opacity:1}

body.universe--design .display,
body.universe--design .title{
  font-family:var(--sans);
  font-weight:300;
  font-size:clamp(2.1rem,3.6vw,3.5rem);
  line-height:1.16;
  letter-spacing:-.021em;
  color:var(--d-ink);
  max-width:17ch;
  margin:0;
  text-wrap:balance;
}
body.universe--design .display em,
body.universe--design .title em{font-style:normal;color:#8d9a95}

/* The short dash under the headline. Sits between headline and body copy. */
body.universe--design .display::after,
body.universe--design .title::after{
  content:"";display:block;width:46px;height:1px;
  background:#2b3335;margin:2.1rem 0 0;
}

body.universe--design .lede,
body.universe--design .body{
  font-family:var(--sans);font-style:normal;font-weight:300;
  font-size:1rem;line-height:1.78;color:var(--d-body);
  max-width:42ch;margin:1.9rem 0 0;
}
body.universe--design .body + .body{margin-top:1rem}
body.universe--design .marker{
  list-style:none;margin:1.7rem 0 0;padding:0;
  display:flex;flex-direction:column;gap:.5rem;
  font-family:var(--sans);font-weight:300;font-size:.95rem;color:var(--d-body);
}
body.universe--design .marker li{padding-left:1.1rem;position:relative}
body.universe--design .marker li::before{
  content:"";position:absolute;left:0;top:.72em;width:5px;height:1px;background:#9aa3a0;
}

/* ── Actions: solid button + text link ────────────────────────────────── */
body.universe--design .plan-cta{
  align-self:flex-start;margin-top:2.4rem;
  display:inline-flex;align-items:center;gap:.6rem;
  background:#14181a;color:#f4f6f2;border:1px solid #14181a;
  padding:.95rem 1.8rem;
  font-family:var(--sans);font-weight:400;font-size:.86rem;letter-spacing:.01em;
  text-transform:none;
  transition:background .35s,color .35s;
}
body.universe--design .plan-cta:hover{background:transparent;color:#14181a}
body.universe--design .plan-cta--gold{background:#14181a;border-color:#14181a;color:#f4f6f2}
body.universe--design .plan-cta--gold:hover{background:transparent;color:#14181a}

body.universe--design .scroll-hint{
  margin-top:2.6rem;color:#98a19d;opacity:1;
  font-family:var(--mono);font-size:.6rem;letter-spacing:.26em;
}

/* ── Capability strip along the bottom ────────────────────────────────── */
body.universe--design .plan-lines{
  margin-top:auto;padding-top:2.4rem;
  border-top:1px solid var(--d-rule);
  display:grid;gap:0;
  grid-template-columns:repeat(var(--d-cols,3),minmax(0,1fr));
}
body.universe--design .plan-lines[data-count="4"]{--d-cols:4}
body.universe--design .plan-lines[data-count="5"]{--d-cols:5}
body.universe--design .plan-lines[data-count="6"]{--d-cols:3}
body.universe--design .plan-lines[data-count="7"],
body.universe--design .plan-lines[data-count="8"]{--d-cols:4}
body.universe--design .plan-lines[data-count="9"]{--d-cols:3}

body.universe--design .plan-line__head{display:flex;align-items:baseline;gap:.55rem;justify-content:flex-start}
body.universe--design .plan-line__num{
  font-family:var(--mono);font-size:.58rem;letter-spacing:.14em;color:#a8b0ad;
}
body.universe--design .plan-line__name{
  font-family:var(--sans);font-weight:500;
  font-size:.76rem;letter-spacing:.13em;text-transform:uppercase;
  color:var(--d-ink);line-height:1.4;
}
body.universe--design .plan-line__say{
  font-family:var(--sans);font-style:normal;font-weight:300;
  font-size:.88rem;line-height:1.65;color:var(--d-body);max-width:26ch;
}

@media(max-width:900px){
  body.universe--design .plan-lines{grid-template-columns:1fr!important;gap:1.8rem}
  body.universe--design .scene__copy{padding-top:5rem}
}

/* Kinetic blocks (packages, process, industries) run on the same system —
   they are the same page in a different mood, not a separate design. */
body.universe--design .plan-kinetic{
  display:flex;flex-direction:column;align-items:stretch;text-align:left;
  gap:0;
  /* No width/margin here. On these pages .plan-kinetic IS the .scene__copy
     element, so declaring them would cancel the container and run the section
     edge to edge — which is exactly what happened to Process, Industries and
     all four package scenes. Width belongs to .scene__copy alone. */
}
body.universe--design .plan-kinetic::before{display:none}
body.universe--design .plan-kinetic__kicker{
  font-family:var(--mono);font-size:.63rem;letter-spacing:.26em;
  text-transform:uppercase;color:#8a938f;margin:0 0 1.4rem;
}
body.universe--design .plan-kinetic__name{
  font-family:var(--sans);font-weight:300;
  font-size:clamp(2.1rem,3.6vw,3.5rem);line-height:1.16;letter-spacing:-.021em;
  color:var(--d-ink);margin:0;max-width:17ch;text-shadow:none;
}
body.universe--design .plan-kinetic__rule{
  display:block;width:46px;height:1px;background:#2b3335;margin:2.1rem 0 0;
}
body.universe--design .plan-kinetic__tagline{
  font-family:var(--sans);font-style:normal;font-weight:300;
  font-size:1rem;line-height:1.78;color:var(--d-body);
  max-width:42ch;margin:1.9rem 0 0;text-shadow:none;
}
body.universe--design .plan-kinetic__outcome{
  font-family:var(--sans);font-weight:300;font-size:.92rem;line-height:1.7;
  color:var(--d-body);max-width:64ch;margin:1.9rem 0 0;text-shadow:none;
}
body.universe--design .plan-kinetic__outcome-lbl{
  display:block;font-family:var(--mono);font-size:.58rem;letter-spacing:.22em;
  text-transform:uppercase;color:#8a938f;margin-bottom:.5rem;
}
body.universe--design .plan-kinetic__foot{
  display:flex;align-items:center;gap:2rem;margin-top:2.4rem;flex-wrap:wrap;
}
body.universe--design .plan-price{margin:0}
body.universe--design .plan-price__amount{
  font-family:var(--sans);font-weight:300;font-size:1.6rem;color:var(--d-ink);letter-spacing:-.01em;
}
body.universe--design .plan-kinetic .plan-cta{margin-top:0}
body.universe--design .plan-tag{
  align-self:flex-start;margin:0 0 1.2rem;
  font-family:var(--mono);font-size:.58rem;letter-spacing:.2em;text-transform:uppercase;
  color:#14181a;background:transparent;border:1px solid var(--d-rule);padding:.4rem .8rem;
}
body.universe--design .plan-ghost{display:none}
body.universe--design .plan-kinetic .plan-lines{margin-top:2.6rem}

/* ── Corrections after seeing it at 1440 ─────────────────────────────── */

/* The pin is a full viewport and the nav floats over its top edge. Clear it,
   and reserve the foot for the capability strip. */
body.universe--design .scene__copy{
  padding-top:clamp(8rem,15vh,11rem);
  padding-bottom:clamp(3rem,6vh,4.5rem);
  justify-content:flex-start;
}
body.universe--design .plan-lines{margin-top:auto}

/* Emphasis was splitting the headline into two colours. In the reference the
   headline is one weight, one colour — the italic belongs to the dark half. */
body.universe--design .display em,
body.universe--design .title em,
body.universe--design .plan-kinetic__name em{color:inherit;font-style:normal}

/* Headline measure: two or three lines, never four short ones. */
body.universe--design .display,
body.universe--design .title,
body.universe--design .plan-kinetic__name{max-width:22ch}

/* The per-line stagger is a City Plans device driven by scroll progress, which
   never fires for a strip sitting in the first viewport — the items simply
   stayed invisible. On this half the strip rides its parent's reveal instead. */


/* Clear the nav's underline properly — the eyebrow was sitting on it. */
body.universe--design .scene__copy{padding-top:clamp(9.5rem,18vh,13rem)}

/* The reference nav is quiet sentence-case sans, not the software half's
   mono-uppercase HUD. Same links, different register. */
body.universe--design .nav__link{
  font-family:var(--sans);font-weight:400;font-size:.92rem;
  letter-spacing:0;text-transform:none;color:#4a5450;
}
body.universe--design .nav__link:hover{color:#14181a}
body.universe--design .nav__links{gap:2.1rem}
body.universe--design .nav__cta{
  font-family:var(--sans);font-weight:400;font-size:.86rem;
  letter-spacing:0;text-transform:none;
  background:#14181a;color:#f4f6f2;border-color:#14181a;padding:.8rem 1.5rem;
}
body.universe--design .nav__links a.nav__cta:hover{background:transparent;color:#14181a;letter-spacing:0}
body.universe--design .lang-switcher{font-size:.7rem;letter-spacing:.1em}
body.universe--design .nav__universe{
  font-family:var(--sans);font-size:.78rem;letter-spacing:.02em;text-transform:none;
}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · guaranteed reading ground
   Copy sits over film whose luminance shifts frame to frame, so no fixed text
   colour is safe on its own — the eyebrow and body were dropping to ~2.9:1
   over the bright patches. The reference composition already answers this: the
   copy lives on clean paper and the photograph reads to the right of it.
   So the veil becomes a left-anchored paper wash rather than an even scrim.
   It is the composition AND the contrast fix, not a panel behind the text.
   ════════════════════════════════════════════════════════════════════════ */
/* The wash lives on the stage itself, NOT on .stage__veil — those are gated by
   a data-veil attribute that JS only sets once a scene activates. Before that
   (first paint, slow JS, a tab that never scrolled) there is no veil at all and
   the copy sits on raw film: measured 2.1:1. A reading ground cannot depend on
   JS having run. This pseudo-element is always painted.
   Two layers: a band across the foot for the capability strip, which runs the
   full container past where the side wash fades, and the left wash for copy. */
body.universe--design .stage::after{
  content:"";position:absolute;inset:0;z-index:3;pointer-events:none;
  background:
    linear-gradient(to top,
      rgba(246,248,244,.975) 0%,
      rgba(246,248,244,.94)  17%,
      rgba(246,248,244,.58)  26%,
      rgba(246,248,244,0)    34%),
    linear-gradient(97deg,
      rgba(246,248,244,.99)  0%,
      rgba(246,248,244,.975) 32%,
      rgba(246,248,244,.88)  45%,
      rgba(246,248,244,.5)   59%,
      rgba(246,248,244,.15)  77%,
      rgba(246,248,244,0)    92%);
}
/* The JS veils would double up on top of that, so this half opts out of them. */
body.universe--design .stage__veil,
body.universe--design .stage__veil--right,
body.universe--design .stage__veil--center{background:none;mix-blend-mode:normal}

/* The nav floats over the top of the film, past the wash. Its ground goes on
   the element's own background — an ::before at z-index:-1 was painting over
   the lockup and ghosting it out. A background can never cover its own
   content, and it fades out before it reads as a bar. */
body.universe--design .nav{
  background:linear-gradient(to bottom,
    rgba(246,248,244,.97) 0%,
    rgba(246,248,244,.9)  52%,
    rgba(246,248,244,.62) 80%,
    rgba(246,248,244,0)   100%);
}
/* Scenes flagged right/centre keep the same reading column — alternating the
   wash would move the text off its ground. The veil attribute still drives the
   dark half, which is why the rule is scoped here. */

/* ── Contrast pass (measured against the wash, #f6f8f4) ────────────────
   ink      #14181a  17.0:1
   body     #48524e   7.3:1
   muted    #5a655f   5.4:1  — labels only, never running text
   hairline .22 alpha         visible without becoming a border            */
body.universe--design{
  --d-ink:#14181a;
  --d-body:#48524e;
  --d-muted:#5a655f;
  --d-rule:rgba(20,24,26,.22);
}
body.universe--design .hud__tag{color:var(--d-muted)}
body.universe--design .hud__line{background:rgba(20,24,26,.34)}
body.universe--design .lede,
body.universe--design .body,
body.universe--design .marker,
body.universe--design .plan-kinetic__tagline,
body.universe--design .plan-kinetic__outcome,
body.universe--design .plan-line__say{color:var(--d-body)}
body.universe--design .plan-kinetic__kicker,
body.universe--design .plan-kinetic__outcome-lbl,
body.universe--design .plan-line__num,
body.universe--design .scroll-hint{color:var(--d-muted)}
body.universe--design .marker li::before{background:#7d867f}
body.universe--design .display::after,
body.universe--design .title::after,
body.universe--design .plan-kinetic__rule{background:#14181a}

/* Nav sits on the same wash at the top of the frame. */
body.universe--design .nav__link{color:#3d4643}
body.universe--design .lang-switcher{color:#5a655f}
body.universe--design .nav__universe{color:#3d4643;border-color:rgba(20,24,26,.28)}

/* The lockup is screen-blended so the source PNG's near-black backing drops
   out against the dark nav. On paper, screen blends it to white — which is
   what was ghosting the mark. Multiply is the light-ground equivalent: it
   drops the white and keeps the linework and wordmark. */
body.universe--design .nav__lockup,
body.universe--design .foot__lockup-img{
  mix-blend-mode:multiply;
  filter:none;
}
body.universe--design .nav__mark:hover .nav__lockup{filter:contrast(1.06)}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · one container, everywhere
   Packages was rendering four different measures on a single page — 1024 for
   the scenes, 1352 for add-ons, 1480 for footer and contact — because each
   block inherited a different legacy max-width. Every top-level container on
   this half now resolves to --d-container so the left edge is a straight line
   from the nav to the footer.
   ════════════════════════════════════════════════════════════════════════ */
body.universe--design .scene__copy,
body.universe--design .design-addons__inner,
body.universe--design .ecosystem__head,
body.universe--design .ecosystem__split,
body.universe--design .foot__top,
body.universe--design .foot__bottom{
  width:var(--d-container);
  max-width:var(--d-container);
  max-inline-size:var(--d-container);
  margin-left:auto;margin-right:auto;
  padding-left:0;padding-right:0;
}
/* .page is the contact section's own box; give it the same measure and let the
   inner grid sit flush with everything above it. */
body.universe--design .page:not(body){
  max-width:none;padding-left:0;padding-right:0;
}
body.universe--design .page:not(body) > *{
  width:var(--d-container);max-width:var(--d-container);
  margin-left:auto;margin-right:auto;
}
body.universe--design .design-addons{padding-left:0;padding-right:0}

@media(max-width:900px){
  body.universe--design .scene__copy,
  body.universe--design .design-addons__inner,
  body.universe--design .ecosystem__head,
  body.universe--design .ecosystem__split,
  body.universe--design .foot__top,
  body.universe--design .foot__bottom,
  body.universe--design .page:not(body) > *{
    width:auto;max-width:none;max-inline-size:none;
    margin-left:var(--gutter);margin-right:var(--gutter);
  }
}

/* The strip does not always sit at the foot — on package scenes it lands
   mid-viewport, past both the side wash and the foot band, where the two
   rightmost columns measured 6.2:1 and 4.9:1. Give it its own ground so it is
   guaranteed wherever it appears. A soft vertical fade rather than a flat fill,
   so it reads as light on the wall and not as a panel. */
body.universe--design .plan-lines{
  position:relative;
  isolation:isolate;
}
body.universe--design .plan-lines::before{
  content:"";position:absolute;z-index:-1;pointer-events:none;
  left:-2.5rem;right:-4rem;top:0;bottom:-.6rem;
  /* Vertical fade in the paint, horizontal fade in the mask. Both axes have to
     fade or the ground ends on a hard edge and reads as a panel — which is the
     boxed look this design already rejected once. */
  background:linear-gradient(to bottom,
    rgba(246,248,244,0)   0%,
    rgba(246,248,244,.90) 10%,
    rgba(246,248,244,.93) 50%,
    rgba(246,248,244,.88) 86%,
    rgba(246,248,244,0)   100%);
  -webkit-mask-image:linear-gradient(to right, transparent 0%, #000 4%, #000 76%, transparent 100%);
  mask-image:linear-gradient(to right, transparent 0%, #000 4%, #000 76%, transparent 100%);
}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · mobile
   The desktop composition is "copy on paper at the left, film breathing on the
   right". On a 390px screen there is no right — the film sits directly under
   the text and the page reads as muddy grey with 2:1 copy. Mobile therefore
   gets a near-solid paper ground with the film as faint texture, not a
   side-by-side. Same palette, different composition.
   ════════════════════════════════════════════════════════════════════════ */
/* body.is-mobile .stage::after is set to display:none!important further up —
   it carries the software half's split-tone grade, which is unwanted on
   mobile. On the design half that same pseudo-element carries the paper
   ground, so it has to come back. Higher specificity, since both are
   !important. */
body.is-mobile.universe--design .stage::after{display:block!important}

/* body.is-mobile .stage__veil forces a dark bottom-weighted scrim with
   !important — correct for the night reel, but on the paper half it is what
   was turning the whole mobile page grey. Neutralise it here; the wash on
   .stage::after is this half's ground. */
body.is-mobile.universe--design .stage__veil,
body.is-mobile.universe--design .stage__veil--right,
body.is-mobile.universe--design .stage__veil--center{
  background:none!important;
  opacity:0!important;
}

@media(max-width:900px){
  body.universe--design .stage::after{
    background:
      linear-gradient(to bottom,
        rgba(246,248,244,.985) 0%,
        rgba(246,248,244,.955) 42%,
        rgba(246,248,244,.94)  78%,
        rgba(246,248,244,.985) 100%);
  }
  /* Let a little of the film survive as grain rather than as a photograph. */
  body.universe--design .stage__v,
  body.universe--design .stage__c{filter:saturate(.35)}

  /* The lockup was rendering ~270px wide on a 390px screen — two thirds of the
     viewport. Size it to the bar, not to the desktop. */
  body.universe--design .nav__lockup{height:clamp(44px,12vw,68px)}

  body.universe--design .scene__copy{
    padding-top:6.5rem;padding-bottom:3rem;
    justify-content:flex-start;
  }
  body.universe--design .scene__pin{min-height:auto}
  body.universe--design .display,
  body.universe--design .title,
  body.universe--design .plan-kinetic__name{
    font-size:clamp(1.75rem,7.4vw,2.3rem);max-width:none;
  }
  body.universe--design .lede,
  body.universe--design .body,
  body.universe--design .plan-kinetic__tagline{font-size:.97rem;max-width:none}

  /* The strip becomes a stacked list; its ground was bleeding 4rem past the
     copy column, which reads as a stray panel at this width. */
  body.universe--design .plan-lines{margin-top:2.4rem;padding-top:1.8rem}
  body.universe--design .plan-lines::before{left:-1rem;right:-1rem}
  body.universe--design .plan-line__say{max-width:none}
}

@media(max-width:480px){
  body.universe--design .scene__copy{padding-top:5.5rem}
}

/* ─── Ecosystem disc · mobile chevrons ───
   Appended at the end on purpose: .ecosystem__core-arrow--l/--r set left/right
   further up the sheet, and at equal specificity source order decides — a
   mid-file media query loses to them and leaves the chevrons pinned to the rim
   pointing sideways. On mobile the halves stack, so the drag axis is vertical
   and the arrows must point up and down. */
@media(max-width:780px){
  .ecosystem__core-arrow--l,
  .ecosystem__core-arrow--r{
    left:50%;right:auto;margin-top:0;
    transform:translateX(-50%) rotate(90deg);
  }
  .ecosystem__core-arrow--l{top:9px;bottom:auto;animation-name:coreNudgeUp}
  .ecosystem__core-arrow--r{bottom:9px;top:auto;animation-name:coreNudgeDown}
  @keyframes coreNudgeUp{
    0%,100%{transform:translateX(-50%) rotate(90deg) translateX(0)}
    50%{transform:translateX(-50%) rotate(90deg) translateX(-3px)}
  }
  @keyframes coreNudgeDown{
    0%,100%{transform:translateX(-50%) rotate(90deg) translateX(0)}
    50%{transform:translateX(-50%) rotate(90deg) translateX(3px)}
  }
}

/* ─── Ecosystem disc · show only the arrow you can actually go ───
   Two arrows implied the disc could be dragged either way, but one of the two
   halves is always the one you are already in and refuses the drop. Show only
   the chevron pointing at the half that will accept it.

   The modifiers keep one meaning across both breakpoints — --l is left on
   desktop and up on mobile (both = toward Software); --r is right and down
   (both = toward Design) — so a single pair of rules covers all four cases.

   Note for the four-way version (adding Energía + Marketing): this assumes
   exactly two halves. That layout will need the arrows driven per-half rather
   than from the body class. */
body.universe--software .ecosystem__core-arrow--l{display:none}
body.universe--design   .ecosystem__core-arrow--r{display:none}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · richness pass
   The flat sans treatment read as a spec sheet. City Plans works because it
   varies the voice — serif names, an italic one-liner, a mono detail, a gold
   rule — and keeps the rhythm tight. Same devices here, on paper instead of
   night. The light ground stays; the flatness goes.
   ════════════════════════════════════════════════════════════════════════ */
body.universe--design{ --d-accent:#a8894a; }

/* ── Rhythm: pull the content together, centre the block in the frame ──
   The strip was pushed to the foot with margin-top:auto, which left a long
   dead gap under the headline and stranded the cards at the bottom edge. */
body.universe--design .scene__copy{justify-content:center}
body.universe--design .plan-lines{margin-top:2.4rem}
body.universe--design .display::after,
body.universe--design .title::after,
body.universe--design .plan-kinetic__rule{margin-top:1.5rem;background:var(--d-accent);width:54px;height:2px}
body.universe--design .lede,
body.universe--design .body{margin-top:1.5rem}

/* ── The statement list — was uppercase mono, which read as a spec dump ──
   Italic serif statements on hairlines, the way City Plans sets its one-liners. */
body.universe--design .marker{
  text-transform:none;letter-spacing:0;
  font-family:var(--serif);font-style:italic;font-weight:300;
  font-size:clamp(1rem,1.25vw,1.15rem);line-height:1.45;
  color:var(--d-ink);
  gap:0;margin-top:2rem;
  border-top:1px solid rgba(20,24,26,.12);
  max-width:52ch;
}
body.universe--design .marker li{
  padding:.9rem 0 .9rem 1.7rem;
  border-bottom:1px solid rgba(20,24,26,.12);
  transition:padding-left .45s cubic-bezier(.2,.7,.2,1),color .45s;
}
body.universe--design .marker li::before{
  content:"";position:absolute;left:0;top:1.45em;
  width:7px;height:7px;border-radius:50%;background:var(--d-accent);
  transition:transform .45s cubic-bezier(.2,.7,.2,1);
}
body.universe--design .marker li:hover{padding-left:2.1rem;color:#000}
body.universe--design .marker li:hover::before{transform:scale(1.35)}

/* Names get the serif voice; the numeral becomes an accent, not a label. */
body.universe--design .plan-line__head{gap:.7rem;align-items:baseline}
body.universe--design .plan-line__num{
  font-family:var(--mono);font-size:.62rem;letter-spacing:.14em;
  color:var(--d-accent);
}
body.universe--design .plan-line__name{
  font-family:var(--serif);font-weight:400;
  font-size:clamp(1.1rem,1.5vw,1.32rem);line-height:1.2;
  letter-spacing:0;text-transform:none;color:var(--d-ink);
}
body.universe--design .plan-line__say{
  margin-top:.6rem;font-size:.92rem;line-height:1.62;max-width:34ch;
}

@media(prefers-reduced-motion:reduce){
  body.universe--design .plan-lines .plan-line,
  body.universe--design .marker li{transition:none}
  body.universe--design .plan-lines .plan-line:hover{transform:none}
}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · Packages, on the City Plans composition
   Explicitly requested: the packages page should read like the software plans
   page. City Plans works as a stack of centred title cards — eyebrow, big
   serif name, accent rule, italic promise, then the contents, then the price
   and its CTA. The design HOME stays left-aligned editorial; a package is a
   title card, a narrative scene is not. That is the distinction, not a lapse.
   ════════════════════════════════════════════════════════════════════════ */
/* Centring is for PACKAGE scenes only. .plan-kinetic is also used by the
   design home's Process scene, so targeting it directly pulled the editorial
   page into centre-alignment too. */
body.universe--design .plan-scene .scene__copy,
body.universe--design .plan-scene .plan-kinetic{
  align-items:center;text-align:center;
}
body.universe--design .plan-kinetic__kicker{
  margin-bottom:1.1rem;color:var(--d-muted);
}
body.universe--design .plan-scene .plan-kinetic__name{
  font-family:var(--serif);font-weight:300;
  font-size:clamp(2.6rem,5vw,4.2rem);line-height:1.02;letter-spacing:-.015em;
  max-width:none;
}
body.universe--design .plan-scene .plan-kinetic__rule{margin-inline:auto}
body.universe--design .plan-kinetic__tagline{
  font-family:var(--serif);font-style:italic;font-weight:300;
  font-size:clamp(1.15rem,1.7vw,1.45rem);line-height:1.45;
  color:var(--d-ink);max-width:44ch;margin-top:1.5rem;
}
body.universe--design .plan-scene .plan-line__say{margin-inline:auto}
body.universe--design .plan-scene .plan-line{text-align:left}

body.universe--design .plan-scene .plan-kinetic__outcome{
  margin-inline:auto;text-align:center;max-width:58ch;
  margin-top:clamp(1.2rem,2.2vh,1.9rem);
}
body.universe--design .plan-kinetic__outcome-lbl{color:var(--d-accent)}

body.universe--design .plan-scene .plan-kinetic__foot{
  justify-content:center;gap:1.6rem;margin-top:clamp(1.3rem,2.4vh,2rem);
}
body.universe--design .plan-price__amount{
  font-family:var(--serif);font-weight:300;
  font-size:clamp(2rem,3.2vw,2.8rem);letter-spacing:-.02em;color:var(--d-ink);
}
body.universe--design .plan-scene .plan-tag{
  margin-inline:auto;color:var(--d-accent);border-color:var(--d-accent);
}
body.universe--design .plan-scene--featured .plan-kinetic__name{color:#0b0e0f}

@media(max-width:900px){
  body.universe--design .plan-scene .scene__copy,
  body.universe--design .plan-kinetic{align-items:flex-start;text-align:left}
  body.universe--design .plan-kinetic__rule,
  body.universe--design .plan-kinetic__tagline,
  body.universe--design .plan-kinetic__outcome,
  body.universe--design .plan-tag{margin-inline:0;text-align:left}
  body.universe--design .plan-kinetic__foot{justify-content:flex-start}
}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · SPECIMEN PLATES
   The signature of this page. A bordered box with text in it is what every
   generic template does, and it is what the client rejected — twice. This is
   not a card.

   A plate is a designer's specimen sheet: an oversized outlined numeral, a
   serif name, and a frame that DRAWS ITSELF as the plate enters — top edge
   left-to-right, right edge down, bottom edge right-to-left, left edge up.
   The page sells design, so the page performs design: the frame is literally
   being ruled in front of the visitor.

   Built from four hairline elements rather than a border, because a border
   cannot be drawn progressively. Transform/opacity only — no layout work per
   frame. Everything collapses to a static frame under reduced-motion.
   ════════════════════════════════════════════════════════════════════════ */
body.universe--design .plan-lines{
  align-items:stretch;
  gap:clamp(1.5rem,2.4vw,2.4rem);
  border-top:0;padding-top:0;
}

body.universe--design .plan-lines .plan-line{
  /* The watermark is deliberately larger than the plate; the frame crops it. */
  position:relative;isolation:isolate;overflow:hidden;
  display:flex;flex-direction:column;align-items:flex-start;
  gap:0;margin:0;height:100%;
  padding:clamp(2rem,2.6vw,2.6rem) clamp(1.6rem,2.2vw,2.2rem) clamp(2rem,2.6vw,2.4rem);
  border:0;background:none;text-align:left;text-shadow:none;
  transition:transform .5s cubic-bezier(.22,.7,.24,1);
}

/* ── The frame. Two elements, four edges, drawn with scaled hairlines. ── */
body.universe--design .plan-lines .plan-line::before,
body.universe--design .plan-lines .plan-line::after{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
}
/* ::before carries the top + right edges via two backgrounds. */
body.universe--design .plan-lines .plan-line::before{
  background:
    linear-gradient(90deg, var(--d-ink), var(--d-ink)) left top / 0 1px no-repeat,
    linear-gradient(180deg, var(--d-ink), var(--d-ink)) right top / 1px 0 no-repeat;
  opacity:.34;
  transition:background-size .95s cubic-bezier(.62,0,.2,1);
}
/* ::after carries bottom + left, delayed so the line travels the full circuit. */
body.universe--design .plan-lines .plan-line::after{
  background:
    linear-gradient(90deg, var(--d-ink), var(--d-ink)) right bottom / 0 1px no-repeat,
    linear-gradient(180deg, var(--d-ink), var(--d-ink)) left bottom / 1px 0 no-repeat;
  opacity:.34;
  transition:background-size .95s cubic-bezier(.62,0,.2,1) .5s;
}

/* ── The plate number: oversized, outlined, bleeding past the frame ── */
/* The numeral lives INSIDE the plate. It used to be absolutely placed at
   top:-.42em so it bled above the frame, which read as a cropping bug rather
   than a device — the frame sliced straight through it. */
body.universe--design .plan-line__num{
  position:static;display:block;
  font-family:var(--serif);font-weight:300;font-style:normal;
  font-size:clamp(2.4rem,3.2vw,3.4rem);line-height:.9;letter-spacing:-.03em;
  color:transparent;
  -webkit-text-stroke:1px rgba(20,24,26,.28);
  margin-bottom:.2rem;
  transition:-webkit-text-stroke-color .45s ease, color .45s ease;
}

body.universe--design .plan-line__head{display:block;margin-top:0}
/* Only reserve headroom when a plate actually carries a numeral. The hero
   strip does not, so this was holding open an empty band at the top of every
   plate there. */
body.universe--design .plan-line__num ~ .plan-line__head{
  margin-top:clamp(.5rem,1vw,.9rem);
}
body.universe--design .plan-line__name{
  font-family:var(--serif);font-weight:400;text-transform:none;letter-spacing:0;
  font-size:clamp(1.25rem,1.65vw,1.55rem);line-height:1.18;color:var(--d-ink);
}
body.universe--design .plan-line__say{
  margin-top:.85rem;font-family:var(--sans);font-weight:300;font-style:normal;
  font-size:.92rem;line-height:1.68;color:var(--d-body);max-width:32ch;
}

/* ── Hover: the plate is picked up off the table ── */
body.universe--design .plan-lines .plan-line:hover,
body.universe--design .plan-lines .plan-line:focus-within{
  transform:translateY(-6px);
}
body.universe--design .plan-lines .plan-line:hover::before,
body.universe--design .plan-lines .plan-line:hover::after,
body.universe--design .plan-lines .plan-line:focus-within::before,
body.universe--design .plan-lines .plan-line:focus-within::after{opacity:.85}
body.universe--design .plan-lines .plan-line:hover .plan-line__num,
body.universe--design .plan-lines .plan-line:focus-within .plan-line__num{
  color:var(--d-accent);
  -webkit-text-stroke-color:transparent;
  transform:translateY(-4px);
}

/* ── Entrance: content rises under the frame as it is ruled ── */
body.universe--design .plan-line{
  opacity:0;transform:translateY(22px);filter:none;
  transition:opacity .75s cubic-bezier(.22,.7,.24,1),
             transform .75s cubic-bezier(.22,.7,.24,1);
}
body.universe--design .plan-line:nth-child(1){transition-delay:.06s}
body.universe--design .plan-line:nth-child(2){transition-delay:.17s}
body.universe--design .plan-line:nth-child(3){transition-delay:.28s}
body.universe--design .plan-line:nth-child(4){transition-delay:.39s}
body.universe--design .plan-line:nth-child(5){transition-delay:.50s}
body.universe--design .plan-line:nth-child(6){transition-delay:.61s}
body.universe--design .plan-line:nth-child(7){transition-delay:.72s}
body.universe--design .plan-line:nth-child(8){transition-delay:.83s}
body.universe--design .plan-line:nth-child(9){transition-delay:.94s}
body.universe--design .scene.in .plan-line:hover{transition-delay:0s}

@media(max-width:900px){
  body.universe--design .plan-lines{grid-template-columns:1fr!important;gap:1.4rem}
  body.universe--design .plan-lines .plan-line{height:auto;padding:1.9rem 1.4rem 1.8rem}
  body.universe--design .plan-line__num{font-size:3.6rem;top:-.34em}
  body.universe--design .plan-line__say{max-width:none}
}

@media(prefers-reduced-motion:reduce){
  body.universe--design .plan-line{opacity:1;transform:none;transition:none}
  body.universe--design .plan-lines .plan-line::before,
  body.universe--design .plan-lines .plan-line::after{
    transition:none;background-size:100% 1px, 1px 100%;
  }
  body.universe--design .plan-lines .plan-line:hover{transform:none}
  body.universe--design .plan-line__num{transition:none}
}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · hero schematic
   The banner was a left third of copy against two thirds of empty film. This
   fills the right with a drafting schematic that rules itself in as the hero
   enters — construction circle, proportion square, diagonals, axes, then the
   intersection nodes. The page opens by performing design rather than
   describing it. Pure stroke-dashoffset; no layout work per frame.
   ════════════════════════════════════════════════════════════════════════ */
/* .scene__copy is the positioning context for the schematic, so it pins to the
   container's right edge rather than the viewport's. */
body.universe--design .scene__copy{position:relative}
body.universe--design .hero-schematic{
  position:absolute;z-index:-1;pointer-events:none;
  right:clamp(-1rem,0vw,3rem);
  /* Anchored to the upper right — the band the copy leaves empty. Centring it
     put the drawing behind the capability plates and muddied them. */
  top:clamp(2%,6vh,8%);
  width:clamp(300px,34vw,500px);
  aspect-ratio:1;
  opacity:1;
  /* Fade the foot so the drawing dissolves before it reaches the strip. */
  -webkit-mask-image:linear-gradient(to bottom, #000 58%, transparent 92%);
  mask-image:linear-gradient(to bottom, #000 58%, transparent 92%);
}
body.universe--design .hero-schematic svg{width:100%;height:100%;display:block;overflow:visible}
body.universe--design .hs-line{
  stroke:#14181a;stroke-width:1.1;fill:none;vector-effect:non-scaling-stroke;
  stroke-dasharray:1800;stroke-dashoffset:1800;
  opacity:.30;                 /* over pale film, .22 effective was invisible */
}
body.universe--design .hs-node{
  fill:var(--d-accent);opacity:0;transform-box:fill-box;transform-origin:center;
}
@keyframes hsDraw{to{stroke-dashoffset:0}}
@keyframes hsNode{0%{opacity:0;transform:scale(.3)}60%{opacity:1;transform:scale(1.4)}100%{opacity:.9;transform:scale(1)}}

@media(max-width:900px){
  /* On a phone the schematic would sit under the copy and muddy it. */
  body.universe--design .hero-schematic{display:none}
}
@media(prefers-reduced-motion:reduce){
  body.universe--design .hs-line{stroke-dashoffset:0;animation:none}
  body.universe--design .hs-node{opacity:.9;animation:none}
}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · plates build like a drawing
   A plate used to fade up as a finished box. Now it is constructed in the
   order a draughtsman works: the four corner ticks land first, the frame is
   ruled between them, then the content settles in. Sequenced with delays off
   the same --d the stagger already uses.
   ════════════════════════════════════════════════════════════════════════ */
body.universe--design .plan-lines .plan-line{
  --tick:14px;
}
/* Corner ticks — two gradients per pseudo-element, so four marks in total,
   sized before the frame edges grow past them. */
body.universe--design .plan-lines .plan-line::before{
  background:
    linear-gradient(90deg, var(--d-ink), var(--d-ink)) left top / var(--tick) 1px no-repeat,
    linear-gradient(180deg, var(--d-ink), var(--d-ink)) right top / 1px var(--tick) no-repeat;
  transition:background-size 1.1s cubic-bezier(.62,0,.2,1) .28s;
}
body.universe--design .plan-lines .plan-line::after{
  background:
    linear-gradient(90deg, var(--d-ink), var(--d-ink)) right bottom / var(--tick) 1px no-repeat,
    linear-gradient(180deg, var(--d-ink), var(--d-ink)) left bottom / 1px var(--tick) no-repeat;
  transition:background-size 1.1s cubic-bezier(.62,0,.2,1) .62s;
}

/* Content arrives after the frame has been ruled, not with it. */
body.universe--design .plan-line__num,
body.universe--design .plan-line__head,
body.universe--design .plan-line__say{
  opacity:0;transform:translateY(10px);
  transition:opacity .6s cubic-bezier(.22,.7,.24,1) .75s,
             transform .6s cubic-bezier(.22,.7,.24,1) .75s,
             color .45s ease, -webkit-text-stroke-color .45s ease;
}
body.universe--design .plan-line__head{transition-delay:.86s}
body.universe--design .plan-line__say{transition-delay:.96s}

@media(prefers-reduced-motion:reduce){
  body.universe--design .plan-line__num,
  body.universe--design .plan-line__head,
  body.universe--design .plan-line__say{opacity:1;transform:none;transition:none}
}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · scrubbed by the scroll, not played on entry
   --p is the scene's scroll progress (0→1), set per frame in main.js off the
   same ScrollTrigger that scrubs the video. Reading it here means the drawing
   and the plates advance and REVERSE with the wheel, in lockstep with the
   footage, instead of firing once when the scene arrives.

   Fallbacks matter: --p only exists on the desktop scrub path. On mobile and
   under reduced motion it is pinned to 1 below, so those paths show the
   finished drawing rather than an empty frame.
   ════════════════════════════════════════════════════════════════════════ */

/* ── The schematic rules itself in as you scroll ── */
body.universe--design .hs-line{
  /* Each line owns a slice of the scroll starting at --s and lasting ~0.28. */
  --lp:clamp(0, (var(--p, 0) - var(--s, 0)) * 3.6, 1);
  stroke-dashoffset:calc(1800 * (1 - var(--lp)));
  opacity:calc(.30 * min(1, var(--lp) * 6));
  animation:none;
}
body.universe--design .hs-node{
  --lp:clamp(0, (var(--p, 0) - var(--s, 0)) * 8, 1);
  opacity:calc(.9 * var(--lp));
  transform:scale(calc(.4 + .6 * var(--lp)));
  animation:none;
}

/* ── Plates settle as the scene scrolls ──
   Each plate owns a later slice than the one before, so the row assembles
   left to right under the wheel instead of arriving together. */
body.universe--design .plan-lines .plan-line{
  --pp:clamp(0, (var(--p, 0) - var(--ps, .06)) * 5, 1);
  --enter:translateY(calc((1 - var(--pp)) * 30px));
  transform:var(--enter);
  opacity:calc(.15 + .85 * var(--pp));
  transition:transform .18s linear, opacity .18s linear,
             box-shadow .35s ease, border-color .25s ease;
}
body.universe--design .plan-line:nth-child(1){--ps:.06}
body.universe--design .plan-line:nth-child(2){--ps:.11}
body.universe--design .plan-line:nth-child(3){--ps:.16}
body.universe--design .plan-line:nth-child(4){--ps:.21}
body.universe--design .plan-line:nth-child(5){--ps:.26}
body.universe--design .plan-line:nth-child(6){--ps:.31}
body.universe--design .plan-line:nth-child(7){--ps:.36}
body.universe--design .plan-line:nth-child(8){--ps:.41}
body.universe--design .plan-line:nth-child(9){--ps:.46}

/* The frame is ruled by the same slice — corner ticks first, then the edges
   grow out of them as the plate settles. */
body.universe--design .plan-lines .plan-line::before{
  background-size:
    max(var(--tick), calc(100% * var(--pp))) 1px,
    1px max(var(--tick), calc(100% * var(--pp)));
  transition:none;
}
body.universe--design .plan-lines .plan-line::after{
  --pp2:clamp(0, (var(--p, 0) - var(--ps, .06) - .04) * 5, 1);
  background-size:
    max(var(--tick), calc(100% * var(--pp2))) 1px,
    1px max(var(--tick), calc(100% * var(--pp2)));
  transition:none;
}

/* Card interior rides the plate, so it does not appear before its frame. */
body.universe--design .plan-line__num,
body.universe--design .plan-line__head,
body.universe--design .plan-line__say{
  opacity:calc(max(0, (var(--pp, 0) - .45)) * 1.82);
  transform:none;
  transition:color .45s ease, -webkit-text-stroke-color .45s ease;
}

/* Hover still wins — it must not be fought by the scrub transition. */
body.universe--design .plan-lines .plan-line:hover,
body.universe--design .plan-lines .plan-line:focus-within{
  transform:translateY(calc((1 - var(--pp)) * 30px - 6px));
}

/* ── Paths where --p is never set ── */
body.is-mobile .scene,
body.universe--design .scene.in:not([style*="--p"]){--p:1}
@media(prefers-reduced-motion:reduce){
  body.universe--design .scene{--p:1}
  body.universe--design .plan-lines .plan-line{transition:none}
  body.universe--design .plan-lines .plan-line:hover{transform:none}
}

/* ═════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · the convergence fan (scene 3 — who we design for)

   Nine trades as a ruled list was still a list, and read as one. The scene's
   claim is convergence, so it is drawn instead: one hub, nine spokes, each
   ruled outward by the scroll to the trade it reaches. The SVG stretches
   with the block (preserveAspectRatio="none" + non-scaling-stroke), so the
   spoke ends stay on their terms at any width without measuring in JS.
   ═════════════════════════════════════════════════════════════════════════ */
.fan{
  margin-top:clamp(1.8rem,3vw,2.6rem);
  display:grid;
  grid-template-columns:auto clamp(96px,9vw,132px) minmax(0,1fr);
  align-items:center;
  /* Height and web width are held near a 30:100 ratio to match the viewBox. */
  height:clamp(360px,44vh,440px);
}
.fan__hub{
  display:flex;flex-direction:column;align-items:center;gap:.7rem;
  padding-right:.2rem;
}
.fan__hub-dot{
  width:9px;height:9px;border-radius:50%;
  background:var(--d-accent);
  /* The hub lands before any spoke leaves it. */
  transform:scale(clamp(0, var(--p, 0) * 12, 1));
  box-shadow:0 0 0 calc(6px * clamp(0, (var(--p,0) - .06) * 8, 1)) rgba(168,137,74,.13);
}
.fan__hub-label{
  font-family:var(--mono);font-size:.58rem;letter-spacing:.18em;
  text-transform:uppercase;color:var(--d-muted);
  writing-mode:vertical-rl;transform:rotate(180deg);
  opacity:clamp(0, (var(--p, 0) - .04) * 10, 1);
}
.fan__web{
  width:100%;height:100%;display:block;overflow:visible;
  stroke:rgba(20,24,26,.42);stroke-width:1;fill:none;
}
.fan__spoke{
  --ip:clamp(0, (var(--p, 0) - var(--ps, 0)) * 7, 1);
  stroke-dasharray:1;
  stroke-dashoffset:calc(1 - var(--ip));
}
.fan__terms{
  list-style:none;margin:0;padding:0;height:100%;
  display:grid;grid-template-rows:repeat(9,1fr);
}
.fan__term{
  --ip:clamp(0, (var(--p, 0) - var(--ps, 0) - .02) * 7, 1);
  display:flex;align-items:center;gap:.8rem;
  padding-left:.5rem;
  /* The term arrives along its own spoke rather than fading in place. */
  opacity:calc(.14 + .86 * var(--ip));
  transform:translateX(calc((1 - var(--ip)) * -14px));
  transition:opacity .12s linear, transform .12s linear;
}
.fan__term-n{
  font-family:var(--mono);font-size:.58rem;letter-spacing:.14em;
  color:var(--d-accent);
}
.fan__term-t{
  font-family:var(--serif);font-weight:400;
  font-size:clamp(1.02rem,1.3vw,1.24rem);line-height:1.2;
  color:var(--d-ink);
}

@media(min-width:900px){
  /* Argument left, diagram right — the empty half this scene used to have. */
  body.universe--design .scene__copy:has(.fan){
    display:grid;
    grid-template-columns:minmax(0,1fr) minmax(0,1fr);
    column-gap:clamp(2.5rem,5vw,6rem);
    align-content:center;align-items:start;
  }
  body.universe--design .scene__copy:has(.fan) > *{grid-column:1}
  body.universe--design .scene__copy:has(.fan) > .fan{
    grid-column:2;grid-row:1 / span 20;align-self:center;margin-top:0;
  }
}
@media(max-width:899px){
  /* No room to fan on a phone: the hub and spokes go, the terms stay. */
  .fan{display:block;height:auto;margin-top:1.6rem}
  .fan__hub,.fan__web{display:none}
  .fan__terms{display:flex;flex-direction:column;height:auto}
  .fan__term{
    padding:.62rem 0;transform:none;
    border-bottom:1px solid var(--d-rule);
  }
}
@media(prefers-reduced-motion:reduce){
  .fan__term{transform:none;transition:none}
  .fan__spoke{stroke-dashoffset:0}
}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · specimen sheet (scene 4 — what we design)

   Scene 4 used to be a second copy of the ruled index. Three narrative
   scenes wearing the same device read as one long list; each now gets its
   own instrument. Here: nine tiles that draw their frame and their glyph as
   the scroll reaches them — a system assembling itself, not an enumeration.
   ════════════════════════════════════════════════════════════════════════ */
.spec-sheet{
  list-style:none;margin:clamp(1.6rem,2.6vw,2.4rem) 0 0;padding:0;
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  /* Hairlines as cell borders, not a gap over a filled sheet: the footage has
     to stay visible behind the grid. */
  border-top:1px solid var(--d-rule);border-left:1px solid var(--d-rule);
}
.spec-sheet__cell{
  --ip:clamp(0, (var(--p, 0) - var(--ps, 0)) * 8, 1);
  position:relative;background:transparent;
  border-right:1px solid var(--d-rule);border-bottom:1px solid var(--d-rule);
  /* Glyph and label on one baseline: three stacked rows of a tall cell put
     the last row of the sheet below the fold. */
  display:flex;align-items:center;gap:clamp(.8rem,1.4vw,1.2rem);
  padding:clamp(1rem,1.5vw,1.35rem) clamp(1.1rem,1.8vw,1.5rem);
  min-height:clamp(5.2rem,6.4vw,6.4rem);
  /* The cell lifts out of the sheet as it is reached. */
  opacity:calc(.34 + .66 * var(--ip));
  transform:translateY(calc((1 - var(--ip)) * 14px));
  transition:opacity .14s linear, transform .14s linear, background-color .3s ease;
}
.spec-sheet__n{
  position:absolute;top:.7rem;right:.9rem;
  font-family:var(--mono);font-size:.58rem;letter-spacing:.16em;
  color:var(--d-accent);
}
.spec-sheet__glyph{
  width:clamp(28px,2.6vw,34px);height:auto;flex:none;
  fill:none;stroke:var(--d-ink);stroke-width:1.15;
  stroke-linecap:round;stroke-linejoin:round;
}
/* pathLength="1" on every shape, so one offset draws them all. */
.spec-sheet__glyph *{
  stroke-dasharray:1;
  stroke-dashoffset:calc(1 - var(--ip));
}
.spec-sheet__t{
  font-family:var(--serif);font-weight:400;
  font-size:clamp(.98rem,1.15vw,1.12rem);line-height:1.28;
  color:var(--d-ink);
}
@media(hover:hover){
  .spec-sheet__cell:hover{background:rgba(20,24,26,.035)}
  .spec-sheet__cell:hover .spec-sheet__glyph{stroke:var(--d-accent)}
}
@media(max-width:899px){
  .spec-sheet{grid-template-columns:repeat(2,minmax(0,1fr))}
  .spec-sheet__cell{min-height:4.6rem;padding:.9rem 1rem;transform:none}
}
@media(max-width:520px){
  .spec-sheet{grid-template-columns:1fr}
  .spec-sheet__cell{min-height:0}
  .spec-sheet__glyph{width:26px}
}
@media(prefers-reduced-motion:reduce){
  .spec-sheet__cell{transform:none;transition:none}
}

/* ════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · the standard gauge (scene 7 — quality standard)

   The closing scene claims a standard. A checklist asserts it; an instrument
   shows it being applied — each criterion's track fills under the scroll and
   only then reads MET.
   ════════════════════════════════════════════════════════════════════════ */
.std-gauge{
  list-style:none;margin:clamp(2rem,3.4vw,3rem) 0 clamp(2rem,3.4vw,2.8rem);padding:0;
  display:flex;flex-direction:column;
  border-top:1px solid var(--d-rule);
}
.std-gauge__row{
  --ip:clamp(0, (var(--p, 0) - var(--ps, 0)) * 9, 1);
  display:grid;
  grid-template-columns:2.6rem minmax(0,15rem) minmax(0,1fr) 3.6rem;
  align-items:center;gap:1rem;
  padding:clamp(.62rem,1.1vw,.9rem) 0;
  border-bottom:1px solid var(--d-rule);
}
.std-gauge__n{
  font-family:var(--mono);font-size:.6rem;letter-spacing:.14em;
  color:var(--d-accent);opacity:calc(.3 + .7 * var(--ip));
}
.std-gauge__t{
  font-family:var(--serif);font-weight:400;
  font-size:clamp(1rem,1.2vw,1.15rem);line-height:1.25;
  color:var(--d-ink);opacity:calc(.42 + .58 * var(--ip));
}
/* A ruler: ticks above a baseline, filled by a bar that travels under them.
   At 1px it read as a dashed line, not an instrument. */
.std-gauge__track{
  position:relative;display:block;height:12px;
  background:
    repeating-linear-gradient(90deg,
      rgba(20,24,26,.26) 0 1px, transparent 1px 11px) 0 0 / 100% 6px no-repeat,
    linear-gradient(rgba(20,24,26,.20), rgba(20,24,26,.20)) 0 100% / 100% 1px no-repeat;
}
.std-gauge__track i{
  position:absolute;left:0;bottom:0;height:3px;
  width:calc(100% * var(--ip));
  background:var(--d-ink);
}
/* The head of the measure, riding the leading edge until it lands. */
.std-gauge__track i::after{
  content:"";position:absolute;right:0;bottom:0;
  width:1px;height:12px;background:var(--d-accent);
  opacity:calc(1 - var(--ip) * var(--ip));
}
.std-gauge__flag{
  font-family:var(--mono);font-size:.56rem;letter-spacing:.18em;
  color:var(--d-accent);text-align:right;
  opacity:clamp(0, (var(--ip) - .82) * 6, 1);
}
@media(max-width:899px){
  .std-gauge__row{
    grid-template-columns:2.2rem 1fr auto;
    grid-template-areas:"n t flag" ". track track";
    row-gap:.5rem;
  }
  .std-gauge__n{grid-area:n}
  .std-gauge__t{grid-area:t}
  .std-gauge__track{grid-area:track}
  .std-gauge__flag{grid-area:flag}
}

/* ═════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · the plate is still being drawn

   The crosshair and corner ticks that lived here read as a stray plus sign,
   and being static marks they showed no movement once the frame had closed.
   Replaced by two things actually in motion under the wheel: a drafting hatch
   wiping across the floor of the plate, and the rule the draughtsman is
   drawing, travelling down the plate and running out at the bottom edge.
   ═════════════════════════════════════════════════════════════════════════ */
body.universe--design .plan-lines .plan-line{
  /* Hatch fills over the first half of the plate's slice ... */
  --mp:clamp(0, (var(--p, 0) - var(--ps, .06) - .05) * 4, 1);
  /* ... the rule travels over the whole of it, so the two never finish
     together and the plate keeps moving after its border has landed. */
  --msweep:clamp(0, (var(--p, 0) - var(--ps, .06) - .05) * 2, 1);
  background-image:
    repeating-linear-gradient(45deg,
      rgba(20,24,26,.10) 0 1px, transparent 1px 8px),
    linear-gradient(90deg, var(--d-accent), var(--d-accent));
  background-repeat:no-repeat;
  background-position:
    left bottom,
    left calc(12% + 78% * var(--msweep));
  background-size:
    calc(100% * var(--mp)) clamp(46px,6.5vw,72px),
    /* squared, so the rule thins out as it lands rather than parking there */
    calc(100% * (1 - var(--msweep) * var(--msweep))) 1px;
}
@media(hover:hover){
  /* Deepen whatever fill this plate happens to carry — never replace it. */
  body.universe--design .plan-lines .plan-line:hover{--mp:1}
}
@media(prefers-reduced-motion:reduce){
  body.universe--design .plan-lines .plan-line{background-image:none}
}

/* ── Six fills, not one ───────────────────────────────────────────────────
   Every plate on the site wore the same 45° hatch, which made a row of six
   read as one repeated object. Each position now gets its own fill and its
   own direction of travel for the rule; the frame, the timing and the gold
   rule stay shared, so they still read as one family.
   --fill is the sweeping texture, --dir flips the rule's travel.            */
body.universe--design .plan-lines .plan-line{
  --fill:repeating-linear-gradient(45deg,
    rgba(20,24,26,.10) 0 1px, transparent 1px 8px);
  --dir:0;
  background-image:var(--fill), linear-gradient(90deg, var(--d-accent), var(--d-accent));
  background-position:
    left bottom,
    left calc(12% + 78% * (var(--msweep) * (1 - var(--dir)) + (1 - var(--msweep)) * var(--dir)));
}

/* 02 · wide-gauge hatch, rule travelling the other way */
body.universe--design .plan-line:nth-child(6n+2){
  --fill:repeating-linear-gradient(45deg,
    rgba(20,24,26,.11) 0 1px, transparent 1px 17px);
  --dir:1;
}
/* 03 · ruled paper */
body.universe--design .plan-line:nth-child(6n+3){
  --fill:repeating-linear-gradient(180deg,
    rgba(20,24,26,.13) 0 1px, transparent 1px 7px);
}
/* 04 · counter-hatch */
body.universe--design .plan-line:nth-child(6n+4){
  --fill:repeating-linear-gradient(-45deg,
    rgba(20,24,26,.10) 0 1px, transparent 1px 8px);
  --dir:1;
}
/* 05 · crosshatch — the densest, for the heaviest position in the row */
body.universe--design .plan-line:nth-child(6n+5){
  --fill:
    repeating-linear-gradient(45deg, rgba(20,24,26,.08) 0 1px, transparent 1px 9px),
    repeating-linear-gradient(-45deg, rgba(20,24,26,.08) 0 1px, transparent 1px 9px);
  background-image:var(--fill), linear-gradient(90deg, var(--d-accent), var(--d-accent));
  background-position:
    left bottom, left bottom,
    left calc(12% + 78% * var(--msweep));
  background-size:
    calc(100% * var(--mp)) clamp(46px,6.5vw,72px),
    calc(100% * var(--mp)) clamp(46px,6.5vw,72px),
    calc(100% * (1 - var(--msweep) * var(--msweep))) 1px;
}
/* 06 · column rules */
body.universe--design .plan-line:nth-child(6n){
  --fill:repeating-linear-gradient(90deg,
    rgba(20,24,26,.12) 0 1px, transparent 1px 10px);
  --dir:1;
}


/* ── The mark ─────────────────────────────────────────────────────────────
   An abstract artifact behind a deliverable name reads as decoration. A mark
   that means the thing named reads as a specimen — keyword-matched against
   both languages in inc/design-icons.php, drawn by the same --mp as the fill. */
body.universe--design .plate-icon{
  position:absolute;
  top:clamp(.85rem,1.25vw,1.15rem);
  right:clamp(.9rem,1.35vw,1.3rem);
  width:clamp(21px,2.1vw,27px);height:auto;
  fill:none;stroke:var(--d-ink);stroke-width:1.15;
  stroke-linecap:round;stroke-linejoin:round;
  opacity:calc(.22 + .78 * var(--mp));
  transition:stroke .3s ease;
}
body.universe--design .plate-icon *{
  stroke-dasharray:1;
  stroke-dashoffset:calc(1 - var(--mp));
}
@media(hover:hover){
  body.universe--design .plan-line:hover .plate-icon{stroke:var(--d-accent)}
}
@media(prefers-reduced-motion:reduce){
  body.universe--design .plate-icon *{stroke-dashoffset:0}
}

/* ── Six entrances, to go with the six fills ──────────────────────────────
   The fill alone still left every plate arriving the same way. Each position
   now enters on its own axis; --enter is read once by the base rule above. */
body.universe--design .plan-line:nth-child(6n+2){--enter:translateX(calc((1 - var(--pp)) * -30px))}
body.universe--design .plan-line:nth-child(6n+3){--enter:scale(calc(.93 + .07 * var(--pp)))}
body.universe--design .plan-line:nth-child(6n+4){--enter:translateX(calc((1 - var(--pp)) * 30px))}
body.universe--design .plan-line:nth-child(6n+5){--enter:translateY(calc((1 - var(--pp)) * 34px))}
body.universe--design .plan-line:nth-child(6n+5){filter:blur(calc((1 - var(--pp)) * 5px))}
body.universe--design .plan-line:nth-child(6n){--enter:translateY(calc((1 - var(--pp)) * -28px))}
@media(prefers-reduced-motion:reduce){
  body.universe--design .plan-line:nth-child(6n+5){filter:none}
}


/* ── The watermark, and six ways the mark arrives ─────────────────────────
   A service plate is mostly running text, so the mark has to carry the
   plate. Two passes of the same glyph: a large watermark that drifts and
   turns behind the copy, and the crisp mark that draws as the scroll
   reaches it. Then each of the six positions moves its mark differently, on
   top of the fill and the entrance it already had.
   ═════════════════════════════════════════════════════════════════════════ */
body.universe--design .plate-ghost{
  position:absolute;z-index:-1;pointer-events:none;
  right:calc(-14px + 10px * var(--mp));
  bottom:calc(-18px + 12px * var(--mp));
  width:clamp(96px,10vw,148px);height:auto;
  fill:none;stroke:var(--d-ink);stroke-width:.8;
  stroke-linecap:round;stroke-linejoin:round;
  vector-effect:non-scaling-stroke;
  opacity:calc(.10 * var(--mp));
  transform:rotate(calc(-14deg + 14deg * var(--mp))) scale(calc(.86 + .14 * var(--mp)));
  transform-origin:100% 100%;
}
body.universe--design .plate-icon--lg{
  width:clamp(28px,2.8vw,36px);
  top:clamp(1.1rem,1.7vw,1.7rem);
  right:clamp(1.2rem,1.9vw,1.9rem);
}

/* Six mark motions, matched to the six entrances. */
body.universe--design .plan-line:nth-child(6n+2) .plate-icon{
  transform:translateX(calc((1 - var(--mp)) * 18px));
}
body.universe--design .plan-line:nth-child(6n+3) .plate-icon{
  transform:scale(calc(.55 + .45 * var(--mp)));transform-origin:100% 0;
}
body.universe--design .plan-line:nth-child(6n+4) .plate-icon{
  transform:rotate(calc((1 - var(--mp)) * 32deg));transform-origin:50% 50%;
}
body.universe--design .plan-line:nth-child(6n+5) .plate-icon{
  /* Uncovered rather than drawn — the one mark that does not use its dashes. */
  -webkit-mask-image:linear-gradient(180deg, #000 0 0);
  mask-image:linear-gradient(180deg, #000 0 0);
  -webkit-mask-size:100% calc(100% * var(--mp));
  mask-size:100% calc(100% * var(--mp));
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:bottom;mask-position:bottom;
}
body.universe--design .plan-line:nth-child(6n+5) .plate-icon *{stroke-dashoffset:0}
body.universe--design .plan-line:nth-child(6n) .plate-icon{
  transform:translateY(calc((1 - var(--mp)) * -20px));
}
/* The watermark counter-drifts against its plate's entrance, which is what
   gives the plate depth rather than a flat slide. */
body.universe--design .plan-line:nth-child(6n+2) .plate-ghost,
body.universe--design .plan-line:nth-child(6n+4) .plate-ghost{
  transform:rotate(calc(12deg - 12deg * var(--mp))) scale(calc(.86 + .14 * var(--mp)));
}

@media(max-width:900px){
  body.universe--design .plate-ghost{width:88px;opacity:calc(.07 * var(--mp))}
}
@media(prefers-reduced-motion:reduce){
  body.universe--design .plate-ghost{transform:none;opacity:.08}
  body.universe--design .plan-line .plate-icon{transform:none}
  body.universe--design .plan-line:nth-child(6n+5) .plate-icon{
    -webkit-mask-image:none;mask-image:none;
  }
}

/* ═════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · six services scenes, six plate languages

   The six fills cycle on nth-child WITHIN a list, so every scene on the
   services page ran the same 01–06 sequence and all six scenes looked
   identical. The fill now belongs to the SCENE, not the position: each
   service gets one artifact and one motion for all of its plates, and no two
   services share a gesture.

   Each variant redeclares --fill (and where it needs to, background-size),
   so it must sit after the six positional fills it is overriding.
   ═════════════════════════════════════════════════════════════════════════ */
/* Normalise every services plate to the two-layer form first. The positional
   rules this overrides declare three layers for position 05 (crosshatch), and
   a variant that only swaps --fill leaves the gold rule reading the leftover
   third size — which paints it as a solid block, not a hairline. */
body.universe--design .plan-lines.svc-items .plan-line{
  --dir:0;
  background-image:var(--fill), linear-gradient(90deg, var(--d-accent), var(--d-accent));
  background-repeat:no-repeat;
  background-position:left bottom, left calc(12% + 78% * var(--msweep));
  background-size:
    calc(100% * var(--mp)) clamp(46px,6.5vw,72px),
    calc(100% * (1 - var(--msweep) * var(--msweep))) 1px;
}

/* ── s1 · hatch ── the house fill, kept for the first service. */
body.universe--design .plan-lines.svc-items--s1 .plan-line{
  --fill:repeating-linear-gradient(45deg,
    rgba(20,24,26,.11) 0 1px, transparent 1px 8px);
}

/* ── s2 · contour ── rings opening out of the top-left corner, like a survey
   drawing. Radial stops, because a conic slice gives a rectangle. */
body.universe--design .plan-lines.svc-items--s2 .plan-line{
  --r1:calc(20px + 130px * var(--mp));
  --r2:calc(8px + 84px * var(--mp));
  --fill:
    radial-gradient(circle at 0 0,
      transparent calc(var(--r1) - 1px), rgba(20,24,26,.30) calc(var(--r1) - 1px),
      rgba(20,24,26,.30) var(--r1), transparent var(--r1)),
    radial-gradient(circle at 0 0,
      transparent calc(var(--r2) - 1px), rgba(20,24,26,.18) calc(var(--r2) - 1px),
      rgba(20,24,26,.18) var(--r2), transparent var(--r2));
  background-image:var(--fill), linear-gradient(90deg, var(--d-accent), var(--d-accent));
  background-position:left top, left top, left calc(12% + 78% * var(--msweep));
  background-size:100% 100%, 100% 100%,
    calc(100% * (1 - var(--msweep) * var(--msweep))) 1px;
}
body.universe--design .plan-lines.svc-items--s2 .plate-icon{
  transform:rotate(calc((1 - var(--mp)) * -30deg));transform-origin:50% 50%;
}

/* ── s3 · plot ── a measuring grid that builds outward from the corner while
   a crosshair rides the diagonal. */
body.universe--design .plan-lines.svc-items--s3 .plan-line{
  background-image:
    repeating-linear-gradient(90deg, rgba(20,24,26,.10) 0 1px, transparent 1px 18px),
    repeating-linear-gradient(180deg, rgba(20,24,26,.10) 0 1px, transparent 1px 18px),
    linear-gradient(90deg, var(--d-accent), var(--d-accent)),
    linear-gradient(180deg, var(--d-accent), var(--d-accent));
  background-repeat:no-repeat;
  background-position:
    left bottom, left bottom,
    left calc(6% + 86% * var(--msweep)),
    calc(6% + 86% * var(--msweep)) top;
  background-size:
    calc(100% * var(--mp)) 100%,
    100% calc(100% * var(--mp)),
    14px 1px,
    1px 14px;
}

/* ── s4 · step ── a tonal ramp climbing the plate in discrete bands rather
   than sweeping: the plate gains weight instead of area. */
body.universe--design .plan-lines.svc-items--s4 .plan-line{
  --fill:repeating-linear-gradient(180deg,
    rgba(20,24,26,.09) 0 calc(3px * var(--mp)),
    transparent calc(3px * var(--mp)) 9px);
  background-image:var(--fill), linear-gradient(90deg, var(--d-accent), var(--d-accent));
  background-repeat:repeat, no-repeat;
  background-position:left bottom, left calc(90% - 78% * var(--msweep));
  background-size:100% 100%,
    calc(100% * (1 - var(--msweep) * var(--msweep))) 1px;
}
body.universe--design .plan-lines.svc-items--s4 .plate-icon{
  transform:translateY(calc((1 - var(--mp)) * -18px));
}

/* ── s5 · trace ── one chevron line threading across the plate floor,
   revealed left to right. */
body.universe--design .plan-lines.svc-items--s5 .plan-line{
  --fill:repeating-linear-gradient(135deg,
    rgba(20,24,26,.16) 0 1px, transparent 1px 14px);
  background-image:var(--fill), linear-gradient(90deg, var(--d-accent), var(--d-accent));
  background-repeat:no-repeat;
  background-position:left bottom, left calc(12% + 78% * var(--msweep));
  background-size:
    calc(100% * var(--mp)) clamp(54px,7.5vw,84px),
    calc(100% * (1 - var(--msweep) * var(--msweep))) 1px;
}
body.universe--design .plan-lines.svc-items--s5 .plate-icon{
  transform:translateX(calc((1 - var(--mp)) * 20px));
}

/* ── s6 · halftone ── the only variant whose texture does not wipe: the tile
   stays put and the dots swell. */
body.universe--design .plan-lines.svc-items--s6 .plan-line{
  background-image:
    /* Full-plate rather than a floor band, so it has to stay light: at .24
       the field read through the outlined numerals and fought the copy. */
    radial-gradient(circle at center,
      rgba(20,24,26,.15) calc(.3px + 1.35px * var(--mp)),
      transparent calc(.3px + 1.35px * var(--mp))),
    linear-gradient(90deg, var(--d-accent), var(--d-accent));
  background-repeat:repeat, no-repeat;
  background-position:left bottom, left calc(12% + 78% * var(--msweep));
  background-size:
    12px 12px,
    calc(100% * (1 - var(--msweep) * var(--msweep))) 1px;
}
body.universe--design .plan-lines.svc-items--s6 .plate-icon{
  transform:scale(calc(.5 + .5 * var(--mp)));transform-origin:100% 0;
}

@media(prefers-reduced-motion:reduce){
  body.universe--design .plan-lines.svc-items .plan-line{background-image:none}
  body.universe--design .plan-lines.svc-items .plate-icon{transform:none}
}

/* ═════════════════════════════════════════════════════════════════════════
   DESIGN UNIVERSE · four plate variations (packages)

   The plate is the component the client picked, so packages keep it — but a
   component repeated across four scenes with one animation is still one
   scene shown four times. Each package runs a different artifact inside the
   same frame, off the same scrubbed --pp/--mp/--msweep the base plate uses.

   Services and process keep the base plate (six sweeping fills, alternating
   rule direction). These four are for packages only.
   ═════════════════════════════════════════════════════════════════════════ */

/* Package plates carry a name and nothing else, so they can be shorter and
   sit four across — seven items in two rows instead of spilling past the pin. */
/* Beats the [data-count] column rules, which are tuned for wide plates. */
body.universe--design .plan-lines.plan-lines--compact{--d-cols:4}
/* On a package scene the plate grid was pushed to the foot by margin-top:auto
   and then ran over the "Ideal for" block and the price. Package scenes carry
   more blocks than a narrative one, so the copy is centred and the grid sits
   in the flow instead of being pushed down. */
body.universe--design .plan-scene .scene__copy{
  justify-content:center;
  padding-top:clamp(5rem,8.5vh,6.8rem);
}
body.universe--design .plan-scene .plan-lines{
  margin-top:clamp(1.1rem,1.8vw,1.7rem);
  padding-top:clamp(1.1rem,1.8vw,1.7rem);
}
body.universe--design .plan-lines--compact .plan-line{
  padding:clamp(.9rem,1.3vw,1.2rem) clamp(1rem,1.4vw,1.4rem) clamp(.95rem,1.4vw,1.3rem);
}
body.universe--design .plan-lines--compact .plan-line__num{
  font-size:clamp(1.5rem,2vw,2rem);margin-bottom:.1rem;
}
body.universe--design .plan-lines--compact .plan-line__name{
  font-size:clamp(1rem,1.2vw,1.15rem);line-height:1.22;
}
@media(max-width:1100px){
  body.universe--design .plan-lines--compact{--d-cols:3}
}

/* ── v2 · the mark ────────────────────────────────────────────────────────
   An ellipse opening behind the text said nothing about the deliverable. This
   scene's whole artifact is the mark itself: set large, drawn stroke by
   stroke, with the numeral growing against it. Nothing else in the plate. */
body.universe--design .plan-lines--v2 .plan-line{
  background-image:linear-gradient(90deg, var(--d-accent), var(--d-accent));
  background-position:center bottom;
  background-size:calc(100% * var(--msweep)) 1px;
}
body.universe--design .plan-lines--v2 .plate-icon{
  width:clamp(30px,3vw,38px);
  stroke-width:1;
  opacity:calc(.18 + .82 * var(--mp));
}
body.universe--design .plan-lines--v2 .plan-line__num{
  transform:scale(calc(.82 + .18 * var(--mp)));transform-origin:left bottom;
}

/* ── v3 · the scan ────────────────────────────────────────────────────────
   A soft band crosses the whole plate top to bottom and leaves a fine grid
   behind it — the plate being read, not drawn. */
body.universe--design .plan-lines--v3 .plan-line{
  background-image:
    linear-gradient(180deg,
      transparent, rgba(168,137,74,.30) 45%, rgba(168,137,74,.06) 55%, transparent),
    repeating-linear-gradient(90deg, rgba(20,24,26,.09) 0 1px, transparent 1px 22px),
    repeating-linear-gradient(180deg, rgba(20,24,26,.09) 0 1px, transparent 1px 22px);
  background-repeat:no-repeat;
  background-position:
    center calc(-14% + 128% * var(--msweep)),
    left top, left top;
  background-size:
    100% clamp(38px,5vw,58px),
    100% calc(100% * var(--mp)),
    100% calc(100% * var(--mp));
}

/* ── v4 · the shutter ─────────────────────────────────────────────────────
   Vertical slats whose width grows rather than a fill whose extent grows:
   the plate closes like a louvre, every slat at once. */
body.universe--design .plan-lines--v4 .plan-line{
  --slat:calc(15px * var(--mp));
  background-image:
    repeating-linear-gradient(90deg,
      rgba(20,24,26,.13) 0 var(--slat), transparent var(--slat) 30px),
    linear-gradient(90deg, var(--d-accent), var(--d-accent));
  background-repeat:repeat, no-repeat;
  background-position:left bottom, left calc(90% - 78% * var(--msweep));
  background-size:
    100% 100%,
    calc(100% * (1 - var(--msweep) * var(--msweep))) 1px;
}


/* Each package variant treats the mark differently too, so the four scenes
   never repeat a gesture: v3 rides the scan band down, v4 is uncovered by the
   shutter, v5 swings in with the arcs. */
body.universe--design .plan-lines--v3 .plate-icon{
  transform:translateY(calc((1 - var(--mp)) * -14px));
}
body.universe--design .plan-lines--v4 .plate-icon{
  -webkit-mask-image:linear-gradient(90deg, #000 0 0);
  mask-image:linear-gradient(90deg, #000 0 0);
  -webkit-mask-size:calc(100% * var(--mp)) 100%;
  mask-size:calc(100% * var(--mp)) 100%;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
}
body.universe--design .plan-lines--v4 .plate-icon *{stroke-dashoffset:0}
body.universe--design .plan-lines--v5 .plate-icon{
  transform-origin:100% 100%;
  transform:rotate(calc((1 - var(--mp)) * -26deg)) scale(calc(.7 + .3 * var(--mp)));
}
@media(prefers-reduced-motion:reduce){
  body.universe--design .plan-lines--v3 .plate-icon,
  body.universe--design .plan-lines--v5 .plate-icon{transform:none}
  body.universe--design .plan-lines--v4 .plate-icon{
    -webkit-mask-image:none;mask-image:none;
  }
}

/* ── v5 · the compass ─────────────────────────────────────────────────────
   Two arcs swung out of the lower-right corner as the plate is read, at
   different radii so they open like a compass rather than a fill. A conic
   slice was tried first and gives a rectangle, not an arc — conic gradients
   have no radius, so the sweep has to come from radial stops. */
body.universe--design .plan-lines--v5 .plan-line{
  --r1:calc(26px + 120px * var(--mp));
  --r2:calc(10px + 74px * var(--mp));
  background-image:
    radial-gradient(circle at 100% 100%,
      transparent calc(var(--r1) - 1px),
      rgba(20,24,26,.34) calc(var(--r1) - 1px),
      rgba(20,24,26,.34) var(--r1),
      transparent var(--r1)),
    radial-gradient(circle at 100% 100%,
      transparent calc(var(--r2) - 1px),
      rgba(168,137,74,.55) calc(var(--r2) - 1px),
      rgba(168,137,74,.55) var(--r2),
      transparent var(--r2)),
    linear-gradient(90deg, var(--d-accent), var(--d-accent));
  background-repeat:no-repeat;
  background-position:right bottom, right bottom, left calc(12% + 78% * var(--msweep));
  background-size:
    100% 100%,
    100% 100%,
    calc(100% * (1 - var(--msweep) * var(--msweep))) 1px;
}
body.universe--design .plan-lines--v5 .plan-line__num{
  transform:translateX(calc((1 - var(--mp)) * -12px));
}

@media(prefers-reduced-motion:reduce){
  body.universe--design .plan-lines--v2 .plan-line,
  body.universe--design .plan-lines--v3 .plan-line,
  body.universe--design .plan-lines--v4 .plan-line,
  body.universe--design .plan-lines--v5 .plan-line{background-image:none}
  body.universe--design .plan-lines--v2 .plan-line__num,
  body.universe--design .plan-lines--v5 .plan-line__num{transform:none}
}


/* Content travel, made legible. 10px of movement over a pale ground reads as
   nothing; this is the "more prominent" the client asked for. */
body.universe--design .plan-line__num,
body.universe--design .plan-line__head,
body.universe--design .plan-line__say{
  opacity:calc(max(0, (var(--pp, 0) - .40)) * 1.7);
  transform:translateY(calc((1 - clamp(0, (var(--pp, 0) - .40) * 1.7, 1)) * 22px));
  transition:color .45s ease, -webkit-text-stroke-color .45s ease;
}
body.universe--design .plan-line__head{
  transform:translateY(calc((1 - clamp(0, (var(--pp, 0) - .48) * 1.9, 1)) * 22px));
  opacity:calc(max(0, (var(--pp, 0) - .48)) * 1.9);
}
body.universe--design .plan-line__say{
  transform:translateY(calc((1 - clamp(0, (var(--pp, 0) - .56) * 2.2, 1)) * 22px));
  opacity:calc(max(0, (var(--pp, 0) - .56)) * 2.2);
}
body.universe--design .plan-lines .plan-line:hover .plan-line__num{
  color:var(--d-accent);-webkit-text-stroke-color:transparent;
}

@media(prefers-reduced-motion:reduce){
  body.universe--design .plan-line__num,
  body.universe--design .plan-line__head,
  body.universe--design .plan-line__say{opacity:1;transform:none}
}
