/* JCG Studio — site-v6 canvas: studio floor world, frames, placeholder
   artifacts, /work HUD, drawer, index, and the home preview window.
   World units are CSS px before the camera transform. `--inv` = 1 / scale,
   so labels can hold a constant on-screen size. */

/* ── Floor root ─────────────────────────────────────────────────── */
.floor {
  position: relative;
  overflow: hidden;
  background: var(--void);
  contain: strict;
  --inv: 1;
  /* Layout grid unit (world CSS-px). JS sets these from concepts.json layout.grid;
     fallback keeps the classic 24px studio floor even before createFloor runs. */
  --floor-grid: 24px;
  --floor-grid-n: 24;
}
.floor--full {
  position: fixed;
  inset: 0;
  touch-action: none;
  cursor: grab;
  view-transition-name: floor;
}
.floor--full.is-panning, .floor--preview.is-unlocked.is-panning { cursor: grabbing; }
.floor--preview { position: absolute; inset: 0; touch-action: auto; }
.floor--preview.is-unlocked { touch-action: none; cursor: grab; }

.floor-grid {
  position: absolute; inset: 0;
  pointer-events: none;
  /* Dot pitch + position are driven by canvas.js apply() so they track the
     camera (screen pitch = --floor-grid * scale). Vars document the unit. */
  background-image:
    radial-gradient(circle, rgba(230,233,237,.11) 1px, transparent 1.3px),
    radial-gradient(circle, rgba(230,233,237,.24) 1.2px, transparent 1.7px);
  background-size: var(--floor-grid) var(--floor-grid), calc(var(--floor-grid) * 5) calc(var(--floor-grid) * 5);
}

