/* ===========================================================================
 * RBGI — FIDELITY TEST 2 · ENTIRE STUDIOS
 * ---------------------------------------------------------------------------
 * Style 086fdbd2-9763-40d2-9859-f90b4ef2c500, entirestudios.com.
 * Standalone: imports nothing, shares nothing. Test 1 (Iad-lab) is untouched
 * so the two can be compared side by side.
 *
 * MEASURED OFF THE ACTUAL FRAME, not the written export. What preview_0 shows:
 *
 *   · a thin black announcement strip, full width, tiny mono, centred
 *   · a REAL navigation bar in pale slate — utility left, brand centred,
 *     utilities right. This is the thing Iad-lab does not have and the thing
 *     RBGI needs: it is a commercial site, not an exhibition
 *   · one full-bleed photograph filling everything below the bar, edge to
 *     edge, uncropped, unangled, unmasked — the photograph IS the page
 *   · a centred lockup floating over it: mark, hairline rule, name
 *   · a small mono label in the top-right corner, on the photograph
 *   · every piece of type monospaced, at 12px or 16px, and nothing else
 *   · 0px radius on everything. No shadows. No gradients.
 *
 * WHY THIS SUITS RBGI AND IAD-LAB DID NOT. Iad-lab is an art-school exhibition
 * site: one word per screen, no product, no navigation, nothing to buy. RBGI
 * sells manufacturing programmes to brands. Every failure of test 1 — no
 * navigation, oversized type, dead space, nothing to click — came from that
 * mismatch rather than from execution. This reference is a storefront that
 * still behaves like a gallery, which is exactly the brief.
 *
 * TYPEFACE NOTE. The reference specifies Space Mono, which is not installed
 * here. The stack falls to SF Mono, which is a good mono and holds the same
 * fixed-width, technical rhythm. If Space Mono is licensed it drops straight
 * in at the head of the stack and nothing else changes.
 * ======================================================================== */

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

:root {
  --ink:   #000000;   /* Midnight Ink  — text, borders, the announcement bar */
  --slate: #e7ecea;   /* Pale Slate    — section grounds, the nav bar        */
  --white: #ffffff;   /* Arctic White  — page ground                         */

  /* One family for everything. The reference is explicit: no sans, no serif. */
  --mono: "Space Mono", "SF Mono", ui-monospace, Menlo, monospace;

  --slow: cubic-bezier(0.22, 0.61, 0.24, 1);
}

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--white);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.5;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
img { display: block; }
h1, h2, h3, p { margin: 0; font-weight: 400; }

/* Two sizes. That is the whole type system — the reference uses 12 and 16 and
   nothing between or beyond, and the discipline is most of the effect. */
.t12 { font-size: 12px; line-height: 1.33; }
.t16 { font-size: 16px; line-height: 1.50; }
.up  { text-transform: uppercase; }

/* ---------- ANNOUNCEMENT STRIP ------------------------------------------ */
.strip {
  background: var(--ink);
  color: var(--white);
  text-align: center;
  padding: 8px 16px;
  font-size: 12px;
  letter-spacing: 0.06em;
}

/* ---------- NAVIGATION ---------------------------------------------------
 * Pale slate, three zones: utility left, brand centred, utilities right.
 * Sticky, because a storefront's nav goes with you and an exhibition's does
 * not — this is the single biggest behavioural difference from test 1.
 * -------------------------------------------------------------------- */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--slate);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 12px 16px;
  font-size: 12px;
}
.nav__left  { display: flex; gap: 18px; }
.nav__right { display: flex; gap: 18px; justify-content: flex-end; }
.nav__brand { font-size: 16px; white-space: nowrap; }
.nav a { padding: 0 6px; transition: opacity 0.3s var(--slow); }
.nav a:hover { opacity: 0.55; }
.nav a[aria-current="page"] { text-decoration: underline; text-underline-offset: 4px; }
.nav .held { padding: 0 6px; opacity: 0.34; cursor: default; }

/* ---------- HERO ---------------------------------------------------------
 * One photograph, everything below the bar, edge to edge. No mask, no angle,
 * no overlay, no scrim — the reference's imagery note is explicit that the
 * treatment is raw and untamed. The lockup floats on it unaided, which means
 * the photograph has to be dark enough to carry white type; that is a
 * photo-selection constraint, not a CSS one.
 * -------------------------------------------------------------------- */
.hero {
  position: relative;
  width: 100%;
  height: calc(100vh - 76px);
  min-height: 520px;
  overflow: hidden;
  background: var(--ink);
}
.hero img { width: 100%; height: 100%; object-fit: cover; }

