/* ============================================================================
   ART DIRECTION: "DICHROIC"

   Futurism by way of thin-film interference rather than neon signage. Dichroic
   glass splits light into cyan and violet depending on the angle you catch it
   at, and that is the whole scheme: one spectrum, two temperatures, nothing
   borrowed from 1999 cyberpunk.

   Three devices carry it:
     1. Notched HUD chips instead of printed slabs. Cut corners, hairline
        borders, a spectral wash inside.
     2. A spectral wash for the ground. Atmosphere, not graph paper.
     3. The pointer as an optical source. It throws Newton's rings, the
        interference fringes a thin dichroic film actually produces, cyan at
        the core falling to violet at the edge.

   Deep blue-black ground, cool white type, cyan on the prices because that is
   the hottest information on the page, violet on structure, magenta reserved
   entirely for caution.
   ============================================================================ */

@font-face{
  font-family:"Big Shoulders";
  src:url("fonts/big-shoulders.woff2") format("woff2");
  font-weight:100 900;          /* variable axis: kinetic type is driven off this */
  font-display:swap;
  font-style:normal;
}

:root{
  color-scheme:dark;

  --void:#07080F;       /* deep blue-black, the ground */
  --slab:#10121F;       /* raised surfaces */
  --seam:#242945;       /* hairlines */
  --bone:#E8ECFF;       /* type */
  --fissure:#9B6BFF;    /* violet: structure, edges, seals */
  --ember:#48F2E2;      /* cyan: prices and primary action only */
  --jade:#5CE6B0;       /* mint, positives only */
  --ash:#8E95BF;        /* secondary type */
  --magenta:#FF5FA8;    /* caution only */

  /* legacy aliases, see the note above */
  --narra:var(--void); --narra-2:var(--slab); --narra-3:var(--seam);
  --capiz:var(--bone); --lamp:var(--ember); --sili:var(--fissure);
  --dahon:var(--jade); --dim:var(--ash);
  --sili-warn:var(--magenta);

  --disp:"Big Shoulders","Arial Narrow",system-ui,sans-serif;
  --body:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --mono:ui-monospace,"Cascadia Mono",Consolas,Menlo,monospace;

  /* 4/8 rhythm */
  --s1:8px; --s2:16px; --s3:24px; --s4:40px; --s5:64px; --s6:104px;
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--narra);color:var(--capiz);
  font:17px/1.65 var(--body);-webkit-font-smoothing:antialiased;
}
img{max-width:100%;display:block}
a{color:inherit}
h1,h2,h3,p,li,dt{overflow-wrap:break-word}
h1,h2,h3{text-wrap:balance}
a,button{touch-action:manipulation;-webkit-tap-highlight-color:rgba(72,242,226,.22)}
:focus-visible{outline:3px solid var(--lamp);outline-offset:3px}

.wrap{
  max-width:1180px;margin:0 auto;
  padding-left:max(22px,env(safe-area-inset-left));
  padding-right:max(22px,env(safe-area-inset-right));
}
.skip{position:absolute;left:-9999px;top:0;z-index:99;background:var(--lamp);color:var(--narra);
  padding:12px 20px;font:600 .8rem/1 var(--mono);text-decoration:none}
.skip:focus{left:12px;top:12px}

.eyebrow{font:600 .7rem/1 var(--mono);letter-spacing:.2em;text-transform:uppercase;color:var(--dim);margin:0 0 var(--s2)}

/* ---------------------------------------------------------------- lattice bar */
.bar{border-bottom:1px solid var(--narra-3);background:rgba(7,8,15,.88);backdrop-filter:blur(10px);
  position:sticky;top:0;z-index:20}
.bar .wrap{display:flex;align-items:center;gap:var(--s2);padding-top:12px;padding-bottom:12px}
/* DF monogram as an identification plate: bone slab, red seal edge, the same
   device as the section title cards so the mark and the page speak once. */