.world {
  position: absolute; left: 0; top: 0;
  transform-origin: 0 0;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.world.is-moving { will-change: transform; }

/* ── Clusters ───────────────────────────────────────────────────── */
.cluster { position: absolute; transition: opacity var(--dur-3) var(--ease-out), transform 520ms var(--ease-out), filter 420ms linear; }
.cluster::before { --t: 18px; --c: rgba(230,233,237,.14); inset: -28px -28px -28px -28px; }
.cluster.is-dim { opacity: .16; }
.floor--preview .cluster.is-away { visibility: hidden; }
/* Cluster titles counter-scale via --inv so they hold ~constant screen size
   while zoomed in/around fit. Cap inv so world-space type doesn't explode and
   collide when the camera goes far out; below FAR (lod-far) the whole head
   fades away — overview is a constellation of covers, labels return when readable. */
.cluster-head {
  position: absolute; left: 0; right: 0;
  bottom: calc(100% - 140px + 28px * min(var(--inv), 3.2));
  display: grid; gap: calc(10px * min(var(--inv), 2));
  pointer-events: none;
  opacity: 1;
  visibility: visible;
  transition: opacity 160ms linear, visibility 0s linear 0s;
}
.cluster-meta {
  display: flex; align-items: center; gap: calc(12px * min(var(--inv), 2.6));
  font-size: calc(11px * min(var(--inv), 2.6));
  color: var(--chrome-2);
}
.cluster-meta > * { white-space: nowrap; }
.cluster-meta .chip { font-size: inherit; padding: .5em .7em; border-width: calc(1px * min(var(--inv), 2.6)); }
.cluster-name {
  font-family: var(--font-display);
  font-stretch: 122%;
  font-weight: 560;
  letter-spacing: -.025em;
  line-height: 1;
  color: var(--chrome);
  /* Cap matches meta/tag LOD (~fit-all). Uncapped inv kept titles ~22px on
     screen at 8% while covers shrank — names overlapped each other + meta. */
  font-size: max(52px, calc(22px * min(var(--inv), 2.8)));
}
.cluster-member {
  font: 400 calc(13px * min(var(--inv), 2.4))/1.4 var(--font-sans);
  color: var(--chrome-3);
}
.lod-far .cluster-head {
  opacity: 0;
  visibility: hidden;
  transition: opacity 160ms linear, visibility 0s linear 160ms;
}

/* ── Frames ─────────────────────────────────────────────────────── */
.frame {
  position: absolute;
  display: block;
  overflow: visible;
  background: var(--ph-1);
  color: var(--chrome-2);
  -webkit-user-drag: none;
  -webkit-tap-highlight-color: transparent;
}
/* No border at rest (2026-10-01); outlines only mark selection and key focus. */
.frame.is-selected { outline: calc(1px * var(--inv)) solid var(--chrome); }
.frame:focus-visible { outline: calc(1px * var(--inv)) solid var(--chrome); outline-offset: calc(4px * var(--inv)); }
.frame.is-tiny { cursor: zoom-in; }

/* Portfolio covers: flat grey at rest, a media carousel (concepts.json
   media[] → mp4/jpg), or concept art: inline SVG drawn for the Studio
   Concept (assets/concepts/, 2026-10-02). The grey shows until art loads. */
.frame-body { position: absolute; inset: 0; overflow: hidden; }
.frame.is-off .frame-body { content-visibility: hidden; }
.frame-poster, .frame-full { position: absolute; inset: 0; }
.frame-poster { background: var(--ph-1) center / cover no-repeat; }
.frame--cover .frame-poster { background-color: var(--ph-2); }
.frame-full img, .frame-full video,
.cover-slide-media { width: 100%; height: 100%; object-fit: cover; display: block; }
.frame--plan .frame-poster { display: none; }
.concept-art, .concept-art > svg { display: block; width: 100%; height: 100%; }
.lod-poster .frame:not(.frame--plan) .frame-full { display: none; }
.frame-tag {
  position: absolute; z-index: 2;
  left: calc(12px * min(var(--inv), 2.4)); right: calc(12px * min(var(--inv), 2.4)); top: calc(11px * min(var(--inv), 2.4));
  display: flex; justify-content: space-between; align-items: baseline; gap: 1em;
  font-size: calc(11px * min(var(--inv), 2.2));
  color: var(--chrome-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  pointer-events: none;
  transition: color var(--dur-2) linear;
}
.frame--cover .frame-tag { font-size: calc(11px * min(var(--inv), 3.4)); left: calc(16px * min(var(--inv), 3)); right: calc(16px * min(var(--inv), 3)); top: calc(15px * min(var(--inv), 3)); }
.frame-tag b { display: inline-block; font-weight: 400; color: var(--chrome-2); margin-left: .4em; transition: transform var(--dur-3) var(--ease-out); }
.frame:hover .frame-tag, .frame.is-selected .frame-tag, .frame:focus-visible .frame-tag, .is-open > .frame--cover .frame-tag { color: var(--chrome); }
.frame.is-selected .frame-tag > span:first-child::before { content: ""; display: inline-block; width: .55em; height: .55em; margin-right: .6em; background: var(--signal); vertical-align: .05em; }
.lod-far .frame--kid .frame-tag { display: none; }

/* Scan tag inside frames scales with the camera like labels */
.frame .scan-tag { font-size: calc(11px * min(var(--inv), 2.4)); right: calc(8px * min(var(--inv), 2.4)); bottom: calc(8px * min(var(--inv), 2.4)); padding: .45em .6em; border-width: calc(1px * min(var(--inv), 2.4)); }
.frame .scan-band { border-bottom-width: calc(1px * var(--inv)); }

/* ── Covers on the floor ─────────────────────────────────────────────
   Art (grey or living media carousel) + a caption strip under it, no border.
   Hover brightens the caption. Click / tap / Enter / deep link → the
   full-screen item (in-canvas solo panel; neighbors exit). Esc / Close /
   outside restores the camera. The title-card band below is no longer opened
   on the floor (captions carry the info). Reduced motion: simple fades. */

.frame--cover {
  cursor: pointer;
  transition: opacity var(--dur-2) linear;
}
.frame--cover .frame-tag { display: none; } /* rest: no on-tile text */
.frame--cover .scan-tag { display: none !important; } /* no STUDIO CONCEPT chip over media; the scan band runs on hover */
.cluster-head { display: none; } /* titles live on the title card */

/* Cover caption — the reference grid's style (2026-10-01): name + snippet and
   a chip under the art, on pure black, no rule above. Sized for 100% (the
   landing zoom). Below ~60% (lod-poster) it can't be read, so it hides and the
   art takes its space. Height comes from layout.caption (--caption-h). */
.frame--cover .frame-body { bottom: var(--caption-h, 0px); transition: bottom 240ms var(--ease-out); }
.frame-caption {
  /* 2026-10-08 (JC: "the portfolio caption text is tiny even at the default zoom ... shouldn't it be using a similar
     logic to ... the corner widgets?"): zoomed out (below 100%, down to where captions hide at 60%) the caption keeps
     its on-screen size, like the HUD (--inv is 1 / zoom; --k never drops below 1). It grows down into the gutter
     under the cover (the gutter fits it at 60%); zoomed in, it scales with the page as before. */
  --k: max(1, var(--inv, 1));
  position: absolute; left: 0; right: 0; top: calc(100% - var(--caption-h, 0px));
  height: calc(var(--caption-h, 0px) * var(--k));
  display: flex; flex-direction: column; justify-content: space-between;
  padding: calc(16px * var(--k)) calc(18px * var(--k)) calc(18px * var(--k));
  background: #000; /* pure black, not the --void off-black */
  color: var(--chrome-2);
  overflow: hidden;
  pointer-events: none;
  transition: opacity 200ms linear, color var(--dur-2) linear;
}
.frame-caption-text {
  margin: 0;
  font: 400 calc(15px * var(--k))/1.4 var(--font-sans);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
.frame-caption-text b { font-weight: 400; color: var(--chrome); }
.frame-caption-meta {
  margin: 0;
  display: flex; align-items: center; gap: .9em;
  font-size: calc(12px * var(--k));
  color: var(--chrome-3);
  white-space: nowrap; overflow: hidden;
}
.frame-caption-meta .chip { font-size: inherit; padding: .45em .65em; border-width: 1px; }
.frame--cover:hover .frame-caption,
.frame--cover:focus-visible .frame-caption { color: var(--chrome); }
.frame-caption-open {
  margin-left: auto;
  display: inline-flex; gap: .6em;
  color: var(--chrome);
  opacity: 0;
  transition: opacity 160ms linear;
}
.frame-caption-open .arr { transition: transform var(--dur-2) var(--ease-out); }

/* Hover lock-on (canvas.js toggles .is-hot on mouse hover / key focus): the
   corner ticks start loose, overshoot and seat while they flicker bright
   (HUD Label Snap), a scanline sweeps the art (scanline.js) and the caption
   flips to Open → (splitflap.js). Says "this opens" without a title card. */
.cluster.is-hot::before {
  --c: var(--chrome-2);
  animation: tick-lock 520ms var(--ease-snap) both, snap-text 360ms steps(3, end) both;
}
@keyframes tick-lock { from { transform: scale(1.07, 1.09); } to { transform: none; } }
.cluster.is-hot .frame-caption-open { opacity: 1; }
.cluster.is-hot .frame-caption-open .arr { transform: translateX(3px); }
.cluster.is-solo-open::before { opacity: 0; animation: none; } /* the item is opening: no reticle */
.lod-poster .frame--cover .frame-body { bottom: 0; }
.lod-poster .frame-caption { opacity: 0; visibility: hidden; transition: opacity 160ms linear, visibility 0s linear 160ms; }

.cluster.is-open, .cluster.is-picked { z-index: 5; }

/* ── Cover media: manual carousel or one static/looping asset ───── */
.cover-carousel,
.cover-carousel-track,
.cover-slide,
.cover-media-single {
  position: absolute;
  inset: 0;
}
.cover-carousel,
.cover-media-single { z-index: 1; background: var(--ph-2); }
/* Living covers keep their media visible at every LOD. */
.cover-media-slot { position: absolute; inset: 0; z-index: 1; }
.frame--cover.has-media .frame-poster { opacity: 0; }
.frame--cover.has-media .cover-carousel,
.frame--cover.has-media .cover-media-single { z-index: 1; }
.lod-poster .frame--cover.has-media .frame-full { display: none; }

.cover-slide {
  opacity: 0;
  transition: opacity 700ms var(--ease-in-out);
  pointer-events: none;
}
.cover-slide.is-active { opacity: 1; }
.cover-slide-media {
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--ph-2);
}
/* Carousel controls: thin arrows at the edges, dots centred (2026-10-01).
   Constant on-screen size down to 40% zoom (--k), hidden at far zoom. The row
   itself lets clicks through to the cover; only the buttons take input. */
.cover-carousel-controls {
  --k: min(var(--inv, 1), 2.5);
  position: absolute;
  z-index: 3;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: calc(6px * var(--k)) calc(8px * var(--k));
  color: var(--chrome);
  pointer-events: none;
  filter: drop-shadow(0 0 calc(4px * var(--k)) rgba(0, 0, 0, .6));
}
.cover-carousel-controls button {
  appearance: none;
  border: 0;
  padding: 0;
  background: none;
  color: inherit;
  cursor: pointer;
  pointer-events: auto;
  -webkit-tap-highlight-color: transparent;
}
.cover-carousel-arrow {
  min-width: calc(32px * var(--k));
  min-height: calc(32px * var(--k));
  font: 300 calc(17px * var(--k))/1 var(--font-sans);
  opacity: .7;
  transition: opacity var(--dur-2) linear;
}
.cover-carousel-arrow:hover,
.cover-carousel-arrow:focus-visible { opacity: 1; }
.cover-carousel-dots {
  display: flex;
  align-items: center;
}
.cover-carousel-dots > button {
  display: grid;
  place-items: center;
  width: calc(16px * var(--k));
  height: calc(32px * var(--k));
}
.cover-carousel-dots > button::after {
  content: "";
  width: calc(6px * var(--k));
  height: calc(6px * var(--k));
  border-radius: 50%;
  box-shadow: inset 0 0 0 calc(1px * var(--k)) currentColor;
  transition: background-color var(--dur-2) linear;
}
.cover-carousel-dots > button.is-on::after { background-color: currentColor; }
.lod-far .cover-carousel-controls { display: none; }
.folio-stage-cover-media {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: min(52vh, 640px);
  margin: 0 0 36px;
  overflow: hidden;
  background: var(--ph-2);
  outline: 1px solid var(--line-strong);
}
.folio-stage-cover-media .cover-carousel,
.folio-stage-cover-media .cover-media-single,
.folio-stage-cover-media .cover-carousel-track,
.folio-stage-cover-media .cover-slide { position: absolute; inset: 0; }
.folio-stage-cover-media .cover-carousel-controls { --k: 1; padding: 8px 12px; }
.folio-stage-cover-media.is-art {
  aspect-ratio: var(--ar);
  width: min(100%, calc(min(52vh, 640px) * var(--ar)));
  max-height: none;
}
@media (prefers-reduced-motion: reduce) {
  .cover-slide,
  .frame--cover .frame-body,
  .frame-caption { transition: none; }
}

.cluster-band {
  position: absolute;
  visibility: hidden;
  pointer-events: none;
  transition: visibility 0s linear 340ms;
}
.is-open > .cluster-band {
  visibility: visible;
  pointer-events: auto;
  cursor: pointer; /* the whole card opens the item */
  transition-delay: 0s;
}
.band-rule, .band-sheet { position: absolute; display: block; }
.band-rule {
  left: 0; right: 0; top: 50%;
  height: calc(1px * var(--inv));
  background: var(--chrome-3);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 180ms var(--ease-in-out) 140ms, opacity 120ms linear 140ms;
}
[data-dir="left"] > .cluster-band .band-rule { transform-origin: 100% 50%; }
.band-sheet {
  inset: 0;
  background: var(--void-2);
  box-shadow: inset 0 0 0 calc(1px * var(--inv)) var(--line-strong);
  clip-path: inset(50% 0 50% 0);
  transition: clip-path 200ms var(--ease-in-out);
  overflow: hidden;
}
.band-sheet::before { --t: calc(14px * min(var(--inv), 2)); }
.is-open > .cluster-band .band-rule {
  transform: scaleX(1); opacity: 0;
  transition: transform 260ms var(--ease-out), opacity 200ms linear 300ms;
}
.is-open > .cluster-band .band-sheet {
  clip-path: inset(0 0 0 0);
  transition: clip-path 380ms var(--ease-out) 200ms;
}

/* Title card — response rules (2026-09-30, sizes retuned 2026-10-01)
   1. Text inside a card scales with the card, never with zoom: no --inv in this
      block. Sizes are cqi (percent of the band's width), proportioned for the
      landing zoom (100%); rule 4 keeps them legible below it.
   2. The title fits its card: the smaller of its design size (--name) and the
      text column ÷ its longest word (--chars, set in canvas.js). Words never break.
   3. Nothing clips: the description stops at 3 lines, facts stay one line each,
      and short cards (landscape covers) drop the facts.
   4. Legibility comes from level of detail, not inflation: below ~60% zoom
      (lod-poster) only the title is big enough to read, so only the title shows. */
.band-sheet { container: band / size; }
.title-card {
  --pad: clamp(24px, 5.5cqi, 56px);
  --gap: clamp(10px, 1.8cqi, 18px);
  --meta: 1.7cqi;   /* 12px at 100% on a 720 card; ~7px at the 60% detail floor */
  --body: 2.2cqi;   /* 16px at 100%; ~9.5px at 60% */
  --name: 6.5cqi;   /* title design size */
  --advance: .78;   /* widest average glyph advance for the title face, in em */
  position: absolute; inset: 0;
  display: flex; flex-direction: column; gap: var(--gap);
  padding: var(--pad) calc(var(--pad) * 1.1) calc(var(--pad) * .9);
  color: var(--chrome);
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 140ms linear, transform 200ms var(--ease-in-out);
  pointer-events: none;
}
.is-open > .cluster-band .title-card {
  opacity: 1;
  transform: none;
  pointer-events: auto;
  transition: opacity 280ms linear 320ms, transform 420ms var(--ease-out) 300ms;
}
.title-card-meta {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: .9em;
  font-size: var(--meta);
  color: var(--chrome-3);
}
.title-card-meta .chip {
  font-size: inherit;
  padding: .5em .7em;
  border-width: 1px;
}
.title-card-name {
  margin: 0;
  font-family: var(--font-display);
  font-stretch: 122%;
  font-weight: 560;
  letter-spacing: -.03em;
  line-height: .95;
  color: var(--chrome);
  /* Floor of 28px for narrow cards, but the fit clause always wins. */
  font-size: min(max(28px, var(--name)), calc((100cqi - 2.2 * var(--pad)) / (var(--chars, 10) * var(--advance))));
  overflow-wrap: normal;
  word-break: normal;
  hyphens: none;
  text-wrap: balance;
}
.title-card-desc {
  max-width: 36ch;
  font: 400 var(--body)/1.45 var(--font-sans);
  color: var(--chrome-2);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}
.title-card-facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .9em 2.2em;
  margin-top: auto;
  padding-top: 1.4em;
  border-top: 1px solid var(--line);
  font-size: var(--meta);
  color: var(--chrome-3);
}
.title-card-facts div { display: grid; gap: .35em; min-width: 0; }
.title-card-facts dt {
  font-family: var(--font-hud);
  letter-spacing: var(--track-hud);
  text-transform: uppercase;
  color: var(--chrome-3);
}
.title-card-facts dd {
  margin: 0;
  font: 400 calc(var(--meta) * 1.18)/1.3 var(--font-sans);
  color: var(--chrome);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.title-card-open {
  align-self: flex-start;
  min-height: 5cqi;
  padding: 0 2em;
  font: 400 var(--meta)/1 var(--font-hud);
  letter-spacing: var(--track-hud);
  text-transform: uppercase;
  color: var(--void);
  background: var(--chrome);
  border: 1px solid var(--chrome);
  cursor: pointer;
  transition: background var(--dur-1) linear, color var(--dur-1) linear, transform var(--dur-2) var(--ease-out);
}
.title-card-open:hover,
.title-card-open:focus-visible {
  background: transparent;
  color: var(--chrome);
}
.title-card-open:focus-visible {
  outline: 2px solid var(--chrome);
  outline-offset: 3px;
}

/* Rule 4 — below ~60% zoom the card keeps the title only. */
.lod-poster .title-card-meta,
.lod-poster .title-card-desc,
.lod-poster .title-card-facts,
.lod-poster .title-card-open { display: none; }
/* Rule 3 — after the base facts rule, so it wins on source order. */
@container band (max-height: 420px) {
  .title-card-facts { display: none; }
  .title-card-open { margin-top: auto; } /* Open stays at the foot, as on tall cards */
}

/* Title-card personality per layoutMotif — type only, same ink-on-void card.
   Title variants change --name (size) and --advance (glyph width), never the fit rule. */
.title-card--swatch-grid .title-card-name {
  --advance: .64;
  font-family: var(--font-hud); font-stretch: 100%; font-weight: 400;
  letter-spacing: -.02em; line-height: 1;
}
.title-card--swatch-grid .title-card-facts {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .55em 1.3em;
}
.title-card--swatch-grid .title-card-facts dd { font-family: var(--font-hud); }

.title-card--browser-stack .title-card-meta {
  padding: .7em .9em;
  background: var(--void-3);
  box-shadow: inset 0 0 0 1px var(--line);
}
.title-card--browser-stack .title-card-meta::before {
  content: ""; width: 3.1em; height: .7em;
  background: radial-gradient(circle, var(--ph-4) 0 38%, transparent 42%) 0 50% / 1.05em 100% repeat-x;
}

.title-card--deck-spread .title-card-name,
.title-card--deck-stack .title-card-name {
  --name: 5.3cqi;
  --advance: .95;
  font-stretch: 125%; font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .04em; line-height: 1;
}
.title-card--deck-spread .title-card-meta,
.title-card--deck-stack .title-card-meta { letter-spacing: .12em; }

.title-card--doc-rail {
  padding: calc(var(--pad) * 1.3) calc(var(--pad) * 1.2) var(--pad);
}
.title-card--doc-rail .title-card-meta {
  padding-bottom: .9em;
  border-bottom: 1px solid var(--line);
}
.title-card--doc-rail .title-card-name { --name: 5.1cqi; --advance: .64; font-stretch: 100%; }
.title-card--doc-rail .title-card-desc { max-width: 28ch; line-height: 1.6; }
.title-card--doc-rail .title-card-facts { grid-template-columns: 1fr; }

.title-card--poster-hero { gap: calc(var(--gap) * 1.5); padding-top: calc(var(--pad) * 1.5); }
.title-card--poster-hero .title-card-name {
  --name: 7.4cqi;
  line-height: .9;
}

.title-card--social-mosaic .title-card-meta { gap: .5em; }
.title-card--social-mosaic .title-card-meta > span {
  padding: .5em .7em;
  box-shadow: inset 0 0 0 1px var(--line-strong);
  color: var(--chrome-2);
}
.title-card--social-mosaic .title-card-meta .chip { background: var(--chrome); color: var(--void); box-shadow: none; }

.title-card--kit-shelf {
  gap: calc(var(--gap) * .7);
  padding: calc(var(--pad) * .8) calc(var(--pad) * .9) calc(var(--pad) * .7);
}
.title-card--kit-shelf .title-card-name { --name: 5.1cqi; }
.title-card--kit-shelf .title-card-desc { max-width: 52ch; font-size: calc(var(--body) * .87); }
.title-card--kit-shelf .title-card-facts {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .5em 1.2em;
  padding-top: .9em;
}

/* Kids never appear on the floor — dive is the in-canvas solo panel */
.frame--kid { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  .cluster-band, .band-rule, .band-sheet,
  .is-open > .cluster-band .band-rule,
  .is-open > .cluster-band .band-sheet,
  .title-card, .is-open > .cluster-band .title-card {
    transition-delay: 0s !important;
    transition-duration: 160ms !important;
  }
  .band-rule { opacity: 0 !important; transform: none !important; }
  .band-sheet { clip-path: none !important; }
  .title-card { transform: none !important; }
}

/* ── Full-screen item (2026-10-01) ────────────────────────────────────
   Not a modal: one morph (canvas.js morph()). The item's tile grows straight
   into the page's frame while the camera dives (the dot grid zooms, the
   neighbors fly off and fade here); the cover is clipped to that rect and the
   page crossfades in over it: pure black like the captions, corner ticks,
   no border or shadow, the dot grid showing in the margins. Close runs the
   same morph backwards. The sheet's clip and opacity are driven by JS.
   Timeline (ms): morph 0–700 · page ~390–700 · content 600–900.
   Inner content keeps the .folio-stage-* type system. */
.has-solo > .cluster.is-exiting {
  opacity: 0;
  pointer-events: none;
  transition: opacity 360ms linear;
}
.cluster.is-solo { z-index: 8; }
.cluster.is-solo-open > .cluster-band {
  visibility: hidden !important;
  pointer-events: none !important;
  transition: none !important;
}
.cluster.is-solo-open > .frame--cover.is-under-solo {
  opacity: 0; /* set as the morph ends, under the opaque page */
  pointer-events: none;
  transition: none;
}

.folio-panel {
  position: absolute; /* in the floor root, over the world: screen space */
  z-index: 6;
  /* Full screen (JC 2026-10-19): the same HUD edge inset on all four sides; the logo + top nav step away while it's open. */
  top: var(--edge); right: var(--edge); bottom: var(--edge); left: var(--edge);
  display: flex;
  flex-direction: column;
  pointer-events: none;
}
.folio-panel.is-open { pointer-events: auto; }
.folio-panel-sheet {
  position: absolute; inset: 0;
  background: #000; /* the caption's pure black */
  opacity: 0; /* clip + opacity animate from canvas.js during the morph */
  display: flex; flex-direction: column;
  overflow: hidden;
}
.folio-panel-sheet::before { --t: 14px; }
.folio-panel.is-open .folio-panel-sheet { opacity: 1; }
.folio-panel-x {
  position: absolute; z-index: 3;
  top: 12px; right: 12px;
  display: grid; place-items: center;
  width: 40px; height: 40px;
  background: var(--void);
  border: 1px solid var(--line-strong);
  color: var(--chrome-3);
  font: 400 20px/1 var(--font-hud);
  opacity: 0;
  cursor: pointer;
  transition: color var(--dur-1) linear, background var(--dur-1) linear, opacity 160ms linear;
}
.folio-panel.is-open .folio-panel-x { opacity: 1; transition-delay: 0s, 0s, 640ms; }
.folio-panel-x:hover, .folio-panel-x:focus-visible { color: var(--chrome); background: var(--void-3); }
.folio-panel-scroll {
  flex: 1;
  overflow: auto;
  overscroll-behavior: contain;
  padding: 56px 48px 48px;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 140ms linear, transform 200ms var(--ease-in-out);
  outline: none;
  width: 100%;
  max-width: none;
  margin: 0;
  touch-action: pan-y; /* wheel / touch scroll the item, not the floor */
  cursor: default;
  scrollbar-width: none; /* the browser bar is replaced by .folio-panel-thumb */
}
.folio-panel-scroll::-webkit-scrollbar { display: none; }
.folio-panel.is-open .folio-panel-scroll {
  opacity: 1;
  transform: none;
  transition: opacity 300ms linear 600ms, transform 420ms var(--ease-out) 560ms;
}
/* Scroll thumb: a 2 px HUD line on the right edge, shown while scrolling
   (canvas.js sizes and moves it), fading out when idle. No track. */
.folio-panel-thumb {
  position: absolute; top: 0; right: 6px; z-index: 3;
  width: 2px; height: 0;
  background: var(--chrome-3);
  opacity: 0;
  pointer-events: none;
  transition: opacity 400ms linear;
}
.folio-panel-thumb.is-on { opacity: 1; transition-duration: 120ms; }
@media (max-width: 520px) {
  .folio-panel-scroll { padding: 48px 20px 32px; }
}
/* A live page in the panel (the Etherea Loft viewer): edge to edge, it scrolls and pans itself. */
.folio-panel--embed .folio-panel-scroll { padding: 0; overflow: hidden; display: flex; touch-action: none; }
.folio-stage-embed { flex: 1; display: block; width: 100%; height: 100%; border: 0; background: #c8c4bd; }
/* Open item: every HUD piece steps away (logo + Subscribe/menu slide up and fade, zoom/views fade); only the item's × stays.
   They come back on close (×, Esc, back). */
.hud-bottom { transition: opacity 200ms linear, visibility 0s; }
.solo-open .hud-bottom {
  opacity: 0;
  visibility: hidden;
  transition: opacity 200ms linear, visibility 0s linear 200ms;
}
.page-work .hud-brand.hud-panel, .page-work .hud-actions.hud-panel {
  transition: opacity 200ms linear 120ms, translate 280ms var(--ease-out) 120ms, visibility 0s;
}
.solo-open .hud-brand.hud-panel, .solo-open .hud-actions.hud-panel, .solo-open .rm-note {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  translate: 0 -10px;
  transition: opacity 160ms linear, translate 220ms var(--ease-in-out), visibility 0s linear 220ms;
}
.solo-open .rm-note { translate: -50% -10px; }
.folio-stage-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  color: var(--chrome-3);
}
.folio-stage-title {
  margin-top: 20px;
  font: 560 clamp(42px, 6vw, 88px)/.95 var(--font-display);
  font-stretch: 122%;
  letter-spacing: -.03em;
  color: var(--chrome);
}
.folio-stage-member {
  margin-top: 14px;
  font: 400 14px/1.5 var(--font-sans);
  color: var(--chrome-3);
  max-width: 52ch;
}
.folio-stage-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 16px 28px;
  margin-top: 28px;
  padding: 20px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  color: var(--chrome-3);
}
.folio-stage-facts div { display: grid; gap: 6px; }
.folio-stage-facts dt {
  font-family: var(--font-hud);
  letter-spacing: var(--track-hud);
  text-transform: uppercase;
  font-size: 11px;
}
.folio-stage-facts dd {
  margin: 0;
  font: 400 14px/1.35 var(--font-sans);
  color: var(--chrome);
}
.folio-stage-desc {
  margin-top: 28px;
  max-width: 58ch;
  font: 400 clamp(17px, 1.2vw + 12px, 20px)/1.55 var(--font-sans);
  color: var(--chrome);
}
.folio-stage-ask {
  margin-top: 22px;
  max-width: 52ch;
  padding-left: 16px;
  border-left: 1px solid var(--line-strong);
  font: 400 15px/1.5 var(--font-sans);
  color: var(--chrome-3);
}
.folio-stage-shipped { margin-top: 36px; }
.folio-stage-shipped h3,
.folio-stage-assets h3 {
  color: var(--chrome-3);
  margin-bottom: 14px;
}
.folio-stage-shipped ul {
  display: grid; gap: 8px;
  max-width: 48ch;
}
.folio-stage-shipped li {
  position: relative;
  padding-left: 18px;
  font: 400 15px/1.45 var(--font-sans);
  color: var(--chrome-2);
}
.folio-stage-shipped li::before {
  content: "+";
  position: absolute; left: 0; top: 2px;
  font: 400 11px/1 var(--font-hud);
  color: var(--chrome-3);
}
/* The studio's three moves (Designed / Taught / Stayed on), in order */
.folio-stage-moves { margin-top: 36px; }
.folio-stage-moves h3 { color: var(--chrome-3); margin-bottom: 14px; }
.folio-stage-moves ol { list-style: none; margin: 0; padding: 0; display: grid; gap: 18px; }
.folio-stage-moves li { display: grid; gap: 6px; align-content: start; padding-top: 12px; border-top: 1px solid var(--line); }
.folio-stage-moves h4 { font: 540 15px/1.3 var(--font-sans); color: var(--chrome); }
.folio-stage-moves p { max-width: 48ch; font: 400 15px/1.5 var(--font-sans); color: var(--chrome-2); }
@media (min-width: 900px) { .folio-stage-moves ol { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; } }
.folio-stage-assets { margin-top: 48px; }
.folio-stage-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px 24px;
}
@media (min-width: 700px) {
  .folio-stage-grid { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 1100px) {
  .folio-stage-grid { grid-template-columns: 1fr 1fr 1fr; }
}
.folio-asset {
  display: grid; gap: 10px;
  color: inherit;
  transition: opacity var(--dur-2) linear;
}
.folio-asset { min-width: 0; }
.folio-asset-thumb {
  position: relative;
  display: block; width: 100%;
  background: var(--ph-2);
  outline: 1px solid var(--line-strong);
}
.folio-asset-view { position: relative; display: block; width: 100%; }
.folio-asset-view > .concept-art { position: absolute; inset: 0; }
.folio-asset-view > .concept-still { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.folio-asset.has-art .folio-asset-thumb { background: var(--void-2); }
/* Every motif: on a phone, wide art (fa-lg: drawn 560+ px wide) keeps a
   legible 560 px and scrolls sideways instead of shrinking to half. */
.folio-stage-assets { container-type: inline-size; }
@container (max-width: 599px) {
  .folio-asset.fa-lg.has-art .folio-asset-thumb { overflow-x: auto; overscroll-behavior-x: contain; }
  .folio-asset.fa-lg.has-art .folio-asset-thumb > * { width: 560px; }
}
.folio-asset:hover .folio-asset-thumb,
.folio-asset.is-focus .folio-asset-thumb {
  outline-color: var(--chrome);
}
.folio-asset:focus-visible .folio-asset-thumb {
  outline: 1px solid var(--chrome);
  outline-offset: 4px;
}
.folio-asset-label { color: var(--chrome-2); }
.folio-asset:hover .folio-asset-label,
.folio-asset.is-focus .folio-asset-label { color: var(--chrome); }
.folio-asset-note {
  font: 400 13px/1.45 var(--font-sans);
  color: var(--chrome-3);
}
/* ── Folio stage: asset layout per layoutMotif ──────────────────────
   Same links, different structure. Flat grey only — the one allowed
   furniture is structural (browser bar, shelf rule, swatch index). */
.folio-stage--deck-spread .folio-stage-scroll,
.folio-stage--social-mosaic .folio-stage-scroll,
.folio-stage--kit-shelf .folio-stage-scroll { max-width: 1360px; }

/* swatch-grid — the kit sheet: each page of the system on hairlines, numbered.
   On a wide panel, sheets take 2 of 6 columns and fa-lg pages 3, so the art
   lands near 1:1. Narrower panels stack them (phones: see fa-lg above). */
.fa-swatch {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
@container (min-width: 1100px) {
  .fa-swatch { grid-template-columns: repeat(6, 1fr); }
  .fa-swatch .folio-asset { grid-column: span 2; }
  .fa-swatch .folio-asset.fa-lg { grid-column: span 3; }
}
.fa-swatch .folio-asset { align-content: start; gap: 10px; padding-bottom: 14px; background: var(--void); }
.fa-swatch .folio-asset-thumb { outline: none; }
.fa-swatch .folio-asset:hover .folio-asset-thumb,
.fa-swatch .folio-asset.is-focus .folio-asset-thumb { outline: 1px solid var(--chrome); outline-offset: -1px; }
.fa-swatch .folio-asset-label { display: flex; justify-content: space-between; gap: 12px; font-size: 11px; }
.fa-swatch-no { color: var(--chrome-3); }
/* Stacked (narrow panels): cap the art near 1.5× so sheets don't balloon. */
.fa-swatch .folio-asset > * { max-width: 640px; }
.fa-swatch .folio-asset.fa-lg > * { max-width: 960px; }
.fa-swatch .folio-asset-label,
.fa-swatch .folio-asset-note { padding: 0 12px; }
.fa-swatch .folio-asset-note { font-size: 12px; max-width: 64ch; }

/* browser-stack — each page in a bare browser frame, stacked, alternately offset */
.fa-browser { display: grid; gap: 56px; }
.fa-browser .folio-asset {
  --off: 0px;
  /* one scale for every page (1.25× its drawn width), so type sizes match across the stack */
  width: min(calc(100% - var(--off)), calc(var(--w) * 1.25px));
  margin-left: var(--off);
}
.fa-browser .folio-asset:nth-child(even) { --off: clamp(0px, 6vw, 72px); }
.fa-chrome {
  display: flex; align-items: center; gap: 6px;
  height: 26px; padding: 0 12px;
  background: var(--ph-3);
  border-bottom: 1px solid var(--line-strong);
}
.fa-chrome i { width: 8px; height: 8px; border-radius: 50%; background: var(--ph-4); }
.fa-phone .folio-asset-thumb { border-radius: 28px; overflow: hidden; }

/* deck-spread — slides dealt across a table: overlap, slight tilt */
.fa-spread {
  --slide-h: clamp(140px, 12.5vw, 200px);
  display: flex; align-items: flex-start;
  overflow-x: auto;
  padding: 24px 12px 16px;
  scrollbar-width: thin;
}
.fa-spread .folio-asset {
  position: relative;
  flex: 0 0 auto;
  width: max(200px, calc(var(--ar) * var(--slide-h)));
}
.fa-spread .folio-asset + .folio-asset { margin-left: -36px; }
.fa-spread .folio-asset:not(:last-child) .folio-asset-label,
.fa-spread .folio-asset:not(:last-child) .folio-asset-note { padding-right: 48px; }
.fa-spread .folio-asset-thumb {
  width: calc(var(--ar) * var(--slide-h));
  transform: rotate(-1.4deg);
  box-shadow: 0 0 0 5px var(--void);
}
.fa-spread .folio-asset:nth-child(even) .folio-asset-thumb { transform: translateY(12px) rotate(1.1deg); }
.fa-spread .folio-asset:nth-child(even) .folio-asset-label { margin-top: 12px; }
.fa-spread .folio-asset:hover,
.fa-spread .folio-asset.is-focus,
.fa-spread .folio-asset:focus-visible { z-index: 2; }

/* deck-stack — slides piled in Z: each one steps right and overlaps the last */
.fa-stack { display: grid; gap: 28px; }
.fa-stack .folio-asset {
  position: relative; z-index: var(--i);
  grid-template-columns: minmax(0, 1fr);
}
.fa-stack .folio-asset-thumb { width: min(100%, calc(var(--ar) * 315px)); box-shadow: 0 0 0 6px var(--void); }
@media (min-width: 760px) {
  .fa-stack { gap: 0; }
  .fa-stack .folio-asset {
    grid-template-columns: minmax(0, 560px) minmax(200px, 1fr);
    grid-template-rows: auto 1fr;
    column-gap: 32px; row-gap: 8px;
    align-content: start;
    margin-left: calc(var(--i) * 22px);
  }
  .fa-stack .folio-asset + .folio-asset { margin-top: -56px; }
  .fa-stack .folio-asset-thumb { grid-row: 1 / span 2; }
  .fa-stack .folio-asset-label { padding-top: 12px; }
}

/* doc-rail — one dominant page, supporting files in a narrow rail */
.fa-rail { display: grid; gap: 32px; }
.fa-doc .folio-asset-thumb { max-width: 640px; background: var(--ph-1); }
.fa-rail-side { display: grid; gap: 20px; align-content: start; }
.fa-rail-side .folio-asset {
  grid-template-columns: 88px minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  column-gap: 14px; row-gap: 6px;
  align-items: start;
}
.fa-rail-side .folio-asset-thumb { grid-row: 1 / span 2; }
.fa-rail-side .folio-asset-note { font-size: 12px; }
@media (min-width: 800px) {
  .fa-rail { grid-template-columns: minmax(0, 1.9fr) minmax(220px, 1fr); align-items: start; }
  .fa-rail-side { padding-left: 24px; border-left: 1px solid var(--line); }
}

/* poster-hero — one tall hero on the wall, companions small on a ledge */
.fa-poster { display: grid; gap: 40px; }
.fa-hero { grid-template-columns: minmax(0, 1fr); }
.fa-poster-row {
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: 24px 28px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}
.fa-poster-row .folio-asset { flex: 0 0 auto; width: max(160px, min(100%, calc(var(--ar) * 140px))); }
.fa-poster-row .folio-asset-thumb { width: min(100%, calc(var(--ar) * 140px)); }
.fa-poster-row .folio-asset-note { font-size: 12px; }
@media (min-width: 700px) {
  .fa-hero {
    grid-template-columns: auto minmax(0, 32ch);
    grid-template-rows: 1fr auto;
    column-gap: 32px; row-gap: 8px;
    justify-content: start; align-items: end;
  }
  .fa-hero .folio-asset-thumb { grid-row: 1 / span 2; height: min(70vh, 880px); width: auto; aspect-ratio: var(--ar); }
  .fa-hero .folio-asset-view { height: 100%; }
}

/* social-mosaic — justified rows: every card keeps its own ratio, rows share a height */
.fa-mosaic { display: flex; flex-wrap: wrap; gap: 28px 12px; }
.fa-mosaic::after { content: ""; flex: 999 1 0; }
.fa-mosaic .folio-asset { flex: var(--ar) 1 calc(var(--ar) * 260px); gap: 8px; }
.fa-mosaic .folio-asset-note { font-size: 12px; }

/* kit-shelf — components standing on shelf rules, labels above, dense */
.fa-shelves { display: grid; gap: 56px; }
.fa-shelf { position: relative; border-bottom: 3px solid var(--ph-3); }
.fa-shelf-items { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 20px 28px; }
.fa-shelf .folio-asset { flex: 0 1 auto; width: min(100%, calc(var(--ar) * 200px)); gap: 6px; }
.fa-shelf .folio-asset-label { order: 1; }
.fa-shelf .folio-asset-note { order: 2; font-size: 12px; margin-bottom: 6px; }
.fa-shelf .folio-asset-thumb { order: 3; }
.fa-shelf-no { position: absolute; right: 0; bottom: -24px; font-size: 11px; color: var(--chrome-3); }
/* legacy .stage-open class no longer applied; solo-open keeps HUD faintly */

@media (prefers-reduced-motion: reduce) {
  .folio-panel-sheet, .folio-panel-scroll, .folio-panel-x,
  .has-solo > .cluster.is-exiting {
    transition-delay: 0s !important;
    transition-duration: 160ms !important;
  }
  .folio-panel-scroll { transform: none !important; }
  .folio-panel-sheet { transition: opacity 160ms linear !important; } /* no morph: a plain fade */
  .page-work .hud-brand.hud-panel, .page-work .hud-actions.hud-panel, .hud-bottom, .rm-note,
  .solo-open .hud-brand.hud-panel, .solo-open .hud-actions.hud-panel, .solo-open .hud-bottom, .solo-open .rm-note {
    transition: none !important; /* the HUD just goes and comes back */
  }
}

/* ── End-of-floor plan card (frames.js; live HTML, not portfolio media) ── */
.wf {
  position: absolute; inset: 0;
  display: grid; gap: 10px; align-content: start;
  padding: 20px;
  font: 400 10px/1.2 var(--font-sans);
  color: var(--ph-4);
}

.wf-plan {
  display: flex; flex-direction: column; gap: 8px;
  padding: 18px 20px;
  background: var(--void-2);
  font-family: var(--font-sans);
  user-select: none;
}
.wf-plan-top { display: flex; justify-content: space-between; color: var(--chrome-3); }
.wf-plan-top .hud:first-child { color: var(--signal); }
.wf-plan-h { margin: 4px 0 2px; font: 540 22px/1.1 var(--font-display); font-stretch: 118%; letter-spacing: -.015em; color: var(--chrome); }
.wf-plan-row {
  display: grid; grid-template-columns: 1fr auto; align-items: center; column-gap: 8px; row-gap: 3px;
  min-height: 44px; padding: 6px 0;
  border-top: 1px solid var(--line);
  color: var(--chrome-2); font-size: 14px;
  transition: color var(--dur-1) linear;
}
.wf-plan-row b { grid-row: span 2; font: 520 20px/1 var(--font-display); font-stretch: 125%; letter-spacing: -.02em; color: var(--chrome); font-variant-numeric: tabular-nums; }
.wf-plan-row b small { font: 400 11px/1 var(--font-hud); color: var(--chrome-3); letter-spacing: .04em; margin-left: 2px; }
.wf-plan-row .hud { font-size: 11px; }
.wf-plan-row:hover { color: var(--chrome); }
.wf-plan-cta { margin-top: auto; width: 100%; }
.frame--plan { background: var(--void-2); outline-color: var(--line-strong); }

/* ── /work page chrome ──────────────────────────────────────────── */
.page-work { overflow: hidden; overscroll-behavior: none; height: 100%; }
.page-work body { height: 100%; overflow: hidden; overscroll-behavior: none; }
.page-work[data-view="index"] body,
.page-work[data-view="grid"] body,
.page-work[data-view="list"] body,
.no-js.page-work body { overflow: auto; }
.page-work.no-js,
.page-work[data-view="index"],
.page-work[data-view="grid"],
.page-work[data-view="list"] { overflow: auto; height: auto; min-height: 100%; }

.hud-bottom {
  position: fixed; z-index: 20; left: var(--edge); right: var(--edge); bottom: var(--edge);
  display: flex; align-items: flex-end; justify-content: space-between; gap: 8px;
  pointer-events: none;
}
.hud-bottom > * { pointer-events: auto; }
.hud-btn {
  display: inline-grid; place-items: center;
  min-width: 36px; height: 34px; padding: 0 8px;
  font: 400 11px/1 var(--font-hud); letter-spacing: var(--track-hud); text-transform: uppercase;
  color: var(--chrome-2);
  transition: color var(--dur-1) linear, background var(--dur-1) linear;
}
.hud-btn:hover { color: var(--chrome); background: var(--void-3); }
.hud-btn + .hud-btn, .hud-readout + .hud-btn, .hud-btn + .hud-readout { border-left: 1px solid var(--line); }
.hud-btn svg { width: 12px; height: 12px; }
.hud-readout { min-width: 52px; height: 34px; display: inline-grid; place-items: center; font: 400 11px/1 var(--font-hud); color: var(--chrome); font-variant-numeric: tabular-nums; }
@media (max-width: 520px) {
  .hud-btn { min-width: 40px; height: 40px; padding: 0 8px; }
  .hud-readout { min-width: 48px; height: 40px; }
  .hud-btn[data-fit] .lbl { display: none; }
}

/* View switcher (Grid / List / Canvas): the same panel as the other corners;
   the current view is lit, the others sit back. */
.hud-views .hud-btn { padding: 0 12px; color: var(--chrome-3); }
.hud-views .hud-btn:hover { color: var(--chrome-2); }
.hud-views .hud-btn[aria-pressed="true"] { color: var(--chrome); background: var(--void-3); }
@media (max-width: 520px) { .hud-views .hud-btn { padding: 0 8px; } }   /* zoom + views fit between the 12 px edges on a 375 px phone */

/* Zoom is canvas-only; the view switcher stays bottom-right in every view. */
.hud-bottom > .hud-views { margin-left: auto; }
.page-work[data-view="grid"] .hud-bottom > .hud-panel:not(.hud-views),
.page-work[data-view="list"] .hud-bottom > .hud-panel:not(.hud-views),
.page-work[data-view="index"] .hud-bottom > .hud-panel:not(.hud-views) { display: none; }
.page-work[data-view="grid"] .hud-bottom,
.page-work[data-view="list"] .hud-bottom,
.page-work[data-view="index"] .hud-bottom { justify-content: flex-end; }

.rm-note {
  position: fixed; z-index: 21; left: 50%; top: calc(var(--edge) + var(--hud-row) + 10px); translate: -50% 0;
  display: flex; align-items: center; gap: 10px;
  padding: 0 4px 0 12px;
  background: var(--void-2); border: 1px solid var(--line-strong);
  color: var(--chrome-2);
  white-space: nowrap;
}
.rm-note button { min-height: 44px; padding: 0 10px; color: var(--chrome); font: 400 11px/1 var(--font-hud); letter-spacing: var(--track-hud); text-transform: uppercase; }

.floor-error {
  position: fixed; z-index: 21; left: 50%; bottom: calc(var(--edge) + 64px); translate: -50% 0;
  padding: 10px 14px; max-width: calc(100vw - 2 * var(--edge));
  background: var(--void-3); border: 1px solid color-mix(in srgb, var(--signal) 45%, transparent); color: var(--chrome);
}

/* ── Drawer ─────────────────────────────────────────────────────── */
.drawer {
  position: fixed; z-index: 25;
  top: calc(var(--edge) + var(--hud-row) + 10px); right: var(--edge); bottom: calc(var(--edge) + 56px);
  width: min(400px, calc(100vw - 2 * var(--edge)));
  display: flex; flex-direction: column;
  background: var(--void-3);
  border: 1px solid var(--line-strong);
  transform: translateX(calc(100% + 2 * var(--edge)));
  transition: transform var(--dur-3) var(--ease-out);
}
.drawer.is-open { transform: none; }
.drawer-grip { display: none; }
.drawer-x {
  position: absolute; top: 8px; right: 8px; z-index: 2;
  display: grid; place-items: center; width: 44px; height: 44px;
  color: var(--chrome-3); font: 400 22px/1 var(--font-hud);
}
.drawer-x:hover { color: var(--chrome); }
.drawer-scroll { flex: 1; overflow: auto; overscroll-behavior: contain; padding: 18px 22px 22px; }
.drawer-top { display: flex; align-items: center; gap: 10px; padding-right: 40px; min-height: 28px; }
.drawer-frame { margin-top: 18px; color: var(--chrome-3); display: flex; align-items: center; gap: 8px; }
.drawer-frame::before { content: ""; width: 6px; height: 6px; background: var(--signal); box-shadow: 0 0 0 3px var(--signal-glow); }
.drawer-title { margin-top: 10px; font: 560 30px/1.04 var(--font-display); font-stretch: 120%; letter-spacing: -.02em; color: var(--chrome); outline: none; }
.drawer-member { margin-top: 8px; font: 400 13px/1.5 var(--font-sans); color: var(--chrome-3); }
.drawer-thumb { position: relative; margin-top: 18px; width: 100%; overflow: hidden; background: var(--ph-1); outline: 1px solid var(--line); }
.drawer-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.thumb-label { position: absolute; left: 10px; top: 10px; color: var(--chrome-3); }
.thumb-tag { position: absolute; right: 8px; bottom: 8px; padding: 5px 7px; background: var(--void); border: 1px solid var(--line-strong); color: var(--chrome-3); }
.drawer-note { margin-top: 16px; font-size: 15px; line-height: 1.55; color: var(--chrome); }
.drawer-meta { margin-top: 18px; border-top: 1px solid var(--line); }
.drawer-meta > div { display: grid; grid-template-columns: 84px 1fr; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.drawer-meta dt { color: var(--chrome-3); padding-top: 4px; }
.drawer-meta dd { margin: 0; font-size: 14px; line-height: 1.5; color: var(--chrome-2); }
.drawer-meta dd.hud { padding-top: 4px; color: var(--chrome); }
.drawer-meta li { position: relative; padding-left: 16px; }
.drawer-meta li::before { content: "+"; position: absolute; left: 0; top: 4px; font: 400 11px/1 var(--font-hud); color: var(--chrome-3); }
.drawer-frames { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 18px; }
.drawer-frames .chip { min-height: 44px; padding: 0 10px; }
.drawer-frames .chip:hover { color: var(--chrome); border-color: var(--line-strong); }
.drawer-frames .chip[aria-current] { color: var(--void); background: var(--chrome); border-color: var(--chrome); }
.drawer-pager { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 16px; }
.drawer-cta { display: grid; gap: 10px; padding: 14px 22px 18px; border-top: 1px solid var(--line); }
.drawer-cta .btn { width: 100%; }
.drawer-cta p { color: var(--chrome-3); text-align: center; }

@media (max-width: 759px) {
  .drawer {
    top: auto; left: 0; right: 0; bottom: 0;
    width: auto; max-height: 58vh; max-height: 58dvh;
    border-width: 1px 0 0;
    transform: translateY(100%);
  }
  .drawer.is-open { transform: none; }
  .drawer.is-dragging { transition: none; }
  .drawer-grip { display: grid; place-items: center; height: 28px; touch-action: none; cursor: grab; }
  .drawer-grip i { width: 40px; height: 3px; background: var(--line-strong); }
  .drawer-x { top: 2px; }
  .drawer-scroll { padding-top: 4px; }
  .drawer-open .hud-bottom { opacity: 0; pointer-events: none; }
}

/* ── Grid + List portfolio views (scrollable; filters apply) ─────── */
.folio {
  position: relative;
  padding: 96px 0 120px;
  min-height: 100vh;
}
.js .folio {
  position: fixed; inset: 0; overflow: auto; z-index: 10;
  background: var(--void); overscroll-behavior: contain;
  padding-bottom: 100px;
}
.folio-wrap { padding-top: 8px; }
/* JC 2026-10-22: no headline in Grid or List; the heading stays for screen readers (as .sr-only) */
.folio-head { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* Grid: 2×2 covers with clear horizontal + vertical gutters (~80–120px). */
.folio-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(56px, 7vw, 120px);
  padding-bottom: 40px;
}
@media (min-width: 760px) {
  .folio-grid {
    grid-template-columns: 1fr 1fr;
    column-gap: clamp(64px, 8vw, 120px);
    row-gap: clamp(72px, 9vw, 124px);
  }
}
.folio-card {
  display: grid;
  gap: 16px;
  color: inherit;
  min-width: 0;
  transition: opacity var(--dur-2) linear;
}
.folio-card.is-dim, .folio-row.is-dim { opacity: .28; }
.folio-cover {
  position: relative;
  aspect-ratio: 960 / 600;
  width: 100%;
  background: var(--ph-2);
  outline: 1px solid var(--line-strong);
  overflow: hidden;
}
.folio-cover .cover-carousel,
.folio-cover .cover-carousel-track,
.folio-cover .cover-slide { position: absolute; inset: 0; }
.folio-cover .cover-carousel-controls { --k: 1; }
.folio-cover-tag {
  position: absolute; left: 16px; right: 16px; top: 15px;
  display: flex; justify-content: space-between; gap: 1em;
  color: transparent; /* quiet covers; meta lives under the card */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  pointer-events: none;
  transition: color var(--dur-2) linear;
}
.folio-card:hover .folio-cover { outline-color: var(--chrome-3); }
.folio-card:hover .folio-cover-tag,
.folio-card:focus-visible .folio-cover-tag { color: var(--chrome); }
.folio-card:focus-visible .folio-cover {
  outline: 1px solid var(--chrome);
  outline-offset: 4px;
}
.folio-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  color: var(--chrome-3);
}
.folio-name {
  font: 560 clamp(26px, 1.6vw + 16px, 36px)/1.05 var(--font-display);
  font-stretch: 120%; letter-spacing: -.02em; color: var(--chrome);
}
.folio-member {
  font: 400 13px/1.45 var(--font-sans); color: var(--chrome-3);
}
.folio-desc {
  font: 400 14px/1.45 var(--font-sans); color: var(--chrome-2);
  max-width: 42ch;
}
.folio-facts {
  margin-top: 2px;
  color: var(--chrome-3);
}

/* List: compact rows — id · name · kind · frames. */
.folio-list {
  display: grid;
  border-top: 1px solid var(--line);
}
.folio-list-head,
.folio-row {
  display: grid;
  grid-template-columns: 72px minmax(0, 1.6fr) 110px 72px 36px;
  gap: 12px;
  align-items: center;
  min-height: 56px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}
.folio-list-head {
  color: var(--chrome-3);
  min-height: 40px;
  padding-top: 0;
  border-bottom-color: var(--line-strong);
}
.folio-row {
  color: inherit;
  transition: background var(--dur-1) linear, opacity var(--dur-2) linear;
}
.folio-row:hover { background: rgba(230, 233, 237, .03); }
.folio-row:focus-visible {
  outline: 1px solid var(--chrome);
  outline-offset: 2px;
}
.folio-row-id { color: var(--chrome-2); font-variant-numeric: tabular-nums; }
.folio-row-name {
  display: grid; gap: 4px; min-width: 0;
}
.folio-row-name b {
  font: 520 16px/1.2 var(--font-display);
  font-stretch: 118%; letter-spacing: -.015em; color: var(--chrome);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.folio-row-name .mute {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font: 400 12px/1.3 var(--font-sans);
}
.folio-row-kind { color: var(--chrome-3); }
.folio-row-frames {
  color: var(--chrome-2);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.folio-row-go { color: var(--chrome-3); text-align: right; transition: transform var(--dur-2) var(--ease-out), color var(--dur-1) linear; }
.folio-row:hover .folio-row-go { color: var(--chrome); transform: translateX(3px); }
@media (max-width: 700px) {
  .folio-list-head { display: none; }
  .folio-row {
    grid-template-columns: 64px minmax(0, 1fr) auto 28px;
    gap: 2px 10px;
    min-height: 64px;
    align-items: center;
  }
  .folio-row-id { grid-column: 1; grid-row: 1 / span 2; align-self: start; padding-top: 4px; }
  .folio-row-name { grid-column: 2 / span 2; grid-row: 1; }
  .folio-row-kind { grid-column: 2; grid-row: 2; font-size: 11px; }
  .folio-row-frames { grid-column: 3; grid-row: 2; font-size: 11px; text-align: left; }
  .folio-row-frames::before { content: "· "; color: var(--chrome-3); }
  .folio-row-go { grid-column: 4; grid-row: 1 / span 2; }
}

/* ── Index view (also the no-JS + screen-reader path) ───────────── */
.index {
  position: relative;
  padding: 96px 0 120px;
  min-height: 100vh;
}
.js .index { position: fixed; inset: 0; overflow: auto; z-index: 10; background: var(--void); overscroll-behavior: contain; }
.index-head { display: grid; gap: 16px; padding-bottom: 40px; }
.index-head .h2 { margin-top: 8px; }
.idx-concept { display: grid; gap: 24px; padding: 40px 0; border-top: 1px solid var(--line); scroll-margin-top: 100px; }
@media (min-width: 900px) { .idx-concept { grid-template-columns: .9fr 1.4fr; gap: 56px; } }
.idx-concept .idx-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; color: var(--chrome-3); }
.idx-concept h2 { margin-top: 12px; font: 560 clamp(28px, 2vw + 18px, 40px)/1.05 var(--font-display); font-stretch: 120%; letter-spacing: -.02em; color: var(--chrome); }
.idx-concept .member { margin-top: 10px; font: 400 13px/1.5 var(--font-sans); color: var(--chrome-3); }
.idx-concept .blurb { color: var(--chrome-2); max-width: 62ch; }
.idx-concept blockquote { margin-top: 16px; padding-left: 14px; border-left: 1px solid var(--line-strong); color: var(--chrome-3); font-size: 15px; }
.idx-moves { display: grid; gap: 8px; max-width: 62ch; margin: 16px 0 0; padding: 0; list-style: none; font-size: 14px; line-height: 1.5; color: var(--chrome-2); }
.idx-moves strong { margin-right: 6px; font-weight: 540; color: var(--chrome); }
.idx-frames { display: grid; gap: 0; margin-top: 20px; border-top: 1px solid var(--line); }
@media (min-width: 600px) { .idx-frames { grid-template-columns: 1fr 1fr; column-gap: 24px; } }
.idx-frames a, .idx-frames .idx-plan {
  display: grid; grid-template-columns: 64px 1fr; gap: 14px; align-items: center;
  min-height: 64px; padding: 10px 0;
  border-bottom: 1px solid var(--line);
  scroll-margin-top: 100px;
}
.idx-frames a:hover .lbl { color: var(--chrome); }
.idx-thumb { height: 40px; width: auto; max-width: 64px; background: var(--ph-1); outline: 1px solid var(--line); justify-self: start; }
.idx-frames .lbl { color: var(--chrome-2); }
.idx-frames .note { display: block; margin-top: 4px; font-size: 13px; line-height: 1.4; color: var(--chrome-3); }
.index-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px; padding-top: 40px; border-top: 1px solid var(--line); }
.no-js .floor, .no-js .hud-bottom { display: none; }

/* ── Home preview window ────────────────────────────────────────── */
.floor-window {
  position: relative;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line);
  background: var(--void);
  view-transition-name: floor;
}
.floor-window::before { inset: -7px; z-index: 3; }
@media (max-width: 759px) { .floor-window { aspect-ratio: 4 / 5; } }
.fw-hud {
  position: absolute; z-index: 4; left: 0; right: 0;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 12px;
  pointer-events: none;
}
.fw-hud > * { pointer-events: auto; }
.fw-hud--top { top: 0; background: linear-gradient(var(--void) 10%, rgba(11,12,14,0)); }
.fw-hud--bottom { bottom: 0; background: linear-gradient(rgba(11,12,14,0), var(--void) 90%); }
.fw-hud .hud { color: var(--chrome-3); }
.fw-hud .hud b { font-weight: 400; color: var(--chrome); }
.fw-explore[aria-pressed="true"] { background: var(--chrome); color: var(--void); border-color: var(--chrome); }
.fw-fallback { position: absolute; inset: 0; display: grid; place-items: center; padding: 64px 40px; }
.fw-fallback span { width: min(60%, 560px); aspect-ratio: 8 / 5; background: var(--ph-1); outline: 1px solid var(--line); display: grid; place-items: center; font: 400 11px/1 var(--font-hud); color: var(--ph-4); letter-spacing: .06em; }
.js .floor-window .fw-fallback { display: none; }
.js .floor-window.is-failed .fw-fallback { display: grid; }

@media (prefers-reduced-motion: reduce) {
  .cluster, .cluster-head, .drawer, .frame, .folio-panel { transition: none; }
}

/* Target acquired (play layer, 2026-10-05): a locked-on cover shows mono tags of real facts from concepts.json (id, work
   type, frames, date), top left over the art, at a constant screen size like the floor's other labels. On a touch screen
   the first tap locks on and the second opens (canvas.js). */
.lock-tags {
  position: absolute; z-index: 4;
  left: calc(12px * min(var(--inv), 2.4)); top: calc(12px * min(var(--inv), 2.4));
  display: flex; flex-wrap: wrap; gap: calc(6px * min(var(--inv), 2.4));
  max-width: calc(100% - 24px * min(var(--inv), 2.4));
  margin: 0; pointer-events: none;
  opacity: 0; translate: 0 calc(4px * min(var(--inv), 2.4));
  transition: opacity var(--dur-2) linear, translate var(--dur-2) var(--ease-out);
}
.lock-tags span {
  padding: .45em .6em;
  font-size: calc(11px * min(var(--inv), 2.4));
  background: var(--void); color: var(--chrome);
  border: calc(1px * min(var(--inv), 2.4)) solid var(--line-strong);
}
.cluster.is-hot .lock-tags { opacity: 1; translate: 0 0; }
.cluster.is-solo-open .lock-tags { opacity: 0; }

/* A live 3D cover (belt-3d.js card mode, 2026-10-12): the model on a light studio sweep, in front of the product HUD
   (product-3d.js hud(), styled in product.css), over the poster until it loads. On the floor and in the Grid. */
.cover-3d { position: absolute; inset: 0; z-index: 5; pointer-events: none; overflow: hidden; opacity: 0; transition: opacity 600ms; }
.cover-3d.belt3d-ready { opacity: 1;
  background: radial-gradient(120% 70% at 50% 64%, #F7F8FA 0%, #E6E9ED 46%, #CFD3D9 100%); }
.cover-3d .product-hud { z-index: 0; }
.cover-3d canvas { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; display: block; }
.frame-poster.belt3d-hidden { opacity: 0; transition: opacity 600ms; }
.folio-cover:has(> .cover-3d) { position: relative; }
/* The Etherea Loft's cover (2026-10-15): its 3D viewer in ?cover mode, transparent, in front of the HUD's name. */
.cover-3d--embed iframe { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; border: 0; pointer-events: none; background: transparent; }
.cover-3d--embed .ph-status { display: none; }
/* Loft posters (JC 2026-10-22): one flat warm ivory for all three ("warm ivory, not glow"; no per-loft colour, no
   circle behind the model) and one shared warm ink for the names and hairlines, so the three read as a deck.
   The per-loft palettes stay in works.json for the saved poster art. */
.cover-3d--warm { --ink: #2B2623; }
.cover-3d--warm.belt3d-ready { background: #F5EFE4; }
/* the loft names in Mak Bold, 719's display face (assets/fonts/mak-bold.woff2, from JC's installed MAK-bold.otf:
   "Free for personal and commercial use") */
@font-face { font-family: 'Mak'; src: url('../fonts/mak-bold.woff2') format('woff2'); font-weight: 700; font-display: swap; }
.cover-3d--warm .product-hud .ph-name { fill: var(--ink); opacity: 1; font-family: 'Mak', Georgia, serif; font-weight: 700; font-stretch: normal; letter-spacing: 0; font-size: 118px !important; }
.cover-3d--warm .product-hud .ph-sub { fill: var(--ink); opacity: .7; }
.cover-3d--warm .product-hud .ph-line { stroke: var(--ink); stroke-opacity: .14; }
.cover-3d--warm .product-hud .ph-line circle, .cover-3d--warm .product-hud .ph-dash { display: none; }
.cover-3d--warm .product-hud .ph-ink { stroke: var(--ink); stroke-opacity: .45; }
.cover-3d--warm .product-hud .ph-text { fill: var(--ink); fill-opacity: .72; }
.cover-3d--embed.belt3d-ready { pointer-events: auto; cursor: grab; touch-action: pan-y; }
.cover-3d--embed.is-turning { cursor: grabbing; }
.cover-3d.cover-3d--photo.belt3d-ready { background: linear-gradient(rgba(0,0,0,.42), rgba(0,0,0,0) 42%, rgba(0,0,0,0) 78%, rgba(0,0,0,.36)); }   /* Terra, Solaris: the HUD over a real photo stays legible */
.cover-3d--photo .ph-status, .cover-3d--photo .ph-line circle, .cover-3d--photo .ph-dash { display: none; }
.cover-3d--photo .product-hud .ph-text { fill: rgba(255, 255, 255, .88); }
.cover-3d--photo .product-hud .ph-ink { stroke: rgba(255, 255, 255, .7); }
.cover-3d--photo .product-hud .ph-line { stroke: rgba(255, 255, 255, .28); }

/* ── The Work grid (2026-10-21): pieces, filters, the side card, the phone sheet ─────────────────────────
   One cluster per highlight piece (works.json); the masonry is computed in canvas.js. Three text styles in
   view: the HUD mono (filters, meta, facts, buttons), the display face (project title), the sans (summary). */
.floor--pieces .cluster.is-filtered { display: none; }
.world.is-relayout > .cluster { transition: left 560ms var(--ease-out), top 560ms var(--ease-out), opacity 300ms linear; }
.world.is-relayout > .cluster:not(.is-filtered) { animation: piece-in 420ms var(--ease-out) both; }
@keyframes piece-in { from { opacity: 0; } to { opacity: 1; } }
.floor--pieces .world.has-open > .cluster:not(.is-open):not(.is-picked):not(.is-solo) { opacity: .14; }
.floor--pieces .world.has-solo > .cluster.is-exiting { opacity: 0; }
.floor--pieces .frame-caption-meta { gap: 1em; }
/* JC 2026-10-22: "when the captions appear, the gaps between items vertically disappears". On the Work grid the gutter
   is only layout.gap, so a caption keeping its on-screen size grows up into its own tile (the art crops a little)
   instead of down into the gutter; the gap between tiles stays the same at every zoom. */
.floor--pieces .world:not(.lod-poster) .frame--cover .frame-body { bottom: calc(var(--caption-h, 0px) * max(1, var(--inv, 1))); }
.floor--pieces .frame-caption { top: calc(100% - var(--caption-h, 0px) * max(1, var(--inv, 1))); }
.floor--pieces .frame-caption-meta > span:first-child { color: var(--chrome); }

/* Staged (local only): a quiet outline badge, the same mono as the meta around it. */
.chip--staged { color: var(--chrome-3); border: 1px dashed var(--line-strong); background: transparent; }
.frame-caption-meta .chip--staged, .title-card-meta .chip--staged { padding: .35em .6em; }

/* Side card: the 9/30 hairline → clip-path sheet, then a short glitch as it lands. */
.floor--pieces .is-open > .cluster-band .band-sheet { animation: band-glitch 360ms steps(1, end) 260ms both; }
@keyframes band-glitch {
  0%   { transform: none; filter: none; }
  18%  { transform: translateX(calc(-6px * var(--inv))); filter: drop-shadow(calc(3px * var(--inv)) 0 0 rgba(255, 60, 60, .5)) drop-shadow(calc(-3px * var(--inv)) 0 0 rgba(60, 200, 255, .5)); }
  34%  { transform: translateX(calc(4px * var(--inv))) skewX(-2deg); }
  52%  { transform: translateX(calc(-2px * var(--inv))); filter: drop-shadow(calc(2px * var(--inv)) 0 0 rgba(255, 60, 60, .35)); }
  70%  { transform: none; filter: none; }
}
.piece-card { --name: 9cqi; --body: 3.4cqi; --meta: 2.3cqi; --gap: 3cqi; }
.piece-card .title-card-meta { color: var(--chrome-3); }
.piece-card .piece-card-name { color: var(--chrome); }
.piece-card .title-card-desc { -webkit-line-clamp: 4; line-clamp: 4; max-width: none; }   /* the card's full width (JC 2026-10-22) */
.piece-card .title-card-facts { margin-top: auto; }
.piece-card .title-card-facts dd { font: 400 var(--meta)/1.3 var(--font-hud); letter-spacing: var(--track-hud); text-transform: uppercase; white-space: normal; }
.piece-thumbs { display: flex; flex-wrap: wrap; gap: 1.4cqi; margin-top: 1cqi; }
.piece-thumb {
  all: unset; box-sizing: border-box; cursor: pointer;
  width: 11.4cqi; aspect-ratio: 1; overflow: hidden;
  border: 1px solid var(--line); background: var(--void-3);
  opacity: .62; transition: opacity var(--dur-1) linear, border-color var(--dur-1) linear;
}
.piece-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.piece-thumb:hover, .piece-thumb:focus-visible { opacity: 1; border-color: var(--chrome-3); }
.piece-thumb[aria-current="true"] { opacity: 1; border-color: var(--chrome); }
.piece-card .title-card-open { display: inline-flex; align-items: center; gap: .8em; min-height: 6cqi; }
@container band (max-height: 420px) { .piece-card .title-card-facts { display: grid; } }
.lod-poster .piece-thumbs { display: none; }
@media (max-width: 759px) { .floor--pieces .cluster-band { display: none; } }

/* Phone: the same card as a bottom sheet in screen space (a hairline, the sheet opening from its centre line, the glitch). */
.piece-sheet {
  position: fixed; z-index: 26; left: var(--edge); right: var(--edge); bottom: var(--edge);
  max-height: 64svh;
  container: band / inline-size;
  pointer-events: auto;
}
.piece-sheet .band-rule { left: 0; right: 0; top: 50%; height: 1px; transform-origin: 50% 50%; }
.piece-sheet .band-sheet { box-shadow: inset 0 0 0 1px var(--line-strong); }
.piece-sheet .band-sheet::before { --t: 10px; }
.piece-sheet.is-open .band-rule { transform: scaleX(1); opacity: 0; transition: transform 240ms var(--ease-out), opacity 200ms linear 280ms; }
.piece-sheet.is-open .band-sheet { clip-path: inset(0 0 0 0); transition: clip-path 360ms var(--ease-out) 180ms; animation: sheet-glitch 340ms steps(1, end) 240ms both; }
.piece-sheet.is-open .title-card { opacity: 1; transform: none; pointer-events: auto; transition: opacity 260ms linear 300ms, transform 380ms var(--ease-out) 280ms; }
@keyframes sheet-glitch {
  0% { transform: none; filter: none; }
  20% { transform: translateX(-5px); filter: drop-shadow(3px 0 0 rgba(255, 60, 60, .5)) drop-shadow(-3px 0 0 rgba(60, 200, 255, .5)); }
  40% { transform: translateX(3px) skewX(-2deg); }
  60% { transform: translateX(-1px); filter: none; }
  80% { transform: none; }
}
.piece-sheet .band-sheet { position: relative; inset: auto; max-height: 64svh; overflow-y: auto; }
.piece-sheet .piece-card { --pad: 20px; --gap: 12px; --meta: 11px; --body: 14px; --name: 40px; position: relative; inset: auto; }
.piece-sheet .title-card-facts { margin-top: 4px; }
.piece-sheet .piece-thumbs { gap: 6px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; flex: 0 0 auto; }
.piece-sheet .piece-thumb { width: 44px; flex: 0 0 44px; }
.piece-sheet .title-card-open { min-height: 44px; flex: 0 0 auto; }
.piece-sheet .title-card-facts { padding-top: 10px; }
.piece-sheet-x {
  all: unset; position: absolute; top: 6px; right: 6px; z-index: 2;
  width: 44px; height: 44px; display: grid; place-items: center; cursor: pointer;
  font: 400 18px/1 var(--font-hud); color: var(--chrome-2);
}
.piece-sheet-open .hud-bottom, .piece-sheet-open .hud-filters { opacity: 0; pointer-events: none; }

/* Filter bar: top centre between the logo and the menu on desktop; a scroll strip above the bottom HUD on a phone. */
.hud-filters.hud-panel {
  position: fixed; z-index: 30; top: var(--edge); left: 50%; transform: translateX(-50%);
  display: inline-flex; align-items: stretch; max-width: calc(100vw - 2 * var(--edge) - 420px);
  overflow-x: auto; scrollbar-width: none;
  transition: opacity 200ms linear;
}
.hud-filters::-webkit-scrollbar { display: none; }
.hud-filters .hud-btn { flex: 0 0 auto; height: 36px; padding: 0 12px; gap: 6px; display: inline-flex; align-items: center; color: var(--chrome-3); white-space: nowrap; }
.hud-filters .hud-btn:hover { color: var(--chrome-2); }
.hud-filters .hud-btn[aria-pressed="true"] { color: var(--chrome); background: var(--void-3); }
.hud-count { color: var(--chrome-3); opacity: .7; font-variant-numeric: tabular-nums; }
.hud-filters.hud-panel::before { inset: -5px; --t: 6px; }
.solo-open .hud-filters, .page-work[data-view="index"] .hud-filters { opacity: 0; pointer-events: none; visibility: hidden; }
/* Phones (JC 2026-10-22: the stacked controls took a fifth of the screen): one bottom row, filters scrolling on the left of
   the view switcher; no zoom panel (pinch zooms) and no staged toggle (dev only). */
@media (max-width: 759px) {
  .hud-filters.hud-panel { top: auto; bottom: var(--edge); left: var(--edge); right: calc(var(--edge) + var(--views-w, 162px) + 12px); transform: none; max-width: none; }
  .hud-bottom > .hud-panel:not(.hud-views), .hud-bottom > .hud-staged { display: none; }
  .hud-filters .hud-btn { height: 40px; }
}
.page-work[data-view="grid"] .hud-filters, .page-work[data-view="list"] .hud-filters { position: fixed; }
.hud-bottom > .hud-staged:not([hidden]) { margin-left: auto; padding: 0 12px; color: var(--chrome-3); }
.hud-bottom > .hud-staged:not([hidden]) + .hud-views { margin-left: 0; }
.hud-staged[aria-pressed="false"] { color: var(--chrome); }
@media (prefers-reduced-motion: reduce) {
  .world.is-relayout > .cluster, .world.is-relayout > .cluster:not(.is-filtered) { transition: none; animation: none; }
  .floor--pieces .is-open > .cluster-band .band-sheet, .piece-sheet.is-open .band-sheet { animation: none; }
}

/* Hover focus (JC 2026-10-22: "when I hover on one item ... the others go a bit dark", about 20%): the board's hot
   cluster stays bright and the rest dim; in Grid view the hovered card does the same. */
.floor--pieces .cluster { transition: filter 220ms linear; }
.floor--pieces .world:has(.cluster.is-hot) .cluster:not(.is-hot) { filter: brightness(.6); }
.folio-card { transition: filter 220ms linear; }
@media (hover: hover) { .folio-grid:has(.folio-card:hover) .folio-card:not(:hover) { filter: brightness(.6); } }

/* the bottom HUD at the shared 40 px (38 inside the border), on every screen size */
.hud-btn, .hud-readout { height: 38px; }
.hud-filters .hud-btn { height: 38px; }
@media (max-width: 759px) { .hud-btn, .hud-readout, .hud-filters .hud-btn { height: 38px; } }

/* the project's handle under a caption (@719studios): its own lowercase spelling, clickable through the caption */
.frame-caption-handle { text-transform: none; letter-spacing: .04em; color: var(--chrome-2); pointer-events: auto; cursor: pointer; text-decoration: none; }   /* the caption text's grey */
.frame-caption-handle:hover, .frame-caption-handle:focus-visible { color: var(--chrome-2); text-decoration: underline; text-underline-offset: 3px; }

/* A piece card's three ways in (JC 2026-10-22): Explore in 3D (filled), the case study and the story (outlined),
   at the card's own scale. */
.piece-ctas { display: flex; flex-wrap: wrap; gap: 1.2cqi; }
.piece-ctas > .btn {
  display: inline-flex; align-items: center; gap: .7em;
  min-height: 5cqi; padding: 0 1.6em; border-radius: 0;
  font: 400 var(--meta)/1 var(--font-hud); letter-spacing: var(--track-hud); text-transform: uppercase;
}
.piece-ctas > .btn--ghost { background: transparent; color: var(--chrome); border: 1px solid var(--line-strong); }
.piece-ctas > .btn--ghost:hover, .piece-ctas > .btn--ghost:focus-visible { background: var(--void-3); border-color: var(--chrome-3); }
.lod-poster .piece-ctas { display: none; }

/* ── Type study: "notebook" (JC 2026-10-22, after mek.gallery: "more interesting font ... more branded/stylized").
   Only with ?type=note. The small text becomes one voice: the brand's Departure Mono, bigger, lowercase, untracked;
   captions are a note plus the @handle (underlined, like a footnote) instead of a title and a label. */
.t-note .hud-btn, .t-note .hud-readout, .t-note .hud-actions .hud-subscribe { font-size: 14px; text-transform: lowercase; letter-spacing: 0; }
.t-note .frame-caption { --k: max(1, var(--inv, 1)); }
.t-note .frame-caption-text { font-family: var(--font-hud); font-size: calc(17px * var(--k)); line-height: 1.35; letter-spacing: 0; color: var(--chrome); -webkit-line-clamp: 3; line-clamp: 3; }
.t-note .frame-caption-text b { display: none; }
.t-note .frame-caption-meta { font-size: calc(15px * var(--k)); letter-spacing: 0; }
.t-note .frame-caption-handle { text-decoration: underline; text-underline-offset: .25em; text-decoration-thickness: 1px; color: var(--chrome-3); }
.t-note .product-hud .ph-text { text-transform: lowercase; letter-spacing: 0; font-size: 26px; }
.t-note .product-hud .ph-sub { text-transform: lowercase; letter-spacing: .3em; }
.t-note .title-card-meta, .t-note .title-card-facts, .t-note .piece-ctas > .btn { text-transform: lowercase; letter-spacing: 0; }

/* A piece card's media reel (JC 2026-10-22): the highlights at one height, side by side, filling the room between the
   description and the facts; swipe or scroll sideways, or the arrows. */
.piece-reel { position: relative; flex: 1 1 0; min-height: 18cqi; margin-top: 1cqi; display: flex; flex-direction: column; gap: 1.2cqi; }
.piece-reel-track { flex: 1 1 0; min-height: 0; display: flex; gap: 1.2cqi; overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory; scrollbar-width: none; overscroll-behavior-x: contain; }
.piece-reel-track::-webkit-scrollbar { display: none; }
.piece-reel-track > img, .piece-reel-track > video { flex: none; height: 100%; width: auto; max-width: none; display: block; object-fit: cover; scroll-snap-align: start; background: var(--void-3); }
.piece-reel-nav { display: flex; justify-content: flex-end; gap: .6cqi; }
.piece-reel-nav button { all: unset; cursor: pointer; display: inline-grid; place-items: center; min-width: 5cqi; height: 4.4cqi; border: 1px solid var(--line); font: 400 var(--meta)/1 var(--font-hud); color: var(--chrome-2); }
.piece-reel-nav button:hover, .piece-reel-nav button:focus-visible { color: var(--chrome); border-color: var(--chrome-3); }
.lod-poster .piece-reel { display: none; }
/* the notebook voice through the top panels, the menu and the open card (JC 2026-10-22: "carry that voice through") */
.t-note .site-menu-panel a, .t-note .site-menu-panel .hud, .t-note .piece-card .title-card-facts dt, .t-note .piece-card .title-card-facts dd,
.t-note .frame-caption-open, .t-note .hud-filters .hud-btn, .t-note .piece-reel-nav button { text-transform: lowercase; letter-spacing: 0; }
.t-note .site-menu-panel a { font-size: 15px; }
.t-note .piece-card .title-card-facts dt, .t-note .piece-card .title-card-facts dd { font-size: calc(var(--meta) * 1.15); }
/* (the 2026-10-22 bleed-off-the-right-edge reel is gone: lightbox pass 2026-10-27, one slide fills the content width) */
.piece-card .piece-reel-track { scroll-padding-left: 0; }

/* Open card: the corner brackets frame the poster and its info card as one piece (JC 2026-10-22: "the corner chevron
   brackets should expand to the full card when the item is expanded"). */
.floor--pieces .cluster::before { transition: inset 260ms var(--ease-out); }
.floor--pieces .cluster.is-open[data-dir="right"]::before { inset: -28px calc(-28px - var(--band-w, 0px)) calc(-28px - var(--band-xh, 0px)) -28px; }
.floor--pieces .cluster.is-open[data-dir="left"]::before { inset: -28px -28px calc(-28px - var(--band-xh, 0px)) calc(-28px - var(--band-w, 0px)); }

/* The open card drops its headline: the poster beside it already says the name, big; the description names it
   instead (JC 2026-10-22). The heading stays for screen readers. */
.piece-card .title-card-name { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* One card when open (JC 2026-10-22: "the panel should wrap around the original poster a bit so when it's expanded it
   looks like the portfolio and description stuff on the right are all on one big card"): a single sheet sits behind
   the poster and the info panel, a margin proud of the poster; the poster loses its own outline and the panel its own
   border, so the two read as one piece. */
.floor--pieces .cluster { isolation: isolate; --wrap: 16px; }
.floor--pieces .cluster::after {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  background: var(--void-2); box-shadow: inset 0 0 0 calc(1px * var(--inv, 1)) var(--line-strong);
  opacity: 0; transition: opacity 200ms linear, inset 260ms var(--ease-out);
  inset: calc(var(--wrap) * -1);
}
.floor--pieces .cluster.is-open::after { opacity: 1; }
.floor--pieces .cluster.is-open[data-dir="right"]::after { inset: calc(var(--wrap) * -1) calc(var(--wrap) * -1 - var(--band-w, 0px)) calc(var(--wrap) * -1 - var(--band-xh, 0px)) calc(var(--wrap) * -1); }
.floor--pieces .cluster.is-open[data-dir="left"]::after { inset: calc(var(--wrap) * -1) calc(var(--wrap) * -1) calc(var(--wrap) * -1 - var(--band-xh, 0px)) calc(var(--wrap) * -1 - var(--band-w, 0px)); }
.floor--pieces .cluster.is-open > .frame--cover.is-selected { outline: none; }
.floor--pieces .cluster.is-open .band-sheet { background: transparent; box-shadow: none; }
.floor--pieces .cluster.is-open .band-sheet.ticks::before { content: none; }   /* the shared card has the only corners */
/* A card opening left of its poster (JC 2026-10-22): the margin outside the content (card edge to text) equals the gap
   between the content and the poster, and the reel, its arrows, the divider and the facts all end on that one edge. */
.floor--pieces .cluster[data-dir="left"] .piece-card { padding-left: calc(var(--pad) * 1.1 - var(--wrap)); padding-right: calc(var(--pad) * 1.1); }
.floor--pieces .cluster[data-dir="left"] .piece-card .piece-reel { margin-right: 0; }
.floor--pieces .cluster[data-dir="left"] .piece-card .piece-reel-nav { padding-right: 0; }
/* the same for a card opening right of its poster (JC 2026-10-22: "fix the other ones too same way"): equal gaps both
   sides of the content, and the reel ends on the content edge like everything else */
/* JC 2026-10-22 ("i still would love to see the next item ... going all the way off screen"): the open panel reaches the
   card's outer edge, the content keeps equal margins either side, and the reel runs to that edge, cut by the border;
   the arrows, divider and facts stay on the content edge. */
.floor--pieces .cluster.is-open[data-dir="right"] .band-sheet { right: calc(var(--wrap) * -1); }
.floor--pieces .cluster[data-dir="right"] .piece-card { padding-left: calc(var(--pad) * 1.1); padding-right: calc(var(--pad) * 1.1); }
.floor--pieces .cluster[data-dir="right"] .piece-card .piece-reel { margin-right: 0; }
/* the reel's row height comes from work.js (whole items fill the content width; the next one peeks into the margin) */
.floor--pieces .piece-reel-track { align-items: flex-start; }
.floor--pieces .piece-reel-track { flex: none; }   /* sized by work.js; leftover room falls below the arrows */

/* 719 brand cards (2026-10-26): each loft on its own ground, the wordmark from the posters, Bricolage small caps; no crosshair frame or ruler ticks */
.cover-3d--warm { --ink: #35212D; }
.cover-3d--warm.belt3d-ready { background: var(--ground, #F5EFE4); }
.cover-3d--warm .product-hud .ph-wordmark { fill: var(--ink); }
.cover-3d--warm .product-hud .ph-line, .cover-3d--warm .product-hud .ph-ink { display: none; }
.cover-3d--warm .product-hud .ph-sub, .cover-3d--warm .product-hud .ph-text { font-family: 'Bricolage Grotesque', sans-serif; font-weight: 500; letter-spacing: .17em; text-transform: uppercase; fill: var(--ink); }
.cover-3d--warm .product-hud .ph-sub { opacity: .8; font-size: 22px; }
.cover-3d--warm .product-hud .ph-text { fill-opacity: .85; }

/* ═══ Mobile pass (2026-10-27, JC: "the portfolio grid page is ROUGH on mobile") ═════════════════════════════════════
   Everything here is inside a phone / touch query, so a mouse-and-keyboard desktop is untouched (backup: canvas.css.pre-mob).
   Phone: a 2-up Grid of covers, the view switcher as a safe-area bottom bar, 44 px targets, the filters as a scrolling
   chip row under the top HUD, the item sheet that actually shows (it collapsed to 0 px tall), poster stills for covers. */
@font-face {                                   /* self-hosted (was a render-blocking Google Fonts stylesheet) */
  font-family: 'Bricolage Grotesque'; font-style: normal; font-weight: 300 800; font-stretch: 100%; font-display: swap;
  src: url("../fonts/Bricolage-Grotesque-VF.woff2") format("woff2");
}

/* the item sheet's box was a size container, so its height collapsed to nothing and the sheet opened invisible */
.piece-sheet .band-sheet { container-type: inline-size; overscroll-behavior: contain; touch-action: pan-y; }
.piece-sheet { bottom: max(var(--edge), env(safe-area-inset-bottom)); }

/* touch: 44 px targets for the HUD (the top row and the bottom controls) */
@media (pointer: coarse), (max-width: 759px) {
  :root { --hud-row: 46px; }
  a, button, summary, [role="button"] { -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
  .hud-btn, .hud-readout, .hud-filters .hud-btn, .hud-views .hud-btn { height: 44px; min-width: 44px; }
  .hud-brand .brand { min-height: 44px; }
  .hud-actions.hud-panel, .hud-actions .hud-subscribe { min-height: 44px; }
  .hud-actions .site-menu-btn { width: 44px; height: 44px; min-width: 44px; min-height: 44px; }
  .folio-row { min-height: 72px; }
  .piece-sheet .piece-thumb { width: 44px; flex: 0 0 44px; }
}

/* a phone on its side: the corner HUD stays, the Grid goes three across and tight */
@media (pointer: coarse) and (max-height: 500px) and (min-width: 760px) {
  .folio-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 20px; row-gap: 36px; }
  .js .folio { padding-top: 76px; }
  .folio-name { font-size: 20px; }
}

@media (max-width: 759px) {
  /* Grid: two covers across, the name and a short line under each */
  .js .folio { padding-top: calc(var(--edge) + var(--hud-row) + 16px); padding-bottom: calc(104px + env(safe-area-inset-bottom)); overscroll-behavior-y: contain; touch-action: pan-y; }
  html.has-filters .js .folio, html.has-filters .folio { padding-top: calc(var(--edge) + var(--hud-row) + 16px + 56px); }
  .folio-wrap { padding-top: 0; }
  .folio-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 12px; row-gap: 28px; padding-bottom: 24px; }
  .folio-card { gap: 8px; align-content: start; }
  .folio-meta { gap: 6px; font-size: 11px; line-height: 1.3; letter-spacing: .06em; }
  .folio-name { font-size: clamp(17px, 5.4vw, 22px); line-height: 1.08; overflow-wrap: anywhere; }
  .folio-desc { font-size: 12px; line-height: 1.4; margin: 0; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
  .folio-card .frame-caption-handle { pointer-events: none; }        /* a thumb on the card opens the item; the account link lives in the item */
  .folio-cover { touch-action: pan-y; }

  /* the bottom bar: Grid | List | Canvas full width, clear of the iPhone's home indicator */
  .hud-bottom {
    left: 0; right: 0; bottom: 0; gap: 8px; align-items: stretch;
    padding: 12px var(--edge) calc(10px + env(safe-area-inset-bottom));
    background: linear-gradient(to top, rgba(11, 12, 14, .94) 58%, rgba(11, 12, 14, 0));
  }
  .hud-bottom > .hud-views { flex: 1 1 auto; margin-left: 0; }
  .hud-views .hud-btn { flex: 1 1 0; padding: 0 6px; font-size: 11px; }
  /* Canvas on a phone: pinch zooms, one finger pans; the zoom panel shrinks to the Fit button */
  .page-work[data-view="canvas"] .hud-bottom > .hud-panel[aria-label="Zoom"] { display: flex; }
  .hud-panel[aria-label="Zoom"] :is([data-zoom-out], [data-zoom-in], [data-zoom]) { display: none; }

  /* the filters: a swipeable row of chips under the top HUD */
  .hud-filters.hud-panel {
    top: calc(var(--edge) + var(--hud-row) + 8px); bottom: auto; left: var(--edge); right: var(--edge);
    transform: none; max-width: none; justify-content: flex-start;
    overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch; touch-action: pan-x;
  }
  .hud-filters .hud-btn { padding: 0 16px; }

  /* the find toasts keep inside the screen */
  .toasts { width: calc(100vw - 2 * var(--edge)); }
  .toast { padding-right: 48px; }
  .toast .toast-label, .toast .hud { white-space: normal; overflow-wrap: anywhere; }

  /* the item sheet clears the bottom bar's space and scrolls its own content */
  .piece-sheet { max-height: calc(100svh - var(--edge) - var(--hud-row) - 24px); }
  .piece-sheet .band-sheet { max-height: min(72svh, calc(100svh - var(--edge) - var(--hud-row) - 24px)); }
}

/* Mobile fix (2026-10-27): on a phone the bottom sheet is the title card, so a tapped cover never grows the in-canvas
   card beside it (no .is-open there). It only wears a quiet outline while its sheet is up; closing the sheet clears it. */
.floor--pieces .cluster.is-picked > .frame--cover { outline: calc(2px * var(--inv, 1)) solid var(--chrome); outline-offset: calc(3px * var(--inv, 1)); }
@media (min-width: 760px) { .floor--pieces .cluster.is-picked > .frame--cover { outline: none; } }

/* ═══ Lightbox pass (2026-10-27, JC: "those images ... too small ... open full screen, or at least fill up that panel") ═══
   The card's reel is one big slide at a time (swipe, arrows, "n / total"); a tap or click on it opens the full-screen
   viewer (lightbox.js). Same HUD mono as the rest, three text styles at most (mono counter, mono caption, the glyphs). */
.piece-reel { flex: 1 1 0; min-height: 18cqi; margin-top: 2cqi; gap: 1.6cqi; }
.piece-reel-track { gap: 8px; scroll-snap-type: x mandatory; touch-action: pan-x pan-y; }
.piece-slide {
  appearance: none; -webkit-appearance: none; border: 0; padding: 0; margin: 0; font: inherit; color: inherit; border-radius: 0;
  position: relative; flex: 0 0 100%; height: 100%; display: block; overflow: hidden; cursor: zoom-in;
  background: var(--void-3); scroll-snap-align: start; scroll-snap-stop: always;
}
.piece-slide > img, .piece-slide > video { display: block; width: 100%; height: 100%; object-fit: contain; pointer-events: none; }
.piece-slide[data-fit="cover"] > img, .piece-slide[data-fit="cover"] > video { object-fit: cover; }
.piece-slide:hover, .piece-slide:focus-visible { box-shadow: inset 0 0 0 1px var(--chrome-3); }
.piece-slide:focus-visible { outline: 1px solid var(--chrome); outline-offset: 2px; }
.piece-slide-badge {
  position: absolute; left: 8px; bottom: 8px; padding: .5em .7em; pointer-events: none;
  font: 400 11px/1 var(--font-hud); letter-spacing: var(--track-hud); text-transform: uppercase;
  color: var(--chrome); background: rgba(11, 12, 14, .72); box-shadow: inset 0 0 0 1px var(--line-strong);
}
.piece-reel-nav { align-items: center; justify-content: flex-end; gap: 1.2cqi; }
.piece-reel-nav .piece-reel-count { margin-right: auto; font: 400 var(--meta)/1 var(--font-hud); letter-spacing: var(--track-hud); color: var(--chrome-3); font-variant-numeric: tabular-nums; }
.piece-reel-nav button { min-width: 6cqi; height: 5cqi; }

/* the phone sheet: a big slide, then arrows and the counter on 44 px targets; the sheet scrolls round it */
.piece-sheet .piece-reel { flex: 0 0 auto; min-height: 0; margin-top: 4px; gap: 6px; }
.piece-sheet .piece-reel-track { flex: none; }
.piece-sheet .piece-reel-nav { --meta: 12px; }
@media (pointer: coarse), (max-width: 759px) {
  .piece-reel-nav button { min-width: 44px; height: 44px; font-size: 16px; }
  .piece-reel-nav .piece-reel-count { font-size: 12px; }
}

/* the viewer: above the sheet (26), the card (cluster 5-8), the HUD (20-30), the menu (85-91) and the intro mark (100) */
html.lb-open, html.lb-open body { overflow: hidden; overscroll-behavior: none; }
.lb {
  position: fixed; inset: 0; z-index: 1000; background: #06070A; color: var(--chrome);
  touch-action: none; overscroll-behavior: contain; -webkit-user-select: none; user-select: none;
  animation: lb-in 160ms linear both;
}
.lb[hidden] { display: none; }
@keyframes lb-in { from { opacity: 0; } }
.lb-top {
  position: absolute; z-index: 2; top: 0; left: 0; right: 0; display: flex; align-items: center; justify-content: space-between;
  padding: max(8px, env(safe-area-inset-top)) max(8px, env(safe-area-inset-right)) 0 max(16px, env(safe-area-inset-left)); pointer-events: none;
}
.lb-top > * { pointer-events: auto; }
.lb-count { font: 400 12px/1 var(--font-hud); letter-spacing: var(--track-hud); text-transform: uppercase; color: var(--chrome-2); font-variant-numeric: tabular-nums; }
.lb-x, .lb-arrow {
  appearance: none; -webkit-appearance: none; box-sizing: border-box; margin: 0; padding: 0; cursor: pointer; border-radius: 0;
  width: 44px; height: 44px; display: grid; place-items: center; -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  font: 400 22px/1 var(--font-hud); color: var(--chrome); background: rgba(11, 12, 14, .66); border: 1px solid var(--line-strong);
}
.lb-x { font-size: 28px; }
.lb-x:hover, .lb-arrow:hover, .lb-x:focus-visible, .lb-arrow:focus-visible { border-color: var(--chrome); background: rgba(11, 12, 14, .9); outline: none; }
.lb-x:focus-visible, .lb-arrow:focus-visible { box-shadow: 0 0 0 2px var(--void), 0 0 0 3px var(--chrome); }
.lb-arrow { position: absolute; z-index: 2; top: 50%; translate: 0 -50%; }
.lb-arrow[hidden] { display: none; }
.lb-prev { left: max(8px, env(safe-area-inset-left)); }
.lb-next { right: max(8px, env(safe-area-inset-right)); }
.lb-track {
  position: absolute; inset: 0; display: flex; overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory;
  scrollbar-width: none; overscroll-behavior: contain; touch-action: pan-x; -webkit-overflow-scrolling: touch;
}
.lb-track::-webkit-scrollbar { display: none; }
.lb-slide {
  flex: 0 0 100%; height: 100%; box-sizing: border-box; scroll-snap-align: center; scroll-snap-stop: always;
  padding: calc(60px + env(safe-area-inset-top)) max(8px, env(safe-area-inset-right)) max(16px, env(safe-area-inset-bottom)) max(8px, env(safe-area-inset-left));
}
@media (min-width: 760px) {
  .lb-slide { padding: 64px max(76px, calc(env(safe-area-inset-right) + 64px)) max(24px, env(safe-area-inset-bottom)) max(76px, calc(env(safe-area-inset-left) + 64px)); }
}
.lb-media { display: block; width: 100%; height: 100%; object-fit: contain; background: transparent; -webkit-touch-callout: none; }
video.lb-media { background: #000; touch-action: manipulation; }
@media (prefers-reduced-motion: reduce) { .lb { animation: none; } }

/* Button row (JC 2026-10-28): the piece's three ways in sit on ONE line. Short labels (Explore 3D / Case study / Story),
   auto-sized flexible cells that may shrink, a tighter gap and padding, never wrapping or clipping. */
.piece-ctas { flex-wrap: nowrap; gap: max(6px, 1.2cqi); }
.piece-ctas > .btn,
.piece-card .piece-ctas > .title-card-open {
  flex: 1 1 auto; min-width: 0; align-self: auto; justify-content: center;
  gap: .5em; padding: 0 .9em; white-space: nowrap;
}
.piece-sheet .piece-ctas > .btn, .piece-sheet .piece-ctas > .title-card-open { flex: 1 1 auto; min-height: 44px; }
@media (max-width: 380px) {
  .piece-sheet .piece-ctas { gap: 5px; }
  .piece-sheet .piece-ctas > .btn, .piece-sheet .piece-ctas > .title-card-open { padding: 0 .6em; letter-spacing: .04em; gap: .35em; }
}


/* ── Task L (2026-10-28): nothing live may trap a vertical swipe ─────────────────────────────────────────────
   iOS Safari hands touches that start inside a cross-document iframe to the iframe, and its `touch-action` is not the
   parent's. So the live-3D iframe never takes touches (pointer-events: none above) and the host div over it is the
   shield: pan-y, so an up-down swipe starting on a cover scrolls the Grid (the horizontal drag still turns the cover). */
.cover-3d { touch-action: pan-y; }
.cover-3d iframe, .cover-3d canvas, .cover-3d model-viewer { pointer-events: none; touch-action: pan-y; }
/* Touch screens in Canvas: the floor's root is touch-action: none and pans/pinches from pointer events, but a live cover's
   host is data-floor-ui, which makes that pan skip it: a dead zone (iPad). Let the touch fall through to the cover
   underneath so it pans and pinches like the rest of the floor; the live cover still turns by drag in the Grid. */
@media (pointer: coarse) {
  .floor--full .cover-3d--embed.belt3d-ready { pointer-events: none; cursor: auto; }
}
/* Phone-class screens never show a live cover, even if one mounted before a rotation/resize (canvas.js retires them too). */
@media (max-width: 759px), (pointer: coarse) and (max-height: 500px) {
  .cover-3d { display: none !important; }
  .frame-poster.belt3d-hidden { opacity: 1 !important; }
}

/* ── Task M (2026-10-28, JC: "Grid on mobile: 1 item per row, full width") ──────────────────────────────────────────
   Every phone-class screen (portrait, and a phone on its side) shows ONE cover per row at full width. iPad and desktop
   keep their columns. The cover keeps its own card ratio (inline aspect-ratio) but never grows past 70% of the screen. */
@media (max-width: 759px), (pointer: coarse) and (max-height: 500px) and (min-width: 760px) {
  .folio-grid { grid-template-columns: minmax(0, 1fr); column-gap: 0; row-gap: 36px; padding-bottom: 24px; }
  .folio-cover { max-height: 70vh; max-height: 70svh; }
  .folio-card { gap: 10px; }
  .folio-desc { font-size: 13px; }
  .folio-name { font-size: clamp(20px, 6vw, 26px); }
  .folio-wrap { padding-left: max(var(--gutter), env(safe-area-inset-left)); padding-right: max(var(--gutter), env(safe-area-inset-right)); }
}


/* ═══ Task O (2026-10-28, JC: "it gets covered up by the info panel ... fill the full available space with that panel so
   I don't have to scroll"): on a phone the item sheet is a FULL-HEIGHT panel. Its top edge sits just under the fixed top
   bar (logo + menu), its bottom edge at the safe-area bottom, so nothing half-covered shows behind it. Its height is
   100dvh-based, so Safari's collapsing toolbar can't cut it off. Title, description, media, Year/Role and the buttons all
   fit on normal phones: the media slide flexes (min 160px, max 45vh) and the facts + buttons are pinned to the bottom. If
   the screen is too short (iPhone SE) the panel's own content scrolls; the close button stays put. ═══ */
@media (max-width: 759px), (pointer: coarse) and (max-height: 500px) {
  .piece-sheet {
    --sheet-top: calc(var(--edge) + var(--hud-row) + 8px);
    top: var(--sheet-top); left: max(var(--edge), env(safe-area-inset-left)); right: max(var(--edge), env(safe-area-inset-right));
    bottom: env(safe-area-inset-bottom, 0px);
    height: calc(100svh - var(--sheet-top) - env(safe-area-inset-bottom, 0px));
    height: calc(100dvh - var(--sheet-top) - env(safe-area-inset-bottom, 0px));
    max-height: none;
    display: flex; flex-direction: column;
    background: var(--void-2);
    overscroll-behavior: contain;
  }
  .piece-sheet[hidden] { display: none; }
  .piece-sheet .band-rule { display: none; }
  .piece-sheet .band-sheet {
    flex: 1 1 auto; min-height: 0; max-height: none; height: auto;
    display: flex; flex-direction: column;
    overflow-x: hidden; overflow-y: auto; -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain; touch-action: pan-y;
    clip-path: none !important; transition: none !important; animation: none !important;
  }
  .piece-sheet .piece-card {
    flex: 1 0 auto; opacity: 1; transform: none; transition: none !important; pointer-events: auto;
    --pad: 16px; --gap: 12px;
    padding: 6px 16px 16px;
  }
  /* the close button is always on screen: it floats over the sheet's top-right corner, outside the scrolling box */
  .piece-sheet-x { top: 4px; right: 4px; z-index: 3; width: 44px; height: 44px; min-width: 44px; min-height: 44px; background: var(--void-2); touch-action: manipulation; }
  .piece-sheet .title-card-meta { min-height: 44px; padding-right: 48px; }
  /* the cover is hidden behind the panel now, so the item's name is shown here (it is visually hidden in the in-canvas card) */
  .piece-sheet .piece-card .title-card-name {
    position: static; width: auto; height: auto; padding: 0; margin: 0; overflow: visible; clip: auto; white-space: normal; border: 0;
    flex: none; --name: 40px; margin-top: -4px;
  }
  .piece-sheet .title-card-desc { display: block; -webkit-line-clamp: unset; line-clamp: unset; overflow: visible; max-width: none; }
  /* the media: one slide that takes the room that is left */
  .piece-sheet .piece-reel { flex: 1 1 auto; min-height: 0; max-height: calc(45vh + 56px); margin-top: 0; gap: 6px; }
  .piece-sheet .piece-reel-track { flex: 1 1 auto; min-height: 160px; max-height: 45vh; height: auto; }
  .piece-sheet .piece-reel-nav { flex: none; }
  .piece-sheet .piece-slide { height: auto; align-self: stretch; }
  .piece-sheet .piece-slide > img, .piece-sheet .piece-slide > video { position: absolute; inset: 0; width: 100%; height: 100%; }
  /* Year / Role and the buttons stay pinned to the bottom of the panel */
  .piece-sheet .title-card-facts { margin-top: auto; flex: none; }
  .piece-sheet .piece-ctas, .piece-sheet .piece-card > .title-card-open { flex: none; }
  .piece-sheet .piece-card > .title-card-open { align-self: stretch; justify-content: center; }
  .piece-sheet .piece-thumbs { margin-top: 0; }

  /* the page behind: covered by an opaque backdrop under the sheet (so no half-covered content shows) and scroll-locked */
  html.piece-sheet-open, html.piece-sheet-open body { overflow: hidden; overscroll-behavior: none; }
  html.piece-sheet-open::after {
    content: ''; position: fixed; inset: 0; z-index: 25; background: var(--void); pointer-events: auto; touch-action: none;
    animation: sheet-backdrop-in 240ms linear both;
  }
  /* it slides up */
  .piece-sheet.is-open { animation: sheet-up 340ms var(--ease-out) both; }
  .piece-sheet.is-open .band-sheet, .piece-sheet.is-open .title-card { animation: none; }
}
@keyframes sheet-up { from { transform: translateY(100%); } to { transform: none; } }
@keyframes sheet-backdrop-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .piece-sheet.is-open, html.piece-sheet-open::after { animation: none !important; }
}


/* ═══ Task P (2026-10-28, JC: "optimize the grid and list ... hate the Open buttons ... native expansion cards per view") ═══
   LIST  one clickable row per piece (no Open button): a quiet plus that turns to a cross, a hover cover that follows the
         pointer (mouse only), and the row opens IN PLACE as a drawer with the reel, the line, Year / Role and the buttons.
   GRID  a card opens as a centred panel that grows out of its own cover (a full-height sheet on a phone).
   Canvas is untouched. Text styles: Departure Mono (hud), the display face, the sans body. ═══════════════════════════ */

/* the card both views share: media on one side, the line + facts + buttons on the other */
.fx-card { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: clamp(24px, 3vw, 48px); align-items: start; min-width: 0; --meta: 11px; }
.fx-media { min-width: 0; }
.fx-reel { display: grid; gap: 10px; min-width: 0; }
.fx-track {
  display: flex; column-gap: 8px; overflow-x: auto; overflow-y: hidden; aspect-ratio: 4 / 3; width: 100%;
  scroll-snap-type: x mandatory; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  touch-action: pan-x pan-y; overscroll-behavior-x: contain; background: var(--void-3); outline: 1px solid var(--line);
}
.fx-track::-webkit-scrollbar { display: none; }
.fx-slide {
  appearance: none; -webkit-appearance: none; border: 0; padding: 0; margin: 0; font: inherit; color: inherit; border-radius: 0;
  position: relative; flex: 0 0 100%; height: 100%; display: block; overflow: hidden; cursor: zoom-in;
  background: var(--void-3); scroll-snap-align: start; scroll-snap-stop: always;
}
.fx-slide > img, .fx-slide > video { display: block; width: 100%; height: 100%; object-fit: contain; pointer-events: none; }
.fx-slide[data-fit="cover"] > img, .fx-slide[data-fit="cover"] > video { object-fit: cover; }
.fx-slide:hover, .fx-slide:focus-visible { box-shadow: inset 0 0 0 1px var(--chrome-3); }
.fx-slide:focus-visible { outline: 1px solid var(--chrome); outline-offset: 2px; }
.fx-badge {
  position: absolute; left: 8px; bottom: 8px; padding: .5em .7em; pointer-events: none;
  font: 400 11px/1 var(--font-hud); letter-spacing: var(--track-hud); text-transform: uppercase;
  color: var(--chrome); background: rgba(11, 12, 14, .72); box-shadow: inset 0 0 0 1px var(--line-strong);
}
.fx-nav { display: flex; align-items: center; gap: 6px; }
.fx-count { margin-right: auto; font: 400 11px/1 var(--font-hud); letter-spacing: var(--track-hud); color: var(--chrome-3); font-variant-numeric: tabular-nums; }
.fx-nav button {
  appearance: none; background: transparent; border: 1px solid var(--line-strong); border-radius: 0; color: var(--chrome);
  min-width: 40px; height: 32px; font: 400 14px/1 var(--font-hud); cursor: pointer; transition: border-color var(--dur-1) linear, background var(--dur-1) linear;
}
.fx-nav button:hover { border-color: var(--chrome-3); background: var(--void-3); }
.fx-nav button:focus-visible { outline: 1px solid var(--chrome); outline-offset: 2px; }
.fx-info { display: flex; flex-direction: column; gap: 16px; min-width: 0; align-self: stretch; }
.fx-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 0; color: var(--chrome-3); }
.fx-title { margin: 0; font: 560 clamp(28px, 2.2vw + 14px, 42px)/1.04 var(--font-display); font-stretch: 120%; letter-spacing: -.02em; color: var(--chrome); }
.fx-desc { margin: 0; max-width: 46ch; font: 400 15px/1.55 var(--font-sans); color: var(--chrome-2); }
.fx-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .9em 2em; margin: auto 0 0; padding-top: 18px; border-top: 1px solid var(--line); color: var(--chrome-3); font-size: 11px; }
.fx-facts div { display: grid; gap: .45em; min-width: 0; }
.fx-facts dt { font-family: var(--font-hud); letter-spacing: var(--track-hud); text-transform: uppercase; color: var(--chrome-3); }
.fx-facts dd { margin: 0; font: 400 14px/1.3 var(--font-sans); color: var(--chrome); }
.fx-ctas { display: flex; flex-wrap: nowrap; gap: 8px; margin: 0; }
.fx-ctas > .btn, .fx-ctas > .title-card-open {
  --h: 44px; flex: 1 1 auto; min-width: 0; min-height: 44px; align-self: auto; justify-content: center; gap: .5em; padding: 0 .9em; border-radius: 0;
  font: 400 12px/1 var(--font-hud); letter-spacing: var(--track-hud); text-transform: uppercase; white-space: nowrap;
}
.fx-ctas > .btn--ghost { background: transparent; color: var(--chrome); border: 1px solid var(--line-strong); }
.fx-ctas > .btn--ghost:hover, .fx-ctas > .btn--ghost:focus-visible { background: var(--void-3); border-color: var(--chrome-3); }
.fx-ctas > .btn:focus-visible { outline: 2px solid var(--chrome); outline-offset: 2px; }

/* ── LIST ──────────────────────────────────────────────────────────────────────────────────────────────────── */
.folio-list { --lcols: 84px minmax(0, 1.8fr) minmax(96px, .7fr) 88px 40px; border-top: 1px solid var(--line-strong); }
.folio-list-head { grid-template-columns: var(--lcols); gap: 16px; padding: 0 12px 0 0; min-height: 40px; align-items: center; border-bottom: 1px solid var(--line-strong); }
.folio-list-head > span:nth-child(4) { text-align: right; }
.folio-entry { border-bottom: 1px solid var(--line); }
.folio-entry .folio-row {
  appearance: none; -webkit-appearance: none; background: transparent; border: 0; border-radius: 0; margin: 0; width: 100%;
  text-align: left; font: inherit; color: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent;
  grid-template-columns: var(--lcols); gap: 16px; min-height: 84px; padding: 18px 12px 18px 0; border-bottom: 0;
  transition: background var(--dur-2) var(--ease-out), opacity var(--dur-2) linear;
}
.folio-entry .folio-row:hover, .folio-entry.is-open .folio-row { background: rgba(230, 233, 237, .035); }
.folio-entry .folio-row:focus-visible { outline: 1px solid var(--chrome); outline-offset: -1px; }
.folio-entry .folio-row-name { transition: transform var(--dur-3) var(--ease-out); gap: 6px; }
.folio-entry .folio-row-name b { font-size: 21px; line-height: 1.15; }
.folio-entry .folio-row-name .mute { font-size: 13px; color: var(--chrome-3); }
.folio-entry .folio-row-frames { color: var(--chrome-2); }
.folio-entry .folio-row-plus { position: relative; justify-self: end; width: 16px; height: 16px; color: var(--chrome-3); transition: transform var(--dur-3) var(--ease-out), color var(--dur-1) linear; }
.folio-row-plus::before, .folio-row-plus::after { content: ''; position: absolute; left: 0; top: 50%; width: 100%; height: 1px; background: currentColor; }
.folio-row-plus::after { transform: rotate(90deg); }
.folio-entry .folio-row:hover .folio-row-plus { color: var(--chrome); }
.folio-entry.is-open .folio-row-plus { transform: rotate(45deg); color: var(--chrome); }
@media (hover: hover) { .folio-entry .folio-row:hover .folio-row-name { transform: translateX(6px); } }
.folio-list:has(.folio-entry .folio-row:hover) .folio-entry:not(:hover):not(.is-open) .folio-row { opacity: .55; }
.fx-drawer { padding: 6px 12px 36px 100px; }
.fx-drawer[hidden] { display: none; }
@media (max-width: 1023px) { .fx-drawer { padding-left: 0; padding-right: 0; } .fx-drawer .fx-card { grid-template-columns: minmax(0, 1fr); } }
.fx-drawer .fx-facts { margin-top: 0; }

/* the hover cover (mouse only) */
.fx-peek {
  position: fixed; left: 0; top: 0; z-index: 35; width: 300px; aspect-ratio: 3 / 4; pointer-events: none; opacity: 0; scale: .96;
  background: var(--void-3); outline: 1px solid var(--line-strong); box-shadow: 0 24px 60px rgba(0, 0, 0, .5);
  transition: opacity 180ms linear, scale 320ms var(--ease-out); will-change: transform;
}
.fx-peek.is-on { opacity: 1; scale: 1; }
.fx-peek img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 220ms linear; }
.fx-peek img.is-on { opacity: 1; }
@media (hover: none), (pointer: coarse) { .fx-peek { display: none; } }

/* phone: compact rows (title, type, year); a tap opens the drawer in place */
@media (max-width: 700px) {
  .folio-list { --lcols: minmax(0, 1fr) 28px; }
  .folio-entry .folio-row { grid-template-columns: minmax(0, 1fr) 28px; gap: 4px 12px; min-height: 68px; padding: 14px 0; align-items: center; }
  .folio-entry .folio-row-id, .folio-entry .folio-row-name .mute { display: none; }
  .folio-entry .folio-row-name { grid-column: 1; grid-row: 1; }
  .folio-entry .folio-row-name b { font-size: 19px; }
  .folio-entry .folio-row-kind { grid-column: 1; grid-row: 2; display: inline; font-size: 11px; }
  .folio-entry .folio-row-frames { grid-column: 1; grid-row: 2; justify-self: end; font-size: 11px; text-align: right; }
  .folio-entry .folio-row-frames::before { content: none; }
  .folio-entry .folio-row-plus { grid-column: 2; grid-row: 1 / span 2; }
  .fx-drawer { padding: 4px 0 28px; }
  .fx-drawer .fx-card { gap: 18px; }
}
/* tablet: tighter columns */
@media (min-width: 701px) and (max-width: 1023px) {
  .folio-list { --lcols: 64px minmax(0, 1.8fr) minmax(84px, .7fr) 84px 32px; }
  .folio-entry .folio-row { gap: 12px; min-height: 76px; }
}

/* ── GRID ──────────────────────────────────────────────────────────────────────────────────────────────────── */
@media (min-width: 760px) and (min-height: 501px) {
  .folio-grid { column-gap: clamp(40px, 4.4vw, 72px); row-gap: clamp(56px, 5.6vw, 88px); }
}
@media (min-width: 1200px) and (hover: hover) and (pointer: fine) {
  .folio-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: clamp(32px, 3.4vw, 56px); }
}
.folio-card { cursor: pointer; }
.folio-meta-year { margin-left: auto; color: var(--chrome-3); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .folio-card .folio-cover { transition: transform 360ms var(--ease-out), outline-color var(--dur-1) linear; }
  .folio-card:hover .folio-cover, .folio-card:focus-visible .folio-cover { transform: translateY(-4px); }
}
.folio-card[aria-expanded="true"] .folio-cover { outline-color: var(--chrome-3); }

.fx-layer { position: fixed; inset: 0; z-index: 40; display: grid; place-items: center; }
.fx-layer[hidden] { display: none; }
.fx-backdrop { position: absolute; inset: 0; background: rgba(6, 7, 10, .84); }
.fx-panel {
  position: relative; width: min(1120px, calc(100vw - 64px)); max-height: calc(100vh - 96px); max-height: calc(100dvh - 96px);
  overflow: auto; overscroll-behavior: contain; padding: clamp(24px, 2.6vw, 40px); background: var(--void-2); outline: 1px solid var(--line-strong);
  scrollbar-width: thin;
}
.fx-panel:focus { outline: 1px solid var(--line-strong); }
.fx-panel:focus-visible { outline: 1px solid var(--chrome-3); }
.fx-close {
  position: absolute; top: 8px; right: 8px; z-index: 3; display: grid; place-items: center; width: 44px; height: 44px;
  background: transparent; border: 0; color: var(--chrome-3); font: 400 24px/1 var(--font-hud); cursor: pointer; touch-action: manipulation;
}
.fx-close:hover { color: var(--chrome); }
.fx-close:focus-visible { outline: 1px solid var(--chrome); outline-offset: -4px; color: var(--chrome); }
.fx-panel .fx-card { padding-right: 0; }
.fx-panel .fx-info { padding-top: 6px; }
.fx-panel .fx-meta { padding-right: 44px; min-height: 28px; }
@media (max-width: 899px) { .fx-panel .fx-card { grid-template-columns: minmax(0, 1fr); gap: 22px; } .fx-panel .fx-info { padding-top: 0; } }
.fx-ghost { position: fixed; z-index: 41; object-fit: cover; pointer-events: none; background: var(--void-3); }
html.fx-open, html.fx-open body { overflow: hidden; overscroll-behavior: none; }

/* phone-class: the full-height sheet (Task O's frame) */
@media (max-width: 759px), (pointer: coarse) and (max-height: 500px) {
  .fx-layer.is-sheet { z-index: 26; display: block; }
  .fx-layer.is-sheet .fx-backdrop { background: var(--void); animation: sheet-backdrop-in 240ms linear both; }
  .fx-layer.is-sheet .fx-panel {
    --sheet-top: calc(var(--edge) + var(--hud-row) + 8px);
    position: absolute; top: var(--sheet-top); left: max(var(--edge), env(safe-area-inset-left)); right: max(var(--edge), env(safe-area-inset-right));
    bottom: env(safe-area-inset-bottom, 0px); width: auto; max-height: none; padding: 52px 16px 20px;
    -webkit-overflow-scrolling: touch; touch-action: pan-y;
  }
  .fx-layer.is-sheet.is-in .fx-panel { animation: sheet-up 340ms var(--ease-out) both; }
  .fx-layer.is-sheet .fx-close { top: 4px; right: 4px; background: var(--void-2); }
  .fx-layer.is-sheet .fx-card { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .fx-layer.is-sheet .fx-meta { position: absolute; top: 0; left: 16px; right: 56px; min-height: 52px; padding: 0; align-content: center; }
  .fx-layer.is-sheet .fx-track { aspect-ratio: auto; height: min(45vh, 100vw * .75); height: min(45svh, calc(100vw * .75)); min-height: 160px; }
  .fx-layer.is-sheet .fx-title { font-size: 32px; }
  .fx-layer.is-sheet .fx-facts { margin-top: 0; }
  html.fx-sheet .hud-bottom, html.fx-sheet .hud-filters { opacity: 0; pointer-events: none; }
  .fx-nav button { min-width: 44px; height: 44px; font-size: 16px; }
  .fx-count { font-size: 12px; }
  .fx-ctas { gap: 5px; }
  .fx-ctas > .btn, .fx-ctas > .title-card-open { padding: 0 .6em; letter-spacing: .04em; gap: .35em; font-size: 11px; }
}
@media (max-width: 759px) { .fx-nav button { min-width: 44px; height: 44px; } }

/* the stage opened OVER the Grid or List (Explore 3D / Case study): the floor is only the stage's backdrop */
.floor--over { z-index: 60; }
.floor--over .world, .floor--over .floor-grid { visibility: hidden; }
html.stage-over .fx-peek { display: none; }

@media (prefers-reduced-motion: reduce) {
  .folio-entry .folio-row-name, .folio-entry .folio-row-plus, .fx-peek, .fx-peek img { transition: none; }
  .folio-entry .folio-row:hover .folio-row-name { transform: none; }
  .fx-layer.is-sheet.is-in .fx-panel, .fx-layer.is-sheet .fx-backdrop { animation: none; }
}
.folio-grid { align-items: start; }

/* ═══ Task Q (2026-10-28, JC: "content on the right should be vertically centered, gap above and below equal") ═══
   The List drawer and the Grid panel: the text column is centred against the media block (reel + counter row), so the
   space above the eyebrow equals the space below the buttons. The drawer gets equal top and bottom padding. */
@media (min-width: 1024px) {
  .fx-drawer .fx-card { align-items: center; }
  .fx-drawer .fx-info { align-self: center; }
}
@media (min-width: 900px) {
  .fx-panel .fx-card { align-items: center; }
  .fx-panel .fx-info { align-self: center; padding-top: 0; }
  .fx-panel .fx-meta { min-height: 0; }
}
@media (min-width: 900px) {
  .fx-card .fx-facts { margin-top: 0; }
}
.fx-drawer { padding-top: clamp(24px, 2.4vw, 32px); padding-bottom: clamp(24px, 2.4vw, 32px); }
@media (max-width: 700px) { .fx-drawer { padding-top: 20px; padding-bottom: 20px; } }