.hero__corner {
  position: absolute;
  top: 16px; right: 16px;
  color: var(--white);
  letter-spacing: 0.08em;
}

/* The centred lockup: mark, hairline rule, name. */
.lock {
  position: absolute;
  /* Raised off dead centre: centred, the lockup landed across the rider's
     forearms and the RECKLESS print, and two pieces of white type fought each
     other. 38% puts it on the clean black of the chest. */
  left: 50%; top: 38%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  gap: 28px;
  color: var(--white);
  white-space: nowrap;
}
.lock__mark { height: clamp(40px, 5vw, 74px); width: auto; }
.lock__rule { width: 1px; height: clamp(44px, 6vw, 86px); background: var(--white); opacity: 0.85; }
.lock__name { font-size: clamp(18px, 2.4vw, 34px); letter-spacing: 0.01em; }

/* ---------- BANDS -------------------------------------------------------- */
.band  { padding: 64px 16px; }
.band--slate { background: var(--slate); }
.band--ink   { background: var(--ink); color: var(--white); }

.stack > * + * { margin-top: 6px; }
.gap-lg { margin-top: 64px; }

/* ---------- FULL-BLEED PLATE --------------------------------------------- */
.plate { width: 100%; height: 78vh; min-height: 420px; overflow: hidden; background: var(--ink); position: relative; }
.plate img { width: 100%; height: 100%; object-fit: cover; }
.plate__note { position: absolute; left: 16px; bottom: 16px; color: var(--white); letter-spacing: 0.08em; }

/* ---------- PRODUCT GRID -------------------------------------------------
 * The reference has one, and its card is austere: image on top, name at 16px,
 * meta at 12px, 16px padding, no border, no shadow, 0px radius. Nothing here
 * is a "card" in the glass sense — it is a picture with two lines under it.
 * -------------------------------------------------------------------- */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1px;
  background: var(--slate);   /* the 1px gaps become hairline seams */
  border-block: 1px solid var(--slate);
}
.item { background: var(--white); }
.item__img { aspect-ratio: 3 / 4; overflow: hidden; background: var(--slate); }
.item__img img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.2s var(--slow); }
.item:hover .item__img img { transform: scale(1.03); }
.item__body { padding: 16px; }
.item__name { font-size: 16px; line-height: 1.5; }
.item__meta { font-size: 12px; line-height: 1.33; margin-top: 6px; }

/* The colourway, four panels, as a hairline strip under the name. The only
   colour anywhere in the interface, and it is the product's own. */
.ways { display: flex; height: 6px; margin-top: 12px; }
.ways span { flex: 1; }

/* ---------- MARKS --------------------------------------------------------
 * Provenance, not a sponsor wall: one row, one optical size, black on slate,
 * unboxed.
 * -------------------------------------------------------------------- */
.marks { display: flex; flex-wrap: wrap; align-items: center; gap: clamp(24px, 4vw, 56px); }
.marks img { height: 18px; width: auto; filter: grayscale(1); opacity: 0.75; }
.marks img.onWhite { filter: grayscale(1) invert(0); }
.marks span { font-size: 12px; letter-spacing: 0.06em; opacity: 0.75; }

/* ---------- ARRIVAL ------------------------------------------------------ */
.rise { opacity: 0; transform: translateY(14px); transition: opacity 1s var(--slow), transform 1s var(--slow); }
.rise.seen { opacity: 1; transform: none; }
.no-js .rise { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .001ms !important; scroll-behavior: auto !important; }
}

/* ---------- MOBILE PORTRAIT ---------------------------------------------- */
@media (max-width: 700px) {
  .nav { grid-template-columns: 1fr auto; row-gap: 10px; }
  .nav__left  { order: 2; grid-column: 1; }
  .nav__right { order: 3; grid-column: 2; }
  .nav__brand { order: 1; grid-column: 1 / -1; text-align: center; }
  .hero  { height: calc(100vh - 110px); }
  .lock  { gap: 16px; }
  .band  { padding: 44px 16px; }
  .plate { height: 56vh; }
}

/* ===========================================================================
 * PASS 2 — MOTION, DRILL-DOWN, AND THE FILM
 * ---------------------------------------------------------------------------
 * Aaron's five: heads were being cut off, the stills were dead, the menu did
 * nothing, nothing was clickable, and the film had no home. A website takes you
 * somewhere; this pass is the somewhere.
 * ======================================================================== */