.mark{display:flex;align-items:center;gap:11px;text-decoration:none}
.mark .plate{
  display:inline-flex;align-items:center;color:var(--void);
  font-family:var(--disp);font-weight:800;font-size:1.32rem;line-height:1;
  letter-spacing:.02em;padding:7px 11px 6px;
  background:linear-gradient(135deg,var(--ember),var(--fissure));
  clip-path:polygon(0 0,calc(100% - 8px) 0,100% 8px,100% 100%,8px 100%,0 calc(100% - 8px));
}
.mark b{font-family:var(--disp);font-weight:700;font-size:1.22rem;letter-spacing:.03em;
  line-height:1;text-transform:uppercase;color:var(--bone)}
/* Workflo is the studio, the name is the person behind it. The byline is the
   quieter of the two and it is the first thing to go when the bar gets tight. */
.mark .by{font:600 .64rem/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;
  font-style:normal;color:var(--ash);padding-left:11px;border-left:1px solid var(--seam)}
@media (max-width:900px){.mark .by{display:none}}
.bar nav{margin-left:auto;display:flex;gap:var(--s3);font:600 .74rem/1 var(--mono);letter-spacing:.14em;text-transform:uppercase}
.bar nav a{color:var(--dim);text-decoration:none;padding:6px 0;border-bottom:2px solid transparent;transition:color .18s ease}
.bar nav a:hover{color:var(--capiz);border-bottom-color:var(--lamp)}
.bar .book{
  margin-left:var(--s3);color:var(--narra);background:var(--lamp);text-decoration:none;
  font:700 .72rem/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;
  padding:11px 16px;border-radius:2px;transition:background-color .16s ease;
}
.bar .book:hover{background:#7DF7EB}
/* Phones previously got no navigation at all. A short four-item nav does not
   need a hamburger; it needs to be visible. Wraps to its own scrollable row. */
@media (max-width:700px){
  .bar .wrap{flex-wrap:wrap;gap:10px}
  .bar .book{margin-left:auto}
  .bar nav{
    order:3;flex:1 0 100%;margin:0 -22px;padding:9px 22px 1px;gap:20px;
    border-top:1px solid var(--seam);overflow-x:auto;scrollbar-width:none;
  }
  .bar nav::-webkit-scrollbar{display:none}
  .bar nav a{white-space:nowrap;padding:4px 0 8px}
}

/* ============================================================== THE FISSURE
   The plates run cold until something heats them. A fractured lattice sits at
   the edge of visibility across the whole page; an identical copy, molten, is
   masked to a disc that follows the pointer. Three gradient angles rather than
   a square grid, so it reads as cracks in a shell instead of graph paper.
   ============================================================================ */
/* Ambient: a deep spectral wash so the ground is atmosphere, not graph paper. */
.field{
  position:fixed;inset:0;pointer-events:none;z-index:-2;
  background:
    radial-gradient(70% 54% at 8% 2%, rgba(155,107,255,.26), transparent 60%),
    radial-gradient(58% 50% at 94% 22%, rgba(72,242,226,.18), transparent 58%),
    radial-gradient(80% 58% at 44% 102%, rgba(255,95,168,.14), transparent 64%);
}

/* Pointer: Newton's rings. Thin-film interference is the actual physics behind a
   dichroic surface, so the cursor makes fringes rather than revealing a grid.
   The pattern travels WITH the element, which is why there is no
   background-attachment here: the rings are centred on the pointer, not the page. */
/* ========================================================== DISPERSION
   A prism separates light by wavelength, and it separates it more the harder
   you bend the beam. So the pointer is three colour channels stacked: at rest
   they sit on top of each other and read as one white-ish source, and the
   faster you move the further they slide apart, smearing into cyan, violet and
   magenta before snapping back together when you stop.

   The container also eases toward the pointer rather than tracking it exactly,
   which is what gives the whole thing weight. Everything here is transform and
   opacity, deliberately: the previous version put the signature effect on
   @property interpolation and it silently did nothing.
   ============================================================================ */
.torch{
  position:fixed;pointer-events:none;z-index:-1;
  left:0;top:0;width:460px;height:460px;margin:-230px 0 0 -230px;
  --x:50vw; --y:38vh; --sx:0px; --sy:0px;
  transform:translate3d(var(--x),var(--y),0);
  will-change:transform;
}
.torch i{
  position:absolute;inset:0;border-radius:50%;
  mix-blend-mode:screen;
  will-change:transform;
}
/* cyan leads, magenta trails, violet holds the centre */
.torch i.c{background:radial-gradient(circle at center,rgba(72,242,226,.55),rgba(72,242,226,.12) 34%,transparent 52%);
  transform:translate3d(calc(var(--sx) * -1),calc(var(--sy) * -1),0)}
.torch i.m{background:radial-gradient(circle at center,rgba(255,95,168,.48),rgba(255,95,168,.10) 34%,transparent 52%);
  transform:translate3d(var(--sx),var(--sy),0)}
.torch i.v{background:radial-gradient(circle at center,rgba(155,107,255,.50),rgba(155,107,255,.11) 32%,transparent 50%)}

/* Idle breath so the source is alive when the pointer is parked. */
@media (prefers-reduced-motion:no-preference){
  .torch i.v{animation:pulse 3.4s ease-in-out infinite alternate}
}
@keyframes pulse{from{transform:scale(.84);opacity:.7}to{transform:scale(1.06);opacity:1}}

/* Nothing to track on touch, so the source rests off-centre. The fringes still
   propagate, so it is alive without a pointer. */
@media (hover:none){
  .torch{--tx:78vw; --ty:26vh}
}

.window{position:relative;padding:var(--s5) 0 var(--s6);overflow:hidden}
/* The field is faint enough to sit under body copy, so the hero only needs a soft
   floor to seat the type on, not the heavy scrim the old solid panes required. */
.window::after{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,rgba(7,8,15,.5) 0%,rgba(7,8,15,.16) 42%,transparent 72%,var(--narra) 100%);
}
@media (max-width:820px){.window{padding-top:var(--s4)}}
@media (prefers-reduced-motion:no-preference){
  .field,.torch{animation:wake 1.3s ease-out backwards}
}
@keyframes wake{from{opacity:0}}

