/**
 * lab3d.css — chapter 00's illustrated Experience Lab (js/lab3d.js).
 *
 * A real CSS 3D scene: .lab3d-world is tilted into an isometric view
 * (rotateX / rotateZ, leaning toward the pointer by --lab-tx / --lab-ty),
 * .lab3d-sway rocks it slowly around the floor's normal, and every box's
 * faces are lit from the upper left — the same light as the rest of the
 * site — with a touch of ambient occlusion where they meet the floor.
 * The room is the photographed Experience Lab, so its physical things
 * keep their real colours in both themes (navy carpet and print, white
 * walls, brushed steel, wood, GMP-yellow tape, the stack light) — set
 * once below as --lab-* — and the interface on top (pins, route, light
 * pools, screens) takes the palette tokens.
 *
 * Billboards (.lab3d-bb > .lab3d-billboard) undo the world's rotation so
 * pins and labels always face the camera; .lab3d-bb also undoes the sway,
 * on the same timing.
 *
 * Nothing that loops touches layout or paint: transform / opacity only.
 */

@property --lab-rx { syntax: '<angle>'; inherits: true; initial-value: 57deg; }
@property --lab-rz { syntax: '<angle>'; inherits: true; initial-value: -42deg; }
@property --lab-tx { syntax: '<angle>'; inherits: true; initial-value: 0deg; }
@property --lab-ty { syntax: '<angle>'; inherits: true; initial-value: 0deg; }

/* ── the hero has two columns: the words, and the room ──
   On desktop it fills the first screen (--hero-top: where it starts, from
   js/hero.js), the room takes the larger share, and a scroll cue sits at
   its foot, pointing at the planner just below the fold. */
.lab-hero.has-lab3d {
  max-width: none; display: grid; align-items: center;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.18fr); gap: clamp(8px, 3vw, 40px);
}
.lab-hero-copy { min-width: 0; }
.lab-hero-cue { display: none; }
@media (min-width: 901px) {
  .lab-hero.has-lab3d {
    min-height: calc(100svh - var(--hero-top, 112px));   /* the navy band reaches the bottom of the view */
    grid-template-rows: minmax(0, 1fr) auto; row-gap: 0;
  }
  /* the room, as large as the screen's height allows */
  .lab-hero.has-lab3d .lab3d { width: min(100%, calc((100svh - var(--hero-top, 112px) - 150px) / .86)); justify-self: end; }
  .lab-hero-cue {
    grid-column: 1 / -1; display: flex; align-items: center; gap: 14px;
    padding: 6px 0 2px; margin: 0;
    font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase;
    color: var(--text-faint);
  }
  .lab-hero-cue::after {
    content: ""; flex: 1; height: 1px;
    background: linear-gradient(90deg, color-mix(in srgb, var(--blue) 30%, transparent), transparent);
  }
  .cue-line { position: relative; width: 1px; height: 34px; overflow: hidden; background: color-mix(in srgb, var(--blue) 18%, transparent); }
  .cue-line::before {
    content: ""; position: absolute; left: 0; top: 0; width: 1px; height: 40%;
    background: var(--blue); animation: cue-fall 1.9s var(--ease-out-quart, ease-out) infinite;
  }
  .cue-num { color: var(--blue); font-weight: 700; }
}
@keyframes cue-fall { from { transform: translateY(-100%); } to { transform: translateY(250%); } }
@media (prefers-reduced-motion: reduce) { .cue-line::before { animation: none; transform: translateY(75%); } }

.lab3d {
  --lab-k: .8;
  --sway-dur: 11s;
  --ink: 12, 20, 52;                              /* shadow ink, as r,g,b */
  /* the room's own materials (the photo) */
  --lab-navy: var(--fw-s60); --lab-navy-hi: var(--fw-s40); --lab-navy-lo: var(--fw-s70);
  --lab-wall: #FBF8F1; --lab-wall-lo: #F2ECE0; --lab-side: #F3EEE3;   /* creamy white walls (user, 2026-10-12; were the pale aqua --fw-t90/t80) */
  --lab-carpet: var(--fw-s60); --lab-carpet-hi: var(--fw-s50);
  --lab-white: #FFFFFF; --lab-steel: var(--fw-t80);
  --lab-gmp: #F2C94C;                             /* GMP floor tape, the hazard stencil */
  --lab-ok: #34B36F;                              /* the stack light, the board's checks */
  position: relative; min-width: 0;
  transition: --lab-tx 900ms var(--ease-out-expo), --lab-ty 900ms var(--ease-out-expo);
}
.lab3d-stage {
  position: relative; width: 100%; aspect-ratio: 1 / .86;
  perspective: 2400px; perspective-origin: 50% 30%;
}
/* a soft pool of brand light behind the room */
.lab3d-stage::before {
  content: ""; position: absolute; inset: 6% 4% 0; border-radius: 50%; pointer-events: none;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--blue) 16%, transparent), transparent 72%);
}
.lab3d-world {
  position: absolute; left: 46%; top: 57%;
  transform-style: preserve-3d;
  /* --lab-cam: the camera rising on scroll-out; --lab-pitch / --lab-yaw:
     the visitor's drag while the room is locked (both js/hero.js) */
  transform: scale(var(--lab-k))
             rotateX(calc(var(--lab-rx) + var(--lab-ty) + var(--lab-pitch, 0deg) - var(--lab-cam, 0deg)))
             rotateZ(calc(var(--lab-rz) + var(--lab-tx) + var(--lab-yaw, 0deg)));
}
.lab3d-sway { position: absolute; inset: 0; transform-style: preserve-3d; }
.lab3d-caption {
  margin: 4px 0 0; text-align: center; font-family: var(--font-mono); font-size: 11.5px;
  color: var(--text-faint); letter-spacing: 0;
}

