/* === Bounty Hunter Tracker — Tatooine wanted-poster theme ===
 *
 * Distinct from Galactic Customs (galaxy + passport stamp). This is
 * sun-bleached desert: burnt orange, sand, deep shadow. Wanted posters
 * with stenciled type, silhouettes treated black-on-red, dossier mug
 * grid below. Click a face = decision (no separate Approve/Reject).
 */

:root {
  /* Tatooine palette — recoloured for the photographic backdrop:
   * the bg is a light pink-cream desert sky + sand, so the UI now
   * leans into deep browns (less orange, less rust) for high
   * contrast against the bright photo. The original token names are
   * kept so the rest of the CSS doesn't have to be touched. */
  --bh-sand-1:    #f0e0c4;   /* light cream */
  --bh-sand-2:    #c4a577;   /* mid sand */
  --bh-sand-3:    #7e5a35;   /* deep sand */
  --bh-rust:      #5a3a20;   /* deep brown (was burnt orange) */
  --bh-rust-deep: #2c1a0a;   /* near-black brown */
  --bh-rust-bright: #8a5a30; /* warm brown accent (was bright orange) */
  --bh-paper:     #f6ead6;   /* cream — text on dark surfaces (AA) */
  --bh-paper-dim: #e8d4a8;   /* lighter sand — keeps AA on dark bg */
  --bh-ink:       #1f0e04;   /* near-black brown — text on cream */
  --bh-shadow:    #0d0602;
  --bh-night:     #050201;
  --bh-warn:      #7a2222;   /* deep crimson — used for cards on cream */
  --bh-warn-glow: #ff5a5a;   /* bright red — feedback / glows on dark */
  --bh-gold:      #f0c95c;   /* bright gold — text on dark (AA) */
  --bh-gold-deep: #8a6420;   /* bronze accent for cream surfaces */
  --bh-go:        #3a6b30;   /* deep forest green — text on cream */
  --bh-go-glow:   #6fde6e;   /* bright green — feedback / glows on dark */

  /* Surface tokens — dark panels with cream content for contrast
   * over the light photo backdrop. */
  --bh-surface:   rgba(28, 18, 8, 0.86);
  --bh-surface-2: rgba(246, 234, 214, 0.96);
  --bh-stroke:    rgba(58, 36, 18, 0.5);
}

@media (prefers-color-scheme: dark) { :root { color-scheme: dark; } }

/* Always honor [hidden] inside the game UI — several rules later set
   display:flex/grid/inline-flex on classes that are independently
   marked [hidden] (.bh-btn, .bh-feedback, etc.); the browser's default
   [hidden]{display:none} otherwise loses the specificity battle. */
.bh-stage [hidden] { display: none !important; }

.bh-body { background: var(--bh-sand-1); color: var(--bh-ink); overflow-x: hidden; }
.bh-main { background: var(--bh-sand-1); }

/* ---------- Stage — Tatooine photo backdrop ---------- */
.bh-stage {
  position: relative;
  isolation: isolate;
  min-height: calc(100vh - 96px);
  padding: 24px clamp(16px, 4vw, 56px) 48px;
  background:
    /* Soft warm darkening at the bottom so card overlays read; rest
     * of the photo stays bright. */
    linear-gradient(180deg, transparent 60%, rgba(80, 50, 28, 0.18) 100%),
    url('/bounty/assets/tatooine-bg-sky.jpg') center / cover no-repeat;
  overflow: hidden;
  color: var(--bh-ink);
}

/* ===== Speeder-bike fly-by layer + foreground occlusion =====
 * The new bg is the full Tatooine scene. We layer a speeder-bike
 * track on top of the bg's sky portion (z-2), then re-stamp the
 * houses/dunes/ground on top via a transparent-sky foreground PNG
 * (z-3) so a speeder that dips below the horizon line is hidden
 * behind the silhouettes — gives the parallax depth the brief asks
 * for. The shell content (HUD, poster, mug grid) sits at z-4 above
 * everything so gameplay UI is never occluded.
 *
 * Both layers are pointer-events:none — clicks fall through to the
 * existing .bh-stage shot handler in game.js, which does the
 * speeder hit-test by coordinate proximity. */
.bh-speeders {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* Below the foreground PNG (z-3) so the dome silhouette on the
   * left occludes a passing speeder — that parallax depth is the
   * brief. The fix for "I never see them" is the higher horizon Y
   * (BH_SPEEDER_HORIZON_Y_PCT in game.js), which puts the bikes
   * inside the PNG's transparent sky band (0–45 %) for the bulk of
   * the track and lets the silhouettes only occlude where they
   * actually rise. */
  z-index: 2;
  /* Each child speeder is absolutely positioned within. */
}
.bh-foreground {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;
  background: url('/bounty/assets/tatooine-fg.png') center / cover no-repeat;
}

/* A single speeder bike. The natural orientation of the source PNG
 * is right-facing (rider looks/aims left, vehicle moves to the
 * left); .bh-speeder--rtl flips horizontally for the
 * right→left-direction trips so the bike always faces the way it's
 * traveling. Sized small per direction — "as if floating just
 * above the horizon." Width clamps so a 320 px viewport still gets
 * a recognisable silhouette. */
.bh-speeder {
  position: absolute;
  width: clamp(56px, 7vw, 120px);
  height: auto;
  filter:
    saturate(0.85)
    brightness(1.05)
    drop-shadow(0 2px 4px rgba(60, 36, 18, 0.35));
  /* The source faces left (rider posture). For LTR (left→right)
   * trips we flip horizontally so the bike points the way it
   * travels. */
  will-change: transform, left;
}
.bh-speeder--ltr { transform: scaleX(-1); }

@keyframes bh-speeder-fly-rtl {
  /* Right edge → left edge. Speeder arrives at +6 % over 100 % of
   * its own width past the right edge (offscreen) and exits past
   * -6 % on the left side. Linear motion at ~horizon-cruise pace. */
  0%   { left: calc(100% + 6%); }
  100% { left: -16%; }
}
@keyframes bh-speeder-fly-ltr {
  0%   { left: -16%; }
  100% { left: calc(100% + 6%); }
}
.bh-speeder.is-flying-rtl { animation: bh-speeder-fly-rtl var(--bh-speeder-duration, 4.5s) linear forwards; }
.bh-speeder.is-flying-ltr { animation: bh-speeder-fly-ltr var(--bh-speeder-duration, 4.5s) linear forwards; }

/* Hit-then-explode keyframe: speeder freezes momentum (the JS pauses
 * the animation), tilts, drops a few px, and fades while the
 * explosion sprite renders on top. */
.bh-speeder.is-exploding {
  animation: none !important;
  transition: transform 380ms cubic-bezier(0.4, 0, 0.6, 1),
              opacity   480ms ease-out;
  transform: translate(0, 18px) rotate(-12deg);
  opacity: 0;
}
/* LTR speeders use scaleX(-1) so the bike faces its travel direction
 * (the source PNG faces right). The base `.is-exploding` rule above
 * replaces transform entirely — that drops the mirror, snapping the
 * bike's facing during the 480 ms fade. Re-compose the explode
 * transform with the mirror so the orientation stays put. */
.bh-speeder--ltr.is-exploding {
  transform: scaleX(-1) translate(0, 18px) rotate(-12deg);
}

/* Explosion plume — radial blast at the speeder's last position.
 * Centering is via negative margins (margin -40 on a 80×80 element);
 * the keyframe is pure scale/opacity. The previous version composed
 * `translate(-50%, -50%)` on top of the negative margin, which
 * double-centered and pushed every blast 40 px up and 40 px left of
 * the actual speeder. Mirrors the Customs `.sw-tie-burst` pattern. */
.bh-speeder-blast {
  position: absolute;
  width: 80px; height: 80px;
  margin-left: -40px; margin-top: -40px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 4;     /* above foreground silhouette so the flash is visible */
  background: radial-gradient(
    circle,
    rgba(255, 250, 230, 1)   0%,
    rgba(255, 165, 70, 0.95) 22%,
    rgba(220, 80, 28, 0.7)   48%,
    rgba(110, 30, 12, 0.25)  72%,
    rgba(60, 20, 8, 0)       100%
  );
  filter: blur(1.5px);
  animation: bh-speeder-blast 700ms cubic-bezier(0.18, 0.85, 0.4, 1) forwards;
}
@keyframes bh-speeder-blast {
  0%   { transform: scale(0.2); opacity: 0; }
  18%  { transform: scale(1.4); opacity: 1; }
  60%  { transform: scale(1.1); opacity: 0.7; }
  100% { transform: scale(0.7); opacity: 0; }
}

/* Speeder-bike shrapnel — JS sets per-shard width / height / margin
 * so each fragment is a slightly different rectangle (chassis sliver,
 * armor chunk, panel rivet). The gradient mixes worn off-white
 * (stormtrooper plate) with dark gunmetal (bike body) so the shards
 * read as "bits of bike" rather than uniform 8-bit blocks. JS also
 * sets --fx, --fy, --rot per shard so each one drifts in a different
 * direction. */