.window .wrap{position:relative;z-index:2}
.window h1{
  font-family:var(--disp);font-weight:750;
  font-size:clamp(2.5rem,7.4vw,5.4rem);line-height:.92;letter-spacing:-.008em;
  margin:0 0 var(--s3);text-transform:uppercase;max-width:17ch;
}
.window h1 .lit{
  color:var(--lamp);
  text-shadow:0 0 22px rgba(72,242,226,.22);   /* light through shell, not neon */
}
.window .rule{width:64px;height:2px;background:var(--lamp);margin:0 0 var(--s3);opacity:.8}
/* Kinetic type: the headline gains weight as the page is entered. Zero JS, and
   it degrades to a fixed weight where scroll timelines are unsupported. */
/* The variable-weight move used to be tied to scroll, where nobody saw it. It
   now happens on arrival, staggered with the rest of the hero. */
@media (prefers-reduced-motion:no-preference){
  .window .wrap > *{animation:heroIn .8s cubic-bezier(.2,.8,.25,1) backwards}
  .window .eyebrow{animation-delay:.06s}
  .window h1{animation:heroType 1s cubic-bezier(.2,.8,.25,1) .12s backwards}
  .window .rule{animation-delay:.5s}
  .window .lede{animation-delay:.58s}
  .window .cta{animation-delay:.68s}
  .window .note{animation-delay:.78s}
}
@keyframes heroIn{from{opacity:0;transform:translateY(20px)}}
@keyframes heroType{from{opacity:0;transform:translateY(26px);font-weight:300;letter-spacing:.06em}}

.window .lede{font-size:clamp(1.04rem,2.3vw,1.26rem);color:var(--dim);max-width:46ch;margin:0 0 var(--s4)}
.window .lede b{color:var(--capiz);font-weight:600}