/* ══════════ boxes ══════════
   Faces: ft top · fs front (+y) · fw left (−x) · fn back · fe right.
   A material sets three tones (--c-top / --c-side / --c-front); the
   sides pick up ambient occlusion toward the floor. */
.b3 {
  position: absolute; left: var(--x); top: var(--y); width: var(--w); height: var(--d);
  transform-style: preserve-3d; transform: translateZ(var(--z));
}
.b3 > i { position: absolute; display: block; box-shadow: inset 0 0 0 .6px rgba(var(--ink), .10); }
.b3 > .ft { inset: 0; transform: translateZ(var(--h)); background-color: var(--c-top);
  box-shadow: inset 0 0 0 .6px rgba(var(--ink), .10), inset 1px 1px 0 rgba(255, 255, 255, .45); }
.b3 > .fs { left: 0; bottom: 0; width: 100%; height: var(--h); transform-origin: 50% 100%; transform: rotateX(-90deg);
  background-color: var(--c-front); background-image: linear-gradient(to top, rgba(var(--ink), .16), transparent 60%); }
.b3 > .fn { left: 0; top: 0; width: 100%; height: var(--h); transform-origin: 50% 0; transform: rotateX(90deg);
  background-color: var(--c-front); background-image: linear-gradient(to bottom, rgba(var(--ink), .16), transparent 60%); }
.b3 > .fw { left: 0; top: 0; width: var(--h); height: 100%; transform-origin: 0 50%; transform: rotateY(-90deg);
  background-color: var(--c-side); background-image: linear-gradient(to right, rgba(var(--ink), .14), transparent 60%); }
.b3 > .fe { right: 0; top: 0; width: var(--h); height: 100%; transform-origin: 100% 50%; transform: rotateY(90deg);
  background-color: var(--c-side); background-image: linear-gradient(to left, rgba(var(--ink), .14), transparent 60%); }