.bh-speeder-fragment {
  position: absolute;
  /* width/height/margin set per-fragment by JS (defaults below for
   * any shard that somehow ships without inline overrides). */
  width: 6px; height: 3px;
  margin-left: -3px; margin-top: -1.5px;
  background: linear-gradient(135deg, #d8d2c2 0%, #8a7e68 45%, #2c241a 100%);
  border-radius: 1.5px;
  pointer-events: none;
  z-index: 4;
  box-shadow: 0 0 4px rgba(255, 170, 70, 0.55);
  animation: bh-speeder-fragment 720ms cubic-bezier(0.18, 0.82, 0.45, 1) forwards;
}
@keyframes bh-speeder-fragment {
  0%   { transform: translate(0, 0) rotate(0); opacity: 1; }
  60%  { opacity: 1; }
  100% { transform: translate(var(--fx, 60px), var(--fy, 60px)) rotate(var(--rot, 360deg)); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .bh-speeder.is-flying-rtl,
  .bh-speeder.is-flying-ltr { animation: none !important; }
  .bh-speeder-blast { animation-duration: 220ms; }
  .bh-speeder-fragment { animation-duration: 220ms; }
}

/* The CSS-art sky / dunes / sun / bantha / landspeeder layers are
 * redundant now that the photo provides the whole backdrop. */
.bh-sky,
.bh-sky__sun--primary,
.bh-sky__sun--secondary,
.bh-sky__dust,
.bh-dunes,
.bh-bantha,
.bh-landspeeder { display: none !important; }

.bh-sky {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}

/* Twin suns — Tatooine's signature sky. Pushed to upper corners and
   dimmed so the title + lede stay legible against the sand-colored
   background. */
.bh-sky__sun {
  position: absolute;
  border-radius: 50%;
  filter: blur(0.5px);
  opacity: 0.7;
}
.bh-sky__sun--primary {
  width: clamp(110px, 13vw, 220px);
  aspect-ratio: 1;
  top: 6%;
  left: 4%;
  background:
    radial-gradient(circle, #fff5cf 0%, #ffd06a 42%, rgba(238, 134, 74, 0) 72%);
  filter: blur(1px);
  animation: bh-sun-pulse 8s ease-in-out infinite alternate;
}
.bh-sky__sun--secondary {
  width: clamp(60px, 8vw, 130px);
  aspect-ratio: 1;
  top: 4%;
  right: 6%;
  background:
    radial-gradient(circle, #ffe8a8 0%, #ffb45c 50%, rgba(255, 180, 92, 0) 78%);
  filter: blur(1px);
  animation: bh-sun-pulse 11s ease-in-out infinite alternate-reverse;
  opacity: 0.55;
}
@keyframes bh-sun-pulse {
  0%   { opacity: 0.6;  transform: scale(1); }
  100% { opacity: 0.78; transform: scale(1.03); }
}

/* Sand dust haze */
.bh-sky__dust {
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 80% 30% at 50% 70%, rgba(232, 160, 73, 0.45), transparent 70%),
    radial-gradient(ellipse 70% 40% at 30% 88%, rgba(255, 196, 110, 0.35), transparent 65%);
  mix-blend-mode: screen;
  opacity: 0.7;
}

/* Parallax dunes — three layers, ascending opacity, drifting slowly. */
.bh-dunes {
  position: absolute;
  left: -10%;
  right: -10%;
  height: clamp(120px, 22vh, 260px);
  background-repeat: repeat-x;
  background-position: bottom;
  background-size: 1200px 100%;
  opacity: 0.9;
}
.bh-dunes--far {
  bottom: 18%;
  height: clamp(80px, 14vh, 160px);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 220' preserveAspectRatio='none'><path d='M0,180 Q200,100 400,140 T800,120 T1200,160 L1200,220 L0,220 Z' fill='%23a04621'/></svg>");
  opacity: 0.55;
  animation: bh-dunes-drift 90s linear infinite;
}
.bh-dunes--mid {
  bottom: 8%;
  height: clamp(110px, 18vh, 220px);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 220' preserveAspectRatio='none'><path d='M0,180 Q150,80 350,130 T650,100 T1000,140 T1200,150 L1200,220 L0,220 Z' fill='%237a2c12'/></svg>");
  opacity: 0.75;
  animation: bh-dunes-drift 130s linear infinite reverse;
}
.bh-dunes--near {
  bottom: -2%;
  height: clamp(140px, 24vh, 300px);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 240' preserveAspectRatio='none'><path d='M0,200 Q220,90 440,140 T780,110 T1200,170 L1200,240 L0,240 Z' fill='%2335150a'/></svg>");
  opacity: 0.95;
}
@keyframes bh-dunes-drift {
  0%   { background-position-x: 0; }
  100% { background-position-x: -1200px; }
}

/* X-34 landspeeder zipping across the dunes — uses the Wookieepedia
   image so it's the actual film vehicle, not a vector approximation.
   Travels left-to-right along the mid-dune line, with a slight bob and
   a subtle dust trail to sell the hover. */
.bh-landspeeder {
  position: absolute;
  bottom: 14%;
  left: 0;
  width: clamp(140px, 16vw, 260px);
  height: auto;
  filter:
    drop-shadow(0 6px 14px rgba(0, 0, 0, 0.55))
    drop-shadow(-12px 4px 12px rgba(58, 22, 8, 0.45));
  pointer-events: none;
  opacity: 0;
  animation: bh-landspeeder-pass 28s linear infinite;
  z-index: 2;
}
@keyframes bh-landspeeder-pass {
  0%   { transform: translate3d(-30vw, 0, 0); opacity: 0; }
  10%  { opacity: 0.95; }
  45%  { transform: translate3d(60vw, -6px, 0); opacity: 0.95; }
  90%  { transform: translate3d(120vw, 0, 0); opacity: 0.95; }
  100% { transform: translate3d(130vw, 0, 0); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .bh-landspeeder { animation: none; opacity: 0.6; transform: translate3d(40vw, 0, 0); }
}

/* Bantha silhouette on the horizon */
.bh-bantha {
  position: absolute;
  bottom: 22%;
  left: 12%;
  width: clamp(100px, 12vw, 180px);
  opacity: 0.7;
  animation: bh-bantha-walk 60s linear infinite;
  pointer-events: none;
}
.bh-bantha svg { width: 100%; height: auto; display: block; }
@keyframes bh-bantha-walk {
  0%   { transform: translateX(0)    scaleX(1); opacity: 0.7; }
  47%  { transform: translateX(60vw) scaleX(1); opacity: 0.7; }
  50%  { transform: translateX(60vw) scaleX(-1); opacity: 0.7; }
  97%  { transform: translateX(0)    scaleX(-1); opacity: 0.7; }
  100% { transform: translateX(0)    scaleX(1); opacity: 0.7; }
}
@media (prefers-reduced-motion: reduce) {
  .bh-dunes, .bh-bantha, .bh-sky__sun { animation: none !important; }
}

/* ---------- Shell & brand ---------- */
.bh-shell {
  position: relative;
  z-index: 4;
  max-width: min(960px, 100%);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.bh-brand {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  padding: 8px 0;
  color: var(--bh-ink);            /* dark on the light photo bg */
  flex-wrap: wrap;
}
.bh-brand__logo {
  /* 96×35 → 130×47 (+35 %) → 156×57 (+20 % more, May 3). */
  width: 156px; height: 57px; display: block;
  /* Public bounty uses CDO.me_001-bh.svg pre-coloured #2a1b0c to
   * match the headline brown; no invert needed. The ID.me variant
   * (idme-bountyhunter/index.html) loads a separate ID.me logo
   * file that's already white — no recolour either. */
  filter: drop-shadow(0 1px 2px rgba(255, 240, 220, 0.6));
}
.bh-brand__divider {
  width: 1px; height: 26px;
  background: rgba(58, 36, 18, 0.5);
  margin-bottom: 4px;
}
.bh-brand__tag {
  font-size: 13px;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--bh-rust);           /* deep brown */
  line-height: 1;
  padding-bottom: 6px;
}

/* Public CDO version (body.is-public) centers the tag + divider on
 * the logo instead of baseline-aligning to its bottom. The ID.me
 * version keeps the baseline alignment because the ID.me wordmark
 * sits at the same baseline as the tag text. The +20 % logo size
 * exposed how much vertical asymmetry the baseline alignment had
 * on the public version, where there's no wordmark anchor. */
body.is-public .bh-brand { align-items: center; }
body.is-public .bh-brand__divider { margin-bottom: 0; }
body.is-public .bh-brand__tag    { padding-bottom: 0; }
.bh-brand__ring {
  margin-left: auto;
  display: flex;
  gap: 6px;
  align-items: center;
}
.bh-brand__sibling {
  font-size: 11px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--bh-ink);
  text-decoration: none;
  padding: 6px 12px;
  border: 1px solid rgba(58, 36, 18, 0.55);
  border-radius: 999px;
  background: rgba(255, 250, 240, 0.55);
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.bh-brand__sibling:hover,
.bh-brand__sibling:focus-visible {
  background: rgba(255, 250, 240, 0.85);
  color: var(--bh-rust-deep);
  border-color: var(--bh-rust);
  outline: none;
}
/* Sound toggle — pill button matching the cross-game pill, sits to its
 * left in the brand-strip ring. .sound-off on <body> swaps the icon. */
.bh-brand__mute {
  appearance: none;
  border: 1px solid rgba(58, 36, 18, 0.55);
  background: rgba(255, 250, 240, 0.55);
  color: var(--bh-ink);
  width: 32px; height: 28px;
  border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  padding: 0;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.bh-brand__mute:hover,
.bh-brand__mute:focus-visible {
  background: rgba(255, 250, 240, 0.85);
  color: var(--bh-rust-deep);
  border-color: var(--bh-rust);
  outline: none;
}
.bh-brand__mute-icon { width: 16px; height: 16px; display: none; }
.bh-brand__mute-icon--on  { display: block; }
.bh-brand__mute-icon--off { display: none; }
body.sound-off .bh-brand__mute-icon--on  { display: none; }
body.sound-off .bh-brand__mute-icon--off { display: block; }
body.sound-off .bh-brand__mute {
  border-color: rgba(58, 36, 18, 0.30);
  background: rgba(255, 250, 240, 0.35);
  color: rgba(58, 36, 18, 0.50);
}
@media (max-width: 720px) {
  .bh-brand__ring { margin-left: 0; flex-wrap: wrap; }
  .bh-brand__sibling { padding: 5px 9px; letter-spacing: 1.2px; }
}
/* Mobile: shrink the brand logo so the strip fits on a 375 px
 * viewport without horizontal scroll. Keeps the +35 % bump from
 * desktop (156→128 vs the original 96), still readable. */
@media (max-width: 480px) {
  .bh-brand__logo { width: 128px; height: 47px; }
  .bh-brand { gap: 10px; }
  .bh-brand__tag { font-size: 11px; letter-spacing: 2px; }
  .bh-brand__divider { height: 22px; }
}

/* Mobile / touch: drop the Mandalorian and Boba Fett easter-egg
 * fly-by rigs entirely. The trigger zones are pointer-events:none
 * but the rigs themselves auto-peek and the timing-based animations
 * cover real estate that touch users need for the game-board
 * interactions. Easter eggs are a desktop-pointer flourish; on
 * touch they're not discoverable and they're in the way. */
@media (max-width: 720px), (pointer: coarse) {
  .bh-mando-zone, .bh-mando,
  .bh-boba-zone, .bh-boba { display: none !important; }
}

.bh-h1 {
  font-size: clamp(28px, 5vw, 48px);
  line-height: 1.05;
  margin: 0;
  letter-spacing: -0.6px;
  color: var(--bh-ink);
  text-shadow: 0 1px 0 rgba(255, 245, 225, 0.6);
  text-wrap: balance;
}
/* Orange-leaning rust so the ID.me accent reads clearly against the
 * dark-brown body text on the cream landing background. */
.bh-accent {
  color: #c46a1f;
  text-shadow: 0 1px 0 rgba(255, 245, 225, 0.5);
}
.bh-lede {
  font-size: clamp(15px, 1.6vw, 18px);
  line-height: 1.5;
  color: var(--bh-rust-deep);
  max-width: 56ch;
  margin: 12px 0 0;
}

/* ---------- Views (fade-in) ---------- */
.bh-view {
  display: flex; flex-direction: column;
  gap: clamp(14px, 2.5vw, 22px);
  animation: bh-view-in 380ms ease both;
}
.bh-view[hidden] { display: none !important; }
@keyframes bh-view-in {
  0%   { opacity: 0; transform: translateY(8px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* ---------- Landing ---------- */
.bh-landing {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 14px;
  padding: clamp(20px, 5vw, 56px) 8px;
}
.bh-landing__eyebrow {
  margin: 0;
  text-transform: uppercase;
  letter-spacing: 4px;
  font-size: clamp(11px, 1.2vw, 13px);
  color: var(--bh-rust);
}
.bh-landing__title {
  margin: 0;
  font-size: clamp(40px, 8vw, 84px);
  line-height: 0.95;
  letter-spacing: -2px;
  /* 800 (was 900) so the webfont weight matches what users had with
   * the previous system-ui fallback. text-transform removed so the
   * markup's natural casing renders as written — "ID.me" stays
   * mixed-case (caps ID + lowercase me), matching the customs title. */
  font-weight: 800;
  color: var(--bh-rust-deep);
  text-shadow:
    0 1px 0 rgba(255, 245, 225, 0.7),
    0 4px 24px rgba(255, 245, 225, 0.35);
  text-wrap: balance;
}
.bh-landing__lede {
  margin: 6px 0 14px;
  max-width: 56ch;
  font-size: clamp(15px, 1.6vw, 18px);
  line-height: 1.55;
  color: var(--bh-rust-deep);
}

/* ---------- Buttons ---------- */
.bh-btn {
  appearance: none; border: 0; cursor: pointer;
  font-family: inherit;
  font-size: 15px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 26px;
  border-radius: 999px;
  text-decoration: none;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  transition: transform 120ms ease, background 120ms ease, color 120ms ease, box-shadow 120ms ease, filter 120ms ease;
  white-space: nowrap;
  position: relative;
}
.bh-btn:active { transform: translateY(1px); }
.bh-btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }
.bh-btn:focus-visible { outline: 3px solid var(--bh-gold); outline-offset: 3px; }

.bh-btn--start {
  background: linear-gradient(135deg, #6a4424, #2c1a0a 75%);
  color: #f6ead6;
  font-size: clamp(16px, 1.8vw, 19px);
  padding: 18px 32px;
  letter-spacing: 1px;
  font-weight: 900;
  border: 2px solid #1f0e04;
  box-shadow:
    0 14px 30px rgba(28, 14, 4, 0.55),
    inset 0 0 0 2px rgba(246, 234, 214, 0.22),
    inset 0 -8px 20px rgba(0, 0, 0, 0.22);
  animation: bh-start-pulse 2.4s ease-in-out infinite;
}
.bh-btn--start:hover { filter: brightness(1.12); transform: translateY(-1px); }
@keyframes bh-start-pulse {
  0%, 100% { box-shadow: 0 14px 30px rgba(28, 14, 4, 0.55), inset 0 0 0 2px rgba(246, 234, 214, 0.22), inset 0 -8px 20px rgba(0,0,0,0.22); }
  50%      { box-shadow: 0 18px 42px rgba(60, 36, 18, 0.65), inset 0 0 0 2px rgba(246, 234, 214, 0.32), inset 0 -8px 20px rgba(0,0,0,0.22); }
}

.bh-btn--primary {
  background: linear-gradient(135deg, #6a4424, #2c1a0a 75%);
  color: #f6ead6;
  border: 2px solid #1f0e04;
  font-weight: 800;
  box-shadow:
    0 10px 22px rgba(28, 14, 4, 0.45),
    inset 0 0 0 1px rgba(246, 234, 214, 0.18);
}
.bh-btn--primary:hover { filter: brightness(1.12); }

.bh-btn--text {
  background: transparent;
  color: var(--bh-rust-deep);
  padding: 10px 14px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  font-size: 13px;
  font-weight: 700;
}
.bh-btn--text:hover { color: var(--bh-ink); }

.bh-btn--sm {
  padding: 8px 14px;
  font-size: 12px;
}

/* ---------- Card ---------- */
.bh-card {
  background:
    linear-gradient(180deg, rgba(50, 24, 12, 0.85), rgba(20, 8, 4, 0.92));
  border: 1px solid var(--bh-stroke);
  border-radius: 10px;
  padding: clamp(18px, 3vw, 28px);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  box-shadow:
    0 14px 40px rgba(0, 0, 0, 0.55),
    inset 0 0 0 1px rgba(255, 196, 110, 0.06);
}

/* ---------- Sign-in form (matches Customs avatar component contract) ---------- */
.bh-signin {
  display: grid;
  gap: clamp(14px, 2vw, 22px);
  align-items: center;
  grid-template-columns: minmax(180px, 220px) 1fr;
  grid-template-areas:
    "avatar fields"
    "avatar consent"
    "avatar error"
    "avatar submit";
}
.bh-signin > .bh-avatar       { grid-area: avatar; }
.bh-signin__fields            { grid-area: fields; display: grid; gap: 12px; }
.bh-signin__consent           { grid-area: consent;
                                display: flex;
                                gap: 10px;
                                align-items: flex-start;
                                font-size: 13px;
                                /* The signin card is a dark-brown
                                 * gradient (linear-gradient on
                                 * rgba(50,24,12,0.85)). The previous
                                 * --bh-rust-deep (#2c1a0a) text on
                                 * that surface was effectively
                                 * invisible (~1.3:1 contrast). Cream
                                 * sand-tone gives ~11.8:1 — AAA. */
                                color: var(--bh-paper-dim);
                                line-height: 1.4;
                                cursor: pointer;
                              }
.bh-signin__consent strong    { color: var(--bh-paper); }
/* Custom checkbox so the checked / unchecked state reads at a
 * glance. Default UA accent-color tints the box a shade of
 * background-on-background that's easy to miss. This draws an
 * explicit white check on a solid filled box. */
.bh-signin__consent input     { appearance: none;
                                -webkit-appearance: none;
                                width: 22px;
                                height: 22px;
                                margin: 1px 0 0;
                                flex: 0 0 auto;
                                border: 2px solid var(--bh-paper-dim);
                                border-radius: 4px;
                                background: rgba(255, 250, 240, 0.06);
                                cursor: pointer;
                                position: relative;
                                display: inline-grid;
                                place-content: center;
                                transition: background-color 120ms ease, border-color 120ms ease;
                              }
.bh-signin__consent input:checked {
                                background: var(--bh-paper);
                                border-color: var(--bh-paper);
                              }
.bh-signin__consent input:checked::after {
                                content: '';
                                width: 12px;
                                height: 6px;
                                border-left: 2.5px solid var(--bh-rust-deep);
                                border-bottom: 2.5px solid var(--bh-rust-deep);
                                transform: rotate(-45deg) translate(1px, -1px);
                              }
.bh-signin__consent input:focus-visible {
                                outline: 2px solid var(--bh-rust-bright);
                                outline-offset: 2px;
                              }
.bh-signin__consent input[aria-invalid="true"] {
                                outline: 2px solid var(--bh-warn);
                                outline-offset: 2px;
                              }
.bh-signin__error             { grid-area: error;
                                margin: 0;
                                min-height: 1.2em;
                                font-size: 13px;
                                color: var(--bh-warn);
                              }
.bh-signin > [type="submit"]  { grid-area: submit; justify-self: start; }

@media (max-width: 640px) {
  .bh-signin {
    grid-template-columns: 1fr;
    grid-template-areas:
      "avatar"
      "fields"
      "consent"
      "error"
      "submit";
    justify-items: center;
  }
  .bh-signin__fields { width: 100%; }
  .bh-signin__consent { width: 100%; }
  .bh-signin > [type="submit"] { justify-self: stretch; }
}

/* Avatar — same component logic as Customs (canvas with drag/zoom). */
.bh-avatar { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.bh-avatar__frame {
  position: relative;
  width: 180px; height: 180px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 30% 30%, rgba(255, 196, 110, 0.06), rgba(0, 0, 0, 0.4) 70%),
    rgba(0,0,0,0.3);
  box-shadow:
    inset 0 0 0 1px rgba(255, 196, 110, 0.2),
    inset 0 0 0 6px rgba(0, 0, 0, 0.4),
    0 12px 28px rgba(0, 0, 0, 0.55);
  overflow: hidden;
  isolation: isolate;
}
.bh-avatar[data-avatar-state="filled"] .bh-avatar__frame {
  box-shadow:
    inset 0 0 0 2px rgba(255, 138, 61, 0.85),
    inset 0 0 0 6px rgba(0, 0, 0, 0.4),
    0 12px 30px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(255, 138, 61, 0.5);
}
.bh-avatar__canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
  cursor: grab;
  touch-action: none;
}
.bh-avatar__canvas:active { cursor: grabbing; }
.bh-avatar[data-avatar-state="empty"] .bh-avatar__canvas { display: none; }
.bh-avatar__placeholder {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px;
  color: var(--bh-paper-dim);
  font-size: 13px;
  letter-spacing: 0.5px;
  pointer-events: none;
}
.bh-avatar[data-avatar-state="filled"] .bh-avatar__placeholder { display: none; }
.bh-avatar__hit {
  position: absolute; inset: 0;
  border: 0; background: transparent;
  cursor: pointer;
  border-radius: 50%;
}
.bh-avatar[data-avatar-state="filled"] .bh-avatar__hit { display: none; }
.bh-avatar__controls {
  width: 180px;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
}
.bh-avatar__zoom-label {
  display: flex; align-items: center; gap: 8px;
  width: 100%;
  font-size: 14px;
  color: var(--bh-paper-dim);
}
.bh-avatar__zoom-icon { width: 16px; text-align: center; font-weight: 800; }
.bh-avatar__zoom {
  flex: 1; min-width: 0;
  -webkit-appearance: none; appearance: none;
  height: 4px; border-radius: 2px;
  background: rgba(255, 196, 110, 0.18);
  outline: none;
}
.bh-avatar__zoom:disabled { opacity: 0.4; }
.bh-avatar__zoom::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 18px; height: 18px;
  background: var(--bh-rust-bright);
  border-radius: 50%;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
}
.bh-avatar__zoom::-moz-range-thumb {
  width: 18px; height: 18px;
  background: var(--bh-rust-bright);
  border: 0; border-radius: 50%;
  cursor: pointer;
}
.bh-avatar__hint {
  margin: 0; font-size: 12px;
  color: var(--bh-paper-dim);
  text-align: center;
}
.bh-avatar.is-invalid .bh-avatar__frame {
  box-shadow:
    inset 0 0 0 1px rgba(214, 40, 40, 0.85),
    inset 0 0 0 6px rgba(0, 0, 0, 0.4),
    0 12px 28px rgba(0, 0, 0, 0.55),
    0 0 0 4px rgba(214, 40, 40, 0.18);
}

/* ---------- Form fields ---------- */
.bh-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.bh-field__label {
  font-size: 11px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--bh-paper-dim);
}
.bh-field input {
  font-family: inherit;
  font-size: 15px;
  padding: 12px 14px;
  border-radius: 6px;
  border: 1px solid rgba(255, 196, 110, 0.2);
  background: rgba(20, 8, 4, 0.6);
  color: var(--bh-paper);
  outline: none;
  width: 100%;
}
.bh-field input:focus-visible {
  border-color: var(--bh-rust-bright);
  box-shadow: 0 0 0 4px rgba(238, 134, 74, 0.18);
}
.bh-field input[aria-invalid="true"] {
  border-color: var(--bh-warn);
  box-shadow: 0 0 0 4px rgba(214, 40, 40, 0.18);
}

.bh-card__note {
  margin: 14px 0 0;
  font-size: 13px;
  color: var(--bh-paper-dim);
}

/* ---------- Rules list (briefing) ---------- */
.bh-rules {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: 10px;
}
.bh-rules li {
  position: relative;
  padding: 12px 14px 12px 38px;
  background: rgba(20, 8, 4, 0.62);
  border: 1px solid var(--bh-stroke);
  border-radius: 8px;
  font-size: 14px;
  color: var(--bh-paper);
}
.bh-rules li::before {
  content: "";
  position: absolute;
  left: 14px; top: 50%; width: 14px; height: 14px;
  border-radius: 50%;
  transform: translateY(-50%);
  background: var(--bh-paper-dim);             /* light tan against the dark rule rows */
  box-shadow: 0 0 0 3px rgba(232, 212, 168, 0.18);
}

.bh-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px;
  margin-top: 10px;
}

/* ---------- HUD ---------- */
.bh-hud {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 8px;
  padding: 10px 14px;
  background:
    linear-gradient(180deg, rgba(43, 20, 8, 0.85), rgba(20, 8, 4, 0.95));
  border: 1px solid var(--bh-stroke);
  border-radius: 10px;
  font-variant-numeric: tabular-nums;
  box-shadow: inset 0 0 0 1px rgba(255, 196, 110, 0.06);
}
.bh-hud__cell {
  display: flex; flex-direction: column; gap: 2px;
  min-width: 0;
}
.bh-hud__label {
  font-size: 10px; letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--bh-paper-dim);
}
.bh-hud__value {
  font-size: clamp(14px, 1.6vw, 17px);
  font-weight: 800;
  color: var(--bh-paper);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bh-hud__value--score   { color: var(--bh-paper); }
.bh-hud__value--credits { color: var(--bh-gold); }
.bh-hud__cell--clock .bh-hud__value--clock { font-variant-numeric: tabular-nums; }
.bh-hud__cell--clock.is-warning  .bh-hud__value--clock { color: var(--bh-gold); }
.bh-hud__cell--clock.is-critical .bh-hud__value--clock { color: var(--bh-warn-glow); animation: bh-pulse 800ms ease-in-out infinite; }
@keyframes bh-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: .65; }
}

/* ---------- Stage wrap (poster + dossier) ---------- */
/* Above the fold: the entire poster + 2x2 mug grid must fit within
   one viewport so the bounty hunter never has to scroll to pick a face.
   We cap height to viewport-minus-chrome and shrink internal sizing so
   children fit naturally. */
.bh-stagewrap {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  align-items: stretch;
  max-height: calc(100dvh - 220px);
  min-height: 420px;
}
@media (max-width: 820px) {
  .bh-stagewrap { grid-template-columns: 1fr; gap: 14px; max-height: none; }
}

/* ===================== WANTED POSTER ===================== */
.bh-poster {
  position: relative;
  border-radius: 4px;
  /* Tightened padding so the poster fits without scrolling; the
   * crest, subtitle, and "By order of Jabba" footer are gone, so the
   * vertical rhythm doesn't need the previous breathing room. */
  padding: 10px 14px 12px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  background:
    /* Aged paper texture: layered radial blotches + dirty linen */
    radial-gradient(circle at 18% 28%, rgba(123, 60, 24, 0.18), transparent 24%),
    radial-gradient(circle at 84% 72%, rgba(123, 60, 24, 0.18), transparent 22%),
    radial-gradient(circle at 64% 18%, rgba(45, 20, 8, 0.22), transparent 14%),
    radial-gradient(circle at 30% 88%, rgba(45, 20, 8, 0.22), transparent 18%),
    repeating-linear-gradient(
       90deg,
       rgba(180, 130, 70, 0.05) 0,
       rgba(180, 130, 70, 0.05) 1px,
       transparent 1px,
       transparent 3px),
    repeating-linear-gradient(
       0deg,
       rgba(180, 130, 70, 0.05) 0,
       rgba(180, 130, 70, 0.05) 1px,
       transparent 1px,
       transparent 4px),
    linear-gradient(180deg, #ead7af 0%, #d4be90 60%, #ad9560 100%);
  color: var(--bh-ink);
  border: 1px solid #5a4220;
  box-shadow:
    0 18px 40px rgba(0, 0, 0, 0.55),
    inset 0 0 60px rgba(123, 60, 24, 0.18),
    inset 0 0 0 6px rgba(123, 60, 24, 0.12),
    inset 0 0 0 8px rgba(45, 20, 8, 0.4);
  /* Subtle 1° rotation gives a "tacked to a board" feel */
  transform: rotate(-0.6deg);
  animation: bh-poster-in 420ms ease both;
}
@keyframes bh-poster-in {
  0%   { opacity: 0; transform: rotate(-2deg)   translateY(8px); }
  100% { opacity: 1; transform: rotate(-0.6deg) translateY(0); }
}

/* Burn marks at corners */
.bh-poster::before, .bh-poster::after {
  content: "";
  position: absolute;
  width: 60px; height: 60px;
  background: radial-gradient(circle at 50% 50%, rgba(40, 18, 6, 0.55) 0%, transparent 65%);
  pointer-events: none;
  border-radius: 50%;
}
.bh-poster::before { top: -20px; left: -20px; }
.bh-poster::after  { bottom: -20px; right: -20px; }

.bh-poster__corner {
  position: absolute;
  width: 28px; height: 28px;
  border: 2px solid var(--bh-ink);
  opacity: 0.6;
}
.bh-poster__corner--tl { top: 8px;    left: 8px;    border-right: 0; border-bottom: 0; }
.bh-poster__corner--tr { top: 8px;    right: 8px;   border-left: 0;  border-bottom: 0; }
.bh-poster__corner--bl { bottom: 8px; left: 8px;    border-right: 0; border-top: 0; }
.bh-poster__corner--br { bottom: 8px; right: 8px;   border-left: 0;  border-top: 0; }

.bh-poster__head {
  text-align: center;
  margin-bottom: 6px;
  position: relative;
}
.bh-poster__title {
  display: block;
  font-size: clamp(28px, 4.6vw, 42px);
  font-weight: 900;
  letter-spacing: clamp(3px, 0.6vw, 6px);
  line-height: 0.95;
  text-transform: uppercase;
  color: var(--bh-rust-deep);
  /* Stenciled type — slight irregularity via text-shadow */
  text-shadow:
    1px 0 0 rgba(60, 22, 8, 0.5),
    -1px 0 0 rgba(60, 22, 8, 0.5),
    0 1px 0 rgba(60, 22, 8, 0.4);
  font-family: "Inter", system-ui, sans-serif;
  font-style: italic;
}

/* "Identity classified" window — no silhouette any more. The poster
 * shows a deep-brown well with a big "?" so the player has to rely
 * on the facts list. */
.bh-poster__silhouette {
  position: relative;
  width: 100%;
  /* Slightly taller than the previous 4/2.2 so the revealed portrait
   * has more room to breathe; the "?" still reads compact and the
   * poster as a whole still fits above the fold next to the trimmed
   * mug grid. */
  aspect-ratio: 4 / 2.8;
  flex: 0 0 auto;
  min-height: 0;
  margin: 0 auto;
  background:
    radial-gradient(circle at 50% 35%, #6a4424 0%, #3a2412 55%, #1f0e04 100%);
  border: 3px solid var(--bh-ink);
  overflow: hidden;
  box-shadow:
    inset 0 0 30px rgba(0, 0, 0, 0.55),
    inset 0 0 0 1px rgba(246, 234, 214, 0.10);
  display: flex;
  align-items: center;
  justify-content: center;
}
.bh-poster__classified {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  text-align: center;
  user-select: none;
}
.bh-poster__classified-mark {
  font-family: "Cinzel", "Georgia", serif;
  font-size: clamp(56px, 8.5vw, 110px);
  font-weight: 900;
  line-height: 1;
  color: var(--bh-paper);
  text-shadow:
    0 0 18px rgba(0, 0, 0, 0.55),
    0 2px 0 rgba(0, 0, 0, 0.55);
  letter-spacing: -2px;
  opacity: 0.85;
}
.bh-poster__classified-label {
  font-size: 11px;
  letter-spacing: 4px;
  text-transform: uppercase;
  color: var(--bh-paper);
}

/* Reveal: after the player picks a mug, the placeholder is replaced
 * with the correct character's portrait + their name pinned at the
 * bottom so the player sees who they were chasing. */
.bh-poster__silhouette.is-revealed {
  background: #1f0e04;
  display: block;
}
.bh-poster__reveal {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* contain rather than cover — show more of the source image instead
   * of a tight face crop. Squarer/portraits get scaled down inside
   * the box, with the dark silhouette well visible behind. */
  object-fit: contain;
  object-position: center top;
  animation: bh-reveal-in 240ms ease-out both;
}
.bh-poster__reveal-name {
  position: absolute;
  /* Pinned to the very bottom of the silhouette box, below the
   * contained image. With object-fit:contain + object-position:center
   * top, the photo sits at the top of the box and there's dark empty
   * space below it — the name lives in that empty space without
   * covering any of the photo. */
  bottom: 0;
  left: 0;
  right: 0;
  padding: 6px 10px;
  background: linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.6));
  color: var(--bh-paper);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 2px;
  text-transform: uppercase;
  text-align: center;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
  animation: bh-reveal-in 320ms ease-out 80ms both;
}
@keyframes bh-reveal-in {
  0%   { opacity: 0; transform: scale(0.96); }
  100% { opacity: 1; transform: scale(1); }
}

/* "WANTED" stencil overlay text on top of silhouette */
.bh-poster__overlay {
  position: absolute;
  bottom: 8px;
  left: 0; right: 0;
  text-align: center;
  font-size: 10px;
  letter-spacing: 4px;
  text-transform: uppercase;
  color: var(--bh-paper);
  text-shadow: 0 1px 2px rgba(0,0,0,0.8);
  opacity: 0.9;
  pointer-events: none;
}

/* Reward ribbon under the silhouette */
.bh-poster__reward {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  margin: 8px -10px 8px;
  padding: 6px 14px;
  background: var(--bh-ink);
  color: var(--bh-paper);
  border-radius: 2px;
  position: relative;
  box-shadow:
    0 2px 0 rgba(45, 20, 8, 0.5),
    inset 0 0 0 1px rgba(255, 196, 110, 0.12);
}
.bh-poster__reward::before, .bh-poster__reward::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  width: 12px;
  background: var(--bh-ink);
  /* notched ribbon ends */
  clip-path: polygon(100% 0, 0 50%, 100% 100%);
}
.bh-poster__reward::before { left: -12px; }
.bh-poster__reward::after  { right: -12px; transform: scaleX(-1); }

.bh-poster__reward-label {
  font-size: 10px;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--bh-paper-dim);
}
.bh-poster__reward-amount {
  font-size: clamp(22px, 3vw, 30px);
  font-weight: 900;
  letter-spacing: 0.5px;
  font-variant-numeric: tabular-nums;
  color: var(--bh-gold);
  text-shadow: 0 0 12px rgba(255, 200, 87, 0.4);
}
.bh-poster__reward-currency {
  font-size: 11px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--bh-paper-dim);
  font-weight: 700;
}