.cta{display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.btn{
  display:inline-flex;align-items:center;min-height:48px;padding:14px 28px;
  font:700 .98rem/1 var(--body);text-decoration:none;border-radius:2px;
  transition:transform .16s ease,background-color .16s ease,color .16s ease;
}
.btn-lit{background:var(--lamp);color:var(--narra)}
.btn-lit:hover{background:#7DF7EB}
.btn-ghost{color:var(--capiz);box-shadow:inset 0 0 0 1px var(--narra-3)}
.btn-ghost:hover{background:var(--narra-2);box-shadow:inset 0 0 0 1px var(--lamp)}
.btn:active{transform:translateY(1px)}
.note{font:.76rem/1.5 var(--mono);color:var(--dim);margin:var(--s2) 0 0}

/* ---------------------------------------------------------------- sections */
.sec{padding:var(--s6) 0;border-top:1px solid var(--narra-3)}
/* A small label above each heading. Gives the page an index-like structure
   without resorting to 01 / 02 / 03, which every studio template already uses. */
/* The title card. White slab, heavy condensed type, red seal edge, monospace
   designation alongside. The one device the whole theme hangs on. */
.label{display:flex;align-items:center;flex-wrap:wrap;gap:8px 16px;margin:0 0 var(--s3)}
.label span{
  display:inline-flex;align-items:center;color:var(--bone);
  background:linear-gradient(135deg,rgba(72,242,226,.17),rgba(155,107,255,.12));
  box-shadow:inset 0 0 0 1px rgba(72,242,226,.42);
  font-family:var(--disp);font-weight:800;font-size:.82rem;
  letter-spacing:.11em;text-transform:uppercase;padding:6px 14px;
  clip-path:polygon(0 0,calc(100% - 9px) 0,100% 9px,100% 100%,9px 100%,0 calc(100% - 9px));
}
.label i{
  font-style:normal;font:600 .66rem/1.4 var(--mono);letter-spacing:.2em;
  text-transform:uppercase;color:var(--ash);
}
.sec h2{
  font-family:var(--disp);font-weight:750;text-transform:uppercase;
  font-size:clamp(2rem,5.2vw,3.5rem);line-height:.94;letter-spacing:-.012em;margin:0 0 var(--s2);
}
.sec .sub{color:var(--dim);max-width:58ch;margin:0 0 var(--s5)}

/* reveal-on-enter, scroll-timeline driven, guarded so unsupported browsers just show it */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .rise{animation:rise linear both;animation-timeline:view();animation-range:entry 0% entry 46%}
  }
}
@keyframes rise{from{opacity:0;transform:translateY(26px)}to{opacity:1;transform:none}}

/* ---------------------------------------------------------------- the board */
.board{
  background:var(--narra-2);border:1px solid var(--narra-3);border-radius:3px;
  padding:clamp(26px,4.4vw,52px);position:relative;overflow:hidden;
}
.board::before{                       /* lamp behind the shell */
  content:"";position:absolute;left:-10%;right:-10%;top:-60%;height:120%;
  background:radial-gradient(50% 50% at 50% 50%,rgba(72,242,226,.13),transparent 70%);
  pointer-events:none;
}
.board-head{display:flex;flex-wrap:wrap;gap:6px 16px;align-items:baseline;
  padding-bottom:var(--s3);border-bottom:1px solid rgba(72,242,226,.32);position:relative}
.board-head h2{color:var(--capiz);margin:0;font-size:clamp(1.6rem,3.8vw,2.5rem)}
.board-head .tl{font:600 .7rem/1 var(--mono);letter-spacing:.18em;text-transform:uppercase;color:var(--dim)}
.board-note{color:var(--dim);max-width:56ch;margin:var(--s3) 0 var(--s4);position:relative}

.line{padding:var(--s3) 0;border-bottom:1px solid rgba(233,237,243,.1);position:relative}
.line:last-of-type{border-bottom:0;padding-bottom:0}
.line-top{display:grid;grid-template-columns:1fr auto;gap:2px 14px;align-items:baseline}
.line-name{font-family:var(--disp);font-weight:700;font-size:clamp(1.3rem,3.4vw,1.75rem);
  text-transform:uppercase;letter-spacing:.01em;min-width:0}
.leader{display:none}
.line-price{font-family:var(--disp);font-weight:800;color:var(--lamp);
  font-size:clamp(1.5rem,4vw,2.1rem);white-space:nowrap;font-variant-numeric:tabular-nums}
