/* ==========================================================================
   Anas Web Services: the front page.
   Single-theme by intent: the photograph is lit, and a light palette would
   fight it. Every colour is painted explicitly so nothing is inherited.
   ========================================================================== */

@font-face{
  font-family:'Archivo';
  font-style:normal; font-weight:100 900;
  /* Load-bearing. Without a font-stretch range the browser never uses the
     width axis, and every heading silently renders at default width, which
     reads as a slightly wrong design rather than as a bug. */
  font-stretch:62% 125%;
  font-display:swap;
  src:url(/archivo-variable.woff2) format('woff2');
}
@font-face{ font-family:'Plex Mono'; font-weight:400; font-display:swap; src:url(/plex-mono-400.woff2) format('woff2'); }
@font-face{ font-family:'Plex Mono'; font-weight:600; font-display:swap; src:url(/plex-mono-600.woff2) format('woff2'); }

:root{
  --night:#0B1017;
  --panel:#131C27;
  --rule:#22303F;
  --rule-soft:#1A2532;
  --ink:#E8EDF2;
  --ink-2:#A9B8C6;
  --ink-3:#7E8FA0;
  --ink-4:#5A6B7C;
  --flare:#FF6B1A;
  --flare-hot:#FF9147;
  --live:#3FD07F;
  --rim:#5B8FB9;
  --shell:min(1180px, 92vw);
}

*,*::before,*::after{ box-sizing:border-box }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth }
@media (prefers-reduced-motion:reduce){ html{ scroll-behavior:auto } }

body{
  margin:0;
  background:var(--night);
  color:var(--ink);
  font-family:'Archivo',system-ui,-apple-system,sans-serif;
  font-size:clamp(1rem,.86rem + .7vw,1.18rem);
  line-height:1.62;
  overflow-x:hidden;
}
h1,h2,h3{ margin:0; text-wrap:balance; line-height:1.02; letter-spacing:-.022em }
p{ margin:0 }
img{ max-width:100% }
:focus-visible{ outline:2px solid var(--flare); outline-offset:3px; border-radius:2px }
.mono{ font-family:'Plex Mono',ui-monospace,Menlo,monospace; font-variant-numeric:tabular-nums }

.grain{
  position:fixed; inset:-120px; z-index:60; pointer-events:none;
  opacity:.04; mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:grain 5s steps(5) infinite;
}
@keyframes grain{
  0%{transform:translate(0,0)} 20%{transform:translate(-14px,7px)} 40%{transform:translate(9px,-11px)}
  60%{transform:translate(-7px,13px)} 80%{transform:translate(12px,5px)} 100%{transform:translate(0,0)}
}

/* ---- the mark: the wordmark, and a burst where the smile used to be ---- */
.mark{ display:block; height:1em; width:auto; overflow:visible }
.mark .wm{ fill:currentColor }
.mark .burst line{
  stroke:var(--flare); stroke-width:6; stroke-linecap:round;
}
/* transform-box, or the origin resolves against the element's own tight
   bounding box instead of the viewBox and the burst spins off its centre. */
.mark .burst{ transform-box:view-box; transform-origin:56px 71px }
.mark.animate .burst{
  transform:scale(0) rotate(-70deg);
  animation:burstin .62s cubic-bezier(.2,1.35,.35,1) .12s forwards;
}
@keyframes burstin{ to{ transform:scale(1) rotate(0deg) } }

/* ---- nav ---- */
.nav{
  position:fixed; top:0; left:0; right:0; z-index:50;
  display:flex; align-items:center; gap:2rem;
  padding:1rem max(2rem,(100vw - var(--shell))/2);
  background:linear-gradient(180deg, rgba(11,16,23,.9), rgba(11,16,23,.6) 60%, transparent);
  backdrop-filter:blur(9px); -webkit-backdrop-filter:blur(9px);
  border-bottom:1px solid transparent;
  transition:background .3s ease, border-color .3s ease;
}
.nav.stuck{ background:rgba(11,16,23,.94); border-bottom-color:var(--rule-soft) }
.brand{ display:flex; align-items:center; gap:.62rem; text-decoration:none; font-size:1.02rem; color:inherit }
.brand .mark{ height:2.7em }
.brand b{ font-weight:800; font-stretch:112%; white-space:nowrap }
.nav nav{ margin-left:auto; display:flex; align-items:center; gap:1.9rem }
.nav nav a{ font-size:.87rem; color:var(--ink-2); text-decoration:none; font-weight:500; transition:color .18s }
.nav nav a:hover{ color:var(--ink) }
@media (max-width:900px){ .nav nav a:not(.btn){ display:none } }
@media (max-width:620px){
  .nav{ padding-left:max(1.15rem,(100vw - var(--shell))/2); padding-right:max(1.15rem,(100vw - var(--shell))/2) }
  .nav nav .btn{ display:none }
  .brand{ font-size:.95rem }
}

