/* ==========================================================================
   MAGNETIQ V2 : core.css
   "LIQUID INK" shared design system.

   Owned by the core agent. Page agents add their own stylesheet AFTER this one
   and never redefine anything declared here.

   CONTENTS
     01  Tokens
     02  Surfaces (the inversion system)
     03  Reset and base
     04  Scroll rail (.scrollbar)
     05  Typography
     06  Layout (.wrap, section, grids, .sec-head)
     07  Header (.hdr)
     08  Drawer (fullscreen nav)
     09  Buttons
     10  Custom cursor
     11  Loader and curtain
     12  Grain
     13  WhatsApp bubble
     14  Footer (.ftr)
     15  Marquee
     16  Reveal states (motion engine contract)
     17  WebGL canvas (#gl) and stacking
     18  Utilities
     19  Forms baseline
     20  Print
     21  Reduced motion
   ========================================================================== */


/* ==========================================================================
   01  TOKENS
   ========================================================================== */

:root{
  /* ink family (dark surface) */
  --ink:#0A0A0C; --ink-2:#131318; --ink-3:#1C1C23; --ink-4:#26262F;
  /* bone family (light surface) */
  --bone:#EDE8DE; --bone-2:#E4DDD0; --bone-3:#D8CFBE; --chalk:#FFFFFF;
  /* light SURFACE is plain white (Philip, 2026-09-09); bone stays as the warm
     text colour on dark surfaces. --card is a hair off white so cards still
     read as objects on the white page. */
  --paper:#FFFFFF; --paper-card:#F6F6F4;
  /* accents */
  --volt:#4B2BFF; --volt-2:#7C5CFF; --acid:#D6FF3D; --flare:#FF4D9D;
  --iris:linear-gradient(120deg,#4B2BFF 0%,#7C5CFF 26%,#FF4D9D 58%,#D6FF3D 100%);
  /* type */
  --display:'Bricolage Grotesque','Helvetica Neue',sans-serif;
  --serif:'Instrument Serif',Georgia,serif;
  --body:'Geist','SF Pro Text',system-ui,sans-serif;
  --mono:'Geist Mono',ui-monospace,'SF Mono',monospace;
  /* easing */
  --e-out:cubic-bezier(.16,1,.3,1);
  --e-io:cubic-bezier(.76,0,.24,1);
  --e-spring:cubic-bezier(.34,1.56,.64,1);
  /* rhythm */
  --gut:clamp(20px,4vw,64px);   /* page side padding */
  --maxw:1440px;
  --sec:clamp(90px,14vh,180px); /* section vertical padding */
  --r:14px;  --r-lg:28px;       /* radii */

  /* internal helpers (not part of the public token list, safe to rely on) */
  --hdr-h:clamp(62px,8vh,84px);
  --z-gl:0;
  --z-content:2;
  --z-rail:60;
  --z-grain:64;
  --z-drawer:96;
  --z-hdr:100;   /* above the drawer so the burger stays clickable to close */
  --z-curtain:9400;
  --z-cursor:9600;
  --z-wa:9700;
  --z-loader:9990;
  --drawer-x:calc(100% - 44px);
  --drawer-y:42px;
}

/* Chinese falls back to system CJK faces for display and serif roles. */
html[lang="zh"]{
  --display:'Bricolage Grotesque','PingFang SC','Microsoft YaHei','Helvetica Neue',sans-serif;
  --serif:'Instrument Serif','PingFang SC','Microsoft YaHei',Georgia,serif;
}


/* ==========================================================================
   02  SURFACES
   Two surfaces driven by data-surface. <html> mirrors the section currently in
   view (motion.js calls window.setSurface), so header, cursor and footer all
   invert with the page.
   ========================================================================== */

[data-surface="dark"]{ --bg:var(--ink);  --fg:var(--bone); --fg-dim:#8C8C99;
  --line:rgba(237,232,222,.14); --faint:rgba(237,232,222,.05); --card:var(--ink-2); }
[data-surface="light"]{ --bg:var(--paper); --fg:var(--ink); --fg-dim:#6B665C;
  --line:rgba(10,10,12,.14); --faint:rgba(10,10,12,.035); --card:var(--paper-card); }

/* Safety net: a page that forgets the attribute still gets the light surface. */
html:not([data-surface]){ --bg:var(--paper); --fg:var(--ink); --fg-dim:#6B665C;
  --line:rgba(10,10,12,.14); --faint:rgba(10,10,12,.035); --card:var(--paper-card); }


/* ==========================================================================
   03  RESET AND BASE
   ========================================================================== */

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

html,body,h1,h2,h3,h4,h5,h6,p,figure,blockquote,dl,dd,ol,ul,fieldset,legend{
  margin:0; padding:0;
}

ul[class],ol[class]{ list-style:none; }

html{
  -webkit-text-size-adjust:100%;
  text-size-adjust:100%;
  scroll-behavior:auto;
  background:var(--bg);
  color:var(--fg);
  /* native bar hidden, the .scrollbar rail replaces it */
  scrollbar-width:none;
  -ms-overflow-style:none;
}
html::-webkit-scrollbar,body::-webkit-scrollbar{ width:0; height:0; display:none; }

body{
  min-height:100vh;
  min-height:100svh;
  background:var(--bg);
  color:var(--fg);
  font-family:var(--body);
  font-size:clamp(15px,1.05vw,17px);
  line-height:1.62;
  font-weight:400;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
  transition:background-color .6s var(--e-io), color .6s var(--e-io);
}

img,picture,video,canvas,svg{ display:block; max-width:100%; }
img,video{ height:auto; }

input,button,textarea,select{ font:inherit; color:inherit; }

button{ background:none; border:0; cursor:pointer; }

a{ color:inherit; text-decoration:none; }

hr{ border:0; height:1px; background:var(--line); }

table{ border-collapse:collapse; width:100%; }

::selection{ background:var(--volt); color:#FFFFFF; }

:focus{ outline:none; }
:focus-visible{
  outline:2px solid var(--volt);
  outline-offset:3px;
  border-radius:4px;
}
[data-surface="dark"] :focus-visible{ outline-color:var(--volt-2); }

/* Anything that must never intercept the pointer while the drawer is open. */
html.is-locked, html.is-locked body{ overflow:hidden; }


/* ==========================================================================
   04  SCROLL RAIL
   Markup: <div class="scrollbar"><i></i></div>
   site.js sets --p (0..1) on .scrollbar as the page scrolls.
   ========================================================================== */

.scrollbar{
  position:fixed;
  top:0; right:0;
  width:3px;
  height:100vh;
  height:100svh;
  z-index:var(--z-rail);
  pointer-events:none;
  background:var(--faint);
  --p:0;
}
.scrollbar > i{
  display:block;
  width:100%;
  height:100%;
  background:var(--iris);
  transform:scaleY(var(--p));
  transform-origin:0 0;
  transition:transform .12s linear;
}
@media (max-width:600px){
  .scrollbar{ width:2px; }
}


/* ==========================================================================
   05  TYPOGRAPHY
   ========================================================================== */

h1,h2,h3,h4,h5,h6,.h1,.h2,.h3{
  font-family:var(--display);
  font-weight:500;
  font-variation-settings:'opsz' 96,'wght' 500;
  letter-spacing:-.035em;
  line-height:.92;
  text-wrap:balance;
  color:var(--fg);
}

h1,.h1{ font-size:clamp(2.6rem,8vw,9rem); }
h2,.h2{ font-size:clamp(2rem,5.2vw,5.2rem); }
h3,.h3{ font-size:clamp(1.5rem,2.8vw,2.6rem); letter-spacing:-.03em; line-height:1; }
h4{ font-size:clamp(1.2rem,1.8vw,1.6rem); letter-spacing:-.02em; line-height:1.1;
    font-variation-settings:'opsz' 32,'wght' 500; }
h5{ font-size:clamp(1.05rem,1.4vw,1.25rem); letter-spacing:-.015em; line-height:1.2;
    font-variation-settings:'opsz' 24,'wght' 600; }
h6{ font-size:1rem; letter-spacing:-.01em; line-height:1.3;
    font-variation-settings:'opsz' 18,'wght' 600; }

/* ---- The signature move -------------------------------------------------
   <em> inside a headline becomes Instrument Serif italic, optically larger.
   On section hover it comes alive in the iris colours.

   WHY THIS IS A COLOUR ANIMATION AND NOT background-clip:text
   The first version painted the iris gradient with background-clip:text and
   -webkit-text-fill-color:transparent. Every headline is also split by
   motion.js into .sp-c / .sp-w child spans that carry will-change:transform,
   and Chrome composites those spans on their own layers. A transparent fill
   on a composited child does not show the parent's clipped gradient through
   it, so the whole word vanished on hover while its space stayed. Buyers read
   that as a broken site. A plain `color` inherits into the split spans and
   can never render as nothing, so the word is guaranteed to stay visible.
   The ramp is kept: the hue drifts slowly through the iris stops instead.
   ------------------------------------------------------------------------ */
:is(h1,h2,h3,h4,h5,h6,.h1,.h2,.h3) em,
.serif-cut{
  font-family:var(--serif);
  font-style:italic;
  font-weight:400;
  font-size:1.1em;
  line-height:.9;
  letter-spacing:-.01em;
  display:inline-block;
  padding-bottom:.1em;
  margin-bottom:-.1em;
  color:currentColor;
  text-shadow:none;
  transition:color .55s var(--e-out);
}

@keyframes irisDrift{
  0%   { color:var(--volt); }
  35%  { color:var(--volt-2); }
  65%  { color:var(--flare); }
  100% { color:var(--volt); }
}

section:hover :is(h1,h2,h3,h4,h5,h6,.h1,.h2,.h3) em,
section:hover .serif-cut,
.ftr:hover :is(h1,h2,h3) em,
.drawer :is(h1,h2,h3) em,
.is-lit :is(h1,h2,h3,h4,h5,h6,.h1,.h2,.h3) em,
.is-lit .serif-cut{
  color:var(--volt-2);
  animation:irisDrift 4.2s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce){
  section:hover :is(h1,h2,h3,h4,h5,h6,.h1,.h2,.h3) em,
  section:hover .serif-cut,
  .ftr:hover :is(h1,h2,h3) em,
  .drawer :is(h1,h2,h3) em,
  .is-lit :is(h1,h2,h3,h4,h5,h6,.h1,.h2,.h3) em,
  .is-lit .serif-cut{ animation:none; }
}

/* Always-on gradient variant for hero words that should never wait for hover. */
.iris-text{
  display:inline-block;
  padding-bottom:.1em;
  margin-bottom:-.1em;
  background-image:var(--iris);
  background-size:260% 100%;
  background-position:22% 50%;
  -webkit-background-clip:text;
  background-clip:text;
  -webkit-text-fill-color:transparent;
  text-shadow:none;
}

.kicker{
  font-family:var(--mono);
  text-transform:uppercase;
  font-size:11px;
  letter-spacing:.18em;
  font-weight:500;
  line-height:1.2;
  color:var(--fg-dim);
  display:inline-flex;
  align-items:center;
  gap:.7em;
}
.kicker::before{
  content:"";
  width:26px; height:1px;
  background:currentColor;
  opacity:.55;
  flex:none;
}
.kicker.is-bare::before{ display:none; }

.lede{
  font-family:var(--body);
  font-size:clamp(17px,1.55vw,22px);
  line-height:1.5;
  letter-spacing:-.012em;
  color:var(--fg);
  max-width:56ch;
  font-weight:400;
}

p{
  max-width:62ch;
  color:var(--fg-dim);
}
p + p{ margin-top:1em; }
p strong,li strong{ color:var(--fg); font-weight:600; }

a.link{
  color:var(--fg);
  background-image:linear-gradient(currentColor,currentColor);
  background-size:0% 1px;
  background-position:0 100%;
  background-repeat:no-repeat;
  transition:background-size .45s var(--e-out);
}
a.link:hover{ background-size:100% 1px; }

ul:not([class]),ol:not([class]){
  padding-left:1.1em;
  color:var(--fg-dim);
  max-width:62ch;
}
ul:not([class]) li,ol:not([class]) li{ margin-bottom:.45em; }
ul:not([class]){ list-style:none; padding-left:0; }
ul:not([class]) li{
  position:relative;
  padding-left:1.4em;
}
ul:not([class]) li::before{
  content:"";
  position:absolute;
  left:0; top:.66em;
  width:7px; height:7px;
  border-radius:50%;
  background:var(--iris);
}

blockquote{
  font-family:var(--serif);
  font-style:italic;
  font-weight:400;
  font-size:clamp(1.4rem,3vw,2.5rem);
  line-height:1.24;
  letter-spacing:-.015em;
  color:var(--fg);
  max-width:24ch;
  padding-left:clamp(18px,2vw,32px);
  border-left:1px solid var(--line);
}
blockquote cite{
  display:block;
  margin-top:1.2em;
  font-family:var(--mono);
  font-style:normal;
  font-size:11px;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:var(--fg-dim);
}

/* Big numbers and prices are serif, never mono, never display. */
.num{
  font-family:var(--serif);
  font-style:normal;
  font-weight:400;
  font-size:clamp(2.6rem,6vw,5.4rem);
  line-height:.9;
  letter-spacing:-.02em;
  color:var(--fg);
  font-variant-numeric:lining-nums tabular-nums;
}
.num sup,.num .num-cur{
  font-size:.42em;
  vertical-align:super;
  letter-spacing:0;
  opacity:.7;
}
.num-sm{ font-size:clamp(1.8rem,3.4vw,2.8rem); }

code,kbd,samp,pre{
  font-family:var(--mono);
  font-size:.88em;
}
pre{
  overflow-x:auto;
  padding:18px 20px;
  border-radius:var(--r);
  background:var(--faint);
  border:1px solid var(--line);
}


/* ==========================================================================
   06  LAYOUT
   ========================================================================== */

.wrap{
  width:100%;
  max-width:var(--maxw);
  padding-inline:var(--gut);
  margin-inline:auto;
}
.wrap-narrow{ max-width:960px; }
.wrap-wide{ max-width:1760px; }
.wrap-flush{ padding-inline:0; }

main#smooth{
  position:relative;
  z-index:var(--z-content);
}
/* motion.js adds .is-smooth to <html> when it takes over scrolling. */
html.is-smooth #smooth{
  position:fixed;
  top:0; left:0;
  width:100%;
  will-change:transform;
}