@media (min-width:620px){
  .line-top{display:flex;gap:14px}
  .line-name{flex:0 1 auto}
  .leader{display:block;flex:1 1 24px;border-bottom:1px dotted rgba(233,237,243,.22);transform:translateY(-.3em);min-width:18px}
}
.line-desc{color:var(--dim);font-size:.96rem;margin:10px 0 0;max-width:62ch}
.stamp{display:inline-block;font:600 .68rem/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;
  color:var(--lamp);border:1px solid rgba(72,242,226,.38);padding:5px 10px;border-radius:2px;margin-top:14px}
.stamp.free{color:var(--narra);background:var(--dahon);border-color:var(--dahon)}

/* ---------------------------------------------------------------- work: bento */
/* Panel size carries importance, per the 2026 bento pattern. Two panels are
   double-width because they are the two the buyer should look at first. */
.bento{display:grid;grid-template-columns:repeat(6,1fr);gap:var(--s2)}
.card{position:relative;grid-column:span 6;background:var(--narra-2);border:1px solid var(--narra-3);border-radius:3px;
  display:flex;flex-direction:column;transition:border-color .2s ease,transform .2s ease}
.card:hover{border-color:var(--fissure);transform:translateY(-3px)}
/* HUD registration marks, on demand */
.card::before,.card::after{
  content:"";position:absolute;width:15px;height:15px;z-index:3;pointer-events:none;
  opacity:0;transition:opacity .2s ease;
}
.card::before{top:0;left:0;border-top:2px solid var(--ember);border-left:2px solid var(--ember)}
.card::after{bottom:0;right:0;border-bottom:2px solid var(--ember);border-right:2px solid var(--ember)}
.card:hover::before,.card:hover::after,
.card:focus-within::before,.card:focus-within::after{opacity:1}
@media (min-width:760px){
  .card{grid-column:span 2}
  .card.wide{grid-column:span 4}
  .card.half{grid-column:span 3}
}
/* Hover reveal, the pattern the Ceros survey kept turning up: the designation
   the card already carries, surfaced on demand instead of cluttering the grid.
   Comes from a data-desig attribute, so no extra markup per card. */
.card figure{margin:0;position:relative;background:var(--narra);overflow:hidden;aspect-ratio:16/10}
.card figure::after{
  content:attr(data-desig);
  position:absolute;left:0;bottom:0;
  background:var(--fissure);color:var(--void);   /* black on the seal: 4.99:1, white was 3.42:1 */
  font:700 .62rem/1 var(--mono);letter-spacing:.18em;text-transform:uppercase;
  padding:8px 12px;
  transform:translateY(100%);
  transition:transform .22s cubic-bezier(.2,.7,.3,1);
}
.card:hover figure::after,.card:focus-within figure::after{transform:none}
@media (prefers-reduced-motion:reduce){.card figure::after{transition:none}}
.card img{width:100%;height:100%;object-fit:cover;object-position:top;border-bottom:1px solid var(--narra-3);
  transition:transform .45s cubic-bezier(.2,.7,.3,1)}
.card video{width:100%;height:100%;object-fit:cover;object-position:center;display:block;
  border-bottom:1px solid var(--narra-3);background:var(--void)}
/* the caste line-ups are a 2.85:1 strip; in a 16:10 window they would sit in a bar of dead
   space, so those two figures take the clip's own shape and the pad crops away. */
.card figure.wideclip{aspect-ratio:57/20}

/* the interactive model. model-viewer paints its own canvas, so the slab and the hairline
   are ours and everything inside the box is the element's. */
.viewer{border:1px solid var(--seam);border-radius:3px;background:var(--slab);overflow:hidden;
  margin-bottom:var(--s5)}
.viewer model-viewer{display:block;width:100%;height:min(58vh,520px);
  --poster-color:transparent;background:var(--slab)}
/* before the element upgrades it is an unknown tag with no box of its own, so the still
   render stands in until the script has arrived. */