/* ---------- KEN BURNS ----------------------------------------------------
 * A still photograph on a long, slow drift. 28 seconds a cycle, alternating
 * direction between plates so consecutive images do not slide as a block, and
 * the scale never drops below 1.06 — the moment it touches 1 the edges of the
 * frame show and the drift reads as a bug.
 *
 * It runs on the IMAGE, never on the frame, so nothing around it moves. And it
 * is paused until the plate has been seen, because eight photographs all
 * animating off-screen is eight compositors doing nothing for anybody.
 * -------------------------------------------------------------------- */
@keyframes kb-a {
  0%   { transform: scale(1.10) translate3d(-1.2%, -0.8%, 0); }
  50%  { transform: scale(1.16) translate3d( 1.2%,  0.9%, 0); }
  100% { transform: scale(1.10) translate3d(-1.2%, -0.8%, 0); }
}
@keyframes kb-b {
  0%   { transform: scale(1.14) translate3d( 1.4%,  0.6%, 0); }
  50%  { transform: scale(1.08) translate3d(-1.1%, -0.9%, 0); }
  100% { transform: scale(1.14) translate3d( 1.4%,  0.6%, 0); }
}
.kb img { will-change: transform; animation: kb-a 28s ease-in-out infinite; animation-play-state: paused; }
.kb--b img { animation-name: kb-b; animation-duration: 34s; }
.kb.seen img { animation-play-state: running; }

/* The hero drifts too, but slower still — it is the first thing seen and the
   last thing that should call attention to itself. */
.hero.kb img { animation-duration: 42s; }

@media (prefers-reduced-motion: reduce) {
  .kb img { animation: none !important; transform: scale(1.06) !important; }
}

/* ---------- NAVIGATION · DRILL-DOWN --------------------------------------
 * Each menu item that has somewhere to go opens a panel of its actual
 * destinations. Hover or focus on the desktop, tap on touch. The panel is part
 * of the bar rather than a floating overlay, so the page below is never
 * covered — a storefront should not hide its own goods behind its menu.
 * -------------------------------------------------------------------- */
.nav a, .nav .held { position: relative; }

/* The underline sweep. Grows from the left on hover, and stays put on the
   current page. No colour change, no weight change — one line, one direction. */
.nav a::after {
  content: "";
  position: absolute;
  left: 6px; right: 6px; bottom: -3px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 0.42s var(--slow);
}
.nav a:hover::after,
.nav a:focus-visible::after,
.nav a[aria-expanded="true"]::after { transform: scaleX(1); }
.nav a[aria-current="page"] { text-decoration: none; }
.nav a[aria-current="page"]::after { transform: scaleX(1); }

.navwrap { position: sticky; top: 0; z-index: 50; }

.drawer {
  background: var(--slate);
  border-top: 1px solid rgba(0,0,0,0.14);
  overflow: hidden;
  max-height: 0;
  transition: max-height 0.5s var(--slow);
}
.drawer[data-open="true"] { max-height: 340px; }

.drawer__in {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1px;
  background: rgba(0,0,0,0.14);
}
.drawer__panel { display: none; }
.drawer__panel[data-active="true"] { display: contents; }

.dcell {
  background: var(--slate);
  padding: 18px 16px 22px;
  display: block;
  transition: background 0.35s var(--slow);
}
.dcell:hover { background: var(--white); }
.dcell__k { font-size: 12px; line-height: 1.33; text-transform: uppercase; opacity: 0.55; }
.dcell__v { font-size: 16px; line-height: 1.5; margin-top: 6px; }
.dcell__ways { display: flex; height: 5px; margin-top: 12px; }
.dcell__ways span { flex: 1; }
.dcell--held { opacity: 0.42; }
.dcell--held:hover { background: var(--slate); }

/* ---------- ACTIVATION ---------------------------------------------------
 * Everything that looks like a destination is one. The product items are
 * anchors now, and they say where they go on hover rather than relying on the
 * reader to guess that a picture is a link.
 * -------------------------------------------------------------------- */
a.item { display: block; color: inherit; }
.item__go {
  display: inline-block;
  margin-top: 12px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity 0.4s var(--slow), transform 0.4s var(--slow);
}
a.item:hover .item__go,
a.item:focus-visible .item__go { opacity: 0.7; transform: none; }
a.item:focus-visible { outline: 1px solid var(--ink); outline-offset: -1px; }

/* ---------- THE FILM · 2.35:1 -------------------------------------------
 * Aaron's ratio, exactly: 2.35 to 1, the anamorphic widescreen the film was
 * cut for. A facade, not an embed — the poster frame and a play control sit
 * there until clicked, and only then does the player load. That keeps a
 * megabyte of third-party script and its cookies off a page that is being
 * shown to brands under a confidential deck, and the visitor still gets the
 * film in one click without leaving the site.
 * -------------------------------------------------------------------- */