/* Facts list — telegraphed, stenciled */
.bh-poster__facts {
  list-style: none;
  padding: 0;
  margin: 4px 0 0;
  display: grid;
  gap: 2px;
}
.bh-poster__facts li {
  position: relative;
  padding: 4px 0 4px 22px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--bh-ink);
  border-bottom: 1px dashed rgba(45, 20, 8, 0.35);
}
.bh-poster__facts li:last-child { border-bottom: 0; }
.bh-poster__facts li::before {
  content: "▸";
  position: absolute;
  left: 4px; top: 6px;
  font-size: 13px;
  color: var(--bh-rust-deep);
}

/* Footer — issuer */
.bh-poster__foot {
  margin-top: 14px;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 9.5px;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: rgba(45, 20, 8, 0.7);
  border-top: 1px dashed rgba(45, 20, 8, 0.4);
  padding-top: 10px;
}

/* ===================== DOSSIER MUG GRID ===================== */
.bh-dossier {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-self: stretch;
  min-height: 0;
  /* overflow: visible so the mug hover-grow doesn't clip on the right */
  overflow: visible;
}

.bh-dossier__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  background:
    linear-gradient(180deg, rgba(43, 20, 8, 0.92), rgba(20, 8, 4, 0.95));
  border: 1px solid var(--bh-stroke);
  border-radius: 6px;
}
.bh-dossier__title {
  font-size: 12px;
  letter-spacing: 3px;
  text-transform: uppercase;
  font-weight: 800;
  color: var(--bh-paper);
  margin: 0;
}
.bh-dossier__hint {
  font-size: 10px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--bh-paper-dim);
  margin: 0;
}

