/*
 * 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.22; /* ghost stays tappable: first tap must act on touch */
}
@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;
}



/* ---- Sphere-face menu variants -----------------------------------------
   The controls use the renderer's actual projected face polygons. They sit
   on seven real neighbouring tiles and are reprojected while the camera
   eases in and out. The center face is Reset, matching the base flower. */
.hex-bloom[data-face-takeover="true"] .hex-bloom-scrim {
  background: color-mix(in srgb, var(--hb-paper) 7%, transparent);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.hex-bloom[data-face-takeover="true"] .hb-face-action {
  margin: 0;
  clip-path: var(--face-poly);
  background: color-mix(in srgb, var(--hb-ink) 78%, transparent);
  transform-origin: 50% 50% !important;
  transition:
    transform 210ms cubic-bezier(0.22, 1, 0.3, 1),
    opacity 160ms ease,
    filter 140ms ease,
    background 140ms ease;
}
.hex-bloom[data-face-takeover="true"] .hb-face-action::before {
  inset: 1.5px;
  clip-path: var(--face-poly);
  background: color-mix(in srgb, var(--hb-paper) 92%, transparent);
}
.hex-bloom[data-face-takeover="true"] .hb-face-action .hb-glyph,
.hex-bloom[data-face-takeover="true"] .hb-face-action .hb-icon {
  width: var(--face-icon);
  height: var(--face-icon);
  max-width: none;
  max-height: none;
}
.hex-bloom[data-face-takeover="true"] .hb-face-action.folded {
  transform: scale(0.58);
  opacity: 0;
}
.hex-bloom[data-face-takeover="true"] .hb-face-action.shown {
  transform: scale(0.97);
  opacity: 0.97;
  filter: drop-shadow(
    0 3px 5px color-mix(in srgb, var(--hb-ink) 28%, transparent)
  );
}
.hex-bloom[data-face-takeover="true"] .hb-face-action.shown:hover,
.hex-bloom[data-face-takeover="true"] .hb-face-action.shown:focus-visible {
  transform: scale(1.055);
  opacity: 1;
  z-index: 140 !important;
}
.hex-bloom[data-face-takeover="true"] .hb-face-center.shown {
  filter: drop-shadow(
    0 5px 8px color-mix(in srgb, var(--hb-ink) 38%, transparent)
  );
}

/* The submerged variant stays crisp at its silhouette (so each face remains
   tappable) while light, haze and caustics build inside the water material. */
.hex-bloom[data-underwater-takeover="true"] .hex-bloom-scrim {
  background: linear-gradient(
    to bottom,
    transparent 54%,
    rgb(3 64 91 / 0.08) 66%,
    rgb(2 40 60 / 0.2) 100%
  );
}
.hex-bloom[data-underwater-takeover="true"] .hb-face-action {
  --wet-alpha: 0.24;
  color: #e7fbff;
  background: rgb(104 225 244 / calc(0.62 - var(--water-depth) * 0.16));
  filter:
    drop-shadow(0 2px 5px rgb(0 15 30 / 0.48))
    saturate(calc(1.05 - var(--water-depth) * 0.16));
}
.hex-bloom[data-underwater-takeover="true"] .hb-face-action::before {
  background: linear-gradient(
    155deg,
    rgb(19 117 145 / calc(0.8 - var(--water-depth) * 0.18)),
    rgb(3 54 80 / calc(0.9 - var(--water-depth) * 0.12))
  );
  box-shadow:
    inset 0 1px 0 rgb(207 250 255 / 0.62),
    inset 0 -8px 18px rgb(0 19 43 / calc(0.18 + var(--water-depth) * 0.24));
}
.hex-bloom[data-underwater-takeover="true"] .hb-face-action::after {
  content: "";
  position: absolute;
  inset: 1px;
  z-index: 2;
  pointer-events: none;
  clip-path: var(--face-poly);
  opacity: calc(var(--wet-alpha) + 0.12);
  background:
    repeating-linear-gradient(
      118deg,
      transparent 0 12%,
      rgb(190 250 255 / 0.46) 13% 15%,
      transparent 17% 31%
    ),
    radial-gradient(circle at 32% 22%, rgb(220 253 255 / 0.42), transparent 38%);
  mix-blend-mode: screen;
  animation: hb-underwater-caustic 6.5s ease-in-out infinite alternate;
}
.hex-bloom[data-underwater-takeover="true"] .hb-face-action .hb-glyph,
.hex-bloom[data-underwater-takeover="true"] .hb-face-action .hb-label,
.hex-bloom[data-underwater-takeover="true"] .hb-face-action .hb-theme-dot {
  z-index: 3;
  color: #e9fcff;
  text-shadow:
    0 1px 2px rgb(0 21 38 / 0.95),
    0 0 8px rgb(111 235 255 / 0.78);
  filter: drop-shadow(0 1px 1px rgb(0 15 28 / 0.8));
}
.hex-bloom[data-underwater-takeover="true"] .hb-face-center::before {
  background: linear-gradient(155deg, rgb(0 67 93 / 0.96), rgb(0 29 48 / 0.98));
}
.hex-bloom[data-underwater-takeover="true"] .hb-face-action:focus-visible {
  background: #baf8ff;
  filter:
    drop-shadow(0 0 0.35rem rgb(152 247 255 / 0.9))
    drop-shadow(0 2px 5px rgb(0 15 30 / 0.5));
}
@keyframes hb-underwater-caustic {
  from { transform: translate3d(-10%, -5%, 0) scale(1.12); }
  to { transform: translate3d(10%, 6%, 0) scale(1.22) rotate(3deg); }
}

/* 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;
}
body.hex-bloom-open.hex-bloom-rotatable .canvas-container {
  pointer-events: auto;
}
.hex-bloom[data-rotatable-menu="true"][data-open="true"] .hex-bloom-scrim {
  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);
  }
  .hex-bloom[data-underwater-takeover="true"] .hb-face-action::after {
    animation: none !important;
  }
}

@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;
}