.viewer model-viewer:not(:defined){display:block;width:100%;height:min(58vh,520px);
  background:var(--slab) url("models/ant-poster.jpg") center/contain no-repeat}
.viewer-bar{display:flex;flex-wrap:wrap;align-items:center;gap:10px var(--s3);
  padding:12px var(--s3);border-top:1px solid var(--seam)}
.castes{display:flex;gap:8px}
.caste{font:700 .68rem/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;
  color:var(--ash);background:transparent;border:1px solid var(--seam);border-radius:2px;
  padding:10px 15px;cursor:pointer;
  transition:color .16s ease,border-color .16s ease,background-color .16s ease}
.caste:hover{color:var(--bone);border-color:var(--fissure)}
.caste.on{color:var(--void);background:var(--ember);border-color:var(--ember)}
.caste:focus-visible{outline:2px solid var(--ember);outline-offset:3px}
.viewer-hint{margin:0 0 0 auto;font:600 .64rem/1 var(--mono);letter-spacing:.14em;
  text-transform:uppercase;color:var(--ash)}
.viewer-note{margin:0;padding:4px var(--s3) 18px;color:var(--ash);font-size:.92rem;max-width:74ch}
.viewer-note b{color:var(--bone)}
@media (max-width:759px){.viewer-hint{margin:0}}
@media (max-width:759px){.viewer model-viewer{height:360px}}
.card:hover img{transform:scale(1.05)}
.card-body{padding:var(--s3) var(--s3) calc(var(--s3) + 4px)}
.card h3{font-family:var(--disp);font-weight:700;font-size:1.42rem;text-transform:uppercase;
  letter-spacing:.01em;margin:0 0 4px;line-height:1.05}
.kind{font:600 .66rem/1.5 var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--dim);margin:0 0 12px}
.kind b{color:var(--lamp);font-weight:700}
.card p{margin:0;font-size:.94rem;color:var(--dim)}

/* The three real builds open in a new tab. The line is the visible affordance; the
   pseudo-element stretches it over the whole card so the image is clickable too, and it
   sits under the ::before/::after registration marks (z-index 3) rather than over them. */
.visit{display:inline-block;margin-top:16px;font:700 .68rem/1 var(--mono);letter-spacing:.14em;
  text-transform:uppercase;color:var(--ember);text-decoration:none;
  border-bottom:1px solid transparent;padding-bottom:4px}
.visit::before{content:"";position:absolute;inset:0;z-index:2}
.visit::after{content:"\2009\2192"}
.card.is-live:hover .visit{border-bottom-color:var(--ember)}
.visit:focus-visible{outline:2px solid var(--ember);outline-offset:4px;border-radius:2px}

/* Secondary link on a card that already has a .visit. The .visit::before overlay
   stretches over the whole card at z-index 2 to make the image clickable, so
   anything meant to stay separately clickable has to sit above it. */
.note-link{
  position:relative;z-index:4;display:inline-block;margin-top:12px;
  font:600 .74rem/1.45 var(--body);color:var(--dim);text-decoration:none;
  border-bottom:1px solid var(--seam);padding-bottom:2px;
  transition:color .16s ease,border-color .16s ease;
}
.note-link:hover{color:var(--sili);border-bottom-color:var(--sili)}
.note-link::after{content:"\2009\2192"}
.note-link:focus-visible{outline:2px solid var(--sili);outline-offset:3px;border-radius:2px}
@media (prefers-reduced-motion:reduce){.card.is-live:hover img{transform:none}}

/* ---------------------------------------------------------------- steps */
.steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:var(--s4);counter-reset:s}
/* the capability list: nine short items, so it wants a tighter rhythm than the 3-step
   process grid it borrows from, and a rule under the stack note that closes the section. */
.caps{grid-template-columns:repeat(auto-fit,minmax(268px,1fr));gap:var(--s3) var(--s4)}
.caps .step h3{font-size:1.2rem}
.caps .step p{font-size:.92rem}
.sub.stack{margin-top:var(--s4);padding-top:var(--s3);border-top:1px solid var(--seam)}
.step{counter-increment:s}
.step::before{content:counter(s,decimal-leading-zero);display:block;font:700 .82rem/1 var(--mono);
  letter-spacing:.14em;color:var(--lamp);padding-bottom:12px;border-bottom:1px solid var(--narra-3);margin-bottom:16px}