.bh-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(2, 1fr);
  gap: 10px;
  min-height: 0;
  flex: 1 1 auto;
}
@media (max-width: 420px) {
  .bh-grid { gap: 8px; }
}

.bh-mug {
  appearance: none;
  border: 0; padding: 0;
  cursor: pointer;
  position: relative;
  display: block;
  width: 100%;
  background: transparent;
  font-family: inherit;
  text-align: left;
  border-radius: 4px;
  overflow: hidden;
  transition: transform 140ms ease, box-shadow 140ms ease, filter 140ms ease;
  isolation: isolate;
  /* Mug-shot frame — manilla folder with corner tabs */
  box-shadow:
    0 8px 22px rgba(0, 0, 0, 0.55),
    inset 0 0 0 2px var(--bh-ink),
    inset 0 0 0 4px rgba(255, 196, 110, 0.18);
}
.bh-mug:focus-visible {
  outline: 3px solid var(--bh-gold);
  outline-offset: 4px;
}
.bh-mug:hover:not(:disabled) {
  transform: translateY(-2px) scale(1.02);
  filter: brightness(1.05);
}
.bh-mug:active:not(:disabled) { transform: translateY(0) scale(0.99); }
.bh-mug:disabled { cursor: default; pointer-events: none; }

.bh-mug__frame {
  position: relative;
  display: block;
  width: 100%;
  /* Shorter mug card so the 2-column grid fits above the fold next
   * to the trimmed poster. Photos still show full height (no crop)
   * via object-fit:contain — squarer photos will show some empty
   * dark space top/bottom, which reads like a mugshot frame. */
  aspect-ratio: 4 / 4;
  background: #1a0a04;
  overflow: hidden;
}
.bh-mug__frame img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  /* contain rather than cover — show the FULL height of each photo,
   * never crop. Wider/squarer photos leave horizontal empty space on
   * either side, which is filled by the dark mugshot frame and reads
   * intentionally. Faces never cropped, regardless of source aspect. */
  object-fit: contain;
  object-position: center top;
  /* Sepia treatment so all photos match the bounty-board aesthetic */
  filter:
    sepia(0.45)
    saturate(1.05)
    contrast(1.05)
    brightness(0.92);
}
.bh-mug__frame::after {
  /* Vignette + inner ring */
  content: "";
  position: absolute; inset: 0;
  background:
    radial-gradient(circle at 50% 30%, transparent 50%, rgba(0,0,0,0.55) 100%),
    repeating-linear-gradient(
      0deg,
      rgba(0,0,0,0) 0,
      rgba(0,0,0,0) 3px,
      rgba(0,0,0,0.04) 3px,
      rgba(0,0,0,0.04) 4px
    );
  pointer-events: none;
}