section{
  position:relative;
  z-index:var(--z-content);
  padding-block:var(--sec);
  background:var(--bg);
  color:var(--fg);
  transition:background-color .6s var(--e-io), color .6s var(--e-io);
}
/* Sections that let the 3D object show through. */
section[data-bleed]{ background:transparent; }
section.is-flush{ padding-block:0; }
section.pad-sm{ padding-block:clamp(56px,8vh,110px); }

.sec-head{
  display:grid;
  gap:clamp(18px,2.2vw,32px);
  margin-bottom:clamp(40px,6vh,88px);
}
.sec-head .kicker{ margin-bottom:-6px; }
.sec-head p{ max-width:52ch; }
@media (min-width:900px){
  .sec-head.is-split{
    grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);
    align-items:end;
    column-gap:clamp(32px,5vw,88px);
  }
  .sec-head.is-split .kicker{ grid-column:1 / -1; }
}

/* Default vertical rhythm. Page stylesheets override freely, and anything
   inside a .sec-head or a .stack uses the container gap instead. */
.kicker + h1,.kicker + h2,.kicker + h3,.kicker + .h1,.kicker + .h2,.kicker + .h3{
  margin-top:clamp(14px,2vh,26px);
}
h1 + p,h1 + .lede,h2 + p,h2 + .lede,h3 + p,h3 + .lede,h4 + p,
.h1 + .lede,.h2 + .lede{
  margin-top:clamp(18px,2.4vh,30px);
}
p + .cluster,.lede + .cluster,p + .btn,.lede + .btn{
  margin-top:clamp(22px,3vh,36px);
}
.sec-head > *,.stack > *,.grid > *,.cluster > *{ margin-top:0; }