.step h3{font-family:var(--disp);font-weight:700;font-size:1.4rem;text-transform:uppercase;margin:0 0 8px;line-height:1.05}
.step p{margin:0;color:var(--dim);font-size:.96rem}

/* ---------------------------------------------------------------- two columns */
.cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:var(--s5)}
.cols h3{font:600 .7rem/1 var(--mono);letter-spacing:.18em;text-transform:uppercase;color:var(--dim);margin:0 0 var(--s2)}
.cols ul{margin:0;padding:0;list-style:none}
.cols li{padding:12px 0 12px 28px;border-bottom:1px solid var(--narra-3);position:relative;font-size:.98rem}
.cols li::before{position:absolute;left:0;top:12px;font-family:var(--mono);font-weight:700}
.yes li::before{content:"+";color:var(--dahon)}
.add li{display:flex;gap:14px;align-items:baseline}
.add li::before{content:"+";color:var(--lamp)}
.add li b{flex:1;font-weight:400}
.add li span{font:700 .84rem/1 var(--mono);color:var(--lamp);white-space:nowrap;font-variant-numeric:tabular-nums}
.caveat{margin:var(--s4) 0 0;padding:var(--s3) var(--s3);border-left:2px solid var(--magenta);
  color:var(--dim);font-size:.95rem;max-width:72ch;background:rgba(255,95,168,.05)}
.caveat b{color:var(--capiz);font-weight:600}

/* ---------------------------------------------------------------- close */
.close{border-top:1px solid var(--narra-3);position:relative;overflow:hidden}
.close::before{content:"";position:absolute;left:50%;top:0;width:min(900px,120%);height:100%;
  transform:translateX(-50%);
  background:radial-gradient(60% 70% at 50% 0%,rgba(155,107,255,.14),transparent 70%);pointer-events:none}
.close .wrap{padding-top:var(--s6);padding-bottom:var(--s6);position:relative}
.close h2{font-family:var(--disp);font-weight:750;text-transform:uppercase;color:var(--capiz);
  font-size:clamp(1.9rem,4.8vw,3.2rem);line-height:.96;letter-spacing:-.006em;margin:0 0 var(--s3);max-width:20ch}
.close p{color:var(--dim);max-width:50ch;margin:0 0 var(--s4)}
.who{display:flex;gap:var(--s3);align-items:center;margin-top:var(--s5);padding-top:var(--s3);border-top:1px solid var(--narra-3)}
.who .photo{width:66px;height:66px;flex:none;border-radius:50%;background:var(--narra-2);
  border:1px dashed var(--narra-3);display:flex;align-items:center;justify-content:center;
  font:600 .52rem/1.25 var(--mono);color:var(--dim);text-align:center;padding:6px}
.who p{margin:0;font-size:.95rem}
footer{border-top:1px solid var(--narra-3)}
footer .wrap{padding:var(--s3) 22px var(--s5);font:.74rem/1.6 var(--mono);color:var(--dim);letter-spacing:.04em}

/* "Reduce" means reduce, not eliminate. Travel stops: no marquee scroll, no
   propagating fringes, no slide-in entrances, since those are the vestibular
   ones. What stays is a slow opacity breath, which is non-vestibular and keeps
   the page from reading as a dead screenshot for anyone with the OS setting on.
   Hover and focus feedback also stays; removing it makes a page feel broken. */
@media (prefers-reduced-motion:reduce){
  .band .track,.window .wrap > *,.window h1,.rise,.card figure::after{animation:none!important}
  .rise{opacity:1!important;transform:none!important}
  .card:hover img{transform:none}
  .torch i.c,.torch i.m{display:none}
  .torch{animation:softbreath 7s ease-in-out infinite alternate!important}
  .field{animation:softbreath 11s ease-in-out infinite alternate!important}
}
@keyframes softbreath{from{opacity:.5}to{opacity:1}}