/* Height ruler ticks down the side — cheap mugshot vibe */
.bh-mug__frame::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 14px;
  background:
    repeating-linear-gradient(
      0deg,
      rgba(255, 196, 110, 0.55) 0,
      rgba(255, 196, 110, 0.55) 1px,
      transparent 1px,
      transparent 18px
    ),
    rgba(20, 8, 4, 0.85);
  border-right: 1px solid rgba(255, 196, 110, 0.18);
  pointer-events: none;
  z-index: 1;
}

.bh-mug__placard {
  position: absolute;
  bottom: 6px; left: 18px; right: 6px;
  z-index: 2;
  padding: 4px 8px;
  background: rgba(20, 8, 4, 0.92);
  border: 1px solid rgba(255, 196, 110, 0.4);
  border-radius: 2px;
  font-size: 11px;
  letter-spacing: 1px;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--bh-paper);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
}
.bh-mug__id {
  position: absolute;
  top: 6px; left: 22px;
  z-index: 2;
  padding: 2px 6px;
  background: var(--bh-rust-deep);
  color: var(--bh-paper);
  font-size: 9.5px;
  letter-spacing: 1.5px;
  font-weight: 800;
  text-transform: uppercase;
  border: 1px solid rgba(255, 196, 110, 0.35);
  border-radius: 2px;
}

/* Decision feedback overlays on the picked mug — 60 % dark green/red
 * wash filling the entire card with a bold white HIT / MISS / TARGET
 * label centered. The coloured outer glow + inset border are retained
 * from the previous version so the verdict reads from peripheral
 * vision before the eye lands on the centre label. The .bh-feedback
 * toast (aria-live="assertive") announces the result for screen
 * readers, since CSS ::after content isn't reliably read by all SRs. */
.bh-mug.is-correct {
  box-shadow:
    0 14px 30px rgba(58, 107, 48, 0.55),
    inset 0 0 0 3px var(--bh-go-glow);
}
.bh-mug.is-wrong {
  box-shadow:
    0 14px 30px rgba(122, 34, 34, 0.55),
    inset 0 0 0 3px var(--bh-warn-glow);
}
.bh-mug.is-target {
  /* When the user picks wrong, the actual target glows green so they
   * learn which face was right. */
  box-shadow:
    0 14px 30px rgba(58, 107, 48, 0.45),
    inset 0 0 0 3px var(--bh-go-glow);
}
.bh-mug.is-correct::after,
.bh-mug.is-wrong::after,
.bh-mug.is-target::after {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "Inter", system-ui, sans-serif;
  /* Sized to fit the longest label (TARGET, 6 chars) on the narrowest
   * mug card. Shared across HIT / MISS / TARGET so all three render
   * at exactly the same scale. */
  font-size: clamp(18px, 4.2vw, 40px);
  font-weight: 900;
  letter-spacing: 3px;
  color: #ffffff;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.65);
  text-transform: uppercase;
  white-space: nowrap;
  /* Final safety net: if a card still ends up too narrow for the
   * label at the clamp's lower bound (e.g. 320 px viewport, 2-col
   * grid, after card padding), scale the rendered text down to
   * fit instead of overflowing the wash. Same effect on all three
   * labels so they continue to look identical. */
  padding: 0 8px;
}
.bh-mug.is-correct::after {
  content: "HIT";
  background: rgba(40, 86, 32, 0.6);    /* 60 % deep green */
}
.bh-mug.is-wrong::after {
  content: "MISS";
  background: rgba(110, 20, 20, 0.6);   /* 60 % deep red */
}
.bh-mug.is-target::after {
  content: "TARGET";
  background: rgba(40, 86, 32, 0.55);   /* slightly lighter wash for the auto-revealed correct mug */
  /* No font-size override — inherits the shared HIT/MISS/TARGET size
   * so all three labels render at the exact same scale. */
}