.grid{ display:grid; gap:clamp(20px,2.4vw,40px); }
.g2{ grid-template-columns:repeat(2,minmax(0,1fr)); }
.g3{ grid-template-columns:repeat(3,minmax(0,1fr)); }
.g4{ grid-template-columns:repeat(4,minmax(0,1fr)); }

@media (max-width:1080px){
  .g4{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}
@media (max-width:860px){
  .g3{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}
@media (max-width:640px){
  .g2,.g3,.g4{ grid-template-columns:minmax(0,1fr); }
}

.card{
  background:var(--card);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
  padding:clamp(22px,2.6vw,38px);
  position:relative;
  overflow:hidden;
  transition:border-color .4s var(--e-out), transform .5s var(--e-out);
}
.card:hover{ border-color:color-mix(in srgb,var(--fg) 34%,transparent); }


/* ==========================================================================
   07  HEADER
   ========================================================================== */

.hdr{
  position:fixed;
  top:0; left:0; right:0;
  z-index:var(--z-hdr);
  height:var(--hdr-h);
  display:flex;
  align-items:center;
  gap:clamp(16px,3vw,48px);
  padding-inline:var(--gut);
  color:var(--fg);
  background:transparent;
  border-bottom:1px solid transparent;
  transition:transform .5s var(--e-io),
             background-color .45s var(--e-out),
             border-color .45s var(--e-out),
             backdrop-filter .45s var(--e-out);
}
.hdr.is-stuck{
  background:color-mix(in srgb, var(--bg) 72%, transparent);
  border-bottom-color:var(--line);
  -webkit-backdrop-filter:blur(20px) saturate(1.4);
  backdrop-filter:blur(20px) saturate(1.4);
}
.hdr.is-hidden{ transform:translateY(-110%); }

/* While the drawer is open the header floats on top of the ink panel, so it
   drops its own background and borrows the dark palette. Specificity beats the
   .is-stuck rule above without needing !important. */
html.is-drawer .hdr,
html.is-drawer .hdr.is-stuck{
  background:transparent;
  border-bottom-color:transparent;
  -webkit-backdrop-filter:none;
  backdrop-filter:none;
  color:var(--bone);
  --fg:#EDE8DE;
  --fg-dim:#8C8C99;
  --line:rgba(237,232,222,.14);
}

/* ---- brand --------------------------------------------------------------- */
.brand{
  display:inline-flex;
  align-items:center;
  gap:10px;
  flex:none;
  font-family:var(--display);
  letter-spacing:-.02em;
}
.brand b{
  font-weight:600;
  font-variation-settings:'opsz' 24,'wght' 600;
  font-size:clamp(15px,1.3vw,18px);
  letter-spacing:.01em;
}
.brand-v{
  font-family:var(--mono);
  font-style:normal;
  font-size:9px;
  letter-spacing:.14em;
  padding:2px 5px;
  border:1px solid var(--line);
  border-radius:5px;
  color:var(--fg-dim);
  transform:translateY(-5px);
  transition:color .35s var(--e-out), border-color .35s var(--e-out);
}
.brand:hover .brand-v{ color:var(--fg); border-color:currentColor; }

/* The liquid blob mark: morphs its border-radius on hover. */
.brand-mark{
  width:22px; height:22px;
  flex:none;
  background:var(--iris);
  border-radius:58% 42% 47% 53% / 46% 55% 45% 54%;
  animation:blob 9s var(--e-io) infinite;
  transition:transform .6s var(--e-spring);
}
.brand:hover .brand-mark{
  animation-duration:2.4s;
  transform:scale(1.14) rotate(18deg);
}
@keyframes blob{
  0%,100%{ border-radius:58% 42% 47% 53% / 46% 55% 45% 54%; }
  25%   { border-radius:42% 58% 63% 37% / 60% 40% 60% 40%; }
  50%   { border-radius:50% 50% 34% 66% / 38% 62% 38% 62%; }
  75%   { border-radius:66% 34% 55% 45% / 55% 45% 62% 38%; }
}

/* ---- nav ----------------------------------------------------------------- */
.hdr-nav{
  display:flex;
  align-items:center;
  gap:clamp(14px,2vw,34px);
  margin-right:auto;
}
.hdr-nav a{
  position:relative;
  font-family:var(--mono);
  text-transform:uppercase;
  font-size:11px;
  letter-spacing:.18em;
  color:var(--fg-dim);
  padding-block:6px;
  transition:color .35s var(--e-out);
}
.hdr-nav a::after{
  content:"";
  position:absolute;
  left:0; bottom:0;
  width:100%; height:1px;
  background:currentColor;
  transform:scaleX(0);
  transform-origin:0 50%;
  transition:transform .5s var(--e-out);
}
.hdr-nav a:hover,
.hdr-nav a[aria-current="page"],
.hdr-nav a.is-on{ color:var(--fg); }
.hdr-nav a:hover::after,
.hdr-nav a[aria-current="page"]::after,
.hdr-nav a.is-on::after{ transform:scaleX(1); }

@media (max-width:1023px){
  .hdr-nav{ display:none; }
  .brand{ margin-right:auto; }
}

/* ---- end cluster --------------------------------------------------------- */
.hdr-end{
  display:flex;
  align-items:center;
  gap:clamp(8px,1.1vw,14px);
  flex:none;
}

.lang{
  display:inline-flex;
  align-items:center;
  padding:3px;
  border:1px solid var(--line);
  border-radius:999px;
  gap:2px;
}
.lang button{
  font-family:var(--mono);
  font-size:10px;
  letter-spacing:.12em;
  text-transform:uppercase;
  padding:5px 9px;
  border-radius:999px;
  color:var(--fg-dim);
  line-height:1;
  transition:color .3s var(--e-out), background-color .3s var(--e-out);
}
.lang button:hover{ color:var(--fg); }
.lang button.is-on,
.lang button[aria-pressed="true"]{
  color:var(--bg);
  background:var(--fg);
}

@media (max-width:700px){
  .lang{ display:none; }
}
@media (max-width:1023px){
  .hdr-end .btn-ghost{ display:none; }
}
@media (max-width:520px){
  .hdr-end .btn-solid{ display:none; }
}

/* ---- burger -------------------------------------------------------------- */
.burger{
  width:44px; height:44px;
  flex:none;
  display:none;
  align-items:center;
  justify-content:center;
  position:relative;
  border-radius:50%;
  border:1px solid var(--line);
  transition:border-color .35s var(--e-out), background-color .35s var(--e-out);
}
.burger i{
  position:absolute;
  left:50%;
  width:17px; height:1.5px;
  background:currentColor;
  border-radius:2px;
  transform:translateX(-50%);
  transition:transform .5s var(--e-spring), opacity .3s var(--e-out);
}
.burger i:nth-child(1){ transform:translate(-50%,-4px); }
.burger i:nth-child(2){ transform:translate(-50%,4px); }
.burger:hover{ border-color:color-mix(in srgb,var(--fg) 45%,transparent); }
.burger.is-open i:nth-child(1){ transform:translate(-50%,0) rotate(45deg); }
.burger.is-open i:nth-child(2){ transform:translate(-50%,0) rotate(-45deg); }

@media (max-width:1023px){
  .burger{ display:inline-flex; }
}


/* ==========================================================================
   08  DRAWER (fullscreen nav)
   Markup contract:
     <div class="drawer" id="drawer" aria-hidden="true">
       <nav class="drawer-nav">
         <a href="/work.html"><span>Work</span></a> ...
       </nav>
       <div class="drawer-foot"> .drawer-col × n </div>
     </div>
   site.js sets --drawer-x / --drawer-y from the burger position so the
   clip-path circle opens out of the button itself.
   ========================================================================== */

.drawer{
  position:fixed;
  inset:0;
  z-index:var(--z-drawer);
  display:flex;
  flex-direction:column;
  justify-content:space-between;
  gap:32px;
  padding:calc(var(--hdr-h) + 24px) var(--gut) clamp(24px,5vh,56px);
  background:var(--ink);
  color:var(--bone);
  --line:rgba(237,232,222,.14);
  --fg-dim:#8C8C99;
  overflow-y:auto;
  overscroll-behavior:contain;
  visibility:hidden;
  pointer-events:none;
  clip-path:circle(0px at var(--drawer-x) var(--drawer-y));
  transition:clip-path .8s var(--e-io), visibility 0s linear .8s;
}
.drawer.is-open{
  visibility:visible;
  pointer-events:auto;
  clip-path:circle(150% at var(--drawer-x) var(--drawer-y));
  transition:clip-path .9s var(--e-io), visibility 0s linear 0s;
}

.drawer-nav{
  display:flex;
  flex-direction:column;
  gap:clamp(2px,.6vh,10px);
  margin-top:auto;
}
.drawer-nav a{
  display:block;
  overflow:hidden;
  font-family:var(--display);
  font-weight:500;
  font-variation-settings:'opsz' 96,'wght' 500;
  font-size:clamp(2.6rem,11vw,7rem);
  line-height:1.02;
  letter-spacing:-.04em;
  color:var(--bone);
}
.drawer-nav a > span{
  display:block;
  transform:translateY(110%);
  opacity:0;
  transition:transform .8s var(--e-out), opacity .5s var(--e-out), color .4s var(--e-out);
}
.drawer.is-open .drawer-nav a > span{ transform:translateY(0); opacity:1; }
.drawer.is-open .drawer-nav a:nth-child(1) > span{ transition-delay:.16s; }
.drawer.is-open .drawer-nav a:nth-child(2) > span{ transition-delay:.22s; }
.drawer.is-open .drawer-nav a:nth-child(3) > span{ transition-delay:.28s; }
.drawer.is-open .drawer-nav a:nth-child(4) > span{ transition-delay:.34s; }
.drawer.is-open .drawer-nav a:nth-child(5) > span{ transition-delay:.40s; }
.drawer.is-open .drawer-nav a:nth-child(6) > span{ transition-delay:.46s; }
.drawer.is-open .drawer-nav a:nth-child(7) > span{ transition-delay:.52s; }
.drawer-nav a:hover > span{
  background-image:var(--iris);
  background-size:300% 100%;
  background-position:8% 50%;
  -webkit-background-clip:text;
  background-clip:text;
  -webkit-text-fill-color:transparent;
  text-shadow:none;
}

.drawer-foot{
  display:grid;
  gap:clamp(18px,3vw,44px);
  grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
  padding-top:clamp(20px,3vh,36px);
  border-top:1px solid var(--line);
  opacity:0;
  transform:translateY(18px);
  transition:opacity .6s var(--e-out) .42s, transform .6s var(--e-out) .42s;
}
.drawer.is-open .drawer-foot{ opacity:1; transform:none; }

.drawer-col{ display:flex; flex-direction:column; gap:8px; }
.drawer-col h6{
  font-family:var(--mono);
  font-size:10px;
  letter-spacing:.18em;
  text-transform:uppercase;
  font-weight:500;
  font-variation-settings:'wght' 500;
  color:var(--fg-dim);
  margin-bottom:4px;
}
.drawer-col a,.drawer-col span{
  font-size:15px;
  color:var(--bone);
  transition:color .3s var(--e-out);
}
.drawer-col a:hover{ color:var(--acid); }

.drawer-socials{ display:flex; flex-wrap:wrap; gap:14px; }
.drawer-socials a{
  font-family:var(--mono);
  font-size:11px;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--fg-dim);
}
.drawer-socials a:hover{ color:var(--bone); }


/* ==========================================================================
   09  BUTTONS
   ========================================================================== */

.btn{
  position:relative;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:.7em;
  padding:15px 26px;
  border-radius:999px;
  border:1px solid transparent;
  font-family:var(--mono);
  text-transform:uppercase;
  font-size:11px;
  letter-spacing:.18em;
  font-weight:500;
  line-height:1;
  white-space:nowrap;
  cursor:pointer;
  overflow:hidden;
  isolation:isolate;
  color:var(--fg);
  transition:color .4s var(--e-out), border-color .4s var(--e-out),
             transform .5s var(--e-spring);
  -webkit-tap-highlight-color:transparent;
}
.btn > *{ position:relative; z-index:2; }
.btn::after{
  content:"";
  position:absolute;
  inset:0;
  z-index:1;
  background:currentColor;
  transform:scaleY(0);
  transform-origin:50% 100%;
  transition:transform .55s var(--e-out);
}
.btn:hover::after,
.btn:focus-visible::after{ transform:scaleY(1); }
.btn:active{ transform:scale(.975); }

.arr{
  display:inline-block;
  transition:transform .45s var(--e-out);
}
.btn:hover .arr{ transform:translateX(4px); }
.arr-down{ display:inline-block; transition:transform .45s var(--e-out); }
.btn:hover .arr-down{ transform:translateY(4px); }

/* solid: fg fill, bg text */
.btn-solid{
  background:var(--fg);
  color:var(--bg);
}
.btn-solid::after{ background:var(--bg); }
.btn-solid:hover,
.btn-solid:focus-visible{ color:var(--fg); }

/* ghost: hairline outline */
.btn-ghost{
  border-color:var(--line);
  color:var(--fg);
  background:transparent;
}
.btn-ghost::after{ background:var(--fg); }
.btn-ghost:hover,
.btn-ghost:focus-visible{ color:var(--bg); border-color:var(--fg); }

/* iris: gradient fill, white text, sweep goes to solid ink */
.btn-iris{
  background:var(--iris);
  background-size:220% 100%;
  background-position:0% 50%;
  color:#FFFFFF;
  border-color:transparent;
  transition:color .4s var(--e-out), background-position .9s var(--e-out),
             transform .5s var(--e-spring);
}
.btn-iris::after{ background:var(--ink); }
.btn-iris:hover,
.btn-iris:focus-visible{ color:#FFFFFF; background-position:35% 50%; }

.btn-sm{ padding:11px 18px; font-size:10px; letter-spacing:.16em; }
.btn-lg{ padding:20px 36px; font-size:12px; }
.btn-block{ display:flex; width:100%; }

.btn[disabled],.btn[aria-disabled="true"]{
  opacity:.45;
  pointer-events:none;
}

/* A bare text button that still reads as an action. */
.btn-text{
  display:inline-flex;
  align-items:center;
  gap:.6em;
  font-family:var(--mono);
  text-transform:uppercase;
  font-size:11px;
  letter-spacing:.18em;
  color:var(--fg);
  padding-block:6px;
  border-bottom:1px solid var(--line);
  transition:border-color .4s var(--e-out);
}
.btn-text:hover{ border-color:currentColor; }
.btn-text:hover .arr{ transform:translateX(4px); }


/* ==========================================================================
   10  CUSTOM CURSOR
   Desktop only. The native cursor is hidden only inside the hover/fine query,
   so touch and stylus users keep normal behaviour.
   ========================================================================== */

.cursor{ display:none; }

@media (hover:hover) and (pointer:fine){
  html.has-cursor,
  html.has-cursor body,
  html.has-cursor a,
  html.has-cursor button,
  html.has-cursor [role="button"],
  html.has-cursor input,
  html.has-cursor textarea,
  html.has-cursor select,
  html.has-cursor label{ cursor:none; }

  .cursor{
    display:block;
    position:fixed;
    top:0; left:0;
    z-index:var(--z-cursor);
    pointer-events:none;
    mix-blend-mode:normal;
    opacity:0;
    transition:opacity .3s var(--e-out);
  }
  .cursor.is-live{ opacity:1; }
  .cursor.is-hidden{ opacity:0; }

  .cursor-dot{
    position:fixed;
    top:0; left:0;
    width:8px; height:8px;
    margin:-4px 0 0 -4px;
    border-radius:50%;
    background:#FFFFFF;
    mix-blend-mode:difference;
    transform:translate3d(var(--dx,-100px),var(--dy,-100px),0) scale(var(--ds,1));
    transition:width .35s var(--e-out), height .35s var(--e-out),
               margin .35s var(--e-out);
    will-change:transform;
  }
  .cursor-ring{
    position:fixed;
    top:0; left:0;
    width:36px; height:36px;
    margin:-18px 0 0 -18px;
    border-radius:50%;
    border:1px solid var(--fg);
    opacity:.55;
    transform:translate3d(var(--rx,-100px),var(--ry,-100px),0) scale(var(--rs,1));
    transition:width .45s var(--e-out), height .45s var(--e-out),
               margin .45s var(--e-out), border-color .45s var(--e-out),
               opacity .35s var(--e-out), background-color .45s var(--e-out);
    will-change:transform;
  }
  .cursor-label{
    position:fixed;
    top:0; left:0;
    font-family:var(--mono);
    font-size:10px;
    letter-spacing:.16em;
    text-transform:uppercase;
    line-height:1;
    color:var(--bg);
    white-space:nowrap;
    transform:translate3d(var(--rx,-100px),var(--ry,-100px),0) translate(-50%,-50%) scale(.6);
    opacity:0;
    transition:opacity .3s var(--e-out), transform .001s linear;
    will-change:transform;
  }

  /* ---- states ---- */
  .cursor.is-link .cursor-ring{ width:52px; height:52px; margin:-26px 0 0 -26px; opacity:.9; }
  .cursor.is-link .cursor-dot{ width:5px; height:5px; margin:-2.5px 0 0 -2.5px; }

  .cursor.is-view .cursor-ring,
  .cursor.is-play .cursor-ring,
  .cursor.is-drag .cursor-ring{
    width:88px; height:88px;
    margin:-44px 0 0 -44px;
    opacity:1;
    border-color:transparent;
    background:var(--fg);
  }
  .cursor.is-view .cursor-dot,
  .cursor.is-play .cursor-dot,
  .cursor.is-drag .cursor-dot{ width:0; height:0; margin:0; }

  .cursor.is-view .cursor-label,
  .cursor.is-play .cursor-label,
  .cursor.is-drag .cursor-label{
    opacity:1;
    transform:translate3d(var(--rx,-100px),var(--ry,-100px),0) translate(-50%,-50%) scale(1);
    transition:opacity .3s var(--e-out) .08s, transform .001s linear;
  }
  .cursor.is-drag .cursor-ring{ background:var(--acid); }
  .cursor.is-drag .cursor-label{ color:var(--ink); }
  .cursor.is-play .cursor-ring{ background:var(--flare); }
  .cursor.is-play .cursor-label{ color:#FFFFFF; }
}


/* ==========================================================================
   11  LOADER AND CURTAIN
   Loader markup contract (site.js builds the letter spans if they are absent):
     <div class="loader" id="loader">
       <div class="loader-in">
         <div class="loader-mark">MAGNETIQ</div>
         <div class="loader-rule"><i></i></div>
       </div>
       <div class="loader-count">000</div>
     </div>
   ========================================================================== */

.loader{
  position:fixed;
  inset:0;
  z-index:var(--z-loader);
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:26px;
  background:var(--paper);
  color:var(--ink);
  padding:var(--gut);
  transform-origin:50% 0%;
  transition:clip-path .9s var(--e-io), opacity .3s linear .75s;
  clip-path:inset(0 0 0 0);
  will-change:clip-path;
}
.loader.is-done{
  clip-path:inset(0 0 100% 0);
  opacity:0;
  pointer-events:none;
}
html.is-ready .loader{ pointer-events:none; }

.loader-in{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:22px;
  width:min(760px,100%);
}

.loader-mark{
  display:flex;
  align-items:baseline;
  justify-content:center;
  font-family:var(--display);
  font-weight:600;
  font-variation-settings:'opsz' 96,'wght' 600;
  font-size:clamp(2.2rem,9vw,6rem);
  line-height:1;
  letter-spacing:-.045em;
  overflow:hidden;
}
.loader-mark span{
  display:inline-block;
  transform:translateY(105%);
  opacity:0;
  animation:loaderLetter .85s var(--e-out) forwards;
  animation-delay:calc(var(--i,0) * .052s);
}
@keyframes loaderLetter{
  to{ transform:translateY(0); opacity:1; }
}

.loader-rule{
  width:min(420px,72vw);
  height:1px;
  background:rgba(10,10,12,.16);
  overflow:hidden;
}
.loader-rule > i{
  display:block;
  height:100%;
  width:100%;
  background:var(--iris);
  transform:scaleX(var(--p,0));
  transform-origin:0 50%;
  transition:transform .25s linear;
}

.loader-count{
  position:absolute;
  right:var(--gut);
  bottom:calc(var(--gut) * .8);
  font-family:var(--mono);
  font-size:clamp(11px,1.1vw,13px);
  letter-spacing:.2em;
  color:rgba(10,10,12,.55);
  font-variant-numeric:tabular-nums;
}
.loader-note{
  position:absolute;
  left:var(--gut);
  bottom:calc(var(--gut) * .8);
  font-family:var(--mono);
  font-size:10px;
  letter-spacing:.2em;
  text-transform:uppercase;
  /* .62 alpha clears 4.5:1 against the bone loader plate. */
  color:rgba(10,10,12,.62);
}

/* ---- reusable page-transition curtain ----------------------------------
   site.js injects <div class="curtain"><span>MAGNETIQ</span></div> once per
   page if it is not already in the markup.
   ------------------------------------------------------------------------ */
.curtain{
  position:fixed;
  inset:0;
  z-index:var(--z-curtain);
  display:flex;
  align-items:center;
  justify-content:center;
  background:var(--ink);
  color:var(--bone);
  pointer-events:none;
  transform:translateY(100%);
  transition:transform .62s var(--e-io);
  will-change:transform;
}
.curtain > span{
  font-family:var(--display);
  font-weight:600;
  font-variation-settings:'opsz' 96,'wght' 600;
  font-size:clamp(1.6rem,5vw,3.4rem);
  letter-spacing:-.04em;
  opacity:0;
  transform:translateY(14px);
  transition:opacity .4s var(--e-out), transform .5s var(--e-out);
}
.curtain.is-cover{ transform:translateY(0); pointer-events:auto; }
.curtain.is-cover > span{ opacity:1; transform:none; transition-delay:.18s; }
.curtain.is-open{ transform:translateY(-100%); }
.curtain.is-open > span{ opacity:0; transform:translateY(-14px); transition-delay:0s; }
.curtain.is-instant{ transition:none; }


/* ==========================================================================
   12  GRAIN
   Inline SVG feTurbulence, no network request, no animation on small screens.
   ========================================================================== */

.grain{
  position:fixed;
  inset:0;
  z-index:var(--z-grain);
  pointer-events:none;
  opacity:.05;
  mix-blend-mode:overlay;
  background-repeat:repeat;
  background-size:220px 220px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  will-change:auto;
}
@media (min-width:900px){
  .grain{ animation:grainShift 1.1s steps(4) infinite; }
}
@keyframes grainShift{
  0%   { transform:translate3d(0,0,0); }
  25%  { transform:translate3d(-3%,2%,0); }
  50%  { transform:translate3d(2%,-3%,0); }
  75%  { transform:translate3d(-2%,-2%,0); }
  100% { transform:translate3d(0,0,0); }
}
html.no-gl .grain{ opacity:.045; }


/* ==========================================================================
   13  WHATSAPP BUBBLE
   ========================================================================== */

.wa-bubble{
  position:fixed;
  right:clamp(14px,2.2vw,28px);
  bottom:clamp(14px,2.2vw,28px);
  z-index:var(--z-wa);
  width:60px; height:60px;
  display:inline-flex;
  align-items:center;
  justify-content:flex-start;
  padding:0 18px 0 18px;
  border-radius:999px;
  background:#25D366;
  color:#FFFFFF;
  overflow:hidden;
  white-space:nowrap;
  box-shadow:0 10px 34px rgba(0,0,0,.28);
  transition:width .55s var(--e-out), box-shadow .4s var(--e-out),
             opacity .35s var(--e-out), transform .4s var(--e-spring);
}
.wa-bubble svg{
  width:26px; height:26px;
  flex:none;
  fill:currentColor;
  margin-left:-6px;
}
.wa-bubble em{
  font-family:var(--mono);
  font-style:normal;
  font-size:11px;
  letter-spacing:.16em;
  text-transform:uppercase;
  line-height:1;
  margin-left:12px;
  opacity:0;
  transform:translateX(-6px);
  transition:opacity .35s var(--e-out), transform .45s var(--e-out);
}
.wa-bubble:hover,
.wa-bubble:focus-visible{
  width:206px;
  box-shadow:0 14px 44px rgba(37,211,102,.34);
}
.wa-bubble:hover em,
.wa-bubble:focus-visible em{ opacity:1; transform:none; }
.wa-bubble:active{ transform:scale(.96); }

/* The bubble steps aside for the fullscreen nav and for page transitions. */
html.is-drawer .wa-bubble,
html.is-leaving .wa-bubble{
  opacity:0;
  transform:scale(.82) translateY(10px);
  pointer-events:none;
}

/* It also tucks out of the way while the reader is travelling down the page,
   so it never sits on top of a paragraph, and returns on scroll up or on the
   first pause. site.js owns the .is-wa-tucked flag. */
html.is-wa-tucked .wa-bubble{
  opacity:0;
  transform:scale(.7) translateY(22px);
  pointer-events:none;
}
@media (prefers-reduced-motion:reduce){
  html.is-wa-tucked .wa-bubble{
    opacity:1;
    transform:none;
    pointer-events:auto;
  }
}
html.is-leaving .scrollbar{ opacity:0; transition:opacity .3s var(--e-out); }

.wa-pulse{
  position:absolute;
  left:30px; top:50%;
  width:60px; height:60px;
  margin:-30px 0 0 -30px;
  border-radius:50%;
  border:1px solid #25D366;
  pointer-events:none;
  opacity:0;
  animation:waPulse 4s var(--e-out) infinite;
}
@keyframes waPulse{
  0%   { transform:scale(.72); opacity:.85; }
  55%  { transform:scale(1.75); opacity:0; }
  100% { transform:scale(1.75); opacity:0; }
}

@media (max-width:420px){
  .wa-bubble{ width:52px; height:52px; padding-inline:13px; }
  .wa-bubble svg{ width:23px; height:23px; margin-left:-4px; }
  .wa-bubble:hover,
  .wa-bubble:focus-visible{ width:52px; }
  .wa-bubble:hover em,
  .wa-bubble:focus-visible em{ opacity:0; }
  .wa-pulse{ left:26px; width:52px; height:52px; margin:-26px 0 0 -26px; }
}


/* ==========================================================================
   14  FOOTER
   ========================================================================== */

.ftr{
  position:relative;
  z-index:var(--z-content);
  background:var(--bg);
  color:var(--fg);
  padding-top:clamp(64px,10vh,130px);
  overflow:hidden;
  transition:background-color .6s var(--e-io), color .6s var(--e-io);
}

.ftr-top{
  display:grid;
  gap:clamp(30px,4vw,64px);
  padding-bottom:clamp(40px,6vh,72px);
}
@media (min-width:900px){
  .ftr-top{ grid-template-columns:minmax(0,1.4fr) repeat(3,minmax(0,1fr)); }
}

.ftr-lead h3{ margin-bottom:16px; }
.ftr-lead p{ max-width:38ch; }
.ftr-cta{ display:flex; flex-wrap:wrap; gap:12px; margin-top:26px; }

.ftr-col{ display:flex; flex-direction:column; gap:10px; }
.ftr-col h6{
  font-family:var(--mono);
  font-size:10px;
  letter-spacing:.18em;
  text-transform:uppercase;
  font-weight:500;
  font-variation-settings:'wght' 500;
  color:var(--fg-dim);
  margin-bottom:6px;
}
.ftr-col a,.ftr-col span{
  font-size:15px;
  color:var(--fg-dim);
  transition:color .3s var(--e-out), transform .4s var(--e-out);
}
.ftr-col a:hover{ color:var(--fg); transform:translateX(3px); }

.ftr-contact{ display:flex; flex-direction:column; gap:6px; }
.ftr-contact a{ font-size:16px; color:var(--fg); }

.ftr-lang{
  display:flex;
  align-items:center;
  gap:10px;
  padding-block:clamp(16px,2.4vh,26px);
  border-top:1px solid var(--line);
  border-bottom:1px solid var(--line);
  flex-wrap:wrap;
}
.ftr-lang .kicker{ margin-right:auto; }

/* The big wordmark scales with the viewport and bleeds to both gutters. */
.ftr-mark{
  display:block;
  width:100%;
  padding-top:clamp(28px,5vh,60px);
  font-family:var(--display);
  font-weight:600;
  font-variation-settings:'opsz' 96,'wght' 600;
  font-size:clamp(3.2rem,18.5vw,17rem);
  line-height:.82;
  letter-spacing:-.05em;
  text-align:center;
  color:var(--fg);
  opacity:.96;
  user-select:none;
}
/* The wordmark is the largest painted surface on the site, so it shows only the
   cool half of the iris ramp (violet into magenta). Sliding the window on hover
   keeps the colour alive without letting the warm tail dominate the mark. */
.ftr-mark span{
  display:inline-block;
  background-image:var(--iris);
  background-size:300% 100%;
  background-position:0% 50%;
  -webkit-background-clip:text;
  background-clip:text;
  -webkit-text-fill-color:currentColor;
  text-shadow:none;
  padding-bottom:.16em;   /* room for the Q tail, background-clip:text crops tight */
  transition:-webkit-text-fill-color .6s var(--e-out), background-position 1.4s var(--e-out);
}
.ftr:hover .ftr-mark span{ -webkit-text-fill-color:transparent; background-position:40% 50%; }

/* The extra bottom padding keeps the fine print clear of the fixed WhatsApp
   bubble when the page is scrolled all the way down. */
.ftr-fine{
  display:flex;
  flex-wrap:wrap;
  gap:10px 26px;
  align-items:center;
  justify-content:space-between;
  /* The bubble is 60px tall and sits clamp(14px,2.2vw,28px) off the bottom, so
     the last fine print item (which is right aligned, same as the bubble) needs
     more than 88px of clearance or the bubble lands on top of its hit area. */
  padding-block:clamp(18px,3vh,30px) clamp(106px,13vh,138px);
  border-top:1px solid var(--line);
  margin-top:clamp(20px,3vh,36px);
  font-family:var(--mono);
  font-size:10px;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--fg-dim);
}
.ftr-fine a:hover{ color:var(--fg); }

.ftr-strip{
  border-top:1px solid var(--line);
  border-bottom:1px solid var(--line);
  padding-block:14px;
}


/* ==========================================================================
   15  MARQUEE
   motion.js drives [data-marquee]. When the attribute is absent the CSS
   animation below keeps the strip alive on its own, so a marquee never sits
   frozen if the motion engine is missing.
   ========================================================================== */

.marquee{
  position:relative;
  width:100%;
  overflow:hidden;
  display:flex;
}
.marquee-track{
  display:flex;
  align-items:center;
  gap:clamp(24px,4vw,72px);
  flex:none;
  white-space:nowrap;
  will-change:transform;
  padding-right:clamp(24px,4vw,72px);
}
.marquee:not([data-marquee]) .marquee-track{
  animation:marqueeSlide 28s linear infinite;
}
.marquee:not([data-marquee]):hover .marquee-track{ animation-play-state:paused; }
@keyframes marqueeSlide{
  from{ transform:translate3d(0,0,0); }
  to  { transform:translate3d(-50%,0,0); }
}
.marquee-item{
  display:inline-flex;
  align-items:center;
  gap:.6em;
  font-family:var(--display);
  font-weight:500;
  font-variation-settings:'opsz' 72,'wght' 500;
  font-size:clamp(1.5rem,4vw,3.4rem);
  letter-spacing:-.035em;
  line-height:1;
  color:var(--fg);
}
.marquee-item.is-mono{
  font-family:var(--mono);
  font-size:11px;
  letter-spacing:.2em;
  text-transform:uppercase;
  color:var(--fg-dim);
}
.marquee-dot{
  width:9px; height:9px;
  border-radius:50%;
  background:var(--iris);
  flex:none;
}
.marquee-fade::before,
.marquee-fade::after{
  content:"";
  position:absolute;
  top:0; bottom:0;
  width:clamp(40px,8vw,120px);
  z-index:2;
  pointer-events:none;
}
.marquee-fade::before{ left:0;  background:linear-gradient(90deg,var(--bg),transparent); }
.marquee-fade::after{  right:0; background:linear-gradient(270deg,var(--bg),transparent); }


/* ==========================================================================
   16  REVEAL STATES
   Base states for the motion engine. Everything MUST end visible, so the
   reduced-motion block at the bottom forces the rest state.
   ========================================================================== */

[data-reveal]{
  opacity:0;
  transform:translateY(28px);
  transition:opacity .9s var(--e-out), transform 1s var(--e-out), clip-path 1s var(--e-io), filter .9s var(--e-out);
  will-change:opacity,transform;
}
[data-reveal="left"] { transform:translateX(-42px); }
[data-reveal="right"]{ transform:translateX(42px); }
[data-reveal="scale"]{ transform:scale(.92); }
[data-reveal="clip"] { opacity:1; transform:none; clip-path:inset(0 0 100% 0); }
[data-reveal="blur"] { filter:blur(14px); transform:translateY(18px); }
[data-reveal="none"] { opacity:0; transform:none; }

[data-reveal].is-in{
  opacity:1;
  transform:none;
  filter:none;
}
/* Only the clip variant carries a clip-path. Putting inset(0 0 0 0) on every
   revealed element clips it to its own border box, which slices any decoration
   that is meant to hang outside it (the packages "most chosen" badge straddles
   the top edge of its card). */
[data-reveal="clip"].is-in{ clip-path:inset(0 0 0 0); }

/* Split text parts produced by motion.js: [data-split] wraps each unit in
   .sp-w (word), .sp-c (char) or .sp-l (line), each inside a .sp-m mask. */
.sp-m{ display:inline-block; overflow:hidden; vertical-align:top; }
.sp-w,.sp-c,.sp-l{
  display:inline-block;
  transform:translateY(105%);
  opacity:0;
  transition:transform .95s var(--e-out), opacity .6s var(--e-out);
  will-change:transform;
}
.is-in .sp-w,.is-in .sp-c,.is-in .sp-l,
.sp-w.is-in,.sp-c.is-in,.sp-l.is-in{ transform:translateY(0); opacity:1; }

/* Scrub + pin helpers read --p, which motion.js writes. */
[data-scrub],[data-pin]{ --p:0; }
[data-pin]{ position:sticky; top:0; }


/* ==========================================================================
   17  WEBGL CANVAS AND STACKING
   ========================================================================== */

#gl{
  position:fixed;
  inset:0;
  width:100%;
  height:100%;
  z-index:var(--z-gl);
  pointer-events:none;
  display:block;
}
html.no-gl #gl{ display:none; }

/* Content and chrome always sit above the canvas. Positions are already set in
   each component block, this only guarantees the stacking order. */
#smooth{ z-index:var(--z-content); }
.ftr{ z-index:var(--z-content); }
.scrollbar{ z-index:var(--z-rail); }
.grain{ z-index:var(--z-grain); }
.hdr{ z-index:var(--z-hdr); }
.drawer{ z-index:var(--z-drawer); }


/* ==========================================================================
   18  UTILITIES
   ========================================================================== */

.sr-only{
  position:absolute;
  width:1px; height:1px;
  padding:0; margin:-1px;
  overflow:hidden;
  clip:rect(0,0,0,0);
  clip-path:inset(50%);
  white-space:nowrap;
  border:0;
}
.sr-only-focusable:focus,
.sr-only-focusable:focus-visible{
  position:fixed;
  top:12px; left:12px;
  width:auto; height:auto;
  padding:12px 18px;
  margin:0;
  clip:auto;
  clip-path:none;
  z-index:9999;
  background:var(--fg);
  color:var(--bg);
  border-radius:999px;
  font-family:var(--mono);
  font-size:11px;
  letter-spacing:.16em;
  text-transform:uppercase;
}

.mono{
  font-family:var(--mono);
  font-size:11px;
  letter-spacing:.18em;
  text-transform:uppercase;
  line-height:1.4;
}
.mono-sm{ font-family:var(--mono); font-size:10px; letter-spacing:.16em; }
.serif{ font-family:var(--serif); font-style:normal; font-weight:400; letter-spacing:-.01em; }
.serif-i{ font-family:var(--serif); font-style:italic; font-weight:400; }
.dim{ color:var(--fg-dim); }
.fg{ color:var(--fg); }
.acid{ color:var(--acid); }
.flare{ color:var(--flare); }
.volt{ color:var(--volt-2); }

.rule{
  width:100%;
  height:1px;
  background:var(--line);
  border:0;
  display:block;
}
.rule-iris{ background:var(--iris); height:2px; }

.pill{
  display:inline-flex;
  align-items:center;
  gap:.55em;
  padding:7px 14px;
  border-radius:999px;
  border:1px solid var(--line);
  font-family:var(--mono);
  font-size:10px;
  letter-spacing:.16em;
  text-transform:uppercase;
  line-height:1;
  color:var(--fg-dim);
  transition:color .3s var(--e-out), border-color .3s var(--e-out), background-color .3s var(--e-out);
}
.pill.is-on{ color:var(--bg); background:var(--fg); border-color:var(--fg); }
.pill.is-ok{ color:var(--ink); background:var(--acid); border-color:transparent; }
.pill.is-warn{ color:#FFFFFF; background:var(--flare); border-color:transparent; }
.pill.is-live{ color:#FFFFFF; background:var(--volt); border-color:transparent; }

.tag{
  display:inline-flex;
  align-items:center;
  padding:4px 9px;
  border-radius:6px;
  background:var(--faint);
  font-family:var(--mono);
  font-size:9px;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--fg-dim);
  line-height:1.4;
}

.badge{
  display:inline-flex;
  align-items:center;
  gap:.45em;
  padding:5px 11px;
  border-radius:999px;
  background:var(--iris);
  color:#FFFFFF;
  font-family:var(--mono);
  font-size:9px;
  letter-spacing:.16em;
  text-transform:uppercase;
  line-height:1.3;
}

.dot{
  width:7px; height:7px;
  border-radius:50%;
  background:currentColor;
  display:inline-block;
  flex:none;
}
.dot-live{ background:var(--acid); box-shadow:0 0 0 0 rgba(214,255,61,.6); animation:dotPing 2.6s var(--e-out) infinite; }
@keyframes dotPing{
  0%   { box-shadow:0 0 0 0 rgba(214,255,61,.55); }
  70%  { box-shadow:0 0 0 10px rgba(214,255,61,0); }
  100% { box-shadow:0 0 0 0 rgba(214,255,61,0); }
}

.stack{ display:flex; flex-direction:column; gap:var(--gap,16px); }
.stack-sm{ --gap:8px; }
.stack-lg{ --gap:32px; }

.cluster{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--gap,12px); }

.split{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:var(--gap,18px);
  width:100%;
}
.split-top{ align-items:flex-start; }
.split-mid{ align-items:center; }

.aspect{ position:relative; overflow:hidden; border-radius:var(--r); background:var(--faint); }
.aspect > img,.aspect > video,.aspect > canvas,.aspect > iframe{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
}
.aspect-1   { aspect-ratio:1/1; }
.aspect-4x3 { aspect-ratio:4/3; }
.aspect-3x4 { aspect-ratio:3/4; }
.aspect-16x9{ aspect-ratio:16/9; }
.aspect-21x9{ aspect-ratio:21/9; }
.aspect-3x2 { aspect-ratio:3/2; }

.center{ text-align:center; }
.center .lede,.center p{ margin-inline:auto; }
.right{ text-align:right; }
.nowrap{ white-space:nowrap; }
.full{ width:100%; }
.rel{ position:relative; }
.hide{ display:none; }
@media (max-width:768px){ .hide-m{ display:none; } }
@media (min-width:769px){ .hide-d{ display:none; } }

.media-zoom{ overflow:hidden; }
.media-zoom img{
  transition:transform 1.1s var(--e-out), filter .7s var(--e-out);
  transform:scale(1.001);
}
.media-zoom:hover img{ transform:scale(1.06); }

.surface-card{
  background:var(--card);
  border:1px solid var(--line);
  border-radius:var(--r-lg);
}

.hairline-top{ border-top:1px solid var(--line); }
.hairline-bot{ border-bottom:1px solid var(--line); }


/* ==========================================================================
   19  FORMS BASELINE
   Page stylesheets extend these, they never redeclare them.
   ========================================================================== */

.field{ display:flex; flex-direction:column; gap:8px; }
.field > label{
  font-family:var(--mono);
  font-size:10px;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:var(--fg-dim);
}
.input,
.field input,
.field textarea,
.field select{
  width:100%;
  padding:14px 16px;
  border-radius:var(--r);
  border:1px solid var(--line);
  background:var(--faint);
  color:var(--fg);
  font-family:var(--body);
  font-size:16px;
  line-height:1.4;
  transition:border-color .3s var(--e-out), background-color .3s var(--e-out);
  appearance:none;
}
.field textarea{ min-height:140px; resize:vertical; }
.input:focus,
.field input:focus,
.field textarea:focus,
.field select:focus{
  border-color:color-mix(in srgb,var(--fg) 45%,transparent);
  background:transparent;
}
.input::placeholder,
.field input::placeholder,
.field textarea::placeholder{ color:var(--fg-dim); opacity:.7; }
.field select{
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),
                   linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:calc(100% - 20px) calc(50% + 1px), calc(100% - 14px) calc(50% + 1px);
  background-size:6px 6px,6px 6px;
  background-repeat:no-repeat;
  padding-right:44px;
}
.field .err{
  font-family:var(--mono);
  font-size:10px;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--flare);
}
.field.is-bad input,
.field.is-bad textarea,
.field.is-bad select{ border-color:var(--flare); }