.m-body   { --c-top: var(--surface); --c-side: color-mix(in srgb, var(--surface) 86%, var(--navy)); --c-front: color-mix(in srgb, var(--surface) 74%, var(--navy)); }
.m-tile   { --c-top: var(--tile); --c-side: var(--tile-2); --c-front: color-mix(in srgb, var(--tile-2) 82%, var(--navy)); }
.m-dark   { --c-top: color-mix(in srgb, var(--chrome) 76%, #fff); --c-side: var(--chrome); --c-front: color-mix(in srgb, var(--chrome) 78%, #000); }
.m-accent { --c-top: color-mix(in srgb, var(--accent) 60%, #fff); --c-side: var(--accent); --c-front: color-mix(in srgb, var(--accent) 76%, #000); }
.m-glass  { --c-top: color-mix(in srgb, var(--accent) 45%, transparent); --c-side: color-mix(in srgb, var(--accent) 35%, transparent); --c-front: color-mix(in srgb, var(--accent) 30%, transparent); }
.m-cup    { --c-top: #FFFFFF; --c-side: var(--fw-t90); --c-front: var(--fw-t70); }
.m-carton { --c-top: var(--fw-t80); --c-side: var(--fw-t60); --c-front: var(--fw-t50); }
.m-carton > .ft { background-image: linear-gradient(90deg, transparent 44%, color-mix(in srgb, var(--blue) 45%, transparent) 44% 56%, transparent 56%); }
.m-white  { --c-top: var(--lab-white); --c-side: color-mix(in srgb, var(--lab-white) 84%, var(--lab-navy)); --c-front: color-mix(in srgb, var(--lab-white) 93%, var(--lab-navy)); }
.m-steel  { --c-top: var(--lab-steel); --c-side: color-mix(in srgb, var(--lab-steel) 72%, var(--lab-navy)); --c-front: color-mix(in srgb, var(--lab-steel) 84%, var(--lab-navy)); }
.m-steel > i { background-image: linear-gradient(to top, rgba(var(--ink), .12), rgba(255, 255, 255, .25)); }
.m-navy   { --c-top: var(--lab-navy-hi); --c-side: var(--lab-navy-lo); --c-front: var(--lab-navy); }
.m-wood   { --c-top: #DDA46A; --c-side: #A96E36; --c-front: #C2844A; }
.m-chair  { --c-top: var(--fw-s30); --c-side: var(--fw-s70); --c-front: var(--fw-s50); }
.m-beacon-g { --c-top: #7BE3A6; --c-side: #1F9A57; --c-front: var(--lab-ok); }
.m-beacon-a { --c-top: #B9A26E; --c-side: #7E6630; --c-front: #9A7D3C; }       /* amber and red: off */
.m-beacon-r { --c-top: #B97A7C; --c-side: #7C3A3E; --c-front: #96484C; }
/* the carpet: navy tiles laid at quarter turns, a slab with a light edge */
.m-carpet { --c-top: var(--lab-carpet); --c-side: var(--lab-side); --c-front: color-mix(in srgb, var(--lab-side) 88%, var(--lab-navy)); }
.m-carpet > .ft {
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .06);
  background:
    conic-gradient(rgba(255, 255, 255, .035) 25%, transparent 0 50%, rgba(255, 255, 255, .035) 0 75%, transparent 0) 0 0 / 44px 44px,
    repeating-linear-gradient(45deg, rgba(255, 255, 255, .025) 0 1px, transparent 1px 3px),
    radial-gradient(90% 80% at 45% 30%, var(--lab-carpet-hi), var(--lab-carpet) 70%);
}
.m-carpet > .fs, .m-carpet > .fw { box-shadow: inset 0 1px 0 color-mix(in srgb, var(--accent) 55%, transparent); }

/* details painted on faces */
.is-brushed > .ft { background-image:
  repeating-linear-gradient(90deg, rgba(255, 255, 255, .28) 0 1px, transparent 1px 3px),
  linear-gradient(125deg, rgba(255, 255, 255, .7), transparent 45%, rgba(255, 255, 255, .35) 70%, transparent); }
.is-desk > .fs { background-image: linear-gradient(transparent 32%, color-mix(in srgb, var(--blue) 40%, transparent) 32% 68%, transparent 68%); overflow: hidden; }
.is-keys > .ft { background-image: repeating-linear-gradient(90deg, rgba(255, 255, 255, .22) 0 2px, transparent 2px 3px); }
.is-printer > .fs { background-image: linear-gradient(transparent 30%, #fff 30% 40%, transparent 40%); }
.is-brochure > .ft { background-image: linear-gradient(transparent 18%, rgba(255, 255, 255, .8) 18% 26%, transparent 26% 34%, rgba(255, 255, 255, .45) 34% 40%, transparent 40%); background-size: 70% 100%; background-repeat: no-repeat; background-position: 30% 0; }
.is-lamp > .fs, .is-lamp > .fw { background: linear-gradient(#fff, var(--fw-t90)); box-shadow: 0 2px 10px rgba(var(--fw-t70-rgb), .8); }
.is-camera > .fs { background-image: radial-gradient(circle at 50% 55%, var(--fw-t40) 0 16%, var(--fw-s80) 18% 30%, transparent 32%); }
.is-stepover > .ft { background-image: linear-gradient(90deg, transparent 46%, var(--lab-gmp) 46% 54%, rgba(var(--ink), .08) 54%); }   /* clean side | dirty side */
.is-gown > .fs { background-image: linear-gradient(90deg, transparent 47%, rgba(var(--ink), .14) 47% 53%, transparent 53%), linear-gradient(to top, rgba(var(--ink), .1), transparent 40%); }
.is-bin > .fs { background-image: linear-gradient(transparent 20%, var(--fw-t40) 20% 34%, transparent 34%); }
.is-shield > i { box-shadow: inset 0 0 0 .8px rgba(255, 255, 255, .75); }
.is-beacon > i { animation: beacon 1.6s steps(1, end) infinite; }
.is-beacon > .fs { box-shadow: 0 0 8px var(--lab-ok); }
@keyframes beacon { 50% { opacity: .45; } }
.lamp-wash { position: absolute; inset: 0; background: radial-gradient(70% 90% at 50% 25%, rgba(var(--fw-t60-rgb), .45), transparent); }
.strip-run {                                         /* the pick light running along the desk edge */
  position: absolute; left: 0; top: 22%; width: 16%; height: 56%; border-radius: 2px;
  background: linear-gradient(90deg, transparent, #8FE6FF, transparent);
  animation: strip-run 2.8s var(--ease-in-out-smooth) infinite;
}
@keyframes strip-run { from { transform: translateX(-20%); } to { transform: translateX(620%); } }

/* screens: brand-blue glass with a little live data */
.b3 > .scr {
  background: linear-gradient(160deg, color-mix(in srgb, var(--blue) 80%, #fff) 0%, var(--blue) 40%, color-mix(in srgb, var(--blue) 45%, var(--fw-s90)) 100%);
  display: flex; align-items: flex-end; gap: 6%; padding: 10% 10% 12%; overflow: hidden;
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--chrome) 80%, #000), 0 0 18px color-mix(in srgb, var(--blue) 45%, transparent);
}
.scr-bar {
  flex: 1; height: 70%; border-radius: 1px; background: rgba(255, 255, 255, .78);
  transform-origin: 50% 100%; transform: scaleY(calc(.35 + .12 * var(--k)));
  animation: scr-bar 2.6s var(--ease-in-out-smooth) calc(var(--k) * -0.37s) infinite alternate;
}
@keyframes scr-bar { from { transform: scaleY(.25); } to { transform: scaleY(.95); } }
.scr-title { position: absolute; left: 8%; top: 9%; width: 36%; height: 6%; border-radius: 2px; background: rgba(255, 255, 255, .7); }
.scr-line  { position: absolute; left: 8%; right: 8%; top: 22%; height: 1px; background: rgba(255, 255, 255, .35); }
.scr-dot   { position: absolute; left: 20%; top: 22%; width: 18%; aspect-ratio: 1; border-radius: 50%;
  background: #fff; animation: scr-blink 1.6s steps(2, jump-none) infinite; }
@keyframes scr-blink { 50% { opacity: .25; } }
.scr-rows { flex: 1; align-self: stretch; background: linear-gradient(rgba(255, 255, 255, .9) 0 14%, transparent 14% 24%), repeating-linear-gradient(rgba(255, 255, 255, .55) 0 1.5px, transparent 1.5px 4px) 0 24% / 70% 76% no-repeat; }
.scr-read { flex: 1; align-self: center; height: 60%; background: repeating-linear-gradient(90deg, #8FF5C0 0 2px, transparent 2px 3px); opacity: .9;
  animation: scr-blink 2.4s steps(2, jump-none) infinite; }
/* the sampling dashboard: white, like the real one — a donut and two bar charts */
.b3 > .scr.is-dash {
  display: grid; grid-template: auto 1fr / repeat(3, 1fr); align-items: stretch; gap: 5%; padding: 5% 4% 6%;
  background: var(--fw-t90);
  box-shadow: inset 0 0 0 2px var(--fw-s80), 0 0 22px color-mix(in srgb, var(--blue) 40%, transparent);
}
.dash-top { grid-column: 1 / -1; font-size: 4.6px; font-weight: 700; color: var(--fw-s10); line-height: 1; white-space: nowrap; }
.dash-card { display: flex; align-items: flex-end; justify-content: center; gap: 9%; padding: 10% 9%; background: #fff; border-radius: 1.5px; box-shadow: inset 0 0 0 .6px var(--fw-t70); min-height: 0; }
.dash-card .scr-bar { background: var(--fw-s10); height: 80%; }
.dash-card:nth-child(3) .scr-bar:nth-child(2) { background: #F2B33D; }
.dash-card:nth-child(3) .scr-bar:nth-child(3) { background: #E5484D; }
.dash-donut {
  align-self: center; width: 78%; aspect-ratio: 1; border-radius: 50%;
  background: conic-gradient(var(--fw-s10) 0 36%, #F2994A 0 56%, var(--lab-ok) 0 78%, #E5484D 0);
  -webkit-mask: radial-gradient(circle, transparent 40%, #000 42%); mask: radial-gradient(circle, transparent 40%, #000 42%);
  animation: donut 14s linear infinite;
}
@keyframes donut { to { transform: rotate(360deg); } }

/* ══════════ walls ══════════ */
.lab3d-wall { position: absolute; left: 0; }
/* the feature wall, under its downlights */
.lab3d-wall.is-back {
  transform-origin: 50% 100%; transform: rotateX(-90deg);
  background: linear-gradient(180deg, var(--lab-wall) 0%, var(--lab-wall-lo) 100%);
  border-top: 4px solid color-mix(in srgb, var(--lab-wall) 70%, var(--lab-navy));      /* the wall's thickness */
  box-shadow: inset 0 -8px 0 color-mix(in srgb, var(--lab-wall) 80%, var(--lab-navy));  /* skirting */
}
.wall-cornice { position: absolute; left: 14%; right: 0; top: 0; height: 3.5%; background: var(--lab-navy); }
.wall-wash {                                          /* a downlight's wash down the wall */
  position: absolute; top: 3.5%; width: 15%; height: 70%; translate: -50% 0; pointer-events: none;
  background: radial-gradient(50% 60% at 50% 0, rgba(255, 248, 230, .95), rgba(255, 248, 230, .35) 45%, transparent 80%);
  mix-blend-mode: screen;
}
.wall-wash::before { content: ""; position: absolute; left: 50%; top: 0; width: 12%; height: 2.2%; translate: -50% 0; border-radius: 0 0 3px 3px; background: #FFF6DE; box-shadow: 0 0 6px #FFE9B0; }
.wall-wood {                                          /* the airlock: wood panels, a door, a gauge */
  position: absolute; left: 0; top: 0; bottom: 0; width: 14%;
  background:
    linear-gradient(90deg, rgba(0, 0, 0, .18) 0 1px, transparent 1px) 0 0 / 25% 100%,
    linear-gradient(rgba(0, 0, 0, .14) 0 1px, transparent 1px) 0 0 / 100% 34%,
    linear-gradient(100deg, #D9A064, #C78849 60%, #B9793C);
  box-shadow: inset -2px 0 0 rgba(0, 0, 0, .15);
}
.wall-door {
  position: absolute; left: 12%; width: 46%; top: 30%; bottom: 0;
  background: linear-gradient(100deg, #C17F42, #A96B33); box-shadow: inset 0 0 0 1.5px #8E5826;
}
.wall-door::after { content: ""; position: absolute; right: 10%; top: 52%; width: 22%; height: 2.5%; border-radius: 2px; background: var(--fw-t70); }
.wall-gauge {                                         /* the room's differential-pressure gauge */
  position: absolute; left: 26%; top: 17%; width: 18%; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle, #fff 0 52%, var(--lab-navy) 55% 62%, #fff 64%);
  box-shadow: inset 0 0 0 1px var(--fw-t20);
}
.wall-gauge::after { content: ""; position: absolute; left: 48%; top: 22%; width: 6%; height: 30%; background: #E5484D; transform-origin: 50% 100%; rotate: 35deg; }
.wall-warn {                                          /* a yellow warning sign */
  position: absolute; left: 68%; top: 40%; width: 18%; aspect-ratio: 1.1; background: #F2C94C;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.wall-sanitiser { position: absolute; left: 70%; top: 56%; width: 14%; height: 9%; border-radius: 2px; background: #fff; box-shadow: inset 0 -3px 0 var(--fw-s10); }
.wall-brand {
  position: absolute; left: 17%; top: 10%; display: grid; justify-items: end; line-height: 1;
  color: var(--lab-navy); padding-left: 5px; border-left: 1.5px solid var(--lab-navy);
}
.wbr-name { font-size: 8.5px; font-weight: 600; letter-spacing: .06em; }
.wbr-sub  { font-size: 3.4px; font-weight: 600; letter-spacing: .14em; margin-top: 1.5px; }
.wall-sign {
  position: absolute; left: 39%; top: 8%; display: flex; align-items: center; gap: 6px; white-space: nowrap;
  font-weight: 800; font-size: 19px; line-height: 1; letter-spacing: .01em; color: var(--lab-navy);
}
.wall-logo { display: block; width: 19px; height: 19px; }
.wall-logo svg { display: block; width: 100%; height: 100%; fill: none; stroke: var(--lab-navy); stroke-width: 2; stroke-linecap: round; }

/* the side partition: its face is turned so it reads along the wall
   (left → right runs back → front, top is up) */
.lab3d-wall.is-right {
  top: 0; transform-origin: 0 50%; transform: rotateY(-90deg);
  background: var(--lab-side);
  border-right: 4px solid color-mix(in srgb, var(--lab-side) 70%, var(--lab-navy));
}
.wall-face {
  position: absolute; left: 0; top: 0; transform-origin: 0 0; transform: rotate(90deg) translateY(-100%);
  background: linear-gradient(180deg, color-mix(in srgb, var(--lab-side) 92%, #fff), var(--lab-side));
  box-shadow: inset 0 -8px 0 color-mix(in srgb, var(--lab-side) 80%, var(--lab-navy));
}
.wall-face > span { position: absolute; }
.wall-windows {
  left: 3%; width: 26%; top: 8%; bottom: 20%;
  background:
    linear-gradient(90deg, var(--fw-t60) 0 2%, transparent 2% 98%, var(--fw-t60) 98%),
    repeating-linear-gradient(90deg, transparent 0 24%, var(--fw-t60) 24% 25.5%),
    linear-gradient(180deg, var(--fw-t80), var(--fw-t50));
  box-shadow: inset 0 0 0 2px var(--fw-t60);
}
.wall-board {                                         /* the Enterprise-Scale Reward board */
  left: 37%; width: 31%; top: 10%; height: 44%;
  display: flex; flex-direction: column; gap: 2.4px; padding: 5px 7px;
  background: linear-gradient(160deg, var(--lab-navy-hi), var(--lab-navy) 60%); color: #fff;
  box-shadow: 0 2px 4px rgba(var(--ink), .2);
}
.wb-title { font-size: 5.4px; font-weight: 700; margin-bottom: 1.5px; white-space: nowrap; }
.wb-item  { display: flex; align-items: center; gap: 3px; font-size: 4.2px; white-space: nowrap; }
.wb-item i { width: 4.4px; height: 4.4px; border-radius: 50%; background: var(--lab-ok); flex: none;
  -webkit-mask: radial-gradient(circle, #000 64%, transparent 66%); }
.wall-glassdoor {
  left: 80%; width: 15%; top: 18%; bottom: 0;
  background: linear-gradient(115deg, var(--fw-t70), var(--fw-t90) 40%, var(--fw-t60));
  box-shadow: inset 0 0 0 2px var(--fw-t30);
}
.wall-glassdoor::after { content: ""; position: absolute; left: 12%; top: 48%; width: 4%; height: 16%; background: var(--fw-t30); border-radius: 1px; }

/* ══════════ on the floor ══════════ */
.lab3d-route { position: absolute; inset: 0; }
.lab3d-route svg { width: 100%; height: 100%; overflow: visible; }
.lab3d-route polygon { fill: none; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.lab3d-route .lane      { stroke: rgba(var(--fw-t40-rgb), .10); stroke-width: 24px; }
.lab3d-route .lane-line { stroke: rgba(var(--fw-t50-rgb), .55); stroke-width: 1.5px; stroke-dasharray: 6 8; }
.floor-light {                                        /* a downlight's pool on the carpet */
  position: absolute; top: 0; width: 24%; height: 26%; translate: -50% 0; pointer-events: none;
  background: radial-gradient(50% 55% at 50% 10%, rgba(255, 244, 220, .16), transparent);
}

.lab3d-shade {                                        /* contact shadows, falling away from the light */
  position: absolute; pointer-events: none; border-radius: 30%;
  background: radial-gradient(closest-side, rgba(0, 0, 0, .42), rgba(0, 0, 0, .16) 62%, transparent);
  transform: translateZ(.2px);
}
.lab3d-shade.is-round { border-radius: 50%; background: radial-gradient(closest-side, rgba(0, 0, 0, .3), rgba(0, 0, 0, .1) 60%, transparent); }
.lab3d-tape {                                         /* GMP floor marking around each station */
  position: absolute; pointer-events: none; border-radius: 2px;
  border: 2px dashed color-mix(in srgb, var(--lab-gmp) 78%, transparent);
  transform: translateZ(.4px);
}
.lab3d-stencil {                                      /* GMP AREA · GOWNING REQUIRED */
  position: absolute; pointer-events: none; display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 7.5px; font-weight: 700; letter-spacing: .18em; white-space: nowrap;
  color: color-mix(in srgb, var(--lab-gmp) 85%, transparent);
  border: 1.5px solid color-mix(in srgb, var(--lab-gmp) 70%, transparent);
  background:
    repeating-linear-gradient(-45deg, color-mix(in srgb, var(--lab-gmp) 55%, transparent) 0 3px, transparent 3px 6px) left / 7% 100% no-repeat,
    repeating-linear-gradient(-45deg, color-mix(in srgb, var(--lab-gmp) 55%, transparent) 0 3px, transparent 3px 6px) right / 7% 100% no-repeat;
  transform: translateZ(.3px);
}
.lab3d-spill {                                        /* screen light on the floor */
  position: absolute; pointer-events: none;
  background: radial-gradient(60% 100% at 50% 0, color-mix(in srgb, var(--blue) 45%, transparent), transparent);
  transform: translateZ(.3px);
}
.lab3d-spill.is-lamp { background: radial-gradient(60% 100% at 50% 0, rgba(var(--fw-t70-rgb), .28), transparent); }
.lab3d-pool {
  position: absolute; width: calc(var(--r) * 2); height: calc(var(--r) * 2);
  translate: -50% -50%; border-radius: 50%; pointer-events: none; opacity: .12;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 55%, transparent), transparent);
  transform: translateZ(.5px);
}
.lab3d-pool.is-hover { opacity: 1 !important; }

/* ══════════ the operator ══════════ */
.lab3d-runner { position: absolute; left: 0; top: 0; transform-style: preserve-3d; }
.lab3d-runner-shade {
  position: absolute; width: 44px; height: 30px; translate: -40% -30%; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(var(--ink), .30), transparent);
  transform: translateZ(.6px);
}
.lab3d-runner-glow {
  position: absolute; width: 58px; height: 58px; translate: -50% -50%; border-radius: 50%;
  transform: translateZ(.8px);
}
.lab3d-runner-glow::after {                          /* a ring pulsing out: "live" */
  content: ""; position: absolute; inset: 18%; border-radius: 50%;
  border: 2px solid var(--accent); opacity: 0;
  animation: token-ring 2s var(--ease-out-quart) infinite;
}
@keyframes token-ring { from { opacity: .8; transform: scale(.4); } to { opacity: 0; transform: scale(1.5); } }

.lab3d-person {
  position: absolute; left: 0; top: 0; transform-style: preserve-3d;
  transform: rotateZ(var(--face, 0deg));
  transition: transform 520ms var(--ease-out-quart);   /* turning to face the way they go */
}
.p-body, .p-arm-l, .p-arm-r { position: absolute; left: 0; top: 0; transform-style: preserve-3d; }
.p-limb { position: absolute; transform-style: preserve-3d; }

/* gowned for the GMP area: coverall, hood, mask, nitrile gloves, overshoes */
.m-coat    { --c-top: #FFFFFF; --c-side: var(--fw-t80); --c-front: var(--fw-t90); }
.m-gown    { --c-top: var(--fw-t90); --c-side: var(--fw-t70); --c-front: var(--fw-t90); }
.m-bootie  { --c-top: var(--fw-t80); --c-side: var(--fw-t40); --c-front: var(--fw-t60); }
.m-hood    { --c-top: var(--fw-t90); --c-side: var(--fw-t50); --c-front: var(--fw-t70); }
.m-skin    { --c-top: #F0C7A8; --c-side: #D9A585; --c-front: #E6B696; }
.m-glove   { --c-top: var(--fw-t30); --c-side: var(--fw-s10); --c-front: var(--fw); }
.lab3d-person .b3 > i { box-shadow: none; }
.p-coat > .fs { background-image: linear-gradient(90deg, transparent 48%, rgba(var(--ink), .2) 48% 52%, transparent 52%),       /* the zip */
  radial-gradient(circle at 72% 28%, var(--blue) 0 7%, transparent 8%); }                                         /* the badge */
.p-head > .fs { background-image:
  radial-gradient(circle at 32% 36%, var(--fw-s60) 0 8%, transparent 9%),
  radial-gradient(circle at 68% 36%, var(--fw-s60) 0 8%, transparent 9%),
  linear-gradient(transparent 52%, var(--fw-t90) 52% 94%, transparent 94%); }                                          /* the mask */
.p-head > .fw, .p-head > .fe { background-image: linear-gradient(transparent 60%, var(--fw-t80) 60% 70%, transparent 70%); }   /* its strap */
.p-tote > .ft { background-image: linear-gradient(90deg, transparent 20%, rgba(255, 255, 255, .55) 20% 80%, transparent 80%); background-size: 100% 18%; background-repeat: no-repeat; background-position: 0 50%; }

/* walking: legs and the free arm swing in opposition, the body bobs */
.lab3d-person.is-walking .p-body { animation: p-bob .3s var(--ease-in-out-smooth) infinite alternate; }
.lab3d-person.is-walking .p-body > .p-limb:nth-child(1) { animation: p-swing .6s var(--ease-in-out-smooth) infinite alternate; }
.lab3d-person.is-walking .p-body > .p-limb:nth-child(2) { animation: p-swing .6s var(--ease-in-out-smooth) -.6s infinite alternate; }
.lab3d-person.is-walking .p-arm-l > .p-limb { animation: p-swing .6s var(--ease-in-out-smooth) -.6s infinite alternate; }
.lab3d-person.is-walking .p-arm-r > .p-limb { animation: p-carry .6s var(--ease-in-out-smooth) infinite alternate; }
@keyframes p-swing { from { rotate: x 28deg; } to { rotate: x -28deg; } }
@keyframes p-carry { from { rotate: x 8deg; }  to { rotate: x -4deg; } }
@keyframes p-bob   { from { translate: 0 0 0; } to { translate: 0 0 3px; } }
/* working at a station: the free hand reaches out and taps the screen */
.lab3d-person.is-working .p-arm-l > .p-limb { animation: p-work .55s var(--ease-in-out-smooth) infinite alternate; }
.lab3d-person.is-working .p-arm-r > .p-limb { rotate: x 14deg; transition: rotate .3s var(--ease-out-quart); }
@keyframes p-work { from { rotate: x 72deg; } to { rotate: x 96deg; } }

/* the batch label over the operator's head */
.lab3d-token-id {
  display: inline-flex; align-items: center; gap: 5px; translate: -50% -100%;
  font-family: var(--font-mono); font-size: calc(10px / var(--lab-k)); font-weight: 600; color: var(--navy-deep);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-pill); padding: 2px 8px 2px 6px;
  box-shadow: var(--shadow-sm); white-space: nowrap;
}
.id-dot { width: .65em; height: .65em; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim); }

/* ══════════ billboards: always facing the camera ══════════ */
.lab3d-bb {
  position: absolute; width: 0; height: 0; transform-style: preserve-3d;
  animation: lab3d-unsway var(--sway-dur) var(--ease-in-out-smooth) infinite alternate;
}
.lab3d-billboard {
  position: absolute; left: 0; top: 0; width: max-content;
  transform: rotateZ(calc(-1 * (var(--lab-rz) + var(--lab-tx) + var(--lab-yaw, 0deg))))
             rotateX(calc(-1 * (var(--lab-rx) + var(--lab-ty) + var(--lab-pitch, 0deg) - var(--lab-cam, 0deg))));
  transform-origin: 0 0;
}
.lab3d-sway { animation: lab3d-sway var(--sway-dur) var(--ease-in-out-smooth) infinite alternate; }
@keyframes lab3d-sway   { from { rotate: -5deg; } to { rotate: 5deg; } }
@keyframes lab3d-unsway { from { rotate: 5deg; }  to { rotate: -5deg; } }

/* the station pins: a compact numbered badge; the station's name rises
   above it on hover / focus, and while the operator works there */
.lab3d-pin {
  position: relative; display: inline-grid; place-items: center; translate: -50% -100%;
  padding: 4px; border-radius: 50%; text-decoration: none;
  font-size: calc(11px / var(--lab-k)); font-weight: 700; color: var(--navy-deep); white-space: nowrap;
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow-md);
  transition: transform var(--dur-fast) var(--ease-spring-physical), box-shadow var(--dur-fast) var(--ease-out-quart), border-color var(--dur-fast) var(--ease-out-quart);
}
.lab3d-pin::after {                                   /* the stalk down to the station */
  content: ""; position: absolute; left: 50%; top: 100%; width: 1.5px; height: calc(22px / var(--lab-k));
  background: linear-gradient(var(--navy), transparent); translate: -50% 0;
}
.pin-num {
  display: grid; place-items: center; width: 1.9em; height: 1.9em; border-radius: 50%;
  font-family: var(--font-mono); font-size: .85em; color: var(--on-blue); background: var(--blue);
  transition: box-shadow var(--dur-base) var(--ease-out-quart);
}
.pin-name {
  position: absolute; left: 50%; bottom: calc(100% + .5em); translate: -50% 5px; opacity: 0; pointer-events: none;
  padding: .3em .8em; border-radius: var(--radius-pill);
  background: var(--chrome); color: #fff; box-shadow: var(--shadow-md);
  transition: opacity var(--dur-base) var(--ease-out-quart), translate var(--dur-base) var(--ease-out-expo);
}
.lab3d-pin:hover, .lab3d-pin:focus-visible { transform: translateY(-4px) scale(1.08); border-color: var(--blue); box-shadow: var(--shadow-glow), var(--shadow-md); }
.lab3d-pin:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }
.lab3d-pin:is(:hover, :focus-visible, .is-active) .pin-name { opacity: 1; translate: -50% 0; }
.lab3d-pin.is-active .pin-num { box-shadow: 0 0 0 4px var(--accent-dim), 0 0 0 1.5px var(--accent); }
.lab3d.is-static .pin-name { opacity: 1; translate: -50% 0; }       /* nothing cycles: show every name */

/* the coffee's steam */
.steam {
  position: absolute; left: 0; top: 0; width: 8px; height: 22px; border-radius: 8px;
  background: linear-gradient(transparent, color-mix(in srgb, var(--surface) 80%, var(--blue)));
  translate: calc(-50% + (var(--k) - 1) * 7px) -100%; opacity: 0;
  animation: steam 2.8s var(--ease-out-quart) calc(var(--k) * .9s) infinite;
}
@keyframes steam {
  0%   { opacity: 0; transform: translateY(8px) scaleY(.6); }
  30%  { opacity: .75; }
  100% { opacity: 0; transform: translateY(-26px) scaleY(1.2); }
}
/* printed matter: the cart's plate, the roll-up, the totems */
.brand-plate { position: absolute; inset: 14% 9%; display: grid; align-content: center; justify-items: end; line-height: 1; color: var(--lab-navy); }
.bp-name { font-size: 7px; font-weight: 600; letter-spacing: .05em; padding-left: 3px; border-left: 1px solid var(--lab-navy); }
.bp-sub  { font-size: 3px; font-weight: 600; letter-spacing: .14em; margin-top: 1.5px; }
.banner-face { position: absolute; inset: 0; display: flex; flex-direction: column; padding: 9% 9% 7%; color: #fff; line-height: 1.15;
  background: linear-gradient(170deg, var(--lab-navy-hi), var(--lab-navy) 55%, var(--lab-navy-lo)); }
.bf-brand { font-size: 3.6px; font-weight: 600; letter-spacing: .06em; opacity: .9; }
.bf-title { font-size: 3.9px; font-weight: 700; margin: 8% 0 6%; }
.bf-list  { display: grid; gap: 3.4px; }
.bf-item  { display: flex; align-items: center; gap: 2px; font-size: 2.6px; white-space: nowrap; }
.bf-item i { width: 3.6px; height: 3.6px; flex: none; border-radius: 50%; box-shadow: inset 0 0 0 .6px var(--fw-t40); background: rgba(var(--fw-t40-rgb), .2); }
.bf-foot  { margin-top: auto; font-size: 2.4px; letter-spacing: .1em; text-transform: uppercase; opacity: .75; }
.totem-text {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: flex-start; gap: 3px; padding: 14% 0;
  writing-mode: vertical-rl; rotate: 180deg;
  font-size: 6.4px; font-weight: 700; letter-spacing: .18em; color: #fff;
}
.totem-mark { width: 4px; height: 4px; background: #fff; rotate: 45deg; }
.totem-text.is-side { writing-mode: horizontal-tb; rotate: none; flex-direction: row; justify-content: flex-start; padding: 0 0 0 14%; font-size: 5.6px; font-weight: 600; letter-spacing: .08em; }
/* plants: leaves on a billboard, standing in their pots */
.lab3d-leaves { position: absolute; left: 0; top: 0; width: var(--s); translate: -50% -94%; }
.lab3d-leaves svg { display: block; width: 100%; height: auto; }
.lf-a { fill: #3E9B5F; } .lf-b { fill: #2C7A48; } .lf-c { fill: #5DBA7D; }
/* the meeting table's round top */
.lab3d-disc { position: absolute; border-radius: 50%; pointer-events: none; }
.lab3d-disc.is-foot { background: var(--fw-t20); }
.lab3d-disc.is-edge { background: var(--fw-t60); }
.lab3d-disc.is-top  { background: radial-gradient(110% 110% at 30% 25%, #fff, var(--fw-t90)); box-shadow: inset 0 0 0 .6px rgba(var(--ink), .12); }
/* the IPC vials, reading in turn */
/* (opacity, not background-color: the compositor animates it, no repaint) */
.lab3d-vial > i { background-color: color-mix(in srgb, var(--accent) 90%, #fff); opacity: .35;
  animation: vial 2.4s var(--ease-in-out-smooth) calc(var(--k) * .8s) infinite; }
@keyframes vial { 40% { opacity: 1; } }

/* ══════════ the entrance: the room swings round, things rise, pins pop ══════════ */
.lab3d.is-in { animation: lab3d-intro 1.5s var(--ease-out-expo) both; }
@keyframes lab3d-intro {
  from { --lab-rz: -78deg; --lab-rx: 68deg; opacity: 0; }
  35%  { opacity: 1; }
}
.lab3d:not(.is-in):not(.is-static) { opacity: 0; }
.lab3d.is-in .lab3d-station {
  animation: lab3d-rise 900ms var(--ease-spring-physical) calc(450ms + var(--i) * 100ms) both;
}
@keyframes lab3d-rise { from { scale: 1 1 .02; } }
.lab3d.is-in .lab3d-pin { animation: lab3d-pop 600ms var(--ease-spring-physical) calc(1100ms + var(--i) * 90ms) both; }
@keyframes lab3d-pop { from { opacity: 0; transform: translateY(10px) scale(.6); } }
/* the operator pops in by scale only: an opacity animation on a 3D group
   would make the browser flatten it */
.lab3d.is-in .lab3d-person { animation: p-in 700ms var(--ease-spring-physical) 1400ms both; }
@keyframes p-in { from { scale: .02; } }
.lab3d.is-in .lab3d-token-id { animation: lab3d-pop 600ms var(--ease-spring-physical) 1600ms both; }
.lab3d-station { position: absolute; transform-style: preserve-3d; }

/* dark theme: the lights are down — deeper ink, the walls and the white
   furniture dimmed, the carpet darker; the gown stays a gown */
:root[data-theme="dark"] .lab3d {
  --ink: 0, 0, 0;
  --lab-wall: #E2DCCF; --lab-wall-lo: #D3CCBE; --lab-side: #D8D1C3;   /* the cream walls, lights down */
  --lab-carpet: var(--fw-s80); --lab-carpet-hi: var(--fw-s70);
  --lab-white: var(--fw-t80); --lab-steel: var(--fw-t50);
}

/* off screen: nothing moves */
.lab3d.is-paused, .lab3d.is-paused *, .lab3d.is-paused *::before, .lab3d.is-paused *::after { animation-play-state: paused !important; }

/* reduced motion: the finished room, still */
.lab3d.is-static *, .lab3d.is-static { animation: none !important; }
.lab3d.is-static .lab3d-pool { opacity: .35; }
.lab3d.is-static .lab3d-person { transition: none; }

/* ══════════ "Lock the room" (js/hero.js) ══════════
   Locked: the page stops, the drag turns the room, the sway holds still
   so the room stays where the hand put it, and every station names itself. */
.lab3d-lock {
  position: absolute; top: 4px; right: 4px; z-index: 2;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 11px 6px 9px; border-radius: var(--radius-pill);
  font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: .04em;
  color: var(--navy-deep); background: color-mix(in srgb, var(--surface) 86%, transparent);
  border: 1px solid var(--border); box-shadow: var(--shadow-sm); cursor: pointer;
  backdrop-filter: blur(6px);
  transition: background-color var(--dur-fast) var(--ease-out-quart), border-color var(--dur-fast) var(--ease-out-quart), color var(--dur-fast) var(--ease-out-quart);
}
.lab3d-lock::before {                               /* a small padlock dot */
  content: ""; width: 7px; height: 7px; border-radius: 2px;
  border: 1.5px solid currentColor; opacity: .7;
}
.lab3d-lock:hover { border-color: var(--blue); }
.lab3d-lock:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }
.lab3d.is-locked .lab3d-lock { background: var(--chrome); color: #fff; border-color: var(--chrome); }
.lab3d.is-locked .lab3d-lock::before { background: var(--accent); border-color: var(--accent); opacity: 1; }

.lab3d.is-locked .lab3d-stage { cursor: grab; touch-action: none; }
.lab3d.is-locked.is-dragging .lab3d-stage { cursor: grabbing; }
.lab3d.is-locked .lab3d-sway,
.lab3d.is-locked .lab3d-bb { animation-play-state: paused; }
.lab3d.is-locked .pin-name { opacity: 1; translate: -50% 0; }
.lab3d.is-dragging .lab3d-pin { pointer-events: none; }   /* a drag across a pin is not a click */

/* ══════════ smaller screens: the room sits under the words ══════════ */
@media (max-width: 900px) {
  .lab-hero.has-lab3d { grid-template-columns: 1fr; }
  .lab3d { max-width: 560px; width: 100%; justify-self: center; margin-top: 4px; }
}
@media (max-width: 480px) {
  .lab3d-caption { font-size: 10.5px; }
}

/* ══════════ phones: the room as a still (lab3d.js buildStill) ══════════
   One picture of this model with the pins and the stations' floor lights
   over it — a single layer, where the live room is ~670. It arrives as
   the live room does (the host fades in, the pins pop), then breathes:
   a few px of float, on the compositor, paused off screen. The pins sit
   at true size (--lab-k 1) and take a fingertip's reach. */
.lab3d.is-still { --lab-k: 1; }
.lab3d-still-room { position: absolute; inset: 0; }
.lab3d-still {
  position: absolute; display: block; max-width: none; height: auto;
  pointer-events: none; user-select: none; -webkit-user-drag: none;
}
.lab3d.is-still.is-in .lab3d-still-room {
  animation: still-in 1.4s var(--ease-out-expo) both, still-float 9s var(--ease-in-out-smooth) 1.4s infinite alternate;
}
@keyframes still-in { from { transform: translateY(14px) scale(.94); } }
@keyframes still-float { from { transform: translateY(0); } to { transform: translateY(-6px); } }
.lab3d-still-pin { position: absolute; width: 0; height: 0; }
.lab3d-still-pin .lab3d-pin::before { content: ""; position: absolute; inset: -10px; border-radius: 50%; }
.lab3d-still-pool {
  position: absolute; translate: -50% -50%; border-radius: 50%; pointer-events: none;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 55%, transparent), transparent);
  mix-blend-mode: screen; opacity: 0; transition: opacity .7s var(--ease-out-quart);
}
.lab3d-still-pool.is-lit { opacity: .9; }
.lab3d.is-static .lab3d-still-pool { opacity: .3; }