/* ===================== FEEDBACK BAR ===================== */
.bh-feedback {
  display: grid;
  grid-template-columns: 36px 36px 1fr;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-radius: 8px;
  background: rgba(214, 40, 40, 0.16);
  /* Solid dark border (was translucent) so the toast pops against the
   * cream Tatooine backdrop. Thicker too — 2 px reads at the same
   * weight as the verdict-overlay border on the mug card. */
  border: 2px solid rgba(120, 24, 24, 1);
  color: var(--bh-rust-deep);
  margin-top: 14px;
  animation: bh-view-in 280ms ease both;
}
.bh-feedback[hidden] { display: none !important; }
.bh-feedback[data-kind="correct"] {
  background: rgba(78, 163, 76, 0.18);
  border-color: rgba(40, 100, 40, 1);
  color: var(--bh-rust-deep);
}
.bh-feedback__icon {
  width: 36px; height: 36px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(0,0,0,0.4);
  font-weight: 900; font-size: 18px;
}
.bh-feedback[data-kind="wrong"]   .bh-feedback__icon::before { content: "✕"; color: #ff8b97; }
.bh-feedback[data-kind="correct"] .bh-feedback__icon::before { content: "✓"; color: #9ad48d; }
.bh-feedback__thumb {
  width: 36px; height: 36px;
  border-radius: 50%;
  background: rgba(0,0,0,0.4) center / cover no-repeat;
  filter: sepia(0.3) saturate(1.05);
  box-shadow: inset 0 0 0 1px rgba(255, 196, 110, 0.32);
}
.bh-feedback__text { margin: 0; font-size: 14px; line-height: 1.45; }

/* ===================== RESULTS ===================== */
.bh-result {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
  background:
    linear-gradient(180deg, rgba(50, 24, 12, 0.85), rgba(20, 8, 4, 0.95));
  border: 1px solid var(--bh-stroke);
  border-radius: 10px;
  padding: clamp(18px, 3vw, 28px);
}
.bh-result__final {
  display: flex; flex-direction: column; gap: 4px; align-items: flex-start;
}
.bh-result__label {
  font-size: 11px; letter-spacing: 2px; text-transform: uppercase;
  color: var(--bh-paper-dim);
}
.bh-result__score {
  font-size: clamp(40px, 7vw, 72px);
  font-weight: 900;
  color: var(--bh-gold);
  letter-spacing: -1px;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 30px rgba(255, 200, 87, 0.4);
  line-height: 1;
}
.bh-result__sub {
  margin: 4px 0 0;
  font-size: 14px;
  color: var(--bh-paper-dim);
  font-variant-numeric: tabular-nums;
}
.bh-result__flavor {
  margin: 6px 0 0;
  font-size: clamp(15px, 1.6vw, 18px);
  font-style: italic;
  color: var(--bh-rust-bright);
  text-wrap: balance;
}
.bh-result__rank {
  margin-top: 4px;
  font-size: 14px;
  color: var(--bh-paper-dim);
}
.bh-result__breakdown {
  display: flex; gap: 18px; flex-wrap: wrap;
  font-size: 14px;
  color: var(--bh-paper);
}
.bh-pip {
  display: inline-block;
  width: 10px; height: 10px;
  border-radius: 50%;
  vertical-align: middle;
  margin-right: 6px;
  /* Default: cream, matches the surrounding text colour. Variants
   * below add a thin coloured ring so green / red / grey is still
   * distinguishable without shouting against the cream label. */
  background: var(--bh-paper);
  box-shadow: inset 0 0 0 1.5px var(--bh-paper);
}
.bh-pip--hit  { box-shadow: inset 0 0 0 1.5px var(--bh-go-glow); }
.bh-pip--miss { box-shadow: inset 0 0 0 1.5px var(--bh-warn-glow); }
.bh-pip--skip { box-shadow: inset 0 0 0 1.5px var(--bh-paper-dim); }

/* ---------- Leaderboard ---------- */
.bh-board {
  background:
    linear-gradient(180deg, rgba(50, 24, 12, 0.85), rgba(20, 8, 4, 0.95));
  border: 1px solid var(--bh-stroke);
  border-radius: 10px;
  padding: clamp(16px, 3vw, 24px);
}
.bh-board__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 12px;
}
.bh-board__head h2 {
  font-size: 16px; letter-spacing: 0.6px; margin: 0;
  color: var(--bh-paper);
}
.bh-board__list {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: 6px;
  max-height: 360px; overflow: auto;
}
.bh-board__row {
  display: grid;
  grid-template-columns: 28px 36px 1fr auto auto;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border-radius: 6px;
  background: rgba(255, 196, 110, 0.06);
  border: 1px solid rgba(255, 196, 110, 0.1);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  color: var(--bh-paper);
}
.bh-board__avatar {
  width: 36px; height: 36px;
  border-radius: 50%;
  background: #2a0d05 center / cover no-repeat;
  display: grid; place-items: center;
  color: var(--bh-paper-dim);
  font-weight: 800; font-size: 11px; letter-spacing: 0.5px;
  box-shadow: inset 0 0 0 1px rgba(255, 196, 110, 0.3);
  cursor: zoom-in;
  transition: transform 120ms ease, box-shadow 120ms ease;
  border: 0;
}
.bh-board__avatar:hover {
  transform: scale(1.08);
  box-shadow:
    inset 0 0 0 1px rgba(255, 196, 110, 0.55),
    0 0 0 3px rgba(238, 134, 74, 0.45);
}
.bh-board__who    { min-width: 0; }
.bh-board__time   { color: var(--bh-paper-dim); font-size: 12px; }
.bh-board__row--me {
  background: rgba(238, 134, 74, 0.18);
  border-color: rgba(238, 134, 74, 0.55);
  color: var(--bh-paper);
}
.bh-board__row--placeholder {
  display: block;
  color: var(--bh-paper-dim);
  text-align: center;
  font-style: italic;
}
/* Match name colour for parity / contrast on the dark card. The
 * previous --bh-rust-bright was too dim against the deep-brown
 * card background. */
.bh-board__rank   { font-weight: 800; color: var(--bh-paper); }
.bh-board__name   { color: var(--bh-paper); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bh-board__email  { color: var(--bh-paper-dim); font-size: 12px; }
.bh-board__score  { font-weight: 800; color: var(--bh-gold); }

/* ---------- Avatar lightbox ---------- */
.bh-lightbox {
  position: fixed; inset: 0;
  z-index: 9999;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(16px, 4vw, 48px);
  background: rgba(13, 8, 5, 0.88);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  cursor: zoom-out;
  animation: bh-fade-in 200ms ease both;
}
.bh-lightbox[hidden] { display: none !important; }
@keyframes bh-fade-in {
  0% { opacity: 0; }
  100% { opacity: 1; }
}
.bh-lightbox__close {
  position: absolute; top: clamp(12px, 2vw, 24px); right: clamp(12px, 2vw, 24px);
  width: 44px; height: 44px;
  border-radius: 50%; border: 1px solid rgba(255, 196, 110, 0.3);
  background: rgba(20, 8, 4, 0.6); color: var(--bh-paper);
  font-size: 28px; font-weight: 300; line-height: 1;
  cursor: pointer;
  display: grid; place-items: center;
  transition: background 120ms ease;
}
.bh-lightbox__close:hover { background: rgba(255, 196, 110, 0.16); }
.bh-lightbox__figure {
  display: flex; flex-direction: column; align-items: center;
  gap: 16px;
  cursor: default;
  text-align: center;
}
.bh-lightbox__photo {
  width: clamp(240px, 50vmin, 480px);
  height: clamp(240px, 50vmin, 480px);
  border-radius: 50%;
  background: #2a0d05 center / cover no-repeat;
  box-shadow:
    inset 0 0 0 1px rgba(255, 196, 110, 0.32),
    0 24px 60px rgba(0, 0, 0, 0.6),
    0 0 80px rgba(238, 134, 74, 0.22);
}
.bh-lightbox__cap {
  display: flex; flex-direction: column; gap: 4px;
  color: var(--bh-paper);
}
.bh-lightbox__rank {
  font-size: 13px; letter-spacing: 2px; text-transform: uppercase;
  color: var(--bh-rust-bright);
  font-weight: 800;
}
.bh-lightbox__name { font-size: clamp(20px, 2.4vw, 28px); font-weight: 700; }
.bh-lightbox__score { font-size: 14px; color: var(--bh-paper-dim); font-variant-numeric: tabular-nums; }

/* ---------- Mobile (≤720) ---------- */
@media (max-width: 720px) {
  .bh-hud {
    grid-template-columns: repeat(5, 1fr);
    gap: 4px 8px; padding: 6px 10px;
  }
  .bh-hud__label { font-size: 9px; letter-spacing: 1px; }
  .bh-hud__value { font-size: 12.5px; }
  .bh-poster { padding: 16px 16px 22px; transform: rotate(0deg); }
  .bh-poster__title { font-size: clamp(28px, 9vw, 42px); letter-spacing: 4px; }
  .bh-feedback { padding: 8px 12px; gap: 8px; }
  .bh-feedback__icon, .bh-feedback__thumb { width: 28px; height: 28px; }
  .bh-feedback__text { font-size: 12px; line-height: 1.35; }
  .bh-board__row { grid-template-columns: 24px 32px 1fr auto; gap: 8px; }
  .bh-board__avatar { width: 32px; height: 32px; }
  .bh-board__time   { display: none; }
}

/* ---------- Mobile (≤420) ---------- */
@media (max-width: 420px) {
  .bh-stage { padding: 18px 12px 36px; }
  .bh-poster { padding: 14px 14px 18px; }
  .bh-poster__title { font-size: 30px; letter-spacing: 3px; }
  .bh-poster__sub { font-size: 9.5px; letter-spacing: 3px; }
  .bh-poster__facts li { font-size: 12.5px; padding: 4px 0 4px 18px; }
  .bh-poster__reward { margin: 12px -8px 12px; padding: 8px 12px; }
  .bh-poster__reward-amount { font-size: 22px; }
  .bh-mug__placard { font-size: 10px; padding: 3px 6px; left: 16px; }
  .bh-mug__id { font-size: 8.5px; padding: 1px 4px; left: 18px; }
  /* HUD: drop the Hunter cell on tiny screens — it's already echoed in the
     briefing/results greeting and we need the room for the live counters. */
  .bh-hud { grid-template-columns: repeat(4, 1fr); padding: 5px 8px; gap: 2px 6px; }
  .bh-hud__cell:first-child { display: none; }
  .bh-hud__cell { gap: 0; min-width: 0; }
  .bh-hud__label { font-size: 8.5px; }
  .bh-hud__value { font-size: 11.5px; }
  .bh-grid { gap: 8px; }
  .bh-stagewrap { gap: 16px; }
  .bh-landing { padding: 24px 4px; }
}

/* ===== Brand-strip logo: clickable affordance + Grogu egg =====
 * The logo is a click target that summons Grogu and runs a three-pulse
 * glow cycle (three slow blooms over 3 s, then 30 s rest). The two
 * audiences load different source files:
 *   - public (.is-public)  → CDO.me_001-bh.svg, pre-coloured #2a1b0c
 *   - ID.me  (no .is-public) → idme-logo-white.svg, pure white #fff
 * On the cream brand strip (--bh-sand-1 #f0e0c4) a white SVG would be
 * invisible, so the ID.me variant needs invert(1) to render dark; the
 * public variant must NOT be inverted (its dark brown would flip to
 * light blue). Keep the rule split below intact when editing. */
.bh-brand__logo {
  cursor: pointer;
  filter:
    drop-shadow(0 1px 2px rgba(255, 240, 220, 0.6))
    drop-shadow(0 0 0 rgba(220, 110, 30, 0))
    drop-shadow(0 0 0 rgba(255, 170, 70, 0));
  animation: bh-logo-pulse-public 33s ease-in-out infinite;
}
.bh-brand__logo:hover,
.bh-brand__logo:focus-visible {
  filter:
    drop-shadow(0 1px 2px rgba(255, 240, 220, 0.6))
    drop-shadow(0 0 36px rgba(220, 110, 30, 1))
    drop-shadow(0 0 14px rgba(255, 170, 70, 1));
}
body:not(.is-public) .bh-brand__logo {
  filter:
    invert(1)
    drop-shadow(0 1px 2px rgba(255, 240, 220, 0.6))
    drop-shadow(0 0 0 rgba(220, 110, 30, 0))
    drop-shadow(0 0 0 rgba(255, 170, 70, 0));
  animation: bh-logo-pulse-idme 33s ease-in-out infinite;
}
body:not(.is-public) .bh-brand__logo:hover,
body:not(.is-public) .bh-brand__logo:focus-visible {
  filter:
    invert(1)
    drop-shadow(0 1px 2px rgba(255, 240, 220, 0.6))
    drop-shadow(0 0 36px rgba(220, 110, 30, 1))
    drop-shadow(0 0 14px rgba(255, 170, 70, 1));
}
@keyframes bh-logo-pulse-public {
  0%, 3%, 6%, 9%, 100% {
    filter:
      drop-shadow(0 1px 2px rgba(255, 240, 220, 0.6))
      drop-shadow(0 0 0 rgba(220, 110, 30, 0))
      drop-shadow(0 0 0 rgba(255, 170, 70, 0));
  }
  1.5%, 4.5%, 7.5% {
    filter:
      drop-shadow(0 1px 2px rgba(255, 240, 220, 0.6))
      drop-shadow(0 0 42px rgba(220, 110, 30, 1))
      drop-shadow(0 0 16px rgba(255, 170, 70, 1));
  }
}
@keyframes bh-logo-pulse-idme {
  0%, 3%, 6%, 9%, 100% {
    filter:
      invert(1)
      drop-shadow(0 1px 2px rgba(255, 240, 220, 0.6))
      drop-shadow(0 0 0 rgba(220, 110, 30, 0))
      drop-shadow(0 0 0 rgba(255, 170, 70, 0));
  }
  1.5%, 4.5%, 7.5% {
    filter:
      invert(1)
      drop-shadow(0 1px 2px rgba(255, 240, 220, 0.6))
      drop-shadow(0 0 42px rgba(220, 110, 30, 1))
      drop-shadow(0 0 16px rgba(255, 170, 70, 1));
  }
}
@media (prefers-reduced-motion: reduce) {
  .bh-brand__logo { animation: none; }
}

/* Grogu hologram-style appearance — 3 s fade in + hold + fade out, no
 * flicker. Positioned absolutely below the brand strip; JS computes
 * exact left/top at click time so the egg tracks the logo on resize. */
.bh-grogu {
  position: absolute;
  top: 92px;
  left: 60px;
  width: 280px;
  z-index: 7;
  pointer-events: none;
  opacity: 0;
}
.bh-grogu.is-summoned {
  animation: bh-grogu-fade 3000ms ease-in-out forwards;
}
@keyframes bh-grogu-fade {
  0%   { opacity: 0; transform: translateY(-4px) scale(0.96); }
  10%  { opacity: 1; transform: translateY(0) scale(1); }
  85%  { opacity: 1; transform: translateY(0) scale(1); }
  100% { opacity: 0; transform: translateY(-2px) scale(0.98); }
}
.bh-grogu__img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 10px;
  box-shadow:
    0 12px 36px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(255, 255, 255, 0.1);
}
@media (prefers-reduced-motion: reduce) {
  .bh-grogu.is-summoned { animation: none; opacity: 1; }
}

/* Grogu's Force impact — while the egg is on screen, every foreground
 * UI element except the egg itself and the photo backdrop shakes. The
 * intensity ramps up from a tremor to a violent quake, peaks roughly
 * at the same moment as Grogu's hold, then settles back to rest. The
 * tatooine photo lives on .bh-stage's background and the .bh-sky/
 * .bh-dunes are sibling backdrops, so leaving them untouched and
 * shaking only .bh-shell keeps the "background calm, everything else
 * being thrown around" feel the brief asks for. */
@keyframes bh-grogu-quake {
  /* Peaks bumped roughly 3× from the previous quake for a much more
   * violent impact. Mid-flight excursions reach ±20-22 px and rotate
   * subtly so the whole shell judders rather than just panning. The
   * ramp still escalates from a tremor (≤4 px) through a peak quake
   * around 50-60% of the run, then settles. */
  0%   { transform: translate3d(0, 0, 0) rotate(0deg); }
  4%   { transform: translate3d(-3px, 1.5px, 0)   rotate(-0.2deg); }
  8%   { transform: translate3d(3px, -3px, 0)     rotate(0.3deg); }
  12%  { transform: translate3d(-5px, 3px, 0)     rotate(-0.4deg); }
  16%  { transform: translate3d(6px, -5px, 0)     rotate(0.5deg); }
  20%  { transform: translate3d(-8px, 7px, 0)     rotate(-0.6deg); }
  26%  { transform: translate3d(11px, -8px, 0)    rotate(0.8deg); }
  32%  { transform: translate3d(-13px, 11px, 0)   rotate(-1deg); }
  38%  { transform: translate3d(16px, -13px, 0)   rotate(1.2deg); }
  44%  { transform: translate3d(-18px, 16px, 0)   rotate(-1.4deg); }
  50%  { transform: translate3d(21px, -18px, 0)   rotate(1.6deg); }
  56%  { transform: translate3d(-22px, 21px, 0)   rotate(-1.6deg); }
  62%  { transform: translate3d(20px, -19px, 0)   rotate(1.4deg); }
  68%  { transform: translate3d(-16px, 16px, 0)   rotate(-1.2deg); }
  74%  { transform: translate3d(12px, -12px, 0)   rotate(1deg); }
  80%  { transform: translate3d(-8px, 8px, 0)     rotate(-0.7deg); }
  86%  { transform: translate3d(5px, -4px, 0)     rotate(0.4deg); }
  92%  { transform: translate3d(-2px, 2px, 0)     rotate(-0.2deg); }
  100% { transform: translate3d(0, 0, 0)          rotate(0deg); }
}
body.bh-grogu-active .bh-shell {
  animation: bh-grogu-quake 3s cubic-bezier(0.45, 0, 0.55, 1) forwards;
  will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
  body.bh-grogu-active .bh-shell { animation: none; }
}

/* ===== Darksaber prop (Konami-code unlock) =====
 * Hidden by default. While body.darksaber-active, the native cursor
 * is hidden and the prop tracks the pointer (JS pointermove + a
 * transform that anchors the hilt at the cursor). Each click swings
 * the blade. Escape exits early — same flow as customs' green saber
 * but with this dark, jagged Mandalorian blade and a white halo
 * instead of the green Jedi glow. */
.bh-darksaber {
  position: fixed;
  left: 0;
  top: 0;
  /* 52 px → 39 px (-25 %, May 3). */
  width: 39px;
  height: auto;
  z-index: 9999;
  pointer-events: none;
  transform: translate(-9999px, -9999px);
  transform-origin: 50% 50%;
  filter:
    drop-shadow(0 0 10px rgba(255, 255, 255, 0.55))
    drop-shadow(0 0 22px rgba(220, 220, 240, 0.30));
  display: none;
  will-change: transform;
}
body.darksaber-active .bh-darksaber { display: block; }
/* Hide every cursor flavour while the saber is active — including
 * the play-mode sniper-scope, which has its own !important +
 * descendant-of-body[data-view] selector. */
body.darksaber-active,
body.darksaber-active *,
body.darksaber-active[data-view="play"] .bh-stage,
body.darksaber-active[data-view="play"] .bh-stage * {
  cursor: none !important;
}

/* ===== Mando + Grogu fly-by easter egg =====
 * Hover the lower-left corner zone → full fly-by across the viewport
 * at a ~20° upward angle, exiting past the right edge. Auto-pop peeks
 * just the leftmost edge of the rig at random 30-120 s intervals as a
 * clue that the egg is there. JS toggles .is-flying / .is-peeking--small
 * the way customs' wireR2 does. */
.bh-mando-zone {
  position: absolute;
  left: 0;
  top: 120px;        /* clear of the brand strip so hovering the logo
                        doesn't accidentally launch the rig */
  bottom: 0;
  width: 64px;       /* full vertical edge strip, not just a corner */
  z-index: 8;
  /* pointer-events: none so the strip doesn't intercept hover / clicks
   * on the underlying UI when the shell fills the full stage width on
   * narrower viewports. Trigger detection runs off pointermove with
   * a coordinate check against this element's bounding box. */
  pointer-events: none;
}
.bh-mando {
  position: fixed;
  left: 0;
  bottom: 6vh;
  width: clamp(220px, 32vw, 460px);
  height: auto;
  z-index: 30;
  pointer-events: none;
  transform: translate(-110%, 0) rotate(-14deg);
  filter: drop-shadow(0 12px 28px rgba(0, 0, 0, 0.55));
  opacity: 0;
}
/* Tiny "peek" — about 22 % of the rig pokes out of the left edge as
 * a clue. No sound, brief. */
.bh-mando.is-peeking--small {
  transform: translate(-78%, 0) rotate(-14deg);
  opacity: 1;
  transition: transform 600ms cubic-bezier(0.4, 0, 0.4, 1),
              opacity 200ms ease;
}
/* Full fly-by — both translate axes use vw so the trajectory holds a
 * consistent ~20° angle across viewport sizes (vertical 65vw / lateral
 * 170vw → atan(0.382) ≈ 20.9°). Duration is hard-locked to the
 * fly.mp3 clip length (~3.65 s) so visual + sound end together. */
.bh-mando.is-flying {
  animation: bh-mando-flight 3650ms linear forwards;
}
@keyframes bh-mando-flight {
  0%   {
    transform: translate(-110%, 0) rotate(-14deg);
    opacity: 0;
  }
  10%  {
    transform: translate(-50%, -6vw) rotate(-18deg);
    opacity: 1;
  }
  85%  {
    transform: translate(140vw, -52vw) rotate(-26deg);
    opacity: 1;
  }
  100% {
    transform: translate(170vw, -65vw) rotate(-26deg);
    opacity: 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  /* Belt-and-suspenders: same specificity should already win on
   * cascade, but !important guarantees nothing else (specificity tie,
   * out-of-order rule somewhere, future override) re-enables the
   * fly-by motion. The rig stays at its base offscreen-left state and
   * never animates in. JS additionally skips the class toggles for
   * reduced-motion users so even the auto-peek flash doesn't fire. */
  .bh-mando { transition: none !important; }
  .bh-mando.is-flying,
  .bh-mando.is-peeking--small {
    animation: none !important;
    transition: none !important;
  }
}

/* ===== Boba Fett fly-by easter egg (bottom-right mirror) =====
 * Same shape as the Mando egg but for the lower-right corner — hover
 * the zone → fly-by from the right edge of the viewport across to
 * past the left edge at ~20° up-and-left. Auto-peek from the right
 * edge as a clue. Same 3600 ms speed as Mando. */
.bh-boba-zone {
  position: absolute;
  right: 0;
  top: 120px;        /* clear of the brand strip / cross-game pill */
  bottom: 0;
  width: 64px;       /* full vertical edge strip, not just a corner */
  z-index: 8;
  pointer-events: none;   /* see .bh-mando-zone — coord-based detection */
}
.bh-boba {
  position: fixed;
  right: 0;
  bottom: 6vh;
  width: clamp(264px, 38.4vw, 552px);   /* 20 % larger than Mando */
  height: auto;
  z-index: 30;
  pointer-events: none;
  /* Start fully offscreen-right. The 14° tilt mirrors Mando's pose
   * but flipped via scaleX(-1) is unnecessary — the source image
   * already faces left/right at his natural orientation; the rotation
   * tilts him into the up-left flight pose. */
  transform: translate(110%, 0) rotate(14deg);
  filter: drop-shadow(0 12px 28px rgba(0, 0, 0, 0.55));
  opacity: 0;
}
.bh-boba.is-peeking--small {
  transform: translate(78%, 0) rotate(14deg);
  opacity: 1;
  transition: transform 600ms cubic-bezier(0.4, 0, 0.4, 1),
              opacity 200ms ease;
}
.bh-boba.is-flying {
  animation: bh-boba-flight 3650ms linear forwards;
}
@keyframes bh-boba-flight {
  0%   {
    transform: translate(110%, 0) rotate(14deg);
    opacity: 0;
  }
  10%  {
    transform: translate(50%, -6vw) rotate(18deg);
    opacity: 1;
  }
  85%  {
    transform: translate(-140vw, -52vw) rotate(26deg);
    opacity: 1;
  }
  100% {
    transform: translate(-170vw, -65vw) rotate(26deg);
    opacity: 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  .bh-boba { transition: none !important; }
  .bh-boba.is-flying,
  .bh-boba.is-peeking--small {
    animation: none !important;
    transition: none !important;
  }
}

/* ===== Sniper-scope cursor + bounty-laser shot =====
 * Active across every bh-view (landing / signin / briefing / play /
 * results) so the laser + horizon speeders are continuous through
 * the experience. Form inputs / buttons keep their native cursor via
 * pointer-cursor reset below — text input + button affordance must
 * remain readable. */
.bh-stage,
.bh-stage * {
  cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='37' height='37' viewBox='0 0 32 32'><circle cx='16' cy='16' r='14' fill='none' stroke='black' stroke-width='2.5' opacity='0.55'/><circle cx='16' cy='16' r='14' fill='none' stroke='white' stroke-width='1' opacity='0.95'/><circle cx='16' cy='16' r='6' fill='none' stroke='white' stroke-width='0.5' opacity='0.7'/><line x1='16' y1='0' x2='16' y2='9' stroke='black' stroke-width='2.5' opacity='0.55'/><line x1='16' y1='0' x2='16' y2='9' stroke='white' stroke-width='1'/><line x1='16' y1='23' x2='16' y2='32' stroke='black' stroke-width='2.5' opacity='0.55'/><line x1='16' y1='23' x2='16' y2='32' stroke='white' stroke-width='1'/><line x1='0' y1='16' x2='9' y2='16' stroke='black' stroke-width='2.5' opacity='0.55'/><line x1='0' y1='16' x2='9' y2='16' stroke='white' stroke-width='1'/><line x1='23' y1='16' x2='32' y2='16' stroke='black' stroke-width='2.5' opacity='0.55'/><line x1='23' y1='16' x2='32' y2='16' stroke='white' stroke-width='1'/><circle cx='16' cy='6' r='0.9' fill='white'/><circle cx='16' cy='26' r='0.9' fill='white'/><circle cx='6' cy='16' r='0.9' fill='white'/><circle cx='26' cy='16' r='0.9' fill='white'/><circle cx='16' cy='16' r='1.6' fill='%23ffe55a' stroke='black' stroke-width='0.6'/></svg>") 18 18, crosshair !important;
}
/* Native cursors on form inputs + buttons — sniper-scope on a text
 * field is unusable. */
.bh-stage input,
.bh-stage textarea,
.bh-stage select { cursor: text !important; }
.bh-stage button,
.bh-stage a,
.bh-stage [role="button"] { cursor: pointer !important; }

/* Bright white-yellow sniper-laser shot — perspective view, tapered
 * from user → target. Length is JS-set on .style.width;
 * --bh-laser-angle carries the rotation. */
.bh-laser {
  position: absolute;
  height: 22px;
  margin-top: -11px;
  pointer-events: none;
  z-index: 6;
  background:
    linear-gradient(
      90deg,
      rgba(255, 255, 240, 1)   0%,
      #fff7b0                  10%,
      #ffe44a                  35%,
      #ffe44a                  65%,
      #fff2a8                  88%,
      rgba(255, 240, 160, 0.4) 100%
    );
  clip-path: polygon(0 0%, 100% 44%, 100% 56%, 0 100%);
  filter:
    drop-shadow(0 0 6px #ffe44a)
    drop-shadow(0 0 14px rgba(255, 240, 100, 0.7))
    drop-shadow(0 0 22px rgba(255, 240, 100, 0.4));
  transform-origin: 0 50%;
  transform: rotate(var(--bh-laser-angle, 0rad)) scaleX(0);
  animation: bh-laser-shoot 340ms cubic-bezier(0.22, 0.85, 0.4, 1) forwards;
}
@keyframes bh-laser-shoot {
  0%   { transform: rotate(var(--bh-laser-angle, 0rad)) scaleX(0.05); opacity: 0; }
  12%  { transform: rotate(var(--bh-laser-angle, 0rad)) scaleX(0.35); opacity: 1; }
  55%  { transform: rotate(var(--bh-laser-angle, 0rad)) scaleX(1);    opacity: 1; }
  100% { transform: rotate(var(--bh-laser-angle, 0rad)) scaleX(1);    opacity: 0; }
}

.bh-laser-flash {
  position: absolute;
  width: 90px; height: 90px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 6;
  background: radial-gradient(
    circle,
    rgba(255, 255, 240, 1)   0%,
    rgba(255, 240, 130, 0.95) 22%,
    rgba(255, 220, 70, 0.7)   45%,
    rgba(255, 200, 40, 0)     72%
  );
  filter: blur(2px);
  transform: translate(-50%, -50%) scale(0.2);
  animation: bh-laser-flash 320ms ease-out forwards;
}
@keyframes bh-laser-flash {
  0%   { transform: translate(-50%, -50%) scale(0.2); opacity: 0; }
  18%  { transform: translate(-50%, -50%) scale(1.4); opacity: 1; }
  60%  { transform: translate(-50%, -50%) scale(1.1); opacity: 0.7; }
  100% { transform: translate(-50%, -50%) scale(0.7); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .bh-laser, .bh-laser-flash { animation-duration: 220ms; }
}
