/* ════════════════════════════════════════════════════════════════════════════
   PHOTO BOOTH v2 — the arcade skin (2026-07-30)
   ────────────────────────────────────────────────────────────────────────────
   Built from Mr. Avery's mock. Spec: _specs/2026-07-30-photo-booth-v2-design.md

   ⚠ THIS SKIN IS PHOTO BOOTH ONLY. It deliberately does NOT match Spark Lab's
   v6 language (rounded dark pills, Phosphor chrome, at most two filled buttons)
   and it must never leak outward — Art Studio, Spark Lab, Coloring and By
   Number all share canvas.css's :is() scope, which is exactly why this lives in
   its own file and hangs off .cc-b2 rather than [data-app="canvas"].

   His mock runs five filled colour buttons at once. That is the look; the
   two-filled-buttons discipline from the 2026-07-30 pass is lifted HERE and
   nowhere else.

   TYPE: the pixel faces (fonts.css). Minecraft for display, Pixeloid Sans for
   chrome, Pixeloid Mono for counts. ⚠ Never copy a px size across from the old
   Press Start 2P / VT323 rules — the metrics differ hard. See fonts.css.
   ⚠ Weights are real files: 700 exists, 800/900 do not and get faked.
   ════════════════════════════════════════════════════════════════════════════ */

.cc-booth.cc-b2 {
  --b2-navy:   #0d0a2a;
  --b2-panel:  #16123a;
  --b2-line:   #2e2a5e;
  --b2-edge:   #8b3ff5;   /* the magenta/violet panel border in his mock */
  --b2-cy:     #16E0E0;
  --b2-li:     #C6F542;
  --b2-pk:     #FF2E7E;
  --b2-gold:   #FFB800;
  --b2-ink:    #ffffff;
  --b2-dim:    #9a9ac8;
  --b2-pad:    14px;

  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  gap: 10px; padding: var(--b2-pad);
  /* his starfield sits back; ours rendered brighter and the halftone argued
     with the frame. A flat dark overlay layer knocks it back without ever
     touching the asset — background-color must live in the LAST layer. */
  background:
    linear-gradient(rgba(4, 2, 14, .45), rgba(4, 2, 14, .45)),
    url(../img/booth/v2/starfield.webp) center / cover no-repeat,
    var(--b2-navy);
  color: var(--b2-ink);
  font-family: 'Pixeloid Sans', ui-monospace, monospace;
  overflow: hidden;             /* guard, not a layout tool */
}

/* ── HEADER ─────────────────────────────────────────────────────────────── */
.cc-b2-head {
  position: relative;
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 14px;
  min-width: 0;
}
.cc-b2-title { height: 60px; width: auto; display: block; image-rendering: pixelated; }
.cc-b2-titletxt {   /* onerror fallback — art missing */
  font-family: 'Minecraft', monospace; font-weight: 700;
  font-size: 33px; margin: 0; letter-spacing: 1px;
}
.cc-b2-exit {
  flex: 0 0 auto;
  width: 34px; height: 34px; display: grid; place-items: center;
  background: #241f4d; color: var(--b2-ink);
  border: 2px solid var(--b2-line); border-radius: 9px; cursor: pointer;
}
.cc-b2-exit:hover { background: var(--b2-pk); border-color: var(--b2-pk); }
.cc-b2-exit svg { width: 17px; height: 17px; fill: currentColor; }

/* CAMERA │ IMPORT — one segmented control in a trough, not two buttons. */
.cc-b2-srcwrap {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 4px;
  margin: 0 auto;
  padding: 5px; border-radius: 12px;
  background: #120f30; border: 2px solid var(--b2-line);
}
.cc-b2-src {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 18px; border: 2px solid transparent; border-radius: 9px;
  background: transparent; color: var(--b2-dim); cursor: pointer;
  font-family: inherit; font-weight: 700; font-size: 14px; letter-spacing: .5px;
}
.cc-b2-src:hover { color: var(--b2-ink); }
.cc-b2-src.cc-on {
  background: var(--b2-cy); color: #06121a; border-color: #0b6f7a;
  box-shadow: 0 3px 0 #0b6f7a;
}
.cc-b2-src svg { width: 16px; height: 16px; fill: currentColor; }