.film {
  position: relative;
  width: 100%;
  aspect-ratio: 2.35 / 1;
  overflow: hidden;
  background: var(--ink);
  display: block;
  border: 0;
  padding: 0;
  cursor: pointer;
  color: var(--white);
}
.film img { width: 100%; height: 100%; object-fit: cover; }
.film iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

.film__veil { position: absolute; inset: 0; background: rgba(0,0,0,0.22); transition: background 0.5s var(--slow); }
.film:hover .film__veil { background: rgba(0,0,0,0.08); }

.film__play {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%,-50%);
  width: 74px; height: 74px;
  border: 1px solid var(--white);
  display: grid; place-items: center;
  transition: background 0.45s var(--slow);
}
.film:hover .film__play { background: var(--white); }
.film__play svg { fill: var(--white); transition: fill 0.45s var(--slow); }
.film:hover .film__play svg { fill: var(--ink); }

.film__cap {
  position: absolute; left: 16px; bottom: 16px; right: 16px;
  display: flex; justify-content: space-between; align-items: flex-end; gap: 16px;
  text-align: left;
}
@media (max-width: 700px) {
  .film__play { width: 52px; height: 52px; }
  .drawer[data-open="true"] { max-height: 520px; }
}

/* ---------- MANUFACTURING BAND ------------------------------------------
 * Five photographs of the plant under one heading. The reference's grid
 * pattern, applied to capability rather than product: hairline seams, no
 * borders, no radius, no shadow.
 *
 * Deliberately NOT five equal squares. A capability claim reads as a claim
 * when every picture is the same size; it reads as evidence when the plant
 * shot is allowed to dominate and the macro is allowed to be small. So the
 * first cell spans two columns and two rows, and the rest fall in around it.
 * -------------------------------------------------------------------- */
.mfg {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 20vw;
  gap: 1px;
  background: rgba(0,0,0,0.14);
  border-block: 1px solid rgba(0,0,0,0.14);
}
.mfg figure { margin: 0; position: relative; overflow: hidden; background: var(--slate); }
.mfg img { width: 100%; height: 100%; object-fit: cover; }

.mfg .m1 { grid-column: span 2; grid-row: span 2; }   /* the plant  */
.mfg .m2 { grid-column: span 2; }                     /* the floor  */
.mfg .m3 { grid-column: span 1; }                     /* the bench  */
.mfg .m4 { grid-column: span 1; }                     /* the seam   */
.mfg .m5 { grid-column: span 4; grid-row: span 1; }   /* the layers */

/* The construction diagram is line art on white — cover-cropping it would cut
   the labels off, and it is the one image on the page that is information
   rather than atmosphere. It is contained, on white, and given room. */
.mfg .m5 { background: var(--white); }
.mfg .m5 img { object-fit: contain; padding: 24px 16px; }

.mfg figcaption {
  position: absolute;
  left: 12px; bottom: 10px;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--white);
  mix-blend-mode: difference;
}
.mfg .m5 figcaption { color: var(--ink); mix-blend-mode: normal; }

@media (max-width: 900px) {
  .mfg { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 34vw; }
  .mfg .m1 { grid-column: span 2; grid-row: span 1; }
  .mfg .m2 { grid-column: span 2; }
  .mfg .m5 { grid-column: span 2; }
}

/* ---------- KEN BURNS · THE HERO EXCEPTION ------------------------------
 * The general drift runs 1.10 → 1.16, which is right for a landscape plate and
 * wrong for a portrait subject: on the hero it zoomed straight past the
 * rider's head and re-created the exact fault Aaron flagged. A face is not a
 * texture and cannot be cropped for effect.
 *
 * The hero gets its own, gentler cycle — 1.03 to 1.06, and the vertical travel
 * is downward only, so the drift can never push the head above the frame. It
 * still moves; it just moves inside the headroom rather than through it.
 * -------------------------------------------------------------------- */
@keyframes kb-hero {
  0%   { transform: scale(1.03) translate3d(0, 0.6%, 0); }
  50%  { transform: scale(1.06) translate3d(0, 1.6%, 0); }
  100% { transform: scale(1.03) translate3d(0, 0.6%, 0); }
}
.hero.kb img { animation-name: kb-hero; animation-duration: 46s; }

/* Headroom for that drift: the crop starts higher up the frame than it would
   for a still, because the animation is going to travel down into it. */
.hero img { object-position: 50% 26% !important; }

/* The lockup moves clear of the sleeve print, which the drift walks under. */
.lock { top: 34%; }

