/*
 * Hex bloom chrome for sphere-ux.
 * Closed: one black horizon seed at bottom.
 * Open: bloom roots at the seed; Undo · Close · Flag form its keel.
 * Geometry + fold language from /uxperiments/clex.
 */

.hex-bloom {
  /* Bloom primaries (full size). Dock idle is smaller; grows to match when open. */
  --tile-w: 76px;
  --tile-h: 88px;
  --tile-w-dock-idle: 40px;
  --tile-h-dock-idle: 46px;
  --tile-w-dock: var(--tile-w-dock-idle);
  --tile-h-dock: var(--tile-h-dock-idle);
  --dock-rise: 0px;
  --seed-sink: 44px;
  --border-w: 1.5px;
  --hex-clip: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
  --hb-ink: var(--text-main, #000);
  --hb-paper: var(--bg-color, #fff);
  --hb-fill: color-mix(in srgb, var(--hb-paper) 94%, var(--hb-ink));
  --hb-fill-hover: color-mix(in srgb, var(--hb-paper) 82%, var(--hb-ink));
  --hb-stroke: color-mix(in srgb, var(--hb-ink) 70%, transparent);
  --hb-center-fill: var(--hb-ink);
  --hb-center-ink: var(--hb-paper);
  --hb-active-fill: var(--hb-ink);
  --hb-active-ink: var(--hb-paper);
  --hb-accent: var(--hb-ink);
  --hb-scrim: color-mix(in srgb, var(--hb-paper) 18%, transparent);
  --rise-y: 0px;
  --rise-ms: 220ms;
  --fold-ms: 180ms;

  position: fixed;
  inset: 0;
  z-index: 55;
  pointer-events: none;
  font-family: "IBM Plex Sans", system-ui, sans-serif;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* Full-screen blur plate — only intercepts when open */
.hex-bloom-scrim {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--hb-scrim);
  -webkit-backdrop-filter: blur(5px) saturate(1.02);
  backdrop-filter: blur(5px) saturate(1.02);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.18s ease, visibility 0.18s;
}
.hex-bloom[data-open="true"] .hex-bloom-scrim {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

/* Stage fills viewport; origin is the dock menu (bottom). */
.hex-bloom-stage {
  position: absolute;
  inset: 0;
  z-index: 1;
  perspective: 1100px;
  perspective-origin: 50% 100%;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  /* The petal layer rides the dock's grow+lift: --rise-y starts at the
     idle→open seed delta (dockRiseDelta) and animates to 0, so petals stay
     rooted to the seed instead of hovering at final seats while the dock
     catches up underneath. */
  transform: translateY(var(--rise-y, 0px));
  transition: opacity 0.12s ease, visibility 0.12s;
  /* Room for upward fan without clipping south of the dock */
  overflow: visible;
}
.hex-bloom[data-open="true"] .hex-bloom-stage,
.hex-bloom[data-phase="rising"] .hex-bloom-stage,
.hex-bloom[data-phase="falling"] .hex-bloom-stage {
  opacity: 1;
  visibility: visible;
  transition:
    opacity 0.12s ease,
    visibility 0.12s,
    transform var(--rise-ms) cubic-bezier(0.22, 1, 0.3, 1);
}

/* Bottom chrome: Restart · Menu · Help
   Idle: small + low; open: grow to bloom size and lift with the fan. */
.hex-bloom-dock {
  position: absolute;
  left: 50%;
  bottom: max(2px, env(safe-area-inset-bottom));
  transform: translateX(-50%) translateY(var(--dock-rise, 0px));
  z-index: 3;
  display: flex;
  flex-direction: row;
  align-items: flex-end;
  justify-content: center;
  gap: 0;
  width: auto;
  height: auto;
  pointer-events: none;
  opacity: 1;
  transition:
    opacity 0.28s ease,
    transform var(--rise-ms) cubic-bezier(0.22, 1, 0.3, 1);
}
.hex-bloom[data-phase="open"] .hex-bloom-dock {
  /* Lift so the rooted fan has air and matches bloom height language.
     Only while open: on falling the dock rides back down with the stage
     and the folding petals — one settle, not two. */
  --dock-rise: -36px;
  --tile-w-dock: var(--tile-w);
  --tile-h-dock: var(--tile-h);
}
.hex-bloom-dock .hb-hex.is-dock {
  position: relative;
  left: auto;
  top: auto;
  margin: 0;
  flex: 0 0 auto;
  width: var(--tile-w-dock);
  height: var(--tile-h-dock);
  pointer-events: auto;
  transition:
    width var(--rise-ms) cubic-bezier(0.22, 1, 0.3, 1),
    height var(--rise-ms) cubic-bezier(0.22, 1, 0.3, 1),
    background 0.2s ease,
    color 0.2s ease,
    filter 0.2s ease,
    opacity 0.2s ease;
}
.hex-bloom-dock .is-dock-menu,
.hex-bloom-dock .is-dock-side {
  width: var(--tile-w-dock);
  height: var(--tile-h-dock);
  opacity: 1;
}
/* ?dock=center: the bloom is the chrome — no bottom dock at all. */
.hex-bloom[data-dock-mode="center"] .hex-bloom-dock {
  display: none;
}
/* The flower earns bigger tiles (no dock to clear) and folds like origami:
   deeper fold angle, harder scale-down, slower open. */
.hex-bloom[data-dock-mode="center"] {
  /* Modest fallback only — sizeCenterFlower() in JS overrides --tile-w/-h
     inline against the ACTUAL rendered sphere radius (game.getSphereScreen)
     the instant the menu opens, which is the only way "fits inside the
     sphere" holds at every board size and zoom level. A fixed px guess
     failed twice in testing (too small, then bigger than the sphere itself)
     because the sphere's own on-screen size moves with board size and zoom
     while a CSS constant does not. */
  --tile-w: 84px;
  --tile-h: 96px;
  --fold: 104deg;
  --fold-scale: 0.5;
  --fold-ms: 340ms;
}
.hex-bloom[data-context-menu="true"] {
  --fold: 88deg;
  --fold-scale: 0.68;
  --fold-ms: 140ms;
}
.hex-bloom[data-icon-menu="true"] {
  --border-w: 1px;
  --hb-fill: var(--hb-paper);
  --hb-fill-hover: var(--hb-paper);
  --hb-stroke: var(--hb-ink);
}
.hex-bloom[data-icon-menu="true"] .hb-hex { filter: none; }
.hex-bloom[data-icon-menu="true"] .hb-hex:hover::before,
.hex-bloom[data-icon-menu="true"] .hb-hex:focus-visible::before {
  inset: var(--border-w);
  background: var(--hb-paper);
}
.hex-bloom[data-icon-menu="true"] .hb-hex.is-active::before {
  background: var(--hb-ink);
}
/* Depth that reads at rest: a convex cap viewed slightly off-axis, with a
   short perspective and z-graded shadows. The center rides forward while
   the ring falls away, matching the sphere underneath instead of forming
   the old inside-out bowl. */
/* Spherical seating rotates tiles about their OWN centers (sphere faces
   curve about their centroids, not their inner edges — edge-hinging is what
   broke the tessellation). Overrides place()'s inline fold origin, so the
   fold becomes a center flip; the radial stagger keeps the bloom feel. */
.hex-bloom[data-dock-mode="center"] .hb-hex {
  transform-origin: 50% 50% !important;
}
.hex-bloom[data-dock-mode="center"] .hex-bloom-stage {
  /* Longer than the bottom-dock's 1100px default would be, but longer than
     the earlier 700px here: bigger tiles at the old short distance was
     over-foreshortening (the faceted/octagon look in Luke's screenshot). */
  perspective: 620px;
  perspective-origin: 50% 44%;
  /* No baked tilt: pointer parallax owns the stage transform (JS), so the
     flower sits perfectly aligned at rest and gains depth through motion.
     Transform transition off — the rAF lerp is the damper. */
  transition: opacity 0.12s ease, visibility 0.12s;
  transform-origin: 50% 50%;
}
.hex-bloom[data-dome="true"] .hex-bloom-stage {
  transform-style: preserve-3d;
  transform-origin: 50% 50%;
}
.hex-bloom[data-dome="true"]:not([data-dock-mode="center"]) .hex-bloom-stage {
  perspective: 760px;
  perspective-origin: 50% 100%;
}
.hex-bloom[data-dock-mode="center"] .hb-hex.shown {
  /* Subtle z-graded shadow; max() clamps the recessed center to zero so a
     negative blur can never invalidate the whole filter. */
  filter:
    drop-shadow(
      0
      calc(max(var(--dz, 0px), 0px) * 0.07 + var(--hov, 0px) * 0.25)
      calc(max(var(--dz, 0px), 0px) * 0.13 + 2px)
      rgba(0, 0, 0, 0.26)
    )
    drop-shadow(0 0 2px var(--hb-paper));
}
.hex-bloom[data-icon-menu="true"]:not([data-dome="true"]) .hb-hex.shown {
  /* The flat center flower is still one thin object hovering above the
     sphere. A restrained shared shadow gives the pointer tilt something to
     reveal without making seven independent cards. */
  filter: drop-shadow(0 2px 3px color-mix(in srgb, var(--hb-ink) 18%, transparent));
}
.hex-bloom[data-dome="true"] .hb-hex {
  backface-visibility: hidden;
}
/* Help corner — its own seat, lower right, always idle-sized. It never
   grows with the bloom: it is reference chrome, not part of the flower. */
.hex-bloom-corner {
  position: absolute;
  /* Keep the bare glyph fully inside the visual viewport. Two pixels left
     its stroked circle clipped by desktop browser chrome and mobile bars. */
  right: max(14px, calc(env(safe-area-inset-right, 0px) + 10px));
  bottom: max(12px, calc(env(safe-area-inset-bottom, 0px) + 10px));
  z-index: 3;
  pointer-events: auto;
}
.hex-bloom-corner .hb-hex.is-dock {
  position: relative;
  left: auto;
  top: auto;
  margin: 0;
  width: var(--tile-w-dock-idle);
  height: var(--tile-h-dock-idle);
  pointer-events: auto;
  /* No hex around the ? — bare glyph, same quiet treatment as the idle
     Restart / Flag icons, one step lighter. */
  clip-path: none;
  background: transparent;
  filter: none;
  transition:
    background 0.2s ease,
    color 0.2s ease,
    filter 0.2s ease,
    opacity 0.2s ease;
}
.hex-bloom-corner .hb-hex.is-dock::before {
  opacity: 0;
  background: transparent;
}
.hex-bloom-corner .hb-hex.is-dock .hb-glyph {
  color: var(--hb-ink);
  opacity: 0.6;
  filter:
    drop-shadow(0 0 2px var(--hb-paper))
    drop-shadow(0 0 1px var(--hb-paper));
}
.hex-bloom-corner .hb-hex.is-dock:hover .hb-glyph,
.hex-bloom-corner .hb-hex.is-dock:focus-visible .hb-glyph {
  opacity: 1;
}

/* Flag mode live: the dock tile reads as a planted flag (red face) via the
   shared .is-flag-icon.is-active language. */

/* While board has attention, whole dock recedes */
.hex-bloom[data-sphere-busy="true"][data-phase="closed"] .hex-bloom-dock,
.hex-bloom[data-sphere-busy="true"][data-phase="closed"] .hex-bloom-corner {
  opacity: 0;
}
.hex-bloom[data-sphere-busy="true"][data-phase="closed"] .hb-hex.is-dock {
  pointer-events: none !important;
}
@media (prefers-reduced-motion: reduce) {
  /* Stage / .hb-hex reduced-motion handling lives in the !important block
     near the end of this file — only the dock's own fade is decided here. */
  .hex-bloom-dock {
    transition: opacity 0.12s ease;
  }
}
@media (max-width: 400px) {
  .hex-bloom {
    --tile-w: 66px;
    --tile-h: 76px;
    --tile-w-dock-idle: 36px;
    --tile-h-dock-idle: 42px;
  }
  .hex-bloom[data-phase="open"] .hex-bloom-dock {
    --dock-rise: -28px;
  }
}

/* ---- Hex tile (clex language) ---- */
.hb-hex {
  position: absolute;
  width: var(--tile-w);
  height: var(--tile-h);
  margin-left: calc(var(--tile-w) / -2);
  /* Placed via `bottom` (see place()) — the centering margin lives on the
     bottom side so tiles stay glued to the dock when the mobile URL bar
     resizes the viewport. Dock tiles (.is-dock) reset margin to 0. */
  margin-bottom: calc(var(--tile-h) / -2);
  display: grid;
  place-items: center;
  clip-path: var(--hex-clip);
  background: var(--hb-stroke);
  color: var(--hb-ink);
  border: 0;
  padding: 0;
  cursor: pointer;
  pointer-events: auto;
  /* iOS Safari ignores body-level touch-action for its double-tap-zoom
     heuristic — it must sit on the touched element. Open+close is two taps
     on the same spot; without this Safari smart-zooms and position:fixed
     chrome slides around the visual viewport until the zoom settles. */
  touch-action: manipulation;
  transform-style: preserve-3d;
  transition:
    transform var(--fold-ms) cubic-bezier(0.22, 1, 0.3, 1),
    opacity calc(var(--fold-ms) * 0.85) ease,
    background 0.15s ease,
    color 0.15s ease,
    width var(--rise-ms) cubic-bezier(0.22, 1, 0.3, 1),
    height var(--rise-ms) cubic-bezier(0.22, 1, 0.3, 1),
    margin var(--rise-ms) cubic-bezier(0.22, 1, 0.3, 1);
  will-change: transform, opacity;
  outline: none;
  -webkit-appearance: none;
  appearance: none;
  filter:
    drop-shadow(0 0 3px var(--hb-paper))
    drop-shadow(0 1px 0 var(--hb-paper));
}
.hb-hex::before {
  content: "";
  position: absolute;
  inset: var(--border-w);
  clip-path: var(--hex-clip);
  background: var(--hb-fill);
  transition: inset 0.15s ease, background 0.2s ease;
  z-index: 0;
}
.hb-hex .hb-label {
  position: relative;
  z-index: 1;
  max-width: 88%;
  text-align: center;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: -0.02em;
  line-height: 1.12;
  pointer-events: none;
}
.hb-hex .hb-label[data-size="sm"] { font-size: 10px; }
.hb-hex .hb-label[data-size="xs"] { font-size: 9px; }

/* Icon glyphs on primaries / icon-bearing leaves */
.hb-hex .hb-glyph {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  pointer-events: none;
  color: inherit;
  transition: opacity 0.18s ease;
}
.hb-hex .hb-icon {
  display: block;
  width: 26px;
  height: 26px;
}
.hb-hex.is-primary .hb-glyph {
  width: 30px;
  height: 30px;
}
.hb-hex.is-primary .hb-icon {
  width: 28px;
  height: 28px;
}
.hb-hex.is-sub .hb-glyph {
  width: 24px;
  height: 24px;
}
.hb-hex.is-sub .hb-icon {
  width: 22px;
  height: 22px;
}
/* Visually hide label text while keeping it for SR / aria mirror */
.hb-hex .hb-label.sr-visual-hide,
.hb-hex .hb-label.hb-label-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
/* Size primary: nested-hex icon + letter badge */
.hb-hex.is-primary.has-badge {
  display: grid;
  place-items: center;
}
.hb-hex.is-primary.has-badge .hb-glyph {
  opacity: 0.35;
  position: absolute;
  z-index: 1;
}
.hb-hex.is-primary.has-badge .hb-label {
  position: relative;
  z-index: 2;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.02em;
  max-width: none;
}
/* Hybrid primaries: small glyph + short word */
.hb-hex.is-primary:not(.has-badge) {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  padding: 4px 2px 6px;
}
.hb-hex.is-primary:not(.has-badge) .hb-glyph {
  width: 22px;
  height: 22px;
}
.hb-hex.is-primary:not(.has-badge) .hb-icon {
  width: 20px;
  height: 20px;
}
.hb-hex.is-primary:not(.has-badge) .hb-label:not(.sr-visual-hide) {
  font-size: 9px;
  font-weight: 650;
  letter-spacing: 0.01em;
  line-height: 1.05;
  max-width: 90%;
}
.hb-hex.is-active .hb-glyph,
.hb-hex.is-chosen .hb-glyph {
  color: inherit;
}
@media (hover: hover) and (pointer: fine) {
  .hb-hex:hover .hb-icon,
  .hb-hex:focus-visible .hb-icon {
    transform: scale(1.08);
  }
  .hb-hex .hb-icon {
    transition: transform 0.2s cubic-bezier(0.22, 1, 0.3, 1);
  }
}

/* Dig = open honeycomb cell (hollow stroke hex) */
.hb-hex.is-dig-icon .hb-icon {
  stroke-width: 2;
}

/* Flag = solid red face — same language as in-game flags */
.hb-hex.is-flag-icon {
  color: #ff0000;
}
.hb-hex.is-flag-icon.is-active,
.hb-hex.is-flag-icon.is-chosen {
  background: #ff0000;
  color: #ff0000;
}
.hb-hex.is-flag-icon.is-active::before,
.hb-hex.is-flag-icon.is-chosen::before {
  background: color-mix(in srgb, var(--hb-paper) 12%, #ff0000);
}
.hb-hex.is-flag-icon.is-active .hb-icon,
.hb-hex.is-flag-icon.is-chosen .hb-icon {
  color: #ff0000;
}

/* Contextual flower: Home and Reset share a warm navigation/action signal,
   while Flag stays neutral until the mode is actually active. Tile materials
   never change — state lives in the glyphs only. */
.hex-bloom[data-icon-menu="true"] .cat-home .hb-glyph,
.hex-bloom[data-icon-menu="true"] .is-center-reset .hb-glyph,
.hex-bloom[data-icon-menu="true"] .cat-reset .hb-glyph {
  color: #ffd400;
}
.hex-bloom[data-icon-menu="true"] .cat-undo .hb-glyph {
  color: #18a64a;
}
.hex-bloom[data-icon-menu="true"] .is-flag-toggle .hb-glyph {
  color: var(--hb-ink);
}
.hex-bloom[data-icon-menu="true"] .is-flag-toggle.is-mode-active .hb-glyph {
  color: #ff2200;
}
.hex-bloom[data-icon-menu="true"] .hb-hex.is-primary .hb-glyph {
  width: clamp(44px, calc(var(--tile-h) * 0.38), 66px);
  height: clamp(44px, calc(var(--tile-h) * 0.38), 66px);
}
.hex-bloom[data-icon-menu="true"] .hb-hex.is-primary .hb-icon {
  width: clamp(40px, calc(var(--tile-h) * 0.34), 60px);
  height: clamp(40px, calc(var(--tile-h) * 0.34), 60px);
}
.hex-bloom[data-icon-menu="true"] .hb-icon-sizeXL {
  overflow: visible;
  transform: scale(1.18);
  transform-origin: 50% 50%;
}
.hex-bloom[data-icon-menu="true"] .hb-hex.is-sub .hb-glyph {
  width: clamp(44px, calc(var(--tile-h) * 0.36), 62px);
  height: clamp(44px, calc(var(--tile-h) * 0.36), 62px);
}
.hex-bloom[data-icon-menu="true"] .hb-hex.is-sub .hb-icon {
  width: clamp(40px, calc(var(--tile-h) * 0.32), 56px);
  height: clamp(40px, calc(var(--tile-h) * 0.32), 56px);
}

/* Theme primary = plain circle; tint from current theme when available */
.hb-hex.is-theme-icon .hb-icon {
  stroke-width: 2.1;
  color: var(--theme-edge, currentColor);
}
.hb-hex.is-theme-icon .hb-icon circle {
  fill: var(--theme-fill, transparent);
  fill-opacity: 0.92;
  stroke: var(--theme-edge, currentColor);
}

/* Theme leaves: the hex face is painted like that theme’s shell/field */
.hb-hex.is-theme-swatch {
  background: var(--theme-edge, var(--hb-stroke));
  color: var(--theme-ink, var(--hb-ink));
}
.hb-hex.is-theme-swatch::before {
  background: var(--theme-fill, var(--hb-fill));
  inset: var(--border-w);
}
.hb-hex.is-theme-swatch .hb-theme-dot {
  position: relative;
  z-index: 1;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--theme-field, transparent);
  box-shadow:
    0 0 0 1.5px var(--theme-edge, currentColor),
    inset 0 0 0 1px color-mix(in srgb, var(--theme-field) 40%, var(--theme-edge));
  pointer-events: none;
}
.hb-hex.is-theme-swatch.is-chosen {
  background: var(--theme-accent, #ff0000);
  color: var(--theme-ink, #fff);
}
.hb-hex.is-theme-swatch.is-chosen::before {
  background: var(--theme-fill, var(--hb-fill));
  inset: 3px;
}
.hb-hex.is-theme-swatch.is-chosen .hb-theme-dot {
  box-shadow:
    0 0 0 2px var(--theme-accent, #ff0000),
    inset 0 0 0 1px var(--theme-edge, #000);
}
@media (hover: hover) and (pointer: fine) {
  .hb-hex.is-theme-swatch:hover::before {
    inset: calc(var(--border-w) + 1px);
    background: var(--theme-fill, var(--hb-fill-hover));
  }
}

@media (hover: hover) and (pointer: fine) {
  .hb-hex:hover::before,
  .hb-hex:focus-visible::before {
    background: var(--hb-fill-hover);
    inset: calc(var(--border-w) + 1px);
  }
}
.hb-hex:focus-visible {
  background: var(--hb-accent);
}

/* Dock hexes */
.hb-hex.is-dock {
  z-index: 40;
  color: var(--hb-ink);
  background: var(--hb-stroke);
  pointer-events: auto;
  filter:
    drop-shadow(0 0 2px var(--hb-paper))
    drop-shadow(0 0 1px var(--hb-paper));
}
.hb-hex.is-dock::before {
  background: var(--hb-fill);
  inset: var(--border-w);
  transition: inset 0.2s ease, background 0.2s ease, opacity 0.2s ease;
}
.hb-hex.is-dock .hb-glyph {
  width: 55%;
  height: 55%;
  max-width: 28px;
  max-height: 28px;
  color: var(--hb-ink);
  transition: width 0.2s ease, height 0.2s ease;
}
.hb-hex.is-dock .hb-icon {
  width: 100%;
  height: 100%;
}
.hb-hex.is-dock .hb-label {
  font-size: 11px;
  font-weight: 650;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--hb-ink);
}

/* ---- Idle (closed): sides are borderless icons; menu is a quiet ring + hex icon ---- */
.hex-bloom[data-phase="closed"] .hb-hex.is-dock-side {
  background: transparent;
  filter: none;
}
.hex-bloom[data-phase="closed"] .hb-hex.is-dock-side::before {
  opacity: 0;
  background: transparent;
}
.hex-bloom[data-phase="closed"] .hb-hex.is-dock-side .hb-glyph {
  color: var(--hb-ink);
  opacity: 0.72;
  filter:
    drop-shadow(0 0 2px var(--hb-paper))
    drop-shadow(0 0 1px var(--hb-paper));
}
.hex-bloom[data-phase="closed"] .hb-hex.is-dock-side:hover .hb-glyph,
.hex-bloom[data-phase="closed"] .hb-hex.is-dock-side:focus-visible .hb-glyph {
  opacity: 1;
}
.hex-bloom .hb-hex.is-dock-reset .hb-glyph {
  color: #18a64a;
}
/* Flag mode on: the dock flag turns red — full strength in every phase
   (the idle rule above otherwise pins side glyphs to ink at 0.72). */
.hex-bloom .hb-hex.is-dock-flag.is-flag-icon .hb-glyph {
  color: #ff2200;
  opacity: 1;
}
/* ?seed=bare: idle seed is JUST the gear — hex face appears on activation,
   exactly the treatment Reset and ? already get when closed. */
.hex-bloom[data-seed="bare"][data-phase="closed"] .hex-bloom-dock .hb-glyph {
  width: 78%;
  height: 78%;
  max-width: 36px;
  max-height: 36px;
}
.hex-bloom[data-seed="bare"][data-phase="closed"] .hb-hex.is-dock-menu {
  background: transparent;
  filter: none;
}
.hex-bloom[data-seed="bare"][data-phase="closed"] .hb-hex.is-dock-menu::before {
  opacity: 0;
  background: transparent;
}
.hex-bloom[data-seed="bare"][data-phase="closed"] .hb-hex.is-dock-menu .hb-glyph {
  color: var(--hb-ink);
  opacity: 0.72;
  filter:
    drop-shadow(0 0 2px var(--hb-paper))
    drop-shadow(0 0 1px var(--hb-paper));
}
.hex-bloom[data-seed="bare"][data-phase="closed"] .hb-hex.is-dock-menu:hover .hb-glyph,
.hex-bloom[data-seed="bare"][data-phase="closed"] .hb-hex.is-dock-menu:focus-visible .hb-glyph {
  opacity: 1;
}

/* Menu: light outline + hollow-hex icon (reads as “open”) */
.hex-bloom[data-phase="closed"] .hb-hex.is-dock-menu {
  background: var(--hb-stroke);
  filter:
    drop-shadow(0 0 2px var(--hb-paper))
    drop-shadow(0 0 1px var(--hb-paper));
}
.hex-bloom[data-phase="closed"] .hb-hex.is-dock-menu::before {
  background: var(--hb-fill);
  inset: var(--border-w);
  opacity: 1;
}
.hex-bloom[data-phase="closed"] .hb-hex.is-dock-menu .hb-glyph {
  opacity: 1;
}

/* Default and bottom-dome launch from one deliberate horizon tab. Its full
   88px hex leaves a 44px exposed target; the other two actions retain their
   seats invisibly so the seed never jumps sideways when it blooms. */
.hex-bloom[data-bottom-seed="true"][data-phase="closed"] .hex-bloom-dock {
  --dock-rise: var(--seed-sink);
}
.hex-bloom[data-bottom-seed="true"][data-phase="closed"] .hb-hex.is-dock-side {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: scale(0.72);
}
.hex-bloom[data-bottom-seed="true"][data-phase="closed"] .hb-hex.is-dock-menu {
  width: var(--tile-w);
  height: var(--tile-h);
  background: var(--hb-ink);
  color: var(--hb-paper);
  filter: none;
}
.hex-bloom[data-bottom-seed="true"][data-phase="closed"] .hb-hex.is-dock-menu::before {
  inset: 0;
  opacity: 1;
  background: var(--hb-ink);
}
.hex-bloom[data-bottom-seed="true"][data-phase="closed"] .hb-hex.is-dock-menu .hb-glyph {
  width: 36px;
  height: 36px;
  max-width: none;
  max-height: none;
  color: var(--hb-paper);
  transform: translateY(calc(var(--seed-sink) * -0.48));
}
.hex-bloom[data-bottom-seed="true"][data-phase="open"] .hb-hex.is-dock-menu .hb-glyph,
.hex-bloom[data-bottom-seed="true"][data-phase="falling"] .hb-hex.is-dock-menu .hb-glyph {
  transform: translateY(0);
}

/* ---- Open: full bloom borders on all three; menu = solid × ---- */
.hex-bloom[data-phase="open"] .hb-hex.is-dock-side,
.hex-bloom[data-phase="falling"] .hb-hex.is-dock-side {
  background: var(--hb-stroke);
  filter:
    drop-shadow(0 0 2px var(--hb-paper))
    drop-shadow(0 0 1px var(--hb-paper));
  z-index: 41;
}
.hex-bloom[data-phase="open"] .hb-hex.is-dock-side::before,
.hex-bloom[data-phase="falling"] .hb-hex.is-dock-side::before {
  opacity: 1;
  background: var(--hb-fill);
  inset: var(--border-w);
}
.hex-bloom[data-phase="open"] .hb-hex.is-dock-menu,
.hex-bloom[data-phase="open"][data-dock="ready"] .hb-hex.is-dock-menu {
  background: var(--hb-ink);
  color: var(--hb-paper);
  z-index: 42;
}
.hex-bloom[data-phase="open"] .hb-hex.is-dock-menu .hb-glyph,
.hex-bloom[data-phase="open"][data-dock="ready"] .hb-hex.is-dock-menu .hb-glyph {
  color: var(--hb-paper);
}
.hex-bloom[data-phase="open"] .hb-hex.is-dock-menu::before,
.hex-bloom[data-phase="open"][data-dock="ready"] .hb-hex.is-dock-menu::before {
  background: var(--hb-ink);
  inset: 0;
  opacity: 1;
}
.hex-bloom[data-phase="open"] .hb-hex.is-dock-menu .hb-label,
.hex-bloom[data-phase="open"][data-dock="ready"] .hb-hex.is-dock-menu .hb-label {
  color: var(--hb-paper);
  font-size: clamp(16px, 4vw, 22px);
  font-weight: 500;
  opacity: 1;
}
.hex-bloom[data-phase="open"] .hb-hex.is-dock .hb-glyph,
.hex-bloom[data-phase="open"][data-dock="ready"] .hb-hex.is-dock .hb-glyph {
  width: clamp(44px, calc(var(--tile-h) * 0.38), 66px);
  height: clamp(44px, calc(var(--tile-h) * 0.38), 66px);
  max-width: none;
  max-height: none;
}
.hex-bloom[data-phase="open"] .hb-hex.is-dock .hb-icon,
.hex-bloom[data-phase="open"][data-dock="ready"] .hb-hex.is-dock .hb-icon {
  width: clamp(40px, calc(var(--tile-h) * 0.34), 60px);
  height: clamp(40px, calc(var(--tile-h) * 0.34), 60px);
}
.hex-bloom[data-phase="closed"] .hb-hex.is-dock {
  pointer-events: auto;
}

/* Primary ring */
.hb-hex.is-primary {
  z-index: 20;
  color: var(--hb-ink);
}
.hb-hex.is-primary.is-active {
  background: var(--hb-accent);
  color: var(--hb-active-ink);
  z-index: 28;
}
.hb-hex.is-primary.is-active::before {
  background: var(--hb-active-fill);
  inset: 2px;
}
.hb-hex.is-primary.is-active .hb-label {
  color: var(--hb-active-ink);
}

.hex-bloom[data-branch] .hb-hex.is-primary:not(.is-active) {
  opacity: 1;
}
.hex-bloom[data-branch] .hb-hex.is-primary:not(.is-active) .hb-glyph {
  opacity: 0.42;
}

/* Sub / leaf ring */
.hb-hex.is-sub {
  z-index: 24;
  color: var(--hb-ink);
}
.hb-hex.is-sub .hb-label {
  color: var(--hb-ink);
  font-size: 10px;
}
.hb-hex.is-sub.is-chosen {
  background: var(--hb-accent);
  color: var(--hb-active-ink);
  z-index: 26;
}
.hb-hex.is-sub.is-chosen::before {
  background: var(--hb-active-fill);
  inset: 2px;
}
.hb-hex.is-sub.is-chosen .hb-label {
  color: var(--hb-active-ink);
}

/* Fold / unfold (clex) */
.hb-hex.folded {
  opacity: 0;
  pointer-events: none;
  transform:
    translate(var(--tx, 0), var(--ty, 0))
    rotate3d(var(--ax, 0), var(--ay, 1), 0, var(--fold, 82deg))
    scale(var(--fold-scale, 0.86));
}
.hb-hex.shown {
  opacity: 1;
  /* --domeax/--domeay/--dome/--dz/--dscale: the ?dome=1 bowl (applyCenterDome)
     — a single rotation around each tile's own tangent axis, the exact
     "point this face at the sphere's center" transform (external review,
     2026-08-10: a two-axis rotateX+rotateY split does not commute and only
     half-shares an axis between neighbors — one rotation has no such flaw).
     --hov: hover/select lift. Defaults keep everything flat. */
  transform:
    translate(var(--tx, 0), var(--ty, 0))
    translateZ(calc(var(--dz, 0px) + var(--hov, 0px)))
    rotate3d(var(--domeax, 0), var(--domeay, 1), 0, var(--dome, 0deg))
    scale(var(--dscale, 1));
}
/* Tiles flip up a touch toward the player on hover / keyboard focus.
   Snappier than the fold: the lift must not ride --fold-ms (340ms in
   center mode read as lag, not response). */
.hex-bloom[data-dome="true"] .hb-hex.is-primary.shown:hover,
.hex-bloom[data-dome="true"] .hb-hex.is-primary.shown:focus-visible {
  --hov: 14px;
  transition-duration: 130ms;
}
.hex-bloom[data-dome="true"] .hb-hex.is-primary.shown:active {
  --hov: 7px;
}



/* Stats hub */
.hex-bloom-hub {
  --hub-ink: var(--text-main, #000);
  --hub-halo: var(--bg-color, #fff);
  position: fixed;
  top: max(14px, env(safe-area-inset-top));
  left: 50%;
  transform: translateX(-50%) translateY(-4px);
  z-index: 56;
  display: flex;
  gap: 1.35rem;
  pointer-events: none;
  color: var(--hub-ink);
  font: 600 22px/1 "IBM Plex Sans", system-ui, sans-serif;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.14s ease, transform 0.14s ease, visibility 0.14s;
  text-shadow:
    0 0 12px var(--hub-halo),
    0 0 5px var(--hub-halo),
    0 1px 0 var(--hub-halo),
    0 -1px 0 var(--hub-halo),
    1px 0 0 var(--hub-halo),
    -1px 0 0 var(--hub-halo);
}
body[data-sphere-chrome="dark"] .hex-bloom-hub {
  --hub-ink: #fff;
  --hub-halo: #000;
}
.hex-bloom-hub[data-open="true"] {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}

.hex-bloom-tooltip {
  position: fixed;
  z-index: 90;
  max-width: min(220px, calc(100vw - 16px));
  padding: 5px 8px 6px;
  border: 1px solid var(--hb-paper);
  border-radius: 4px;
  background: var(--hb-ink);
  color: var(--hb-paper);
  box-shadow: 0 2px 10px color-mix(in srgb, var(--hb-ink) 28%, transparent);
  font-size: 11px;
  font-weight: 650;
  line-height: 1;
  letter-spacing: 0.01em;
  white-space: nowrap;
  pointer-events: none;
}
.hex-bloom-tooltip[hidden] {
  display: none;
}

.hex-bloom-live {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  clip-path: inset(50%) !important;
  white-space: nowrap !important;
  border: 0 !important;
  margin: -1px !important;
  padding: 0 !important;
}

/* Hide legacy gear/help chrome */
body.hex-bloom-ui .hud-help-fixed,
body.hex-bloom-ui .hud-cluster {
  display: none !important;
  pointer-events: none !important;
}
body.hex-bloom-ui .legacy-hud {
  display: block !important;
  position: fixed !important;
  left: -10000px !important;
  top: 0 !important;
  width: 0 !important;
  height: 0 !important;
  overflow: hidden !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

/* While menu is the active surface, keep the board inert-looking */
body.hex-bloom-open .canvas-container {
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .hb-hex,
  .hex-bloom-scrim,
  .hex-bloom-stage,
  .hex-bloom-hub {
    transition: none !important;
    transition-delay: 0ms !important;
  }
  .hex-bloom {
    --rise-ms: 0ms;
  }
  .hb-hex.folded {
    transform: translate(var(--tx, 0), var(--ty, 0)) scale(0.92);
  }
}

@media (max-width: 400px) {
  .hex-bloom {
    --tile-w: 66px;
    --tile-h: 76px;
  }
  .hex-bloom[data-icon-menu="true"]:not([data-dock-mode="center"]) {
    --tile-w: 76px;
    --tile-h: 88px;
  }
  .hex-bloom[data-bottom-seed="true"][data-icon-menu="true"]:not([data-dock-mode="center"]) {
    --tile-w: 92px;
    --tile-h: 106px;
    --seed-sink: 53px;
  }
  .hb-hex .hb-label { font-size: 10px; }
}

/* Hub glyphs: bomb by the mine count, clock by the time. */
.hex-bloom-hub .hub-ico {
  width: 14px;
  height: 14px;
  opacity: 0.7;
  vertical-align: -2px;
  margin-right: -3px;
}