/* ==========================================================================
   20  PRINT
   ========================================================================== */

@media print{
  html .loader,
  html .curtain,
  html .cursor,
  html .grain,
  html .scrollbar,
  html .wa-bubble,
  html .drawer,
  html #gl,
  html .hdr{ display:none; }

  html,body{ background:#FFFFFF; color:#000000; }

  html section,
  html .ftr{ background:#FFFFFF; color:#000000; padding-block:18mm; page-break-inside:avoid; }

  html [data-reveal],
  html [data-reveal].is-in,
  html .sp-w,
  html .sp-c,
  html .sp-l{ opacity:1; transform:none; filter:none; clip-path:none; }

  html .loader-mark span{ opacity:1; transform:none; }

  a[href^="http"]::after{ content:" (" attr(href) ")"; font-size:9pt; }
  html .btn{ border:1px solid #000000; color:#000000; background:none; }
  html .btn::after{ display:none; }
  html .ftr-mark{ font-size:36pt; }
}


/* ==========================================================================
   21  REDUCED MOTION
   Content always ends visible. This is the only block allowed to use
   !important, because it must beat every page stylesheet loaded after core.
   ========================================================================== */

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    animation-delay:0s !important;
    transition-duration:.001ms !important;
    transition-delay:0s !important;
    scroll-behavior:auto !important;
  }
  [data-reveal],
  [data-reveal].is-in{
    opacity:1 !important;
    transform:none !important;
    filter:none !important;
    clip-path:none !important;
  }
  .sp-w,.sp-c,.sp-l{
    opacity:1 !important;
    transform:none !important;
  }
  .loader-mark span{
    opacity:1 !important;
    transform:none !important;
  }
  .drawer .drawer-nav a > span{
    opacity:1 !important;
    transform:none !important;
  }
  .drawer-foot{
    opacity:1 !important;
    transform:none !important;
  }
  .grain{ animation:none !important; }
  .brand-mark{ animation:none !important; }
  .wa-pulse{ animation:none !important; opacity:0 !important; }
  .dot-live{ animation:none !important; }
  .marquee:not([data-marquee]) .marquee-track{ animation:none !important; }
  .cursor{ display:none !important; }
  html.has-cursor,html.has-cursor body,html.has-cursor a,html.has-cursor button{ cursor:auto !important; }
}