.cc-b2-headr { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; margin-left: auto; }
.cc-b2-help {
  width: 30px; height: 30px; border-radius: 50%; cursor: pointer;
  background: #241f4d; color: var(--b2-gold);
  border: 2px solid var(--b2-gold);
  font-family: inherit; font-weight: 700; font-size: 14px;
}
.cc-b2-help:hover { background: var(--b2-gold); color: #2a1c00; }
.cc-b2-safe {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 14px; border-radius: 11px;
  background: #1b1240; border: 2px solid var(--b2-pk);
  color: #ffd9e8; font-weight: 700; font-size: 12px; letter-spacing: .6px;
}

/* help card — booth-only, anchored under the header */
.cc-b2-helpcard {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 40;
  width: min(420px, 86vw); padding: 16px 18px;
  background: var(--b2-panel); border: 2px solid var(--b2-edge); border-radius: 14px;
  box-shadow: 0 14px 40px rgba(0,0,0,.55);
}
.cc-b2-helpcard h3 { margin: 0 0 10px; font-size: 14px; color: var(--b2-cy); letter-spacing: 1px; }
.cc-b2-helpcard ol { margin: 0 0 10px; padding-left: 20px; }
.cc-b2-helpcard li { margin-bottom: 7px; font-size: 12px; line-height: 1.6; color: #d9d9f2; }
.cc-b2-helpcard b { color: var(--b2-li); }
.cc-b2-help-safe { margin: 0 0 12px; font-size: 11px; color: var(--b2-dim); }

/* ── MAIN ───────────────────────────────────────────────────────────────── */
/* ⚠ min-width:0 AND min-height:0 are load-bearing on this whole chain. A flex
   item's automatic minimum size is its CONTENT size, so without them the filter
   rail's min-content width (all 35 tiles end to end = 2602px) inflates the app
   past its own window instead of scrolling — measured, twice. */
.cc-b2-main {
  flex: 1 1 auto;
  display: flex; gap: 12px;
  min-width: 0; min-height: 0;
}
.cc-b2-stage {
  position: relative;
  flex: 1 1 auto;
  min-width: 0; min-height: 0;
  display: flex; align-items: center; justify-content: center;
}

/* decorative props — first thing to go as the window narrows.
   z-index 2 puts them IN FRONT of the frame, which is how his mock stages the
   film can: it rests over the frame's lower-right corner rather than being
   clipped by it. They are pointer-events:none, so nothing is made unclickable. */
.cc-b2-prop {
  position: absolute; z-index: 2;
  pointer-events: none; user-select: none;
  image-rendering: pixelated;
  filter: drop-shadow(0 6px 14px rgba(0,0,0,.5));
}
/* kept fully inside the stage — negative insets put them under the booth's
   own overflow:hidden and shaved the camera's left edge */
.cc-b2-prop-cam { left: 2px; bottom: 4px; width: 168px; }
.cc-b2-prop-can { right: 2px; bottom: 10px; width: 92px; }
.cc-b2-noprops .cc-b2-prop { display: none; }

/* ── THE FRAME ──────────────────────────────────────────────────────────── */
.cc-b2-framebox {
  position: relative; z-index: 1;
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  min-width: 0; min-height: 0;
  /* Room for the props to sit BESIDE the frame rather than under its edges,
     which is how his mock stages them. Reclaimed the moment props drop out.
     ⚠ ASYMMETRIC AND IN PERCENT, both on purpose. His mock does not centre the
     frame in the stage: the left gutter carries the photo strip AND the camera
     (14.3% of the app) while the right carries only the film can (4.3%), so a
     symmetric padding puts the frame ~15px left of where he drew it. Percent
     rather than px so the gutters keep their proportion as the window is
     dragged — these resolve against the STAGE's width. */
  padding-left: 19%;
  padding-right: 4.5%;
}
.cc-b2-noprops .cc-b2-framebox { padding-inline: 0; }
/* The pocket is a real occupant of the top-left, not an overlay — without this
   whatever's in it (the tray, or its CTA below .cc-bcompact 2026-07-30) sits on
   top of the curtain in his frame art. Only needed once the props (and with
   them the 19% gutter) have dropped out; above that the gutter is already
   wider than the pocket. Unconditional on strip-on: the CTA occupies this same
   spot while the strip is off, so the reservation is needed either way — only
   .cc-bcompact (which hides both) frees the space back up. */
.cc-b2-noprops:not(.cc-bcompact) .cc-b2-framebox { padding-left: 138px; }
/* sized in PIXELS by fitFrame() in booth.js. ⚠ Deliberately not CSS
   aspect-ratio: with a definite width that computes a height, max-height then
   clamps without shrinking the width back, and his art stretches. */
.cc-b2-frame { position: relative; }
.cc-b2-frameart {
  display: block; width: 100%; height: 100%;
  image-rendering: pixelated; pointer-events: none;
}

/* ⚠ THESE PERCENTAGES ARE MEASURED FROM HIS ART and must agree with ART_W /
   ART_H in booth.js's fitFrame(). Source of truth: the build script's printout
   and _tools/booth-v2/manifest.json. Re-measure if the frame art is ever
   swapped; do NOT eyeball them. */
.cc-b2-well {
  position: absolute;
  left: 14.39%; top: 15.25%; width: 71.02%; height: 72.07%;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; background: #05030f;
}
/* ── THE BULB ───────────────────────────────────────────────────────────── */
/* His 3 bulb frames, packed into one horizontal strip by the build script and
   driven by steps() — the sprite-sheet pattern from ASSET-FRAMEWORK §6.
   `steps(3, jump-none)` over a 0%→100% background-position on a 300%-wide
   background lands exactly on 0 / 50 / 100%, i.e. the three frames.
   ⚠ steps(), not a crossfade: choppy IS the aesthetic on pixel art, and a
   smooth tween between two hand-drawn frames reads as a rendering bug.
   Position/size are MEASURED (manifest.json → bulb.rect), so the bulb tracks
   the frame at any scale without a second copy of the geometry in JS.
   background-position repaints rather than composites, but this is a ~65px box
   changing twice a second — the compositor rule is about large elements
   animating per-frame, which this is the opposite of. */
.cc-b2-bulb {
  position: absolute;
  left: 88.36%; top: 4.89%; width: 7.66%; height: 10.36%;
  background: url(../img/booth/v2/bulb-sheet.webp) 0 0 / 300% 100% no-repeat;
  image-rendering: pixelated;
  pointer-events: none; z-index: 1;
  animation: cc-b2-bulb 1.5s steps(3, jump-none) infinite;
}
@keyframes cc-b2-bulb { from { background-position: 0% 0; } to { background-position: 100% 0; } }
/* 3-2-1 — the bulb winds up with the countdown */
.cc-b2-counting .cc-b2-bulb { animation-duration: .42s; }
.cc-b2-noart .cc-b2-bulb, .cc-b2-tight .cc-b2-bulb { display: none; }
@media (prefers-reduced-motion: reduce) {
  /* hold the middle frame — a still bulb, not a dark one */
  .cc-b2-bulb { animation: none; background-position: 50% 0; }
}

/* art missing, or the window is too small for the bezel to earn its 50% */
.cc-b2-noart .cc-b2-frameart { display: none; }
.cc-b2-noart .cc-b2-well,
.cc-b2-tight .cc-b2-well {
  position: static; inset: auto;
  width: 100%; height: 100%;
  border: 2px solid var(--b2-line); border-radius: 10px;
}
.cc-b2-tight .cc-b2-frame { width: 100% !important; height: 100% !important; }
.cc-b2-tight .cc-b2-frameart { display: none; }

/* ── WELL CONTENTS ──────────────────────────────────────────────────────── */
.cc-b2-cam, .cc-b2-imp, .cc-b2-photo {
  position: relative;
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
}
.cc-b2-cam video {
  width: 100%; height: 100%; object-fit: cover;
  transform: scaleX(-1);            /* selfie mirror — the capture mirrors to match */
  background: #05030f;
}
.cc-b2-photo canvas { display: block; image-rendering: auto; }

.cc-b2-wait, .cc-b2-ready {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  text-align: center; padding: 18px; pointer-events: none;
}
/* sits at the TOP of the well — centred, it would land square on a face */
.cc-b2-ready { justify-content: flex-start; padding-top: 16px; }
.cc-b2-readylbl {
  font-family: 'Minecraft', monospace; font-weight: 700;
  font-size: 20px; letter-spacing: 1px; color: #fff;
  text-shadow: 0 2px 0 #000;
}
.cc-b2-waitlbl { font-weight: 700; font-size: 13px; }
.cc-b2 .cc-bmuted { font-size: 11px; color: var(--b2-dim); }
.cc-b2 .cc-bspin {
  width: 22px; height: 22px; border-radius: 50%;
  border: 3px solid rgba(255,255,255,.25); border-top-color: var(--b2-cy);
  animation: cc-b2-spin .8s linear infinite;
}
@keyframes cc-b2-spin { to { transform: rotate(360deg); } }

.cc-b2-count {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: 'Minecraft', monospace; font-weight: 700; font-size: 92px;
  color: #fff; text-shadow: 0 5px 0 rgba(0,0,0,.65); pointer-events: none;
}
.cc-b2-flash { position: absolute; inset: 0; background: #fff; opacity: 0; pointer-events: none; }
.cc-b2-flash.cc-flash { animation: cc-b2-flash .22s ease-out; }
@keyframes cc-b2-flash { from { opacity: .95; } to { opacity: 0; } }

/* SNAP / RETAKE — the one loud button, inside the well like his mock */
.cc-b2-snap {
  position: absolute; left: 50%; bottom: 7%; transform: translateX(-50%);
  padding: 14px 44px; cursor: pointer;
  background: var(--b2-pk); color: #fff;
  border: 3px solid #a8144d; border-radius: 999px;
  box-shadow: 0 5px 0 #a8144d;
  font-family: 'Minecraft', monospace; font-weight: 700;
  font-size: 26px; letter-spacing: 2px;
}
.cc-b2-snap:hover:not(:disabled) { background: #ff4f92; }
.cc-b2-snap:active:not(:disabled) { transform: translateX(-50%) translateY(4px); box-shadow: 0 1px 0 #a8144d; }
.cc-b2-snap:disabled { opacity: .4; cursor: default; }
.cc-b2-retake { background: #241f4d; border-color: #4a3f8f; box-shadow: 0 5px 0 #4a3f8f; font-size: 19px; padding: 11px 30px; }
.cc-b2-retake:hover { background: #342d68; }
.cc-b2-snap-imp { position: static; transform: none; font-size: 18px; padding: 12px 28px; }
.cc-b2-snap-imp:active { transform: translateY(4px); }

/* IMPORT pane */
.cc-b2-imp {
  flex-direction: column; gap: 12px; padding: 22px; text-align: center;
  border: 3px dashed #453c86; border-radius: 12px; margin: 12px;
  width: calc(100% - 24px); height: calc(100% - 24px);
}
.cc-b2-imp.cc-bdrag { border-color: var(--b2-cy); background: rgba(22,224,224,.08); }
.cc-b2-imp-ico svg { width: 46px; height: 46px; fill: var(--b2-cy); }
.cc-b2-imp-h { margin: 0; font-family: 'Minecraft', monospace; font-weight: 700; font-size: 18px; }
.cc-b2-imp-sub { margin: 0; font-size: 11px; color: var(--b2-dim); line-height: 1.7; }
.cc-b2-imp kbd {
  background: #241f4d; border: 1px solid var(--b2-line); border-radius: 4px;
  padding: 1px 5px; font-family: 'Pixeloid Mono', monospace; font-size: 10px;
}

.cc-b2-err {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 16px; text-align: center;
}
.cc-b2-err .cc-berr-ico svg { width: 34px; height: 34px; fill: var(--b2-pk); }
.cc-b2-err .cc-berr-h { font-family: 'Minecraft', monospace; font-weight: 700; font-size: 16px; }
.cc-b2-err .cc-berr-p { font-size: 11px; color: var(--b2-dim); line-height: 1.6; max-width: 34ch; }
.cc-b2 .cc-bbusy {
  position: absolute; inset: 0; z-index: 6; display: grid; place-items: center;
  background: rgba(9,6,26,.82); font-weight: 700; font-size: 13px;
}

/* ── BEFORE / AFTER wipe ────────────────────────────────────────────────── */
.cc-b2 .cc-bcompare { position: absolute; z-index: 4; pointer-events: auto; cursor: ew-resize; }
.cc-b2 .cc-bcmp-line { position: absolute; top: 0; bottom: 0; width: 3px; background: #fff; box-shadow: 0 0 0 1px rgba(0,0,0,.5); }
.cc-b2 .cc-bcmp-handle {
  position: absolute; top: 50%; width: 40px; height: 40px; margin: -20px 0 0 -20px;
  border-radius: 50%; background: #fff; border: 3px solid #0b0716; cursor: ew-resize;
  display: grid; place-items: center; padding: 0;
}
.cc-b2 .cc-bcmp-grip svg { width: 18px; height: 18px; fill: #0b0716; }
.cc-b2 .cc-bcmp-tag {
  position: absolute; top: 10px; padding: 4px 9px; border-radius: 6px;
  background: rgba(9,6,26,.8); font-size: 10px; font-weight: 700; letter-spacing: 1px;
  opacity: 0; transition: opacity .15s;
}
.cc-b2 .cc-bcmp-tagb { left: 10px; color: var(--b2-dim); }
.cc-b2 .cc-bcmp-taga { right: 10px; color: var(--b2-cy); }
.cc-b2 .cc-bshow-b .cc-bcmp-tagb, .cc-b2 .cc-bshow-a .cc-bcmp-taga { opacity: 1; }

/* ── THE STRIP TRAY ─────────────────────────────────────────────────────── */
/* Pocketed top-left of the stage, where his mock drew the emoji strip. */
.cc-b2-tray {
  position: absolute; left: 0; top: 0; z-index: 3;
  width: 124px;
  display: flex; flex-direction: column; gap: 6px;
}
.cc-b2-traypaper { position: relative; width: 100%; filter: drop-shadow(0 6px 14px rgba(0,0,0,.55)); }
.cc-b2-tray-art {
  position: absolute; inset: 0; width: 100%; height: 100%;
  display: block; image-rendering: pixelated;
}
.cc-b2-tray-emoji { z-index: 0; }
/* ⚠ pointer-events:none is REQUIRED — the frame sits over every slot button and
   would otherwise eat all four clicks (same trap as the arcade cabinet art). */
.cc-b2-tray-frame { z-index: 2; pointer-events: none; }
.cc-b2-tray-slots { position: absolute; inset: 0; z-index: 1; }

.cc-b2-slot {
  position: absolute; padding: 0; overflow: hidden; cursor: pointer;
  background: transparent; border: 0;
  display: grid; place-items: center;
}
.cc-b2-slot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cc-b2-slot:disabled { cursor: default; }
.cc-b2-slot-add {
  font-family: 'Minecraft', monospace; font-weight: 700; font-size: 26px;
  color: #1b1240; background: var(--b2-li);
  width: 100%; height: 100%; display: grid; place-items: center;
}
.cc-b2-slot.cc-next .cc-b2-slot-add { animation: cc-b2-pulse 1.6s ease-in-out infinite; }
@keyframes cc-b2-pulse { 0%,100% { opacity: 1; } 50% { opacity: .55; } }
.cc-b2-slot-x {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgba(9,6,26,.72); color: #fff; font-size: 19px; font-weight: 700;
  opacity: 0; transition: opacity .12s;
}
.cc-b2-slot.cc-filled:hover .cc-b2-slot-x,
.cc-b2-slot.cc-filled:focus-visible .cc-b2-slot-x { opacity: 1; }

/* ADD gets its own full-width row; the three icon actions share the next one.
   All four on one 124px line squeezed the glyphs to unreadable and wrapped the
   ＋ away from its own label. */
.cc-b2-tray-acts { display: flex; flex-wrap: wrap; gap: 4px; }
.cc-b2-tact {
  flex: 1 1 0; padding: 7px 6px; cursor: pointer;
  background: #241f4d; color: var(--b2-ink);
  border: 2px solid var(--b2-line); border-radius: 8px;
  font-family: inherit; font-weight: 700; font-size: 13px; line-height: 1;
}
.cc-b2-tact-go {
  flex: 1 0 100%; background: var(--b2-li); color: #1b1240; border-color: #7d9e12;
  font-size: 11px; letter-spacing: .4px; white-space: nowrap;
}
.cc-b2-tact:hover:not(:disabled) { border-color: var(--b2-cy); }
.cc-b2-tact-clear:hover:not(:disabled) { border-color: var(--b2-pk); color: var(--b2-pk); }
.cc-b2-tact:disabled { opacity: .35; cursor: default; }

/* ── STRIP TRAY CTA — shown while PHOTO STRIP is OFF ───────────────────────
   His mock draws the emoji strip whether or not it holds any photos, so an
   OFF tray left the pocket bare — a hole in the composition. The approved
   fix (his own idea) is the same two art layers as a clickable "turn it on"
   invite. It occupies the IDENTICAL box as .cc-b2-traypaper — same left/top/
   width here, same aspect (set from the one TRAY source of truth in
   booth-strip.js, via booth.js) — so flipping the strip on never shifts
   anything already on screen; the tray simply appears where this was. */
.cc-b2-stripcta {
  position: absolute; left: 0; top: 0; z-index: 3;
  width: 124px; padding: 0; margin: 0; border: 0; background: transparent;
  cursor: pointer;
  filter: drop-shadow(0 6px 14px rgba(0,0,0,.55));
  transition: filter .15s ease, transform .15s ease;
}
.cc-b2-stripcta:hover, .cc-b2-stripcta:focus-visible {
  filter: drop-shadow(0 9px 18px rgba(0,0,0,.6)) brightness(1.15);
  transform: translateY(-2px);
}
.cc-b2-rail .cc-b2-stripcta { width: 92px; }
/* same reasoning as .cc-bcompact .cc-b2-tray below: down here the pocket
   costs the picture too much room, and the dock STRIP button is the way in. */
.cc-bcompact .cc-b2-stripcta { display: none; }

/* ── SIDE PANEL ─────────────────────────────────────────────────────────── */
.cc-b2-side {
  /* His mock gives the filter panel ~30% of the app's width; at a flat 320px it
     read as a cramped afterthought beside the frame and forced the 3-column
     tiles down to ~91px. Proportional, with a floor so it survives the band
     between .cc-b2-rail (920) and .cc-b2-noprops (1180), and a ceiling so a
     maximised 1080p window does not hand it half the app. */
  flex: 0 0 clamp(320px, 30.5%, 470px);
  display: flex; flex-direction: column; gap: 10px;
  min-width: 0; min-height: 0;
  padding: 12px;
  background: rgba(22,18,58,.93);
  border: 3px solid var(--b2-edge); border-radius: 16px;
}
.cc-b2-sidehead { flex: 0 0 auto; display: flex; align-items: center; gap: 10px; }
.cc-b2-sidetitle {
  font-family: 'Minecraft', monospace; font-weight: 700;
  font-size: 21px; letter-spacing: 1px; color: var(--b2-cy);
}
.cc-b2-adjbtn {
  margin-left: auto; display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 13px; cursor: pointer;
  background: #241f4d; color: var(--b2-ink);
  border: 2px solid #6c4bc4; border-radius: 10px;
  font-family: inherit; font-weight: 700; font-size: 11px; letter-spacing: .5px;
}
.cc-b2-adjbtn svg { width: 14px; height: 14px; fill: currentColor; }
.cc-b2-adjbtn:hover { border-color: var(--b2-cy); }
.cc-b2-adjbtn.cc-on { background: var(--b2-cy); color: #06121a; border-color: #0b6f7a; }

/* the panel body is the ONE scroller — nested scrollers fighting over a 520px
   window is what clipped things in v1 */
.cc-b2-panes { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; }

.cc-b2 .cc-bgroups {
  position: sticky; top: 0; z-index: 2;
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 0 0 9px; margin-bottom: 3px;
  background: linear-gradient(#16123a 76%, rgba(22,18,58,0));
}
.cc-b2 .cc-bgroup {
  padding: 7px 12px; cursor: pointer;
  background: #241f4d; color: var(--b2-ink);
  border: 2px solid #4a3f8f; border-radius: 9px;
  font-family: inherit; font-weight: 700; font-size: 12px; letter-spacing: .4px;
}
.cc-b2 .cc-bgroup:hover { border-color: var(--b2-cy); }
.cc-b2 .cc-bgroup.cc-on { background: var(--b2-li); color: #1b1240; border-color: #7d9e12; }

.cc-b2 .cc-bedit-filmstrip {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
}
.cc-b2 .cc-bfilm-head {
  grid-column: 1 / -1;
  margin: 10px 0 1px;
  font-family: 'Minecraft', monospace; font-weight: 700;
  font-size: 13px; letter-spacing: 1px; color: var(--b2-gold);
}
.cc-b2 .cc-bfilm-tile {
  display: flex; flex-direction: column; gap: 5px; padding: 0;
  background: none; border: 0; cursor: pointer; min-width: 0;
}
.cc-b2 .cc-bfilm-shot {
  position: relative; display: block; width: 100%; aspect-ratio: 1;
  border: 3px solid #4a3f8f; border-radius: 10px; overflow: hidden;
  background: #241f4d;
}
.cc-b2 .cc-bfilm-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cc-b2 .cc-bfilm-tile:hover .cc-bfilm-shot { border-color: var(--b2-pk); }
.cc-b2 .cc-bfilm-tile.cc-on .cc-bfilm-shot { border-color: var(--b2-cy); }
.cc-b2 .cc-bfilm-lbl {
  font-weight: 700; font-size: 12px; letter-spacing: .3px; color: var(--b2-dim);
  text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cc-b2 .cc-bfilm-tile.cc-on .cc-bfilm-lbl { color: var(--b2-cy); }
.cc-b2 .cc-bfilm-tick {
  position: absolute; right: 4px; top: 4px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--b2-cy); color: #06121a;
  display: grid; place-items: center; font-size: 12px; font-weight: 700;
  opacity: 0; transition: opacity .12s;
}
.cc-b2 .cc-bfilm-tile.cc-on .cc-bfilm-tick { opacity: 1; }
.cc-b2 .cc-bloading .cc-bfilm-shot { background: #241f4d; }

/* MORE FILTERS — a signpost at the seam, drawn as clearly NOT a filter */
.cc-b2-more .cc-bfilm-shot {
  border-style: dashed; border-color: #6c4bc4;
  display: grid; place-items: center; background: transparent;
}
.cc-b2-more:hover .cc-bfilm-shot { border-color: var(--b2-gold); }
/* the one label allowed to wrap — "MORE FILTERS" ellipsised to "MORE FILTE…" */
.cc-b2-more .cc-bfilm-lbl { white-space: normal; line-height: 1.25; color: var(--b2-gold); }
.cc-b2-more-ico { font-size: 26px; color: var(--b2-gold); }
/* grid-column: the filmstrip is a 3-column grid, so without this the message
   becomes a 1-column-wide ransom note */
.cc-b2-nofilters { grid-column: 1 / -1; margin: 6px 2px; font-size: 11px; line-height: 1.7; color: var(--b2-dim); }

/* ADJUST pane + parameter sheet */
.cc-b2 .cc-badjust { display: flex; flex-direction: column; gap: 10px; }
.cc-b2 .cc-bnow {
  display: flex; align-items: center; gap: 8px; padding: 9px 11px; cursor: pointer;
  background: #241f4d; border: 2px solid #4a3f8f; border-radius: 10px;
  color: var(--b2-ink); font-family: inherit; font-size: 11px; font-weight: 700;
}
.cc-b2 .cc-bnow-k { color: var(--b2-dim); letter-spacing: .5px; }
.cc-b2 .cc-bnow-v { color: var(--b2-cy); }
.cc-b2 .cc-bnow-go { margin-left: auto; }
.cc-b2 .cc-bnow-go svg { width: 13px; height: 13px; fill: currentColor; }
.cc-b2 .cc-bnote { margin: 0; font-size: 11px; line-height: 1.6; color: var(--b2-dim); }
.cc-b2 .cc-brow { display: flex; flex-direction: column; gap: 5px; margin-bottom: 11px; }
.cc-b2 .cc-brow-head { display: flex; justify-content: space-between; font-size: 11px; font-weight: 700; }
.cc-b2 .cc-brow-num { font-family: 'Pixeloid Mono', monospace; color: var(--b2-cy); }
.cc-b2 .cc-brow input[type=range] { width: 100%; accent-color: var(--b2-cy); }
.cc-b2 .cc-bghost {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 9px 13px; cursor: pointer;
  background: #241f4d; color: var(--b2-ink);
  border: 2px solid #4a3f8f; border-radius: 10px;
  font-family: inherit; font-weight: 700; font-size: 11px; letter-spacing: .4px;
}
.cc-b2 .cc-bghost:hover { border-color: var(--b2-cy); }

/* the settings sheet — its own card, so RESET can never fall off the bottom of
   a scrolled list (which is exactly what happened in v1) */
.cc-b2 .cc-bparams {
  flex: 0 0 auto; max-height: 42%;
  display: flex; flex-direction: column; min-height: 0;
  padding: 10px; border-radius: 12px;
  background: #120f30; border: 2px solid var(--b2-line);
}
.cc-b2 .cc-bparams-head { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; margin-bottom: 9px; }
.cc-b2 .cc-bparams-name {
  font-family: 'Minecraft', monospace; font-weight: 700; font-size: 14px; color: var(--b2-gold);
}
.cc-b2 .cc-bparams-head .cc-breset { margin-left: auto; padding: 6px 10px; font-size: 10px; }
.cc-b2 .cc-bparams-rows { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

/* ── DOCK ───────────────────────────────────────────────────────────────── */
/* flex-wrap, because the five buttons plus the tip card exceed a hand-resized
   window long before .cc-bcompact drops their labels at 620 — measured: 965px
   of content in an 856px window, overflowing the app horizontally. */
.cc-b2 .cc-booth-dock {
  position: relative;
  flex: 0 0 auto;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  min-width: 0;
}
/* the contained darker band behind the five action buttons. His mock frames
   them as one bounded object, separate from the TIP card by a visible gap —
   ours had them floating loose on the starfield. There is no wrapper element
   around the buttons (JS out of scope), so this is a ::before sized to stop
   just short of .cc-b2-tip.
   ⚠ The calc below does NOT depend on how much width the buttons take: since
   .cc-b2-tip is `flex: 0 0 <basis>` with `margin-left: auto`, its left edge
   always sits exactly <basis> in from the dock's own right edge, regardless
   of button content width (auto-margin absorbs all leftover space before a
   fixed-basis trailing flex item). So `right: basis + gap` always lands the
   band's edge one gap short of the tip's left edge, at any window width. */
.cc-b2 .cc-booth-dock::before {
  content: "";
  position: absolute;
  top: -8px; bottom: -8px; left: -8px;
  right: calc(clamp(320px, 30.5%, 470px) + 8px);
  background: rgba(7, 5, 22, .55);
  border: 2px solid var(--b2-line);
  border-radius: 16px;
  z-index: 0;
  pointer-events: none;
}
.cc-b2 .cc-bdock-btn, .cc-b2 .cc-b2-tip { position: relative; z-index: 1; }
.cc-b2 .cc-bdock-btn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 13px 17px; cursor: pointer;
  background: #1b1642; color: var(--b2-ink);
  border: 3px solid #4a3f8f; border-radius: 13px;
  font-family: inherit; font-weight: 700; font-size: 13px; letter-spacing: .5px;
  white-space: nowrap;
}
.cc-b2 .cc-bdock-btn:hover:not(:disabled) { border-color: var(--b2-cy); }
.cc-b2 .cc-bdock-btn:disabled { opacity: .38; cursor: default; }
.cc-b2 .cc-bdock-ico svg { width: 17px; height: 17px; fill: currentColor; }
.cc-b2 .cc-bdock-new { background: var(--b2-li); color: #1b1240; border-color: #7d9e12; }
.cc-b2 .cc-bdock-new:hover:not(:disabled) { background: #d7ff5c; border-color: #7d9e12; }
.cc-b2 .cc-bdock-strip.cc-on { background: var(--b2-cy); color: #06121a; border-color: #0b6f7a; }

/* the ON/OFF switch inside PHOTO STRIP */
.cc-b2-switch {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 8px 3px 3px; border-radius: 999px;
  background: rgba(0,0,0,.42);
  font-family: 'Pixeloid Mono', monospace; font-size: 10px; letter-spacing: .5px;
}
.cc-b2-switch i { width: 13px; height: 13px; border-radius: 50%; background: #8b88b0; display: block; }
.cc-bdock-strip.cc-on .cc-b2-switch i { background: #06121a; }

.cc-b2-tip {
  /* Matches .cc-b2-side's basis exactly so its left edge lines up with the
     FILTERS panel's left edge above it, per his mock — both resolve against
     the same full app width since .cc-b2-main and .cc-booth-dock are equal-
     width siblings in the column flex. */
  flex: 0 0 clamp(320px, 30.5%, 470px); min-width: 0;
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; margin-left: auto;
  background: rgba(22,18,58,.9);
  border: 2px solid var(--b2-li); border-radius: 13px;
}
.cc-b2-tip-txt { min-width: 0; font-size: 11px; line-height: 1.5; color: #e4e4f7; }
.cc-b2-tip-txt b { color: var(--b2-li); }
.cc-b2-byte { flex: 0 0 auto; width: 54px; height: auto; margin-left: auto; image-rendering: pixelated; }

/* ── FOCUS — one treatment for the whole mode ───────────────────────────── */
.cc-b2 :focus-visible { outline: 3px solid var(--b2-cy); outline-offset: 2px; }

/* ════════════════════════════════════════════════════════════════════════════
   THE NARROWING LADDER
   Classes come from a ResizeObserver on the APP WINDOW in booth.js, never from
   @media. The window is draggable — a media query measures the viewport, which
   is how a 500px window on a 1366px screen slipped through the last pass.
     .cc-b2-noprops (<1180)  props out
     .cc-b2-rail    (<920)   panel becomes a rail under the stage
     .cc-bcompact   (<620)   dock icon-only
     .cc-b2-short   (h<560)  tighter vertical rhythm
   ════════════════════════════════════════════════════════════════════════════ */
/* ⚠ A vertical panel simply MOVED below the stage is not a rail. The first
   attempt did that with max-height:44%, which left the stage ~218px tall — the
   frame then tripped .cc-b2-tight and dropped out altogether. The panel has to
   become genuinely short, which means the tiles run in a ROW. */
.cc-b2-rail .cc-b2-main { flex-direction: column; }
.cc-b2-rail .cc-b2-stage { flex: 1 1 auto; min-height: 0; }
.cc-b2-rail .cc-b2-side {
  flex: 0 0 auto; max-height: none; border-radius: 14px;
  padding: 9px 10px;
}
.cc-b2-rail .cc-b2-panes { overflow-x: auto; overflow-y: hidden; }
.cc-b2-rail .cc-bgroups { position: static; background: none; padding-bottom: 7px; }
.cc-b2-rail .cc-bedit-filmstrip { display: flex; gap: 8px; align-items: flex-start; }
.cc-b2-rail .cc-bfilm-tile { flex: 0 0 86px; }
/* the group spine survives as an inline marker between runs of tiles */
.cc-b2-rail .cc-bfilm-head {
  flex: 0 0 auto; align-self: center; margin: 0 2px;
  writing-mode: vertical-rl; transform: rotate(180deg); font-size: 11px;
}
.cc-b2-rail .cc-bparams { max-height: 150px; }
.cc-b2-rail .cc-b2-tray { width: 92px; }
.cc-b2-rail .cc-b2-title { height: 40px; }
.cc-b2-rail .cc-b2-safe { display: none; }
/* the tip is the least load-bearing thing in the dock — it goes before the
   dock is forced to wrap */
.cc-b2-rail .cc-b2-tip { display: none; }
/* with the tip gone, the button band runs the full dock width */
.cc-b2-rail .cc-booth-dock::before { right: -8px; }
/* ⚠ Even with the tip gone the five buttons measured 836px in an 828px dock and
   wrapped to a second row — which cost 59px of HEIGHT and starved the stage
   until the frame tripped .cc-b2-tight. Rather than shave paddings and sit one
   pixel from the same cliff, the three export verbs go icon-only here. The two
   that keep their labels are the two that are colour-coded and carry state. */
.cc-b2-rail .cc-bdock-btn:not(.cc-bdock-new):not(.cc-bdock-strip) span:not(.cc-bdock-ico) { display: none; }
.cc-b2-rail .cc-bdock-btn:not(.cc-bdock-new):not(.cc-bdock-strip) { padding: 13px; gap: 0; }

.cc-bcompact .cc-b2 { padding: 9px; }
.cc-b2.cc-bcompact { padding: 9px; gap: 8px; }
.cc-bcompact .cc-bdock-btn span:not(.cc-bdock-ico):not(.cc-b2-switch) { display: none; }
.cc-bcompact .cc-bdock-btn { padding: 12px; gap: 0; }
.cc-bcompact .cc-b2-tip { display: none; }
.cc-bcompact .cc-b2-src span:not(.cc-bico) { display: none; }
.cc-bcompact .cc-b2-src { padding: 9px 12px; }
.cc-bcompact .cc-b2-title { height: 32px; }
.cc-bcompact .cc-b2-side { flex-basis: auto; max-height: 46%; padding: 9px; }
.cc-bcompact .cc-bedit-filmstrip { grid-template-columns: repeat(auto-fill, minmax(74px, 1fr)); }
/* the tray costs the picture too much room down here — it folds behind its
   toggle and the dock button stays the way back to it */
.cc-bcompact .cc-b2-tray { display: none; }

.cc-b2-short .cc-b2-title { height: 34px; }
.cc-b2-short .cc-bdock-btn { padding: 9px 13px; }
.cc-b2-short .cc-b2-snap { padding: 10px 30px; font-size: 20px; }

/* very small VIEWPORT (phone-ish), independent of the window classes above */
@media (max-width: 560px) {
  .cc-b2-head { flex-wrap: wrap; }
  .cc-b2-srcwrap { margin: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .cc-b2 *, .cc-b2 *::before, .cc-b2 *::after { animation: none !important; transition: none !important; }
}

/* ════════════════════════════════════════════════════════════════════════════
   ⚠ THE [hidden] TRAP — LAST RULE IN THE FILE, ON PURPOSE.
   This stylesheet puts an AUTHOR `display` on nearly everything the JS hides
   with the `hidden` attribute: .cc-b2-wait, .cc-b2-ready, .cc-b2-count,
   .cc-b2-err, .cc-badjust, .cc-bparams, .cc-b2-panes, .cc-b2-tray, .cc-bbusy.
   An author display ALWAYS beats the UA's `[hidden] { display: none }`, so
   `el.hidden = true` silently does nothing.

   Observed on the first run, 2026-07-30: the ADJUST sliders rendered underneath
   the filter list, and "Waking up the camera…" never went away after the
   camera came up. Same class of bug as the pet dock (CLAUDE.md gotcha #4) and
   the .cc-pcard specificity trap (gotcha #5b).

   !important rather than a specificity race because these elements are hidden
   from a dozen places and a future rule with one more class would silently
   re-break it.
   ════════════════════════════════════════════════════════════════════════════ */
.cc-b2 [hidden] { display: none !important; }