/* Real client work takes the full width of the grid. */
@media (min-width:760px){.card.full{grid-column:span 6}}
/* A slot that reads as reserved rather than broken while a screenshot is missing. */
.pending{
  display:flex;flex-direction:column;justify-content:center;gap:6px;
  min-height:170px;padding:var(--s3);
  background:
    repeating-linear-gradient(-45deg,rgba(155,107,255,.07) 0 12px,transparent 12px 24px),
    var(--slab);
  border-bottom:1px solid var(--seam);
}
.pending b{font-family:var(--disp);font-weight:800;text-transform:uppercase;font-size:1.15rem;letter-spacing:.03em}
.pending span{font:600 .68rem/1.5 var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ash)}


/* =============================================================== SEAM BAND
   A full-bleed break in the rhythm, and the one place the fissure is stated at
   scale instead of only appearing under the cursor. The page was nine identical
   containers in a row; this interrupts it twice.
   ============================================================================ */
.band{
  position:relative;overflow:hidden;
  border-top:1px solid var(--seam);border-bottom:1px solid var(--seam);
  background:
    repeating-linear-gradient(90deg,rgba(72,242,226,.3) 0 1px,transparent 1px 84px),
    linear-gradient(90deg,rgba(155,107,255,.20),rgba(72,242,226,.14),rgba(255,95,168,.16),rgba(155,107,255,.20)),
    var(--void);
  padding:16px 0;
}
.band .track{display:flex;width:max-content}
.band .track span{
  white-space:nowrap;padding-right:0;
  font:700 .74rem/1 var(--mono);letter-spacing:.34em;text-transform:uppercase;
  color:var(--bone);opacity:.92;
}
@media (prefers-reduced-motion:no-preference){
  .band .track{animation:marquee 30s linear infinite}
}
@keyframes marquee{to{transform:translateX(-50%)}}

/* ============================================================== TOOL ROWS
   The tools used to repeat the sample-site grid card for card, so the page said
   the same visual sentence twice. A dense list changes the pace and is honest
   about these being secondary, while the thumbnails keep the evidence.
   ============================================================================ */
.rows{border-top:1px solid var(--seam)}
.row{
  display:grid;grid-template-columns:132px 1fr auto;gap:4px 22px;align-items:start;position:relative;
  padding:18px 0;border-bottom:1px solid var(--seam);
}
.row img{grid-row:1/3;width:132px;height:84px;object-fit:cover;object-position:top;border:1px solid var(--seam)}
.row h3{font-family:var(--disp);font-weight:700;font-size:1.34rem;text-transform:uppercase;
  letter-spacing:.01em;margin:0;line-height:1.05;align-self:center}
.row .t{font:600 .64rem/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--ash);align-self:center;white-space:nowrap}
.row .visit{grid-column:2/4;margin-top:10px;font-size:.64rem}
.row p{grid-column:2/4;margin:0;color:var(--ash);font-size:.94rem;max-width:74ch}
@media (max-width:640px){
  .row{grid-template-columns:96px 1fr;gap:4px 16px}
  .row img{width:96px;height:62px}
  .row .t{grid-column:2;align-self:start;margin-top:2px}
  .row h3{align-self:start}
  .row p{grid-column:1/3;margin-top:8px}
}

/* The reserved slot must not inherit the 16:10 card ratio, or a full-width card
   with no screenshot yet stretches into 700px of empty stripes. */
.card figure.reserved{aspect-ratio:auto}

/* ---------- picture to 3D to AR: the AR call to action ----------
   model-viewer only reveals this button when the device can actually place the
   model, so it is invisible on desktop by design. */
.ar-cta {
  position: absolute;
  right: 14px;
  bottom: 14px;
  min-height: 44px;
  padding: 0 18px;
  border: 0;
  border-radius: 2px;
  background: #f4f1ea;
  color: #14110f;
  font: 600 12px/44px "IBM Plex Mono", ui-monospace, monospace;
  letter-spacing: .12em;
  text-transform: uppercase;
  cursor: pointer;
}

.ar-cta:hover { background: #fff; }