/* The five-layer construction diagram is out at Aaron's instruction. With it
   gone the band is four photographs and the grid closes up exactly: the plant
   holds two columns and both rows, the floor takes the two columns beside it,
   and the bench and the seam fill the row beneath. No empty cell, no rebalance
   needed. The .m5 rules below are dead and kept only so the reason is on the
   record; delete them whenever this file is next tidied. */
.mfg { grid-auto-rows: 19vw; }
@media (max-width: 900px) { .mfg { grid-auto-rows: 34vw; } }

/* The diagram is replaced by the sheet-stock fan. It is square, so it takes a
   single cell rather than the full-width row the diagram had, and the knitting
   floor drops to one column to make room: plant 2x2, floor 1, fan 1 on the top
   row; bench 1, seam 1 beneath. Eight cells, eight filled.

   It is also the only colour in the entire interface, and it arrives as
   material — a rack of sheet stock — rather than as decoration. That is the
   same rule the colourway strips follow.

   ⚠ 300x300 as supplied, shown here at roughly 340 device pixels and 680 on a
   retina display. It will be visibly soft. A larger original wants sourcing
   before this is shown to anyone. */
.mfg .m2 { grid-column: span 1; }
.mfg .m5 { grid-column: span 1; grid-row: span 1; background: var(--slate); }
.mfg .m5 img { object-fit: cover; padding: 0; }
.mfg .m5 figcaption { color: var(--white); mix-blend-mode: difference; }
@media (max-width: 900px) {
  .mfg .m2 { grid-column: span 1; }
  .mfg .m5 { grid-column: span 1; }
}

/* ---------- HERO CROP · FINAL ------------------------------------------
 * The studio frame is 1412x2200 — a PORTRAIT subject in a LANDSCAPE hero. Any
 * zoom at all walks the face out of the top of the frame, which is why the
 * head kept being cut no matter how the drift was tuned. Two fixes, together:
 *
 *   · the crop is anchored high (14%), so there is headroom above the face
 *     before the animation starts;
 *   · the drift no longer scales. It pans DOWNWARD only, at a fixed 1.05,
 *     which reveals more of the top of the picture as it runs rather than
 *     magnifying past it. The movement is still there; it can no longer
 *     take the head.
 * -------------------------------------------------------------------- */
@keyframes kb-hero {
  0%   { transform: scale(1.05) translate3d(0, 0%,   0); }
  50%  { transform: scale(1.05) translate3d(0, 1.4%, 0); }
  100% { transform: scale(1.05) translate3d(0, 0%,   0); }
}
.hero img { object-position: 50% 14% !important; }
.hero.kb img { animation-name: kb-hero; animation-duration: 40s; }

/* ===========================================================================
 * THE CUSTOM ORDER 2.0 CARD
 * ---------------------------------------------------------------------------
 * Glassmorphic 2.0 on a rounded rectangle, on the cover page — Aaron's ask.
 *
 * Section 11 of the master prompt reserved glass for the functional interfaces
 * and kept it off the public storytelling pages. This does not break that rule
 * so much as sit exactly on it: the card IS the doorway to the configurator,
 * so the one glass object on the public page is the one thing that belongs to
 * the product interface. It is deliberately the ONLY rounded, elevated object
 * on the whole site — which is what makes it read as a door rather than as
 * decoration.
 * ======================================================================== */
.order {
  position: relative;
  display: block;
  border-radius: 20px;
  overflow: hidden;
  min-height: clamp(320px, 34vw, 460px);
  color: var(--white);
  background: #141416;
  isolation: isolate;
}
.order__bg { position: absolute; inset: 0; z-index: 0; }
.order__bg img { width: 100%; height: 100%; object-fit: cover; }

/* The pane. Opaque enough to read type on, transparent enough to be glass. */
.order__pane {
  position: absolute;
  z-index: 2;
  left: clamp(16px, 2.5vw, 40px);
  right: clamp(16px, 2.5vw, 40px);
  bottom: clamp(16px, 2.5vw, 40px);
  padding: clamp(20px, 2.4vw, 34px);
  border-radius: 16px;
  background: rgba(30, 31, 34, 0.58);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
          backdrop-filter: blur(20px) saturate(140%);
}
/* The silver pinline: a gradient ring, not a grey border. Two masks
   differenced, so it follows the radius exactly. */
.order__pane::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(135deg,#ffffff 0%,#9aa0a6 24%,#3a3e42 46%,#5c6166 60%,#d7dade 80%,#ffffff 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: 0.7;
  transition: opacity 0.45s var(--slow);
  pointer-events: none;
}
.order:hover .order__pane::after { opacity: 1; }

