/* ── HERO · CABINET ("Pull the drawer") ─────────────────────────────────────
   A steel filing cabinet built from flat CSS planes in one 3D rendering
   context. Every face is an ink-outlined rectangle; nothing is an image.

   Units: the whole model is drawn in --u, a length derived from the stage's
   own size (container query units), so it scales as one object instead of
   reflowing. Numbers below are "u" in the model: the cabinet is 440u wide,
   410u tall and 280u deep.

   State lives in three custom properties, all set on .hcab-scene:
     --pull-base    0 closed / 1 open. 1 without JS and for reduced motion.
     --pull-js      the physics (hero-cabinet.js) when it has taken over.
     --pull-junk    the stuck bottom drawer.
   With JavaScript, the top drawer starts shut and opens once on entrance. */

.hero--cabinet { --pull-base: 1; }
[data-js] .hero--cabinet { --pull-base: 0; }
@media (prefers-reduced-motion: reduce) {
  [data-js] .hero--cabinet { --pull-base: 1; }
}

/* ── the stage: the blue blueprint panel the object sits on ── */
/* overflow: clip, not hidden: hidden would make the hero a scroll container
   and the stage's view timeline would bind to it and never move. */
.hero.hero--cabinet { overflow: clip; }
.hero--cabinet .hcab-stage {
  position: relative; overflow: clip; container-type: size;
  background: var(--blue); border-left: var(--border);
  /* One model unit. The model is designed on a 690 x 740 board. */
  --u: min(calc(100cqw / 690), calc(100cqh / 740));
  --b: max(2px, calc(3 * var(--u)));
  --lit: color-mix(in srgb, var(--steel) 45%, #fff);
  --shade: #9ba6ad;
  --deep: #7e8a92;
}
.hero--cabinet .hcab-stage::before {
  content: ""; position: absolute; inset: 0; opacity: .13; pointer-events: none;
  background-image:
    repeating-linear-gradient(90deg, transparent 0 32px, rgba(23,25,22,.5) 33px 34px),
    repeating-linear-gradient(0deg, transparent 0 32px, rgba(23,25,22,.35) 33px 34px);
}

.hero--cabinet .hcab-scene {
  --p1: var(--pull-js, var(--pull-base));
  --p2: var(--pull-junk, 0);
  position: absolute; inset: 0;
  perspective: calc(1900 * var(--u));
  perspective-origin: 48% 38%;
  /* The house shadow, cast by the whole silhouette as it moves. */
  filter: drop-shadow(calc(16 * var(--u)) calc(20 * var(--u)) 0 var(--shadow));
}

/* Camera: a little above, a little to the right. The tip wrapper rocks the
   carcass forward on its front-bottom edge when a drawer is yanked too hard. */
.hero--cabinet .hcab-cab {
  position: absolute; width: calc(440 * var(--u)); height: calc(410 * var(--u));
  left: calc(50% - 232 * var(--u)); top: calc(50% - 200 * var(--u));
  transform-style: preserve-3d;
  transform: rotateX(-15deg) rotateY(-25deg);
}
.hero--cabinet .hcab-body {
  position: absolute; inset: 0; transform-style: preserve-3d;
  transform-origin: 50% 100% 0;
  transform: rotateX(calc(var(--tip, 0) * -1deg));
}

.hero--cabinet .hcab-f {
  position: absolute; display: block; box-sizing: border-box;
  border: var(--b) solid var(--ink);
  /* These are painted faces, not controls. In the shared 3D scene a rear
     plane can project over a front handle even when it looks visually behind
     it; keeping decorative geometry out of hit-testing makes the physical
     interaction model match the picture. */
  pointer-events: none;
}

/* ── carcass ── */
.hero--cabinet .hcab-front { left: 0; top: 0; width: calc(440 * var(--u)); height: calc(410 * var(--u)); background: var(--steel); }
.hero--cabinet .hcab-plinth {
  position: absolute; left: 0; right: 0; bottom: 0; height: calc(24 * var(--u));
  background: var(--shade); border-top: var(--b) solid var(--ink);
}
.hero--cabinet .hcab-top {
  left: 0; top: calc(-280 * var(--u)); width: calc(440 * var(--u)); height: calc(280 * var(--u));
  transform-origin: bottom; transform: rotateX(90deg); background: var(--lit);
}
.hero--cabinet .hcab-side {
  left: calc(440 * var(--u)); top: 0; width: calc(280 * var(--u)); height: calc(410 * var(--u));
  transform-origin: left; transform: rotateY(90deg); background: var(--steel-dark);
}
.hero--cabinet .hcab-hole { border: 0; background: var(--ink); transform: translateZ(calc(.6 * var(--u))); }
.hero--cabinet .hcab-hole--top { left: calc(16 * var(--u)); top: calc(18 * var(--u)); width: calc(408 * var(--u)); height: calc(260 * var(--u)); }
.hero--cabinet .hcab-hole--junk { left: calc(16 * var(--u)); top: calc(292 * var(--u)); width: calc(408 * var(--u)); height: calc(92 * var(--u)); }

/* ── drawers: a front 8u proud of the carcass, and an open box behind it ── */
.hero--cabinet .hcab-drawer {
  position: absolute; transform-style: preserve-3d;
  /* The transformed box itself has no action. At some desktop camera angles
     its rectangular hit area projects over the other drawer even though its
     painted faces do not. Real controls opt back in below. */
  pointer-events: none;
}
.hero--cabinet .hcab-drawer--top {
  left: calc(12 * var(--u)); top: calc(14 * var(--u)); width: calc(416 * var(--u)); height: calc(268 * var(--u));
  transform: translateZ(calc(var(--p1) * 210 * var(--u)));
}
.hero--cabinet .hcab-drawer--junk {
  left: calc(12 * var(--u)); top: calc(288 * var(--u)); width: calc(416 * var(--u)); height: calc(100 * var(--u));
  transform: translateZ(calc(var(--p2) * 180 * var(--u)));
}
.hero--cabinet .hcab-d-front {
  left: 0; top: 0; width: 100%; height: 100%;
  background: var(--steel);
  transform: translateZ(calc(18 * var(--u)));
  backface-visibility: hidden;
}
/* The front's thickness, seen from above and from the right. Both stop a
   hair short of the carcass face so they never z-fight with it, and the lip
   carries no border: edge-on, a border aliases into a dotted line. */
.hero--cabinet .hcab-d-lip {
  left: 0; top: calc(-13 * var(--u)); width: 100%; height: calc(13 * var(--u));
  transform-origin: bottom; transform: translateZ(calc(18 * var(--u))) rotateX(90deg);
  background: var(--lit); border: 0;
}
.hero--cabinet .hcab-d-edge {
  left: 100%; top: 0; width: calc(13 * var(--u)); height: 100%;
  transform-origin: left; transform: translateZ(calc(18 * var(--u))) rotateY(90deg);
  background: var(--steel-dark); border-width: var(--b) 0 var(--b) 0;
}
/* Box walls. Both side walls show the face that points right, which is the
   outside of the right wall and the inside of the left one: that is what a
   camera above and to the right actually sees. */
.hero--cabinet .hcab-d-side { transform-origin: left; transform: rotateY(90deg); background: var(--steel-dark); }
.hero--cabinet .hcab-d-side--l { background: var(--deep); }
.hero--cabinet .hcab-d-floor { transform-origin: bottom; transform: rotateX(90deg); background: var(--deep); }
.hero--cabinet .hcab-d-back { background: var(--shade); }

.hero--cabinet .hcab-drawer--top .hcab-d-side { left: calc(12 * var(--u)); top: calc(36 * var(--u)); width: calc(262 * var(--u)); height: calc(226 * var(--u)); }
.hero--cabinet .hcab-drawer--top .hcab-d-side--r { left: calc(404 * var(--u)); }
.hero--cabinet .hcab-drawer--top .hcab-d-floor { left: calc(12 * var(--u)); top: 0; width: calc(392 * var(--u)); height: calc(262 * var(--u)); }
.hero--cabinet .hcab-drawer--top .hcab-d-back { left: calc(12 * var(--u)); top: calc(36 * var(--u)); width: calc(392 * var(--u)); height: calc(226 * var(--u)); transform: translateZ(calc(-262 * var(--u))); }

.hero--cabinet .hcab-drawer--junk .hcab-d-side { left: calc(12 * var(--u)); top: calc(22 * var(--u)); width: calc(220 * var(--u)); height: calc(70 * var(--u)); }
.hero--cabinet .hcab-drawer--junk .hcab-d-side--r { left: calc(404 * var(--u)); }
.hero--cabinet .hcab-drawer--junk .hcab-d-floor { left: calc(12 * var(--u)); top: calc(-128 * var(--u)); width: calc(392 * var(--u)); height: calc(220 * var(--u)); }
.hero--cabinet .hcab-drawer--junk .hcab-d-back { left: calc(12 * var(--u)); top: calc(22 * var(--u)); width: calc(392 * var(--u)); height: calc(70 * var(--u)); transform: translateZ(calc(-220 * var(--u))); }

/* ── the label: two strips of embossed label-maker tape ── */
/* The drawer front is deliberately FLAT (no preserve-3d). Anything tilted
   inside the shared 3D context becomes an infinite splitting plane for the
   browser's depth sort, and at 2x device scale Chrome then paints the dark
   drawer openings over the fronts. So the tape curl is drawn with its own
   local perspective and flattened onto the front. */
.hero--cabinet .hcab-tapes {
  position: absolute; left: 50%; top: calc(38 * var(--u)); translate: -50% 0;
  display: flex; flex-direction: column; align-items: center; gap: calc(9 * var(--u));
}
.hero--cabinet .hcab-tape { display: flex; height: calc(36 * var(--u)); perspective: calc(90 * var(--u)); }
.hero--cabinet .hcab-tape--1 { rotate: -1.4deg; translate: calc(-14 * var(--u)) 0; }
.hero--cabinet .hcab-tape--2 { rotate: .7deg; translate: calc(10 * var(--u)) 0; }
.hero--cabinet .hcab-tape-body, .hero--cabinet .hcab-tape-end { background: #20262a; }
.hero--cabinet .hcab-tape-body {
  display: flex; align-items: center; padding: 0 calc(8 * var(--u));
  font-family: var(--mono); font-weight: 700; font-size: max(9px, calc(19 * var(--u)));
  letter-spacing: .16em; line-height: 1; color: #edf1f3;
  box-shadow: inset 0 calc(2 * var(--u)) 0 rgba(255,255,255,.1);
}
/* The ends lift off the steel a few degrees. */
.hero--cabinet .hcab-tape-end { width: calc(10 * var(--u)); box-shadow: inset 0 calc(2 * var(--u)) 0 rgba(255,255,255,.1); }
.hero--cabinet .hcab-tape-end--l { transform-origin: right; transform: rotateY(-28deg); }
.hero--cabinet .hcab-tape-end--r { transform-origin: left; transform: rotateY(28deg); }
/* Embossed: the raised letter catches light above and throws a hard edge below. */
.hero--cabinet .hcab-ch {
  display: inline-block;
  text-shadow: 0 calc(1.6 * var(--u)) 0 #05080a, 0 calc(-1 * var(--u)) 0 rgba(255,255,255,.35);
}
.hero--cabinet .hcab-ch:nth-child(3n+1) { translate: 0 calc(-.8 * var(--u)); }
.hero--cabinet .hcab-ch:nth-child(4n+2) { translate: 0 calc(.9 * var(--u)); }

/* ── handles ── */
.hero--cabinet .hcab-handle, .hero--cabinet .hcab-junk-handle {
  position: absolute; left: 50%; padding: 0; margin: 0; cursor: grab;
  border: var(--b) solid var(--ink); background: var(--steel-dark); color: inherit;
  transform: translateX(-50%);
  -webkit-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent;
  transition: background-color var(--t-quick) ease, box-shadow var(--t-quick) ease;
  pointer-events: auto;
}
/* A bar pull: grip recess on top, hard shadow cast back onto the drawer. */
.hero--cabinet .hcab-handle {
  top: calc(170 * var(--u)); width: calc(168 * var(--u)); height: calc(34 * var(--u));
  border-radius: calc(17 * var(--u)); touch-action: none;
  box-shadow: inset 0 calc(-7 * var(--u)) 0 rgba(21,25,24,.18), calc(7 * var(--u)) calc(8 * var(--u)) 0 rgba(21,25,24,.28);
}
.hero--cabinet .hcab-handle:hover { background: color-mix(in srgb, var(--steel-dark) 80%, #fff); }
.hero--cabinet .hcab-handle:active, .hero--cabinet .hcab-handle.is-gripped {
  cursor: grabbing; background: var(--shade);
  box-shadow: inset 0 calc(-3 * var(--u)) 0 rgba(21,25,24,.28), calc(4 * var(--u)) calc(5 * var(--u)) 0 rgba(21,25,24,.28);
}
/* A cup pull on the little drawer. */
.hero--cabinet .hcab-junk-handle {
  top: calc(34 * var(--u)); width: calc(116 * var(--u)); height: calc(34 * var(--u)); cursor: pointer;
  border-radius: 0 0 calc(58 * var(--u)) calc(58 * var(--u));
  box-shadow: inset 0 calc(9 * var(--u)) 0 rgba(21,25,24,.3), calc(6 * var(--u)) calc(7 * var(--u)) 0 rgba(21,25,24,.28);
}
.hero--cabinet .hcab-junk-handle:hover { background: color-mix(in srgb, var(--steel-dark) 80%, #fff); }
.hero--cabinet .hcab-junk-handle:active { box-shadow: inset 0 calc(12 * var(--u)) 0 rgba(21,25,24,.36), calc(3 * var(--u)) calc(4 * var(--u)) 0 rgba(21,25,24,.28); }
.hero--cabinet .hcab-handle:disabled, .hero--cabinet .hcab-junk-handle:disabled { cursor: default; }
.hero--cabinet .hcab-handle:focus-visible, .hero--cabinet .hcab-junk-handle:focus-visible {
  outline: max(3px, calc(4 * var(--u))) solid var(--yellow); outline-offset: max(3px, calc(4 * var(--u)));
}
/* The card holder on the junk drawer: one word in Nick's pen. */
.hero--cabinet .hcab-card {
  position: absolute; left: calc(28 * var(--u)); top: calc(30 * var(--u));
  width: calc(88 * var(--u)); height: calc(40 * var(--u));
  display: grid; place-items: center;
  background: var(--paper); border: max(1.5px, calc(2.5 * var(--u))) solid var(--ink);
  outline: calc(5 * var(--u)) solid var(--steel-dark); outline-offset: 0;
  font-family: var(--hand); font-size: max(12px, calc(24 * var(--u))); line-height: 1; color: var(--ink);
  rotate: -2deg;
}
@media (prefers-reduced-motion: no-preference) {
  .hero--cabinet .hcab-drawer--junk.is-rattling { animation: hcab-rattle 300ms linear; }
}
@keyframes hcab-rattle {
  15% { translate: calc(-3 * var(--u)) 0; rotate: -.5deg; }
  35% { translate: calc(3 * var(--u)) calc(-1 * var(--u)); rotate: .6deg; }
  55% { translate: calc(-2 * var(--u)) 0; rotate: -.35deg; }
  75% { translate: calc(1.5 * var(--u)) 0; rotate: .2deg; }
}

/* ── the folders: four hanging files, quarter-cut tabs, one per capability ──
   Down: fully inside the drawer. Risen: the tabs stand above the drawer
   front. Each folder hangs from its rail and sways with the drawer's
   acceleration (--sway, degrees, from the physics). */
.hero--cabinet .hcab-files {
  position: absolute; inset: 0; margin: 0; padding: 0; list-style: none;
  transform-style: preserve-3d;
  /* The list is a 3D positioning plane that spans the whole drawer. Only its
     actual folder tabs are interactive; otherwise the invisible part of the
     plane sits over the physical handle. */
  pointer-events: none;
}
.hero--cabinet .hcab-folder {
  /* Sit the files in the drawer rather than displaying them on a separate
     rack above it. At full lift each tab and only a short shoulder of its
     folder clears the fascia. */
  --rise: calc(128 * var(--u));
  position: absolute; left: calc(20 * var(--u));
  /* Each complete file sits a fraction lower than the one in front. That
     exposes a narrow run of every file's top edge and keeps its tab visibly
     joined to its own body, instead of leaving four labels hovering over one
     unrelated sheet. */
  top: calc((44 - var(--i) * 6) * var(--u));
  /* Only 50u of sheet hangs below the rail. Longer sheets can swing into the
     drawer front, or reach below the top of the box wall once lifted, and in
     both cases the browser's depth sort paints the folder through the steel.
     The rest of a real folder is out of sight below the front anyway. */
  /* Rear files need a longer body because the fascia's top edge recedes in
     perspective. Their progressively longer tails continue down behind that
     edge, where the moving drawer front—not an arbitrary short crop—hides
     them. The tab tops stay in the same aligned row. */
  width: calc(376 * var(--u));
  height: calc((132 + var(--i) * 12) * var(--u));
  transform-origin: 50% calc(74 * var(--u));
  /* The first file sits immediately behind the 18u-proud drawer fascia;
     each following file steps back into the box. Keeping the front file only
     12u behind the fascia makes the stack read as contents of this drawer,
     while retaining one stable plane per file avoids Chrome's 3D split bug. */
  transform: translateZ(calc(6 * var(--u) - var(--i) * 12 * var(--u)));
  backface-visibility: hidden;
  /* Clip the complete folder at the drawer rim. The tab and its sheet now
     emerge as one object; a half-raised file can no longer leave its tab
     floating above a separately clipped body. */
  clip-path: inset(0 0 var(--folder-clip, 16.13%) 0);
  /* --lift: 1 risen (the default: no JS, reduced motion), 0 down in the
     drawer. hero-cabinet.js drives it on a spring per folder. */
  translate: 0 calc(-1 * var(--rise) * var(--lift, 1));
}
.hero--cabinet .hcab-folder[data-color="red"] { --c: var(--red); --tint: #ffdcd7; }
.hero--cabinet .hcab-folder[data-color="blue"] { --c: var(--blue); --tint: #dfe6ff; }
.hero--cabinet .hcab-folder[data-color="green"] { --c: var(--green); --tint: #d9f0e3; }
.hero--cabinet .hcab-folder[data-color="yellow"] { --c: var(--yellow); --tint: #fff0b8; }
/* Down, a folder is out of sight inside the drawer, so it is not drawn at
   all: that keeps it out of the browser's depth sort while the drawer is
   moving, which is exactly when a mis-sort would paint it through the steel.
   It becomes visible the moment it starts to rise. */
[data-js] .hero--cabinet:not(.hcab-ready) .hcab-folder { --lift: 0; visibility: hidden; }
.hero--cabinet.hcab-ready .hcab-folder.is-down { visibility: hidden; }
@media (prefers-reduced-motion: reduce) {
  [data-js] .hero--cabinet:not(.hcab-ready) .hcab-folder { --lift: 1; visibility: visible; }
}
.hero--cabinet .hcab-sheet {
  position: absolute; left: 0; top: calc(72 * var(--u));
  width: 100%; height: calc((60 + var(--i) * 12) * var(--u));
  display: block; box-sizing: border-box;
  background: var(--tint); border: var(--b) solid var(--ink);
  pointer-events: none;
}
.hero--cabinet .hcab-tab {
  position: absolute; top: 0; left: calc(2 * var(--u) + var(--i) * 94 * var(--u));
  width: calc(90 * var(--u)); height: calc(74 * var(--u) + var(--b));
  display: flex; flex-direction: column; justify-content: space-between; gap: calc(4 * var(--u));
  padding: calc(6 * var(--u)) calc(6 * var(--u)) calc(7 * var(--u));
  background: var(--c); color: var(--ink); text-decoration: none;
  border: var(--b) solid var(--ink); border-bottom: 0;
  border-radius: calc(11 * var(--u)) calc(11 * var(--u)) 0 0;
  transition: translate var(--t-quick) var(--ease-drawer);
  pointer-events: auto;
}
/* The coloured plastic tab holds a paper insert: the label reads ink on
   paper at every size, whatever the tab colour. */
.hero--cabinet .hcab-tab-label {
  display: block; padding: calc(4 * var(--u)) calc(3 * var(--u));
  background: var(--paper); border: max(1.5px, calc(2 * var(--u))) solid var(--ink);
  font-family: var(--display); font-weight: 800; font-size: max(11px, calc(12.5 * var(--u)));
  line-height: 1; letter-spacing: -.015em;
}
.hero--cabinet .hcab-tab-label > span { display: block; white-space: nowrap; }
.hero--cabinet .hcab-tab-icon { display: block; width: calc(22 * var(--u)); height: calc(22 * var(--u)); flex: none; }
.hero--cabinet .hcab-tab:hover { translate: 0 calc(-7 * var(--u)); }
.hero--cabinet .hcab-tab:active { translate: 0 calc(-2 * var(--u)); }
.hero--cabinet .hcab-tab:focus-visible { outline: max(3px, calc(4 * var(--u))) solid var(--ink); outline-offset: max(2px, calc(3 * var(--u))); translate: 0 calc(-7 * var(--u)); }

/* ── the junk drawer's contents, once it gives: flat objects on the floor ── */
.hero--cabinet .hcab-junk { position: absolute; inset: 0; margin: 0; padding: 0; list-style: none; pointer-events: none; z-index: 2; }
.hero--cabinet .hcab-junk-item {
  position: absolute; left: var(--x, 0); top: var(--y, 0);
  width: calc(96 * var(--u)); rotate: var(--r, 0deg);
  filter: drop-shadow(calc(5 * var(--u)) calc(6 * var(--u)) 0 var(--shadow));
}
.hero--cabinet .hcab-junk-item svg { display: block; width: 100%; height: auto; overflow: visible; }
.hero--cabinet .hcab-junk-item--ring { width: calc(84 * var(--u)); }
.hero--cabinet .hcab-junk-item--cork { width: calc(76 * var(--u)); }
/* A manila tag on a string. */
.hero--cabinet .hcab-tag {
  position: absolute; left: 6%; top: 94%; rotate: calc(var(--r, 0deg) * -1 + 3deg);
  padding: calc(4 * var(--u)) calc(9 * var(--u)) calc(4 * var(--u)) calc(16 * var(--u));
  background: var(--manila); border: max(1.5px, calc(2 * var(--u))) solid var(--ink);
  clip-path: polygon(calc(9 * var(--u)) 0, 100% 0, 100% 100%, calc(9 * var(--u)) 100%, 0 50%);
  font-family: var(--hand); font-size: max(12px, calc(17 * var(--u))); line-height: 1.05; color: var(--ink);
  white-space: nowrap;
}
.hero--cabinet .hcab-tag::before {
  content: ""; position: absolute; left: calc(7 * var(--u)); top: 50%;
  width: calc(5 * var(--u)); height: calc(5 * var(--u)); translate: 0 -50%;
  border-radius: 50%; background: var(--blue); border: max(1px, calc(1.5 * var(--u))) solid var(--ink);
}

/* ── narrower screens: the cabinet sits below the copy ── */
@media (max-width: 980px) {
  .hero--cabinet .hcab-stage { height: clamp(460px, 78vw, 700px); border-left: 0; border-top: var(--border); }
  .hero--cabinet .hcab-stage { --u: min(calc(100cqw / 560), calc(100cqh / 640)); }
  .hero--cabinet .hcab-cab { left: calc(58% - 220 * var(--u)); top: calc(52% - 170 * var(--u)); }
}
@media (max-width: 720px) {
  /* A phone crops the cabinet's side, never its drawer: the open drawer and
     its tabs are the part that matters, so they get the width. The camera
     pulls back (longer perspective) so the drawer grows less as it opens,
     and the stage keeps a strip of floor for anything that falls out. */
  .hero--cabinet .hcab-stage { height: 660px; --u: min(calc(100cqw / 500), calc(100cqh / 760)); }
  .hero--cabinet .hcab-cab { left: calc(58% - 220 * var(--u)); top: calc(38% - 170 * var(--u)); transform: rotateX(-14deg) rotateY(-18deg); }
  .hero--cabinet .hcab-scene { perspective: calc(2800 * var(--u)); perspective-origin: 50% 30%; }
  .hero--cabinet .hcab-tab { padding: calc(5 * var(--u)) calc(4 * var(--u)) calc(6 * var(--u)); }
  .hero--cabinet .hcab-tab-label { padding: calc(4 * var(--u)) calc(3 * var(--u)); letter-spacing: -.025em; }
}