.btn{
  display:inline-flex; align-items:center; gap:.5rem;
  font:inherit; font-size:.87rem; font-weight:650;
  padding:.62rem 1.15rem; border-radius:3px; text-decoration:none;
  border:1px solid transparent; cursor:pointer;
  transition:transform .16s, box-shadow .22s, background .18s, border-color .18s, color .18s;
}
.btn-primary{ background:var(--flare); color:#150701; box-shadow:0 6px 22px -8px rgba(255,107,26,.7) }
.btn-primary:hover{ background:var(--flare-hot); transform:translateY(-1px); box-shadow:0 0 26px -4px rgba(255,107,26,.55) }
.btn-ghost{ border-color:var(--rule); color:var(--ink); background:rgba(11,16,23,.5) }
.btn-ghost:hover{ border-color:var(--ink-4); background:rgba(255,255,255,.05); transform:translateY(-1px) }
.nav .btn{ padding:.5rem .95rem }

/* ==========================================================================
   HERO: a freight yard in real CSS 3D. Three stacks, three machines.
   ========================================================================== */
.vignette{
  position:absolute; inset:0; z-index:5; pointer-events:none;
  background:radial-gradient(125% 92% at 50% 34%, transparent 42%, rgba(4,7,11,.42) 86%, rgba(4,7,11,.66) 100%);
}
.hero{
  position:relative; isolation:isolate;
  min-height:clamp(680px,100svh,1000px);
  display:grid; grid-template-rows:1fr auto;
  overflow:hidden;
  border-bottom:1px solid var(--rule-soft);
}

/* volumetric haze, a warm key from upper left, a cold fill from lower right */
.haze{ position:absolute; inset:-25%; z-index:0; pointer-events:none; mix-blend-mode:screen }
.haze i{ position:absolute; display:block; border-radius:50%; filter:blur(80px) }
.haze .key{
  width:64%; height:78%; left:-8%; top:-24%;
  background:radial-gradient(circle, rgba(255,107,26,.30) 0%, rgba(255,107,26,.10) 42%, transparent 68%);
  animation:drift1 22s ease-in-out infinite alternate;
}
.haze .fill{
  width:58%; height:66%; right:-10%; bottom:-14%;
  background:radial-gradient(circle, rgba(91,143,185,.26) 0%, rgba(91,143,185,.08) 46%, transparent 70%);
  animation:drift2 27s ease-in-out infinite alternate;
}
@keyframes drift1{ to{ transform:translate3d(5%,4%,0) scale(1.1) } }
@keyframes drift2{ to{ transform:translate3d(-5%,-4%,0) scale(1.12) } }

/* ---- the yard ---- */
.yard{
  position:absolute; top:0; bottom:0; left:44%; right:-7%; z-index:1;
  perspective:1450px; perspective-origin:50% 45%;
  cursor:grab; touch-action:pan-y;
  --s:1;
}
.yard.dragging{ cursor:grabbing }
.yard::after{ /* sink the horizon into the page */
  content:''; position:absolute; left:0; right:0; bottom:0; height:34%;
  background:linear-gradient(180deg, transparent, var(--night) 82%);
  pointer-events:none; z-index:5;
}

.scene{
  position:absolute; left:50%; top:47%;
  width:0; height:0;
  transform-style:preserve-3d;
  transform:
    scale(var(--s,1))
    rotateX(calc(-17deg + var(--rx,0deg)))
    rotateY(calc(23deg + var(--ry,0deg)))
    translateY(var(--dy,0px));
}

/* the drawing floor */
.floor{
  position:absolute; left:50%; top:50%;
  width:1500px; height:1050px;
  transform:translate(-50%,-50%) rotateX(90deg) translateZ(-34px);
  background:
    repeating-linear-gradient(90deg, rgba(91,143,185,.12) 0 1px, transparent 1px 75px),
    repeating-linear-gradient(0deg,  rgba(91,143,185,.12) 0 1px, transparent 1px 75px),
    radial-gradient(ellipse at 50% 44%, rgba(30,44,60,.85) 0%, rgba(11,16,23,0) 66%);
  -webkit-mask-image:radial-gradient(ellipse 52% 44% at 50% 46%, #000 12%, transparent 76%);
  mask-image:radial-gradient(ellipse 52% 44% at 50% 46%, #000 12%, transparent 76%);
}

/* a stack of containers on one node */
.stack{
  position:absolute; left:0; top:0; width:0; height:0;
  transform-style:preserve-3d;
  transform:translate3d(var(--x), 0, var(--z));
}

/* the plinth each node's stack sits on */
.plinth{
  position:absolute; left:50%; top:50%;
  width:236px; height:126px;
  transform:translate(-50%,-50%) rotateX(90deg) translateZ(-30px);
  background:linear-gradient(150deg, #1d2a37, #131c27);
  border:1px solid rgba(91,143,185,.20);
  box-shadow:0 0 34px -14px rgba(91,143,185,.30);
}
/* the node name stands upright in the same plane as the container fronts.
   lying it flat on the plinth foreshortened it into an unreadable smudge. */
.nodelabel{
  position:absolute; left:50%; top:50%; width:220px;
  transform:translate(-50%,-50%) translateY(62px) translateZ(48px);
  font-family:'Plex Mono',monospace; font-size:12px; font-weight:600;
  letter-spacing:.22em; text-transform:uppercase; text-align:center;
  color:rgba(169,184,198,.58); white-space:nowrap;
}

/* ---- one shipping container ---- */
.box{
  position:absolute; left:0; top:0; width:0; height:0;
  transform-style:preserve-3d;
  transform:translate3d(0, var(--y), 0);
}
.box .f{
  position:absolute; left:0; top:0;
  transform-origin:50% 50%;
  background:var(--c);
  border:1px solid rgba(0,0,0,.42);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.045);
}
/* corrugated steel, the ribbing is what makes it read as freight, not a cube */
.box .front,.box .rt,.box .lf{
  background-image:
    repeating-linear-gradient(90deg, rgba(255,255,255,.055) 0 2px, rgba(0,0,0,.10) 2px 5px, transparent 5px 11px),
    linear-gradient(180deg, rgba(255,255,255,.10), transparent 46%, rgba(0,0,0,.34));
}
.box .front{ width:200px; height:56px; transform:translate(-50%,-50%) translateZ(45px) }
.box .rt{ width:90px; height:56px; transform:translate(-50%,-50%) rotateY(90deg) translateZ(100px); filter:brightness(.60) }
.box .lf{ width:90px; height:56px; transform:translate(-50%,-50%) rotateY(-90deg) translateZ(100px); filter:brightness(.42) }
.box .top{
  width:200px; height:90px; transform:translate(-50%,-50%) rotateX(90deg) translateZ(28px);
  filter:brightness(1.34);
  background-image:
    repeating-linear-gradient(90deg, rgba(255,255,255,.05) 0 2px, rgba(0,0,0,.08) 2px 5px, transparent 5px 11px),
    linear-gradient(160deg, rgba(255,255,255,.16), transparent 60%);
}
/* stencilled cargo marking */
.box .front span{
  position:absolute; left:9px; top:50%; transform:translateY(-50%);
  font-family:'Plex Mono',monospace; font-size:10.5px; font-weight:600;
  letter-spacing:.09em; color:rgba(232,237,242,.80);
  text-shadow:0 1px 0 rgba(0,0,0,.55);
  white-space:nowrap;
}
/* the door seam on the right end */
.box .rt::after{
  content:''; position:absolute; inset:7px 5px;
  border:1px solid rgba(0,0,0,.35);
  border-left-width:2px; border-right-width:2px;
}

/* the tenant's own container: lit, tagged, and the point of the whole scene */
.box.yours .f{ box-shadow:inset 0 0 0 1px rgba(255,145,71,.42), 0 0 26px -6px rgba(255,107,26,.55) }
.box.yours .front span{ color:#FFD9C2 }
.box.yours .top{ filter:brightness(1.42) saturate(1.15) }
.tag{
  position:absolute; left:50%; top:50%;
  transform:translate(-50%,-50%) translateZ(46px) translate(64px,-46px);
  display:flex; align-items:center; gap:.36rem;
  padding:.2rem .46rem; border-radius:2px; white-space:nowrap;
  background:rgba(11,16,23,.9); border:1px solid rgba(63,208,127,.45);
  font-family:'Plex Mono',monospace; font-size:9.5px; font-weight:600;
  letter-spacing:.1em; color:var(--live); text-transform:uppercase;
  opacity:0;
}
.tag::before{
  content:''; width:5px; height:5px; border-radius:50%;
  background:var(--live); box-shadow:0 0 7px var(--live);
}
.tag.on{ opacity:1; transition:opacity .5s ease .1s }

/* the landing move: a container descends onto the third machine and goes live */
.box.landing{ transform:translate3d(0, calc(var(--y) - 420px), 0); opacity:0 }
.box.landing.landed{
  transform:translate3d(0, var(--y), 0); opacity:1;
  transition:transform 1.25s cubic-bezier(.22,.9,.24,1), opacity .5s ease;
}



/* ---- hero copy ---- */
.hero-copy{
  position:relative; z-index:10; align-self:center;
  width:var(--shell); margin:0 auto; padding:6rem 0 2rem;
  pointer-events:none;
}
.hero-copy > *{ pointer-events:auto }
.eyebrow{
  font-family:'Plex Mono',monospace; font-size:.72rem; font-weight:600;
  letter-spacing:.24em; text-transform:uppercase; color:var(--ink-3);
  display:flex; align-items:center; gap:.7rem; margin-bottom:1.5rem;
}
.eyebrow s{ width:34px; height:1px; background:var(--flare); display:inline-block; text-decoration:none }
h1{
  /* Sized so the longest line clears the yard's left edge at every width.
     `max-width` cannot help here: text does not break mid-word, so a long
     line stays long and simply overlaps whatever is beside it. The type size
     and the yard's `left` are the only two levers, and they move together. */
  font-size:clamp(2.5rem,1rem + 3.4vw,4.6rem);
  font-weight:850; font-stretch:118%; letter-spacing:-.038em; line-height:.96;
  margin-bottom:1.4rem; max-width:12ch;
}
h1 em{ font-style:normal; color:var(--flare); text-shadow:0 0 54px rgba(255,107,26,.45) }
.lede{
  font-size:clamp(1rem,.94rem + .35vw,1.16rem);
  color:var(--ink-2); max-width:46ch; margin-bottom:2.2rem; line-height:1.6;
}
.hero-cta{ display:flex; gap:.8rem; flex-wrap:wrap; align-items:center }
.hero-cta .btn{ padding:.82rem 1.5rem; font-size:.95rem }
.drag-hint{
  font-family:'Plex Mono',monospace; font-size:.7rem; letter-spacing:.13em;
  text-transform:uppercase; color:var(--ink-4); margin-left:.5rem;
}
@media (hover:none){ .drag-hint{ display:none } }

/* the yard is scaled, not re-laid-out, so the composition survives every width */
@media (max-width:1500px){ .yard{ --s:.88 } }
@media (max-width:1240px){ .yard{ --s:.74; left:46% } }
@media (max-width:1040px){ .yard{ --s:.62; left:50% } }
@media (max-width:900px){
  .hero{ min-height:auto }
  .yard{ left:-12%; right:-12%; top:-2%; bottom:auto; height:56%; --s:.66; opacity:.62 }
  .hero-copy{ padding-top:min(46vh,380px) }
  .hero-copy .lede{ max-width:100% }
}
@media (max-width:560px){ .yard{ --s:.5 } }

.ribbon{
  position:relative; z-index:10; width:var(--shell); margin:0 auto;
  display:grid; grid-template-columns:repeat(4,1fr);
  border-top:1px solid var(--rule-soft);
}
.ribbon div{ padding:1.35rem 1.4rem 1.6rem; border-left:1px solid var(--rule-soft) }
.ribbon div:first-child{ border-left:0; padding-left:0 }
.ribbon dt{
  font-family:'Plex Mono',monospace; font-size:.68rem; font-weight:600;
  letter-spacing:.17em; text-transform:uppercase; color:var(--ink-4); margin-bottom:.45rem;
}
.ribbon dd{
  margin:0; font-size:clamp(1.3rem,1rem + 1vw,1.85rem); font-weight:750;
  font-stretch:108%; line-height:1; font-variant-numeric:tabular-nums;
}
.ribbon dd small{ font-size:.5em; font-weight:600; color:var(--ink-3); margin-left:.15em }
@media (max-width:720px){
  .ribbon{ grid-template-columns:1fr 1fr }
  .ribbon div:nth-child(3){ border-left:0; padding-left:0 }
  .ribbon div:nth-child(-n+2){ border-bottom:1px solid var(--rule-soft) }
}

/* ==========================================================================
   Shared section furniture: below the hero the page is a datasheet
   ========================================================================== */
section{ position:relative; z-index:2 }
.shell{ width:var(--shell); margin:0 auto }
.sec-head{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,44ch);
  gap:2.5rem 4rem; align-items:end; padding:6.5rem 0 3rem;
}
.sec-head h2{
  font-size:clamp(1.9rem,1.2rem + 2.4vw,3.3rem);
  font-weight:800; font-stretch:112%; letter-spacing:-.03em; max-width:16ch;
}
.sec-head p{ color:var(--ink-2); font-size:1.02rem; line-height:1.6 }
.kicker{
  font-family:'Plex Mono',monospace; font-size:.7rem; font-weight:600;
  letter-spacing:.22em; text-transform:uppercase; color:var(--flare);
  display:block; margin-bottom:1.1rem;
}
@media (max-width:900px){ .sec-head{ grid-template-columns:1fr; padding-top:4.5rem } }

.how{ border-bottom:1px solid var(--rule-soft) }
.steps{ display:grid; grid-template-columns:repeat(3,1fr); padding-bottom:2.5rem }
.step{ padding:1.4rem 1.6rem 0; border-left:1px solid var(--rule-soft); position:relative }
.step:first-child{ border-left:0; padding-left:0 }
.step::before{ content:''; position:absolute; top:0; left:0; right:0; height:2px; background:var(--dot,var(--flare)) }
.step .n{
  font-family:'Plex Mono',monospace; font-size:.68rem; font-weight:600;
  letter-spacing:.16em; color:var(--ink-4); text-transform:uppercase; display:block; margin-bottom:.7rem;
}
.step h3{ font-size:1.16rem; font-weight:700; margin-bottom:.6rem }
.step p{ font-size:.92rem; color:var(--ink-3); line-height:1.58 }
code{
  font-family:'Plex Mono',monospace; font-size:.85em;
  color:var(--flare-hot); background:rgba(255,107,26,.09); padding:.08em .3em; border-radius:2px;
}
@media (max-width:760px){
  .steps{ grid-template-columns:1fr; gap:2rem }
  .step{ border-left:0; padding-left:0 }
}

/* ==========================================================================
   THE MACHINE

   The rack is ONE image. Each unit is a clip-path quad over it, and
   hovering lifts that quad out of its bay while the matching part image
   flies into the panel beside it.

   This is the third attempt at this section, and the first two are why it
   is built this way. A photograph of the real shelf was too dark and too
   cluttered, lifting a clipped band out of it read as a sticker peeling.
   A rack drawn in CSS 3D worked but could never look like hardware. What
   makes the same clip-path trick work here is the artwork: studio-lit,
   isolated, and on a flat near-black ground that matches the page, so a
   lifted band has clean edges and the bay behind it is genuinely dark.
   ========================================================================== */
.machine{ border-bottom:1px solid var(--rule-soft) }
.hint-inline{ color:var(--ink); font-weight:600 }

.rig-layout{
  display:grid; grid-template-columns:minmax(0,.86fr) minmax(0,1.14fr);
  gap:2rem 3.5rem; align-items:center; padding-bottom:7rem;
}

.rig{
  position:relative;
  /* visible, not hidden: a unit that slides past the edge of the frame is
     the whole effect. Hiding the overflow would trap it inside. */
  overflow:visible;
  z-index:1;
}
.rig-img{
  display:block; width:100%; height:auto;
  transition:filter .45s ease;
  /* The renders sit on their own near-black, which is not the page's
     near-black, so an unmasked image shows as a faintly lighter rectangle.
     Feathering all four edges makes the box disappear entirely, and is why
     none of these assets needed a transparent cutout. */
  -webkit-mask-image:
    linear-gradient(to right,  transparent 0, #000 7%, #000 93%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 6%, #000 94%, transparent 100%);
  mask-image:
    linear-gradient(to right,  transparent 0, #000 7%, #000 93%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 6%, #000 94%, transparent 100%);
  -webkit-mask-composite:source-in; mask-composite:intersect;
}
/* Deliberately NO brightness filter on the base image. Dimming it darkened
   its background BELOW the page colour, which reinstated the very rectangle
   the black-point match had just removed. The seam came back the moment
   something touched the image as a whole. Focus is carried by the lifted
   part brightening and casting a shadow, not by everything else dimming. */
.rig-veil{
  position:absolute; inset:0; pointer-events:none;
  background:rgba(5,8,13,.26);
  opacity:0; transition:opacity .45s ease;
  /* the same feather as the image, so the veil has no visible edge either */
  -webkit-mask-image:
    linear-gradient(to right,  transparent 0, #000 7%, #000 93%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 6%, #000 94%, transparent 100%);
  mask-image:
    linear-gradient(to right,  transparent 0, #000 7%, #000 93%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 6%, #000 94%, transparent 100%);
  -webkit-mask-composite:source-in; mask-composite:intersect;
}
.rig.focused .rig-veil{ opacity:1 }

.layers{ position:absolute; inset:0; pointer-events:none }

.socket{
  position:absolute; inset:0; clip-path:var(--clip);
  background:linear-gradient(100deg,#04070A,#0A1017 55%,#04070A);
  box-shadow:inset 0 0 40px rgba(0,0,0,.95);
  opacity:0;
  /* Delayed on the way in so the part appears to LEAVE before the bay is
     empty. Without the delay the slot goes dark and the render arrives
     separately, and the two never read as one movement. */
  transition:opacity .45s ease .14s;
}
.socket.on{ opacity:1 }
/* The monitor is not in a bay and cannot be extracted from one, so it gets a
   rim of light instead of a hole. */
.socket[data-p="screen"]{
  /* A WASH, not an inset shadow. An inset box-shadow hugs the element's own
     box, and this element is inset:0 over the whole rack, so clip-path
     then removes all of it except where the polygon happens to touch the
     rack's outer edge, i.e. nothing. Same family as the filter/clip-path
     fight: anything that draws from the box's geometry is lost to the clip.
     A background fills the clipped shape itself and survives.

     The screen is also the one part with no isolated render and nothing to
     extract: it is the view INTO the machine, not a component you pull out
     of it, so it lights up where the others leave a hole. */
  background:radial-gradient(120% 110% at 50% 45%, rgba(255,150,80,.22), rgba(255,107,26,.07) 70%, transparent);
  box-shadow:none;
  mix-blend-mode:screen;
  transition:opacity .35s ease;
}

/* ---- the part, actually slid out of the rack ----------------------------
   Two renders of the same rack are never pixel-registered (measured at RMSE
   4.95% between these two) but all of that drift is invisible at the size
   this displays, and the one place it could show is the overlay's boundary,
   which is feathered. Judging that metric instead of judging the result is
   what made an earlier pass reject this idea outright. */
.out{
  position:absolute; pointer-events:none; height:auto;
  opacity:0; transition:opacity .5s cubic-bezier(.2,.8,.3,1);
}
.out.on{ opacity:1 }
.out[data-p="patch"]{ left:-7.07%; top:10.14%; width:79.87% }
.out[data-p="switch"]{ left:-0.84%; top:19.38%; width:73.59% }
.out[data-p="node1"]{ left:-6.0%; top:29.9%; width:78.72% }
.out[data-p="node2"]{ left:-3.2%; top:39.8%; width:76.0% }
.out[data-p="node3"]{ left:0.0%; top:56.72%; width:72.82% }
.out[data-p="macmini"]{ left:-0.6%; top:75.05%; width:73.33% }

.hit{
  position:absolute; inset:0; clip-path:var(--clip);
  padding:0; border:0; background:transparent; cursor:pointer;
  -webkit-appearance:none; appearance:none;
}
.hit:focus{ outline:none }
.hit:focus-visible{ background:rgba(255,107,26,.28) }

/* Per-unit geometry, calibrated by overlaying these polygons on the render
   and looking. Move one by re-overlaying, not by arithmetic. */
.rig [data-p="patch"]  { --clip:polygon(3.8% 15.4%, 65.1% 16.3%, 65.1% 21.8%, 3.8% 22.5%);  --cx:34.5%; --cy:19.0% }
.rig [data-p="switch"] { --clip:polygon(4.1% 24.7%, 64.7% 25.5%, 64.7% 32.3%, 4.1% 32.9%);  --cx:34.4%; --cy:28.9% }
.rig [data-p="node1"]  { --clip:polygon(5.8% 35.2%, 63.1% 36.0%, 63.1% 42.6%, 5.8% 43.4%);  --cx:34.5%; --cy:39.3% }
.rig [data-p="node2"]  { --clip:polygon(5.8% 44.3%, 63.1% 45.1%, 63.1% 51.8%, 5.8% 52.6%);  --cx:34.5%; --cy:48.5% }
.rig [data-p="node3"]  { --clip:polygon(6.2% 62.0%, 63.3% 62.8%, 63.3% 69.7%, 6.2% 70.5%);  --cx:34.8%; --cy:66.3% }
.rig [data-p="macmini"]{ --clip:polygon(6.7% 80.3%, 63.6% 81.1%, 63.6% 88.4%, 6.7% 89.2%);  --cx:35.2%; --cy:84.8% }
/* The monitor is not in a bay, so it leans the other way and barely moves;
   a screen sliding out of a rack slot would be a lie. */
.rig [data-p="screen"] { --clip:polygon(69.9% 10.8%, 97.4% 14.1%, 96.4% 87.1%, 69.6% 89.6%); --cx:83.3%; --cy:50.4%;
                         --lift-x:3%; --lift-y:-.8%; --lift-s:1.02 }

.rack-hint{
  position:absolute; left:0; right:0; bottom:-2.2rem; text-align:center;
  font-family:'Plex Mono',monospace; font-size:.68rem; letter-spacing:.16em;
  text-transform:uppercase; color:var(--ink-4);
  transition:opacity .3s ease;
}
.rig.focused .rack-hint{ opacity:0 }

/* ---- the panel: cards stacked in one grid cell, cross-faded ---- */
/* Above the rack: the part image starts inside the rack's box and travels
   out of it, so the panel it lives in has to paint on top. */
.specs{ display:grid; position:relative; z-index:2 }
.spec{
  grid-area:1/1;
  /* Hug their own content. Stacked in one grid cell they would otherwise all
     stretch to the tallest of them, giving the short cards a long empty tail
     below the text. */
  align-self:start;
  border:1px solid var(--rule-soft); border-left:2px solid var(--flare);
  background:linear-gradient(160deg, rgba(13,19,27,.92), rgba(11,16,23,.8));
  padding:1.8rem 2rem 2.1rem;
  opacity:0; visibility:hidden;
  transition:opacity .35s ease, visibility .35s;
  pointer-events:none;
}
/* NO transform on the card, deliberately. The flight is measured against the
   part image's resting rectangle, and a card that is itself mid-transform
   reports a moving target: the render would land a few pixels off, every
   time, differently. The card fades; the image moves. */
.spec.on{ opacity:1; visibility:visible }

/* The part images are lit on flat black, and so is the card, so no cutout
   is needed at all. A soft radial mask feathers the last few pixels and the
   rectangle disappears entirely. */
.phero{
  display:block; width:100%; height:auto; margin:-.6rem 0 1rem;
  /* The renders sit on their own near-black, which is not the page's
     near-black, so an unmasked image shows as a faintly lighter rectangle.
     Feathering all four edges makes the box disappear entirely, and is why
     none of these assets needed a transparent cutout. */
  -webkit-mask-image:
    linear-gradient(to right,  transparent 0, #000 7%, #000 93%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 6%, #000 94%, transparent 100%);
  mask-image:
    linear-gradient(to right,  transparent 0, #000 7%, #000 93%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 6%, #000 94%, transparent 100%);
  -webkit-mask-composite:source-in; mask-composite:intersect;
  /* The resting state. app.js measures this rectangle, then throws the image
     back to its bay in the rack, small, tilted and out of focus, and lets
     it return here. A long ease-out with almost no ease-in is what makes it
     read as weight rather than as a slide. */
  transition:
    transform .95s cubic-bezier(.16,.86,.26,1),
    opacity   .45s ease,
    filter    .75s cubic-bezier(.2,.8,.3,1);
  will-change:transform, filter;
}

.spec .tag{
  font-family:'Plex Mono',monospace; font-size:.68rem; font-weight:600;
  letter-spacing:.2em; text-transform:uppercase; color:var(--flare);
  display:block; margin-bottom:.8rem;
}
.spec h3{ font-size:1.45rem; font-weight:800; font-stretch:108%; letter-spacing:-.025em; margin-bottom:.8rem }
.spec > p{ color:var(--ink-2); font-size:.94rem; line-height:1.6; margin-bottom:1.3rem }
.spec dl{
  margin:0; display:grid; grid-template-columns:auto 1fr; gap:.5rem 1.4rem;
  border-top:1px solid var(--rule-soft); padding-top:1.2rem;
}
.spec dt{
  font-family:'Plex Mono',monospace; font-size:.72rem; letter-spacing:.06em;
  color:var(--ink-4); text-transform:uppercase; align-self:center;
}
.spec dd{ margin:0; font-size:.93rem; font-weight:600; font-variant-numeric:tabular-nums }
.spec .foot{
  margin-top:1.2rem; padding-top:1.1rem; border-top:1px solid var(--rule-soft);
  font-size:.84rem; color:var(--ink-4); line-height:1.55;
}

/* ---- the real shelf, as proof that the render is drawn from something ---- */
@media (max-width:940px){
  .rig-layout{ grid-template-columns:1fr; gap:3.2rem }
  .rig{ max-width:420px; margin:0 auto; width:100% }
  .spec{ padding:1.5rem }
}

/* ==========================================================================
   What you get
   ========================================================================== */
.grid{
  display:grid; grid-template-columns:repeat(3,1fr);
  border-top:1px solid var(--rule-soft); border-left:1px solid var(--rule-soft);
}
.cell{
  padding:2rem 1.9rem 2.1rem;
  border-right:1px solid var(--rule-soft); border-bottom:1px solid var(--rule-soft);
  background:linear-gradient(180deg, rgba(24,35,47,.3), transparent 65%);
  transition:background .28s ease;
}
.cell:hover{ background:linear-gradient(180deg, rgba(24,35,47,.72), rgba(24,35,47,.14) 70%) }
.cell .ic{ display:block; width:26px; height:26px; margin-bottom:1.1rem; color:var(--flare) }
.cell h3{ font-size:1.08rem; font-weight:700; margin-bottom:.6rem }
.cell p{ font-size:.92rem; color:var(--ink-3); line-height:1.58 }
@media (max-width:900px){ .grid{ grid-template-columns:1fr 1fr } }
@media (max-width:600px){ .grid{ grid-template-columns:1fr } }

.soon-wrap{ padding:4rem 0 5rem }
.soon-head{
  display:flex; align-items:baseline; gap:1rem; flex-wrap:wrap;
  padding-bottom:1.5rem; margin-bottom:2rem; border-bottom:1px solid var(--rule-soft);
}
.soon-head h3{ font-size:1.16rem; font-weight:700 }
.soon-head p{ font-size:.86rem; color:var(--ink-4) }
.soon{ display:flex; flex-wrap:wrap; gap:.7rem }
.chip{
  display:inline-flex; align-items:center; gap:.62rem;
  padding:.66rem 1rem; border-radius:3px;
  border:1px dashed var(--rule); background:rgba(19,28,39,.42);
  color:var(--ink-4); font-size:.88rem; font-weight:500;
  cursor:not-allowed; user-select:none;
}
/* No per-chip "Coming soon" label: the heading directly above says it once,
   and repeating it eight times under a heading that already says it is noise.
   What marks these as unavailable is the treatment, dashed border, muted ink,
   not-allowed cursor, and aria-disabled for anything not looking at it. */

/* ==========================================================================
   Invite + footer
   ========================================================================== */
.invite{
  border-top:1px solid var(--rule-soft); text-align:center;
  background:radial-gradient(120% 150% at 50% 130%, rgba(255,107,26,.13), transparent 58%), var(--night);
}
.invite .shell{ padding:7rem 0 7.5rem }
.invite h2{
  font-size:clamp(2rem,1.3rem + 2.6vw,3.6rem); font-weight:850; font-stretch:114%;
  letter-spacing:-.032em; margin:0 auto 1.2rem; max-width:18ch;
}
.invite p{ color:var(--ink-2); max-width:48ch; margin:0 auto 2.4rem; font-size:1.04rem }
.invite .btn{ padding:.9rem 1.7rem; font-size:.98rem }
.invite .fine{
  font-family:'Plex Mono',monospace; font-size:.7rem; letter-spacing:.11em;
  text-transform:uppercase; color:var(--ink-4); margin-top:2rem;
}

footer{ border-top:1px solid var(--rule-soft); background:#080C12 }
footer .shell{
  padding:2.6rem 0; display:flex; gap:1.6rem 2.4rem; align-items:center; flex-wrap:wrap;
  font-size:.82rem; color:var(--ink-4);
}
footer .brand{ font-size:.9rem }
footer .brand b{ color:var(--ink-2) }
footer .sp{ margin-left:auto }
footer .status{ display:inline-flex; align-items:center; gap:.5rem; letter-spacing:.08em }
footer .status s{
  width:6px; height:6px; border-radius:50%; background:var(--live);
  box-shadow:0 0 8px var(--live); text-decoration:none;
}

.rise{ opacity:0; transform:translateY(20px) }
.rise.in{ opacity:1; transform:none; transition:opacity .7s ease, transform .7s cubic-bezier(.25,.9,.3,1) }

/* ==========================================================================
   Motion off, every position stays, every movement goes. The rig still
   works: parts still lift, they just arrive rather than travel.
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  .grain{ animation:none }
  /* Cancelling the animations is not enough, each of these has a starting
     state the animation was going to undo, so the resting values have to be
     restored by hand or the mark renders half-drawn and missing its arrow. */
  .mark.animate .burst{ animation:none; transform:none }
  .haze .key,.haze .fill{ animation:none }
  .box.landing{ transform:translate3d(0,var(--y),0); opacity:1 }
  .box.landing.landed{ transition:none }
  .tag{ opacity:1 }
  /* No flight. The image simply appears where it belongs, app.js checks
     the same query and skips throwing it back to the rack at all. */
  .phero{ transform:none !important; filter:none !important; transition:opacity .2s ease }
  .rig{ animation:none }
  .spec{ transition:opacity .2s ease, visibility .2s }
  .spec.on{ transform:none }
  .rise{ opacity:1; transform:none; transition:none }
  .btn:hover{ transform:none }
}