.order__k { font-size: 12px; text-transform: uppercase; letter-spacing: 0.16em; opacity: 0.7; }
.order__v { font-size: clamp(20px, 2.2vw, 30px); line-height: 1.2; margin-top: 8px; }
.order__go { display: inline-flex; align-items: center; gap: 8px; margin-top: 16px; font-size: 12px; text-transform: uppercase; letter-spacing: 0.12em; }
.order__go svg { transition: transform 0.4s var(--slow); }
.order:hover .order__go svg { transform: translateX(5px); }

/* The image drifts under the glass; the glass itself never moves. */
.order__bg img { transform: scale(1.04); transition: transform 1.6s var(--slow); }
.order:hover .order__bg img { transform: scale(1.09); }

/* Waiting for the image Aaron is supplying. A hatched plate at the exact final
   dimensions, named for the picture it wants, so nothing reflows when it
   lands and nobody mistakes it for a finished design. */
.order__slot {
  position: absolute; inset: 0; z-index: 0;
  display: grid; place-items: center;
  background: repeating-linear-gradient(135deg,#191a1c 0 14px,#202124 14px 28px);
}
.order__slot span { font-size: 12px; text-transform: uppercase; letter-spacing: 0.16em; color: #8a8d92; text-align: center; padding: 0 24px; }

/* ===========================================================================
 * PRODUCT GRID — THE NEED ESSENTIALS ARRANGEMENT
 * ---------------------------------------------------------------------------
 * Aaron's reference: each model shown FRONT and BACK side by side as one unit,
 * three models per row, name and detail beneath, white ground, no card, no
 * border, no shadow. Nine to a scrolling page.
 *
 * The pair is the unit. That is the whole idea — a wetsuit is not one
 * photograph, and a buyer judges the back panel as hard as the front.
 * ======================================================================== */
.rack {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(28px, 3vw, 56px) clamp(20px, 2.4vw, 40px);
  padding: clamp(28px, 3vw, 56px) 16px;
}
@media (max-width: 1000px) { .rack { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .rack { grid-template-columns: 1fr; } }

.suit { display: block; color: inherit; }
.suit__pair { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
.suit__view { position: relative; aspect-ratio: 3 / 5; overflow: hidden; background: var(--white); }
.suit__view img { width: 100%; height: 100%; object-fit: contain; transition: transform 1.1s var(--slow); }
.suit:hover .suit__view img { transform: scale(1.03); }

/* The awaiting-photography plate. Correct aspect, named, and it states which
   view it is — so a supplied folder can be matched to it without a briefing. */
.suit__await {
  position: absolute; inset: 0;
  display: grid; place-items: center; align-content: center; gap: 6px;
  background: #f4f6f5;
  border: 1px dashed rgba(0,0,0,0.18);
}
.suit__await b { font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase; font-weight: 400; color: #6a6f6d; }
.suit__await i { font-style: normal; font-size: 12px; color: #9aa09d; }

.suit__cap { text-align: center; margin-top: 14px; }
.suit__name { font-size: 16px; line-height: 1.5; }
.suit__meta { font-size: 12px; line-height: 1.33; margin-top: 4px; opacity: 0.62; }
.suit__ways { display: flex; height: 5px; width: 96px; margin: 12px auto 0; }
.suit__ways span { flex: 1; }

/* "new arrival" tag, top-left of the pair, exactly as the reference has it. */
.suit__tag {
  position: absolute; top: 0; left: 0; z-index: 2;
  background: rgba(0,0,0,0.62); color: var(--white);
  font-size: 11px; letter-spacing: 0.1em;
  padding: 3px 7px;
}

/* ---------- FILTER RAIL --------------------------------------------------
 * Florence Marine X's controls in this site's language: mono, 12px, zero
 * radius, ghost until pressed. Real buttons in real groups, so a keyboard
 * walks them. The filtering itself is not wired in this prototype and the rail
 * says so — a control that looks live and does nothing is worse than no
 * control.
 * -------------------------------------------------------------------- */
.rail {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px clamp(20px, 3vw, 44px);
  padding: 16px;
  background: var(--slate);
  border-block: 1px solid rgba(0,0,0,0.14);
}
.rail__set { display: flex; align-items: center; gap: 6px; }
.rail__k { font-size: 12px; text-transform: uppercase; letter-spacing: 0.12em; opacity: 0.55; margin-right: 4px; }
.rail__note { margin-left: auto; opacity: 0.45; }

.chip {
  font-family: var(--mono);
  font-size: 12px;
  border: 1px solid var(--ink);
  background: transparent;
  color: var(--ink);
  border-radius: 0;
  padding: 3px 9px;
  cursor: pointer;
  transition: background 0.3s var(--slow), color 0.3s var(--slow);
}
.chip:hover { background: rgba(0,0,0,0.07); }
.chip[aria-pressed="true"] { background: var(--ink); color: var(--white); }
.chip:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* An unfilled grid position. Dimmed, not a link, and it says what it is. */
.suit--empty { opacity: 0.5; }
.suit--empty .suit__await { background: #f8f9f9; }

/* ===========================================================================
 * BUILD YOUR 2.0 — THE PANEL CONFIGURATOR
 * ---------------------------------------------------------------------------
 * Front and back outlines, click a panel, choose a colour. Forearms also take
 * a pattern.
 *
 * IT STAYS IN THE PAGE'S LANGUAGE. No glass, no radius, no shadow — black line
 * on white, mono labels, hairline seams, exactly like the rack beneath it and
 * exactly like the factory drawings this is derived from. The configurator is
 * the most technical thing on the site; dressing it up would be the one place
 * decoration actually costs comprehension.
 *
 * PANELS ARE SHARED BETWEEN THE TWO VIEWS. "Front and back" is ONE line on
 * every tech pack in the 2027 decks, so colouring the torso colours it in both
 * drawings at once. That is not a shortcut — it is the specification logic,
 * and showing it is half the point of putting both views on screen.
 * ======================================================================== */

.build { padding: clamp(28px,3vw,56px) 16px; border-block: 1px solid rgba(0,0,0,0.14); }

.build__grid {
  display: grid;
  grid-template-columns: minmax(0,1.4fr) minmax(280px,0.9fr);
  gap: clamp(24px,3vw,56px);
  align-items: start;
}
@media (max-width: 940px) { .build__grid { grid-template-columns: 1fr; } }

/* The two drawings, side by side — the same pairing the rack uses. */
.views { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
.view { position: relative; background: var(--white); border: 1px solid rgba(0,0,0,0.14); }
.view svg { width: 100%; height: auto; display: block; }
.view__k {
  position: absolute; top: 8px; left: 10px;
  font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase; opacity: 0.5;
}

/* Every panel is a target. Black hairline seams, the way a flat is drawn. */
.pnl {
  stroke: #111;
  stroke-width: 1.1;
  cursor: pointer;
  transition: filter 0.25s var(--slow);
}
.pnl:hover { filter: brightness(0.92); }
.pnl[data-on="true"] { stroke: #111; stroke-width: 3; }
.pnl:focus-visible { outline: none; stroke-width: 3; }

/* Not selectable: zip, seams, drawn detail. */
.detail { fill: none; stroke: rgba(0,0,0,0.55); stroke-width: 1.2; pointer-events: none; }

/* ---------- THE CONTROLS ------------------------------------------------- */
.ctrl + .ctrl { margin-top: 28px; }
.ctrl__k { font-size: 12px; text-transform: uppercase; letter-spacing: 0.14em; opacity: 0.55; }
.ctrl__v { font-size: 16px; margin-top: 6px; }

.swatches { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.sw {
  width: 46px; height: 46px;
  border: 1px solid rgba(0,0,0,0.25);
  padding: 0; cursor: pointer;
  position: relative;
  transition: transform 0.25s var(--slow);
}
.sw:hover { transform: translateY(-2px); }
.sw[aria-pressed="true"] { border: 2px solid var(--ink); }
.sw[aria-pressed="true"]::after {
  content: ""; position: absolute; inset: -5px; border: 1px solid rgba(0,0,0,0.4);
}
.sw:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.sw__n { display: block; font-size: 12px; margin-top: 6px; text-align: center; }

/* Pattern buttons: the pattern itself is the label, drawn in the panel's own
   current colour so the choice is shown rather than described. */
.pats { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.pat {
  width: 62px; padding: 0; cursor: pointer; background: none;
  border: 1px solid rgba(0,0,0,0.25);
  transition: transform 0.25s var(--slow);
}
.pat:hover { transform: translateY(-2px); }
.pat[aria-pressed="true"] { border: 2px solid var(--ink); }
.pat svg { display: block; width: 100%; height: 46px; }
.pat span { display: block; font-size: 12px; padding: 4px 0 5px; text-align: center; border-top: 1px solid rgba(0,0,0,0.14); }
.pat:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

.ctrl--off { opacity: 0.4; pointer-events: none; }

/* The running schedule, so the drawing and the paperwork never disagree. */
.sched2 { width: 100%; border-collapse: collapse; margin-top: 14px; }
.sched2 th { text-align: left; font-size: 12px; text-transform: uppercase; letter-spacing: 0.12em; opacity: 0.55; font-weight: 400; padding-bottom: 8px; border-bottom: 1px solid rgba(0,0,0,0.25); }
.sched2 td { font-size: 12px; padding: 8px 8px 8px 0; border-bottom: 1px solid rgba(0,0,0,0.12); }
.sched2 tr[data-on="true"] td { background: rgba(0,0,0,0.045); }
.sched2 tr { cursor: pointer; }
.sched2 .dot { display: inline-block; width: 10px; height: 10px; margin-right: 8px; border: 1px solid rgba(0,0,0,0.3); vertical-align: -1px; }

/* ===========================================================================
 * THE NEXUS — brand marks orbiting Ryan, collapsing into a burst
 * ---------------------------------------------------------------------------
 * Twelve seconds. The marks of the houses he built suits for circle him,
 * accelerating, tightening, until they collect at his chest and go off like a
 * sun. Then the frame is just a man in a room again.
 *
 * The whole thing sits in a layer OVER the photograph and touches nothing
 * underneath — no filter on the picture, no blend that would grey it out. It
 * runs once, when the plate is first seen, and can be run again on click.
 *
 * Positions come from JS per frame rather than from CSS keyframes, because the
 * angular velocity ramps and the radius collapses on two different curves;
 * expressing that in keyframes would mean baking one fixed timeline into the
 * stylesheet and losing the ability to tune either.
 * ======================================================================== */

.nexus { position: absolute; inset: 0; z-index: 3; pointer-events: none; overflow: hidden; }

/* Each orbiting mark. Positioned at the nexus origin; JS supplies the offset,
   so the transform origin is always the point they collapse into. */
.nx {
  position: absolute;
  left: 50%; top: 46%;
  display: grid;
  place-items: center;
  transform-origin: 50% 50%;
  will-change: transform, opacity;
  opacity: 0;
  /* Centred on the nexus origin by its own half-size, whatever that is —
     translate(-50%,-50%) rather than a hard-coded margin, because every mark
     is a different width now. */
  translate: -50% -50%;
}
/* NO INVERT FILTER. The marks in assets/houses/alpha/ already carry their own
   transparency — luminance converted to alpha, ink flattened to white, trimmed
   to the bounding box. Inverting a raster keeps its plate, which is why the
   first pass produced white-on-black rectangles instead of floating logos.
   Width is set per mark inline; they are deliberately unequal, because a set
   of logos scaled to one width reads as a sponsor strip. */
.nx img {
  height: auto;
  filter: drop-shadow(0 0 7px rgba(255,255,255,.5)) drop-shadow(0 0 22px rgba(255,214,150,.28));
}
.nx span {
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: 0.08em;
  color: #fff;
  text-shadow: 0 0 8px rgba(255,255,255,.6);
  white-space: nowrap;
}

/* The core: a small sun that grows as the marks arrive. */
.nx-core {
  position: absolute;
  left: 50%; top: 46%;
  width: 26px; height: 26px;
  margin: -13px 0 0 -13px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff 0%, rgba(255,236,190,.95) 38%, rgba(255,190,90,.45) 62%, rgba(255,170,60,0) 74%);
  transform: scale(0);
  opacity: 0;
  will-change: transform, opacity;
}

/* The burst. One expanding ring plus a full-frame wash, both once. */
.nx-burst {
  position: absolute;
  left: 50%; top: 46%;
  width: 40px; height: 40px;
  margin: -20px 0 0 -20px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,.98) 0%, rgba(255,242,214,.7) 30%, rgba(255,200,110,.25) 55%, rgba(255,190,80,0) 70%);
  transform: scale(0);
  opacity: 0;
  will-change: transform, opacity;
}
.nx-wash {
  position: absolute; inset: 0;
  background: radial-gradient(circle at 50% 46%, rgba(255,255,255,.92) 0%, rgba(255,244,220,.5) 26%, rgba(255,255,255,0) 62%);
  opacity: 0;
  will-change: opacity;
}

/* A quiet control, so it can be watched again without a reload. */
.nx-replay {
  position: absolute;
  right: 16px; bottom: 16px;
  z-index: 4;
  pointer-events: auto;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #fff;
  background: rgba(0,0,0,.42);
  border: 1px solid rgba(255,255,255,.5);
  padding: 6px 12px;
  cursor: pointer;
  opacity: 0;
  transition: opacity .6s var(--slow), background .3s var(--slow);
}
.nx-replay[data-show="true"] { opacity: .85; }
.nx-replay:hover { background: rgba(0,0,0,.7); opacity: 1; }

/* Reduced motion: no orbit, no burst. The marks simply sit in their ring,
   which still says "these are the houses" without moving anything. */
@media (prefers-reduced-motion: reduce) {
  .nx { opacity: .9 !important; }
  .nx-core, .nx-burst, .nx-wash { display: none; }
}
