/* Office — /office "living hive" styles. Tokens, body, and the shared top
   bar/nav live in public/shell.css; this file styles only the hive scene.
   This ticket is the static scaffold: backdrop, 7 hex cells, HUD. No bee or
   animation styles yet. */

:root {
  /* Bee colors (design doc §3). Color is pure CSS so one SVG template can be
     recolored per agent in later tickets. */
  --bee-cbeezy: #f4c542;
  --bee-expert: #3b6cff;
  --bee-medium: #2ce0c0;
  --bee-research: #a06aff;
  --bee-gemma: #7be86d;
  --bee-trading-manager: #10b981; /* emerald — money/markets */
  --bee-trading-worker: #f59e0b; /* amber — alert/signal energy */
  --bee-reserved: #4a566e;
}

.office-main {
  padding: 0;
  margin: 0;
}

/* 16:9 stage holding the SVG canvas plus the HTML HUD overlay. */
.hive-stage {
  /* The hive scene keeps its own cyan/purple accent. The shared chrome moved to
     the amber/gold hive palette (task-0037), but the living-hive dioramas, glow
     filters and terminal screens were tuned against cyan, so we re-pin the accent
     tokens here to render the scene exactly as before — the surrounding app is
     gold, the bee world stays neon-cyan. */
  --accent: #28e0ff;
  --accent-2: #9a6bff;
  --glow: 0 0 18px rgba(40, 224, 255, 0.35);
  --glow-soft: 0 0 12px rgba(40, 224, 255, 0.18);
  --grad-accent: linear-gradient(120deg, #28e0ff, #9a6bff);

  position: relative;
  width: 100%;
  max-width: 1600px;
  margin: 0 auto;
  aspect-ratio: 16 / 9;
  max-height: calc(100vh - 64px);
}

svg.hive {
  display: block;
  width: 100%;
  height: 100%;
}

/* --- Backdrop --- */
.bg-fill {
  fill: var(--bg);
}

/* Tiled hex-grid "hive floor" texture at 10% opacity. */
.hex-floor {
  opacity: 0.1;
}
#hexgrid path {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.2;
}

/* Radial glow centered on the queen; gradient stops are defined in the SVG. */
.queen-glow {
  pointer-events: none;
}

/* --- Hex cells --- */
/* Thin glowing stroke in each bee's color. `color` drives both the stroke and
   the drop-shadow glow (currentColor), and a faint fill adds chamber depth. */
.hex-cell {
  fill: currentColor;
  fill-opacity: 0.04;
  stroke: currentColor;
  stroke-width: 2.5;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 7px currentColor);
}
.hex-cell[data-bee="cbeezy"] {
  color: var(--bee-cbeezy);
  stroke-width: 3.5;
}
.hex-cell[data-bee="expert-coder"] {
  color: var(--bee-expert);
}
.hex-cell[data-bee="medium-coder"] {
  color: var(--bee-medium);
}
.hex-cell[data-bee="web-researcher"] {
  color: var(--bee-research);
}
.hex-cell[data-bee="offline-gemma4"] {
  color: var(--bee-gemma);
}
.hex-cell[data-bee="trading-manager"] {
  color: var(--bee-trading-manager);
}
.hex-cell[data-bee="trading-local-worker"] {
  color: var(--bee-trading-worker);
}
/* Reserved cells: visible but dim gray, no glow. */
.hex-cell.reserved {
  color: var(--bee-reserved);
  fill-opacity: 0.02;
  stroke-width: 1.5;
  opacity: 0.5;
  filter: none;
}

/* --- Office dioramas (task-0030 revision) ----------------------------------
   A full illustrated room per cell in <g id="dressing">, rendered BELOW the hex
   cells and ABOVE the backdrop (z-order is document order in buildScene). Each
   group sets `color` to its agent hue inline and clips to the shared hex, so the
   room matches the cell and never overflows the polygon. This is primary content
   (read clearly at idle), not texture: ~80% layer opacity with dark furniture
   silhouettes + a glowing agent-hue edge, plus brighter screens/accents. The bee
   sprite overlays the room. pointer-events off so it never intercepts the bee.
   Static except offline-gemma4's blinking cursor. */
#dressing {
  pointer-events: none;
}
.dressing {
  opacity: 0.8;
}
/* Floor / faint construction + wall lines. */
.di-floor,
.di-wall {
  fill: none;
  stroke: currentColor;
  stroke-opacity: 0.5;
  stroke-width: 2;
  stroke-linecap: round;
}
.di-wall {
  stroke-opacity: 0.35;
}
/* Furniture silhouette: dark body, glowing colored edge (matches hex-cell look). */
.di-solid {
  fill: #0e1119;
  fill-opacity: 0.92;
  stroke: currentColor;
  stroke-opacity: 0.85;
  stroke-width: 2;
  stroke-linejoin: round;
}
/* Glowing screen objects in the agent hue. */
.di-screen {
  fill: currentColor;
  fill-opacity: 0.32;
  stroke: currentColor;
  stroke-width: 1.5;
  filter: drop-shadow(0 0 4px currentColor);
}
/* Solid accent objects (trinkets, gears, gems). */
.di-accent {
  fill: currentColor;
  fill-opacity: 0.85;
  stroke: none;
}
/* Line-art props: tools, globe meridians, scope traces, cup handles. */
.di-tool,
.di-globe {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Book spines on the researcher's shelf. */
.di-book {
  fill: currentColor;
  fill-opacity: 0.5;
  stroke: currentColor;
  stroke-opacity: 0.8;
  stroke-width: 1;
}
/* gemma's dark terminal room: a near-black panel for the dramatic backdrop. */
.di-room {
  fill: #04060a;
  stroke: none;
}
.di-screen-strong {
  fill-opacity: 0.2;
  filter: drop-shadow(0 0 7px currentColor);
}
.di-term-line {
  fill: currentColor;
  fill-opacity: 0.9;
  stroke: none;
}
.di-cursor {
  fill: #c8ffbe;
  animation: di-cursor-blink 1.1s steps(1, end) infinite;
}
@keyframes di-cursor-blink {
  0%, 50% { opacity: 1; }
  50.01%, 100% { opacity: 0; }
}

/* --- Bees (design doc §5 anatomy, §7.1 accessories) ---
   ONE <symbol id="bee"> recolored per agent: each .bee group sets --bee-color
   (inline) and the body/head/cell parts read it. Glow is an SVG filter
   (#beeGlow / #beeGlowQueen), never a CSS box-shadow on SVG nodes. */
.bee {
  filter: url(#beeGlow);
}
.bee.queen {
  filter: url(#beeGlowQueen);
}
/* Reserved cells: plain bees, dimmed, no glow (design doc §3). */
.bee.role-reserved {
  filter: none;
  opacity: 0.4;
}

/* Body + head carry the agent color; stripes are dark bands clipped to body. */
.bee-body,
.bee-head {
  fill: var(--bee-color);
}
.bee-head {
  fill-opacity: 0.9;
}
.bee-stripe {
  fill: #15171f;
}
/* Wings: semi-transparent ovals. Antenna tips, eyes, stinger glow cyan. */
.bee-wing {
  fill: #bfeaff;
  fill-opacity: 0.32;
  stroke: #d8f3ff;
  stroke-opacity: 0.25;
  stroke-width: 1;
}
.bee-antenna {
  fill: none;
  stroke: #20232e;
  stroke-width: 2;
  stroke-linecap: round;
}
.bee-antenna-tip {
  fill: var(--accent);
}
.bee-eye {
  fill: #28e0ff;
}
.bee-stinger {
  fill: #20232e;
  stroke: #28e0ff;
  stroke-opacity: 0.5;
  stroke-width: 0.8;
}
.bee.role-reserved .bee-eye,
.bee.role-reserved .bee-antenna-tip {
  fill: #6a7080;
}

/* --- Accessories (one <symbol> per agent, design doc §7.1) --- */
/* Queen crown — gold band + cyan gems. */
.crown-band {
  fill: #f4c542;
  stroke: #b8901f;
  stroke-width: 1;
  stroke-linejoin: round;
}
/* Crown gems glow a touch brighter on the queen (task-0030 character pass). */
.crown-gem {
  fill: #28e0ff;
  filter: drop-shadow(0 0 2px #7ef0ff);
}
/* Queen's faint upward smile (task-0030) — drawn in the crown accessory so it
   stays a per-agent feature on the otherwise shared bee template. */
.queen-smile {
  fill: none;
  stroke: #20232e;
  stroke-width: 1.6;
  stroke-linecap: round;
}
/* expert-coder — goggles + multi-tool (metallic). */
.goggle-strap {
  stroke: #20232e;
  stroke-width: 2.5;
}
/* Focused brow RIDGE above the eyes (task-0030 revision) — a single bold
   horizontal stroke so expert-coder reads as the angular/focused worker. */
.bee-brow {
  fill: none;
  stroke: #20232e;
  stroke-width: 3.6;
  stroke-linecap: round;
}
.goggle-lens {
  fill: rgba(40, 224, 255, 0.22);
  stroke: #c7ccd6;
  stroke-width: 1.6;
}
/* Inner lens reticle/crosshair detail (task-0030). Stroke inherits to the child
   <line>s, so the group carries the styling. */
.goggle-reticle {
  fill: none;
  stroke: rgba(40, 224, 255, 0.6);
  stroke-width: 0.8;
  stroke-linecap: round;
}
.multitool .tool-handle,
.multitool .tool-head {
  fill: #c7ccd6;
  stroke: #7c828f;
  stroke-width: 0.6;
}
.multitool .tool-hole {
  fill: var(--bg);
}
/* medium-coder — gear/cog. */
.gear-body {
  fill: #c7ccd6;
  stroke: #7c828f;
  stroke-width: 0.6;
  stroke-linejoin: round;
}
.gear-hole {
  fill: var(--bg);
}
/* web-researcher — magnifier clipped to the side. */
.mag-rim {
  fill: none;
  stroke: #c7ccd6;
  stroke-width: 3;
}
.mag-glass {
  fill: rgba(160, 106, 255, 0.18);
  stroke: rgba(216, 243, 255, 0.4);
  stroke-width: 0.8;
}
.mag-handle {
  fill: #c7ccd6;
  stroke: #7c828f;
  stroke-width: 0.6;
}
/* Crosshair inside the glass (task-0030). Stroke inherits to the child lines. */
.mag-crosshair {
  fill: none;
  stroke: rgba(216, 243, 255, 0.55);
  stroke-width: 0.8;
  stroke-linecap: round;
}
/* offline-gemma4 — hovering hex hologram terminal with green text lines. */
.term-hex {
  fill: rgba(123, 232, 109, 0.12);
  stroke: #7be86d;
  stroke-width: 1.4;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 3px #7be86d);
}
.term-line {
  fill: #7be86d;
}
/* Always-on blinking terminal cursor (task-0030). A small standalone rect; it is
   independent of the specialist --term-anim hook, so it blinks even at idle. */
.term-cursor {
  fill: #aef5a2;
  animation: term-cursor-blink 1.1s steps(1, end) infinite;
}
@keyframes term-cursor-blink {
  0%, 50% { opacity: 1; }
  50.01%, 100% { opacity: 0; }
}
/* trading-manager — rising bar chart with an up-trend arrow, emerald. While
   working, each bar grows from its baseline on a staggered delay (rising bars). */
.acc-chart .chart-bar {
  fill: var(--bee-trading-manager);
  opacity: 0.85;
  transform-box: fill-box;
  transform-origin: center bottom;
  animation-name: var(--chart-rise-anim, none);
  animation-duration: 1.6s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}
.acc-chart .chart-bar:nth-of-type(1) { animation-delay: 0s; }
.acc-chart .chart-bar:nth-of-type(2) { animation-delay: 0.18s; }
.acc-chart .chart-bar:nth-of-type(3) { animation-delay: 0.36s; }
@keyframes trade-chart-rise {
  0%, 100% { transform: scaleY(0.55); opacity: 0.55; }
  50%      { transform: scaleY(1);    opacity: 0.9; }
}
.acc-chart .chart-trend {
  fill: none;
  stroke: #d8f3ff;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.acc-chart .chart-arrow {
  fill: #d8f3ff;
}
/* trading-local-worker — lightning bolt, amber, faint glow. While working it
   pulses with a sharp electric flash (a repeating amber glow burst). */
.acc-bolt .bolt-body {
  fill: var(--bee-trading-worker);
  stroke: #ffe9b8;
  stroke-width: 0.6;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 3px var(--bee-trading-worker));
  transform-box: fill-box;
  transform-origin: center;
  animation-name: var(--bolt-flash-anim, none);
  animation-duration: 0.9s;
  animation-timing-function: ease-out;
  animation-iteration-count: infinite;
}
@keyframes trade-bolt-flash {
  0%, 100% { opacity: 0.85; transform: scale(1);    filter: drop-shadow(0 0 3px var(--bee-trading-worker)); }
  10%      { opacity: 1;    transform: scale(1.18); filter: drop-shadow(0 0 9px var(--bee-trading-worker)); }
  32%      { opacity: 0.7;  transform: scale(0.98); filter: drop-shadow(0 0 2px var(--bee-trading-worker)); }
}

/* Per-agent body proportions (task-0030). The body and its clipped stripes share
   one wrapper (.bee-torso, in <symbol id="bee">) so a scale applies to both and
   the stripe clip stays aligned. fill-box keeps the scale centered on the torso.
   Default 1×; the queen reads slightly rounder, medium-coder slightly stockier.
   Inherited custom props cross the <use> shadow boundary, so the per-agent value
   set on the .bee wrapper reaches the cloned inner group. */
.bee-torso {
  transform-box: fill-box;
  transform-origin: center;
  transform: scale(var(--torso-sx, 1), var(--torso-sy, 1));
}
/* Queen reads wider and noticeably rounder than the workers. */
.bee[data-bee="cbeezy"] {
  --torso-sx: 1.2;
  --torso-sy: 1.12;
}
/* expert-coder: leaner, more angular torso. */
.bee[data-bee="expert-coder"] {
  --torso-sx: 0.86;
  --torso-sy: 1.02;
}
.bee[data-bee="medium-coder"] {
  --torso-sx: 1.1;
  --torso-sy: 1.05;
}
/* offline-gemma4: compact body (paired with the smaller whole-sprite scale). */
.bee[data-bee="offline-gemma4"] {
  --torso-sx: 0.94;
  --torso-sy: 0.92;
}

/* --- HUD overlay (plain HTML, not SVG) --- */
.hud {
  position: absolute;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.8rem;
  color: var(--text);
  background: rgba(8, 11, 20, 0.72);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.45rem 0.6rem;
  box-shadow: var(--glow-soft);
  backdrop-filter: blur(2px);
}
.hud-clock {
  top: 14px;
  left: 14px;
  letter-spacing: 0.08em;
  color: var(--accent);
}
.hud-legend {
  bottom: 14px;
  right: 14px;
  display: grid;
  gap: 0.28rem;
}
.legend-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.legend-row.reserved {
  color: var(--text-dim);
}
.legend-swatch {
  width: 11px;
  height: 11px;
  border-radius: 2px;
  box-shadow: 0 0 6px currentColor;
}
.legend-swatch.reserved {
  background: var(--bee-reserved);
  box-shadow: none;
}

/* ===========================================================================
   State animations (design doc §6 state machine, §7 animation matrix, task-0023)

   Baseline steady-state behaviors only: working / idle / sleeping. CSS keyframes
   only — no JS animation loops (office.js merely toggles the state-<x> class on
   each .bee wrapper and sets data-state on each .hex-cell). talking / bored /
   transmission beams / specialist work anims are tasks 0024-0027 and intentionally
   absent here.

   How the bee sprite is reached: wings + sprite live inside <symbol id="bee">,
   instanced per agent via <use>, i.e. a shadow tree. Descendant selectors that
   cross into that tree from the .bee wrapper are unreliable, but INHERITED CSS
   custom properties cross it (the same mechanism that recolors each bee via
   --bee-color). So the state class on the .bee wrapper sets inherited variables
   (--wing-dur, --wing-flex, --float-*, --wing-rot-*) and the always-on
   animations on the cloned .bee-sprite / .bee-wing-* elements read them. Swapping
   state is one class change; no per-state selector ever has to reach into <use>.

   Perf (design doc §11, <5% idle CPU): idle animations are limited to compositor-
   friendly transform (wing scaleX, sprite translateY) and opacity (hex breathing).
   No stroke-width/filter churn at idle — that lives only in the louder working
   pulse. prefers-reduced-motion halts everything.
   =========================================================================== */

/* Per-bee animation knobs. Defaults describe the idle pose so a bee looks alive
   even before office.js applies its first state class. State classes below
   override only the variables that differ. */
.bee {
  --wing-anim: wing-buzz; /* set to `none` to still the wings (sleeping/offline) */
  --wing-dur: 0.34s;   /* wing-beat period; smaller = faster buzz */
  --wing-flex: 0.7;    /* scaleX at mid-beat; smaller = deeper flap */
  --float-dur: 4s;     /* hover bob period */
  --float-dist: 3px;   /* hover bob amplitude */
  --wing-rot-l: -22deg; /* left/right wing rest tilt; folds down when sleeping */
  --wing-rot-r: 22deg;
  transition: opacity 0.6s ease;
}

/* Whole-sprite hover bob. .bee-sprite carries no inline transform, so animating
   its transform is safe; it composes with the per-bee wrapper translate/scale. */
.bee-sprite {
  /* Default: the idle hover bob. The lazy-buzz-circle bored gag (§7.4) swaps
     these via --sprite-anim/--sprite-dur on the wrapper for its duration. */
  animation-name: var(--sprite-anim, bee-hover);
  animation-duration: var(--sprite-dur, var(--float-dur, 4s));
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}
@keyframes bee-hover {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(calc(-1 * var(--float-dist, 3px))); }
}

/* Working in-hex buzz (task-0043): a busy bee with an active tool drifts in a
   small erratic orbit inside its cell instead of just bobbing, so "working"
   reads as restless motion in addition to the §7.1 specialist overlay. Animates
   .bee-sprite (composes with the wrapper translate/scale, never clobbers the
   migration transform); turned on by setting --sprite-anim on the wrapper below.
   ~6px radius keeps the bee comfortably inside the hex. */
@keyframes bee-work-buzz {
  0%   { transform: translate(0, 0); }
  18%  { transform: translate(5px, -3px); }
  36%  { transform: translate(2px, 4px); }
  54%  { transform: translate(-5px, 1px); }
  72%  { transform: translate(-2px, -5px); }
  88%  { transform: translate(4px, 3px); }
  100% { transform: translate(0, 0); }
}

/* Wing buzz. The rest tilt that the markup carries as a rotate() presentation
   attribute is re-expressed here via the independent `rotate` property (so it can
   transition to a folded pose), while the buzz itself animates `transform:
   scaleX(...)`. The two compose; transform-origin pins both to the wing centre
   (matching the original rotate(angle, cx, cy)). When --wing-dur is 0s (sleeping)
   the buzz is inert and the wing rests at scaleX(1), folded by --wing-rot-*. */
.bee-wing-l {
  transform-origin: -17px -12px;
  rotate: var(--wing-rot-l, -22deg);
  transition: rotate 0.4s ease;
}
.bee-wing-r {
  transform-origin: 17px -12px;
  rotate: var(--wing-rot-r, 22deg);
  transition: rotate 0.4s ease;
}
.bee-wing-l,
.bee-wing-r {
  animation-name: var(--wing-anim, wing-buzz);
  animation-duration: var(--wing-dur, 0.34s);
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}
@keyframes wing-buzz {
  0%, 100% { transform: scaleX(1); }
  50% { transform: scaleX(var(--wing-flex, 0.7)); }
}

/* working — fast buzz + brisk hover (design doc §7). */
.bee.state-working {
  --wing-dur: 0.11s;
  --wing-flex: 0.35;
  --float-dur: 2.2s;
  --float-dist: 4px;
}
/* working WITH an active tool — swap the hover bob for the in-hex orbit buzz so
   a busy bee moves around its cell (task-0043). --sprite-anim is read by the
   .bee-sprite rule across the <use> shadow boundary (inherited custom property),
   the same mechanism the bored gags use. A working bee with no tool keeps the
   plain brisk bob above. */
.bee.state-working.tool-active {
  --sprite-anim: bee-work-buzz;
  --sprite-dur: 0.9s;
}
/* idle — slow buzz, gentle float (the .bee defaults already describe idle; set
   explicitly so the mapping is legible and order-independent). Dimmed a notch
   (task-0043) so active/working bees pop more by contrast. */
.bee.state-idle {
  --wing-dur: 0.34s;
  --wing-flex: 0.7;
  --float-dur: 4s;
  --float-dist: 3px;
  opacity: 0.72;
}
/* sleeping — wings folded down + still, sprite noticeably dimmed (task-0043:
   dimmer than before so away bees clearly recede), no bob. */
.bee.state-sleeping {
  --wing-anim: none;
  --wing-rot-l: 34deg;
  --wing-rot-r: -34deg;
  --float-dist: 0px;
  opacity: 0.42;
}
/* bored — same gentle float as idle but slightly slower; gags fire on top. */
.bee.state-bored {
  --wing-dur: 0.5s;
  --wing-flex: 0.8;
  --float-dur: 6s;
  --float-dist: 2px;
}
/* offline (fetch failure / absent): quiet the sprite, don't leave it buzzing. */
.bee.state-offline {
  --wing-anim: none;
  --float-dist: 0px;
  opacity: 0.5;
}

/* --- Hex cell state effects (light DOM: data-state set on the polygon) --- */
/* working — stroke + glow pulse in the bee's own color (currentColor, never a
   hardcoded color). This is the only state allowed stroke-width/filter motion. */
.hex-cell[data-state="working"] {
  animation: hex-working 1.2s ease-in-out infinite;
}
@keyframes hex-working {
  0%, 100% {
    stroke-width: 3;
    filter: drop-shadow(0 0 6px currentColor);
  }
  50% {
    stroke-width: 5;
    filter: drop-shadow(0 0 16px currentColor);
  }
}
/* bored — very slow, dim amber tinge. Hex mostly still so gag motion stands out. */
.hex-cell[data-state="bored"] {
  animation: hex-bored 8s ease-in-out infinite;
}
@keyframes hex-bored {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 0.75; }
}
/* idle — soft breathing glow, 4s. Opacity only (composited, cheap at idle). */
.hex-cell[data-state="idle"] {
  animation: hex-idle 4s ease-in-out infinite;
}
@keyframes hex-idle {
  0%, 100% { opacity: 0.7; }
  50% { opacity: 1; }
}
/* sleeping — dim and subdued, slow 6s pulse. */
.hex-cell[data-state="sleeping"] {
  animation: hex-sleeping 6s ease-in-out infinite;
}
@keyframes hex-sleeping {
  0%, 100% { opacity: 0.32; }
  50% { opacity: 0.5; }
}

/* --- Transmission beams (task-0024, design doc §7.2) ---
   A glowing Bézier <path> arcing from sender hex edge to recipient hex edge,
   created by public/office.js inside <g id="transmissions">. Color is set
   inline per beam (the sender's --bee-* var) and drives both the stroke and the
   currentColor glow. The dash pattern travels start→end to suggest flow
   direction; after 2s office.js adds .beam-fade and the opacity transition
   carries it out before the node is removed. */
#transmissions {
  pointer-events: none;
}
.beam {
  fill: none;
  stroke: var(--accent);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-dasharray: 13 11; /* sum 24 → matches the beam-flow offset for seamless travel */
  opacity: 0.95;
  filter: drop-shadow(0 0 7px currentColor);
  transition: opacity 0.3s ease;
  animation: beam-flow 0.6s linear infinite;
}
.beam.beam-fade {
  opacity: 0;
}
/* Negative offset pulls the dashes toward the path end (the recipient). */
@keyframes beam-flow {
  to {
    stroke-dashoffset: -24;
  }
}

/* talking overlay (design doc §6): both endpoints of a live beam pulse brighter.
   Placed AFTER the data-state rules so it wins on equal specificity and overlays
   the base working/idle animation for the beam's lifetime. */
.hex-cell.talking {
  animation: hex-talking 0.6s ease-in-out infinite;
}
@keyframes hex-talking {
  0%, 100% {
    stroke-width: 3;
    filter: drop-shadow(0 0 8px currentColor);
  }
  50% {
    stroke-width: 5.5;
    filter: drop-shadow(0 0 20px currentColor);
  }
}

/* --- Living-hive bee migration (task-0025, design doc §7.3) --- */
/* The sender bee's wrapper <g> transform is driven per-frame by office.js while
   it flies to the recipient and back; nothing here animates it (a CSS transform
   on the wrapper would fight the JS-set translate). office.js toggles `.flying`
   on the bee (a styling/debug hook) and `.anchor-dim` on the sender hex, which
   keeps its glow as an anchor but reads as "occupant away" while the bee is out. */
.hex-cell.anchor-dim {
  /* The sender's cell keeps its glow (anchor) but reads as "occupant away". */
  opacity: 0.55;
  transition: opacity 0.25s ease;
}

/* --- Specialist work anims (task-0027, design doc §7.1) -------------------
   A SECOND overlay on top of the generic working buzz/pulse: while a bee is
   state-working with an ACTIVE tool, it shows WHAT it's doing. Three agents wear
   an extra <use class="bee-specialist"> overlay symbol (orbiting orb / weld
   sparks / data scroll); the other two animate their existing accessory (gear
   spin / terminal blink). Activation rides the SAME inherited-custom-property
   trick as the state machine and bored gags: office.js adds `.tool-active` to the
   .bee wrapper for a real tool, which flips that agent's --spec-* / --gear-spin
   / --term-anim variable, and the cloned inner element (reached across the <use>
   shadow boundary by inheritance, not descendant selectors) reads it. A bee
   working with a null/unknown tool gets `.tool-working` instead — no overlay,
   just the generic working animation (the required fallback). Everything is inert
   until the wrapper turns it on, so there is zero idle cost and no regression on
   the core working/idle/bored/sleeping states. */

/* The overlay symbols are hidden until their agent is working-with-tool; the
   inner animations are gated separately (via the --spec-* vars below) so a hidden
   overlay also costs no animation work. */
.bee-specialist {
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}
.bee.state-working.tool-active .bee-specialist {
  opacity: 1;
}

/* Per-agent activation: working + active tool flips the agent's animation vars.
   Selected by data-bee (the wrapper carries no bee-<id> class), matching how the
   hex cells are colored. tool-working (the fallback) deliberately sets none.
   Each agent fires BOTH a visible arm-action overlay and its ambient effect. */
.bee[data-bee="cbeezy"].state-working.tool-active {
  --spec-orb-anim: spec-orb-orbit;
  --spec-hand-anim: spec-hand-tap;         /* directing arm taps at desk */
}
.bee[data-bee="expert-coder"].state-working.tool-active {
  --spec-spark-anim: spec-spark-flash;
  --spec-hammer-anim: spec-hammer-strike;  /* arm swings hammer down */
}
.bee[data-bee="medium-coder"].state-working.tool-active {
  --gear-spin-anim: spec-gear-spin;
  --spec-type-anim: spec-arm-type;         /* L/R arms alternate-type */
}
.bee[data-bee="web-researcher"].state-working.tool-active {
  --spec-scroll-anim: spec-scroll-flow;
  --spec-hand-anim: spec-hand-tap;         /* arm traces along the doc */
}
.bee[data-bee="offline-gemma4"].state-working.tool-active {
  --term-anim: spec-term-blink;
  --spec-hack-anim: spec-arm-hack;         /* two arms blaze alternately */
}
/* The two trading bees have no specialist arm overlay; their worn accessory
   animates on the working state itself (chart bars rise / bolt flashes) so the
   cell shows live activity whenever the bee is working, tool or not. */
.bee[data-bee="trading-manager"].state-working {
  --chart-rise-anim: trade-chart-rise;
}
.bee[data-bee="trading-local-worker"].state-working {
  --bolt-flash-anim: trade-bolt-flash;
}

/* cbeezy — hologram orb orbiting the queen. Pure translate keyframes trace an
   ellipse around the bee center (0,0), so transform-box/origin are irrelevant. */
.spec-orb {
  fill: var(--bee-color);
  stroke: #fff7d6;
  stroke-width: 1;
  filter: drop-shadow(0 0 5px var(--bee-color));
  animation-name: var(--spec-orb-anim, none);
  animation-duration: 2.6s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
@keyframes spec-orb-orbit {
  0%    { transform: translate(0px, -52px); }
  12.5% { transform: translate(32.5px, -43.8px); }
  25%   { transform: translate(46px, -24px); }
  37.5% { transform: translate(32.5px, -4.2px); }
  50%   { transform: translate(0px, 4px); }
  62.5% { transform: translate(-32.5px, -4.2px); }
  75%   { transform: translate(-46px, -24px); }
  87.5% { transform: translate(-32.5px, -43.8px); }
  100%  { transform: translate(0px, -52px); }
}

/* expert-coder — weld sparks: a cluster of particles by the hands that twinkle
   on staggered delays so sparks read as emitted occasionally, not in unison. */
.spec-spark {
  fill: #ffe08a;
  filter: drop-shadow(0 0 3px #ffd23d);
  transform-box: fill-box;
  transform-origin: center;
  animation-name: var(--spec-spark-anim, none);
  animation-duration: 0.9s;
  animation-timing-function: ease-out;
  animation-iteration-count: infinite;
}
.spec-spark:nth-of-type(1) { animation-delay: 0s; }
.spec-spark:nth-of-type(2) { animation-delay: 0.18s; }
.spec-spark:nth-of-type(3) { animation-delay: 0.42s; }
.spec-spark:nth-of-type(4) { animation-delay: 0.6s; }
.spec-spark:nth-of-type(5) { animation-delay: 0.33s; }
.spec-spark-core { fill: #fff4c2; filter: drop-shadow(0 0 4px #ffd23d); animation-delay: 0.1s; }
@keyframes spec-spark-flash {
  0%, 100% { opacity: 0; transform: scale(0.3); }
  20% { opacity: 1; transform: scale(1.3); }
  60% { opacity: 0; transform: scale(0.6); }
}

/* web-researcher — data scroll: text lines scan up/down inside the clipped panel
   window. `alternate` ping-pongs so the loop is seamless (no reset jump). */
.spec-scroll-panel {
  fill: rgba(160, 106, 255, 0.14);
  stroke: var(--bee-color);
  stroke-width: 1.2;
  stroke-linejoin: round;
}
.spec-scroll-line {
  fill: var(--bee-color);
  opacity: 0.85;
}
.spec-scroll-lines {
  animation-name: var(--spec-scroll-anim, none);
  animation-duration: 2.6s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}
@keyframes spec-scroll-flow {
  from { transform: translateY(2px); }
  to { transform: translateY(-14px); }
}

/* medium-coder — the existing gear accessory spins in place while working. The
   inner .gear-spin group rotates around its bbox center (the gear center). */
.gear-spin {
  transform-box: fill-box;
  transform-origin: center;
  animation-name: var(--gear-spin-anim, none);
  animation-duration: 3s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
@keyframes spec-gear-spin {
  to { transform: rotate(360deg); }
}

/* offline-gemma4 — the existing terminal accessory's lines blink/extend in
   sequence (steps), like a terminal printing rows. transform-origin at the left
   edge so scaleX "types" each line rightward. Staggered so rows update in turn. */
.term-line {
  transform-box: fill-box;
  transform-origin: 0 50%;
  animation-name: var(--term-anim, none);
  animation-duration: 1.4s;
  animation-timing-function: steps(2, end);
  animation-iteration-count: infinite;
}
.term-line:nth-of-type(1) { animation-delay: 0s; }
.term-line:nth-of-type(2) { animation-delay: 0.25s; }
.term-line:nth-of-type(3) { animation-delay: 0.5s; }
@keyframes spec-term-blink {
  0%   { opacity: 0.3; transform: scaleX(0.5); }
  35%  { opacity: 1;   transform: scaleX(1); }
  70%  { opacity: 0.6; transform: scaleX(0.8); }
  100% { opacity: 1;   transform: scaleX(1); }
}

/* --- Specialist action overlays (task-0027 v3) -----------------------------
   Arms are now drawn in absolute bee-local coords. Each has a FIXED upper-arm
   line (shoulder→elbow, never moves) and an ANIMATED inner group (forearm+hand).
   Arms start at x=±26, clearly outside the body ellipse (edge ≈ ±21.5 at y=10).
   Motion direction: PRESS DOWN (translateY +) = working; LIFT UP = idle frame.
   Speed tuned to character: cbeezy slow/boss, expert hammer rhythm, medium typing
   cadence, web-researcher pensive trace, gemma frantic blur. */

/* Fixed upper-arm line segments: shoulder → elbow, always anchored to body. */
.spec-arm {
  fill: none;
  stroke: var(--bee-color);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.9;
}

/* Elbow joint dot: moves with the animated forearm group, making the arm
   look like it's articulating at the joint rather than snapping. */
.spec-elbow {
  fill: var(--bee-color);
  opacity: 0.75;
}

/* Hand/fingertip at arm end: filled circle in bee color with subtle glow. */
.spec-hand-tip {
  fill: var(--bee-color);
  opacity: 0.92;
  filter: drop-shadow(0 0 3px var(--bee-color));
}

/* Fingertip circles (medium-coder + gemma): ride along with their forearm group. */
.spec-finger,
.spec-finger-l,
.spec-finger-r {
  fill: var(--bee-color);
  opacity: 0.9;
  filter: drop-shadow(0 0 2px var(--bee-color));
}

/* Hammer hardware styles (expert-coder). */
.spec-hammer-head {
  fill: #c7ccd6;
  stroke: #7c828f;
  stroke-width: 0.8;
  stroke-linejoin: round;
}
.spec-hammer-handle {
  fill: none;
  stroke: #8c8c9a;
  stroke-width: 2;
  stroke-linecap: round;
}

/* cbeezy — LEFT cmd forearm tip: slow deliberate boss tap, presses DOWN to desk (y=40). */
.spec-cmd-forearm {
  animation-name: var(--spec-hand-anim, none);
  animation-duration: 1.1s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-delay: 0s;
}
/* cbeezy — RIGHT cmd forearm: same tap, staggered (half-cycle) — boss reviews both sides. */
.spec-cmd-forearm-r {
  animation-name: var(--spec-hand-anim, none);
  animation-duration: 1.1s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-delay: 0.55s;
}

/* web-researcher — read forearm tip: pensive slow trace, presses DOWN. */
.spec-read-forearm {
  animation-name: var(--spec-hand-anim, none);
  animation-duration: 1.7s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}

/* Shared keyframe: tip at rest hovers just above desk, presses DOWN to surface then lifts.
   +5px lands the hand at the desk surface (y=40 for cbeezy, panel for researcher). */
@keyframes spec-hand-tap {
  0%, 100% { transform: translateY(0); }
  35%      { transform: translateY(5px); }
  45%      { transform: translateY(5px); } /* brief dwell at surface */
}

/* expert-coder — hammer forearm: raised → SLAM into workbench (y=46) → raised.
   Hammer head rect at y=30-39 at rest. -12 lifts to y=18-27; +9 drives to y=39-48,
   burying into workbench surface at y=46 — visible dramatic impact. */
.spec-hammer-forearm {
  animation-name: var(--spec-hammer-anim, none);
  animation-duration: 0.50s;
  animation-timing-function: ease-in;
  animation-iteration-count: infinite;
}
@keyframes spec-hammer-strike {
  0%, 20%   { transform: translateY(-12px); }        /* raised (backswing) */
  48%, 58%  { transform: translateY(9px); }          /* SLAMMED — buries into workbench */
  82%, 100% { transform: translateY(-12px); }        /* raised again */
}

/* medium-coder — forearm L (left presses first) and R (offset: alternates).
   Fingers rest just above desk (y=44). +6px drives them to y=50, past desk (y=48) — expressive. */
.spec-forearm-l {
  animation-name: var(--spec-type-anim, none);
  animation-duration: 0.46s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-delay: 0s;
}
.spec-forearm-r {
  animation-name: var(--spec-type-anim, none);
  animation-duration: 0.46s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-delay: 0.23s; /* half-cycle: R presses when L lifts */
}
@keyframes spec-arm-type {
  0%, 100% { transform: translateY(0); }
  30%      { transform: translateY(6px); } /* fingers hit keyboard */
  45%      { transform: translateY(6px); } /* brief dwell */
}

/* offline-gemma4 — both forearms blaze at max speed, perfectly alternating.
   Fingers rest at y=44. +6px hammers to y=50 into terminal keyboard zone at y=44-50. */
.spec-forearm-hack-l {
  animation-name: var(--spec-hack-anim, none);
  animation-duration: 0.22s;
  animation-timing-function: ease-in;
  animation-iteration-count: infinite;
  animation-delay: 0s;
}
.spec-forearm-hack-r {
  animation-name: var(--spec-hack-anim, none);
  animation-duration: 0.22s;
  animation-timing-function: ease-in;
  animation-iteration-count: infinite;
  animation-delay: 0.11s; /* exact half-cycle: perfect alternating blur */
}
@keyframes spec-arm-hack {
  0%, 100% { transform: translateY(0); }
  35%      { transform: translateY(6px); }
}

/* --- Bored gags (task-0026, design doc §7.4) -----------------------------
   When a bored bee fidgets, office.js (syncBoredGags) picks one of four gags
   every 8–14s and plays it once (≤800ms). Reaching the bee's inner parts (wings,
   antenna, sprite) across the <use> shadow boundary uses the SAME inherited-
   custom-property mechanism as the state machine: office.js sets a gag variable
   on the .bee wrapper for the gag's duration, and a global selector on the inner
   element reads it. The wrapper transform itself is never CSS-animated (that
   would clobber the migration translate); whole-bee motion animates .bee-sprite,
   which composes with the wrapper. office.js clears the variable when the gag
   ends, so the element falls back to its idle/state animation cleanly. */

/* Gag 1 — pollen-ball toss. office.js spawns a .pollen <circle> at the bee
   center inside #particles; this one-shot keyframe arcs it into the cell-wall
   receptacle (.pollen-nook) where it plops and fades. The landing offset MUST
   match POLLEN_NOOK in office.svg.js. */
.pollen {
  fill: #ffcf4d;
  filter: drop-shadow(0 0 4px #ffcf4d);
  transform-box: fill-box;
  transform-origin: center;
  pointer-events: none;
  animation: gag-pollen-toss 0.8s ease-in 1 forwards;
}
@keyframes gag-pollen-toss {
  0%   { transform: translate(0, 0) scale(0.6); opacity: 0; }
  12%  { opacity: 1; }
  45%  { transform: translate(20px, -34px) scale(1); }      /* tossed up + over */
  85%  { transform: translate(30px, 104px) scale(1); opacity: 1; } /* into the nook */
  92%  { transform: translate(30px, 110px) scale(1.25, 0.8); }     /* plop squash */
  100% { transform: translate(30px, 104px) scale(0.9); opacity: 0; }
}
/* Subtle receptacle on the cell wall (server-rendered by buildHexCells). */
.pollen-nook {
  fill: rgba(190, 234, 255, 0.05);
  stroke: rgba(190, 234, 255, 0.28);
  stroke-width: 1.2;
  stroke-linejoin: round;
  pointer-events: none;
}

/* Gag 2 — antenna polish. office.js sets --antenna-anim/--antenna-dur on the
   wrapper; this rule on the (shadow-cloned) antennae reads them and wiggles both
   around their base. Inert until a gag sets the variable. */
.bee-antenna {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation-name: var(--antenna-anim, none);
  animation-duration: var(--antenna-dur, 0s);
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}
@keyframes gag-antenna-polish {
  0%, 100% { transform: rotate(0deg); }
  20% { transform: rotate(-14deg); }
  40% { transform: rotate(10deg); }
  60% { transform: rotate(-12deg); }
  80% { transform: rotate(8deg); }
}

/* Gag 3 — lazy buzz circle: the whole sprite drifts one slow loop, replacing the
   hover bob for the gag (both animate .bee-sprite's transform). Driven by
   --sprite-anim/--sprite-dur, read by the .bee-sprite rule above. */
@keyframes gag-buzz-circle {
  0%, 100% { transform: translate(0, 0); }
  25% { transform: translate(9px, -7px); }
  50% { transform: translate(0, -15px); }
  75% { transform: translate(-9px, -7px); }
}

/* Gag 4 — wing stretch: wings extend wide, hold ~400ms, retract. Reuses the
   existing --wing-anim/--wing-dur buzz hooks — office.js just points them at this
   keyframe for ~700ms, then restores the buzz. */
@keyframes gag-wing-stretch {
  0% { transform: scaleX(1); }
  25% { transform: scaleX(1.7); }
  82% { transform: scaleX(1.7); }
  100% { transform: scaleX(1); }
}

/* --- Z particles (cartoon sleep, design doc §7) --- */
/* Three glyphs per sleeping bee (zzz-0 = small z, zzz-1 = medium z, zzz-2 = big Z).
   They drift diagonally up-right in sequence, growing as they rise — classic 😴.
   Structure (see buildHexCells): each .zzz is a <g> translated to its start
   position; the ANIMATED element is the inner <text>. Animating the <g> instead
   would override its translate attribute and snap every glyph to the SVG origin.
   The wrapping <g class="cell"> scopes the sibling selectors so one sleeping cell
   never lights up another cell's glyphs.
   Inherited text styling (fill/font) lives on .zzz; the per-size and animation
   rules target the <text> child. */
.zzz {
  fill: #bfeaff;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-style: italic;
  font-weight: 700;
  pointer-events: none;
}
.zzz text {
  opacity: 0;
  /* Keyframe offsets are relative to the wrapping <g>'s origin (the bee). */
  transform-origin: 0 0;
}
.zzz-0 text { font-size: 14px; }
.zzz-1 text { font-size: 20px; }
.zzz-2 text { font-size: 28px; }

/* Activate on sleeping — sibling selectors (scoped within .cell) reach each glyph;
   staggered delays give the rising z-z-Z cadence. */
.hex-cell[data-state="sleeping"] ~ .zzz-0 text { animation: z-drift 5s ease-in-out 0s   infinite; }
.hex-cell[data-state="sleeping"] ~ .zzz-1 text { animation: z-drift 5s ease-in-out 1.5s infinite; }
.hex-cell[data-state="sleeping"] ~ .zzz-2 text { animation: z-drift 5s ease-in-out 3s   infinite; }

/* Each glyph fades in near the bee, drifts up-right in a slight arc, then fades out. */
@keyframes z-drift {
  0%   { opacity: 0;    transform: translate(0, 0)      scale(0.6); }
  12%  { opacity: 0.85; }
  50%  { opacity: 0.6;  transform: translate(12px, -44px) scale(1.0); }
  75%  { opacity: 0;    transform: translate(20px, -70px) scale(1.2); }
  100% { opacity: 0;    transform: translate(20px, -70px) scale(1.2); }
}

/* --- Trading-manager mood animations (task-0064) ---------------------------
   Mood classes are applied to .bee[data-bee="trading-manager"] by office.js.
   All overrides use inherited CSS custom properties only — never descendant
   selectors that try to reach inside the <use> shadow DOM. The keyframes below
   animate .bee-sprite (composes with the per-bee wrapper translate/scale). */

.bee[data-bee="trading-manager"].mood-scanning {
  --wing-dur: 0.22s;
  --wing-flex: 0.55;
  --float-dur: 3s;
  --float-dist: 3px;
}
.bee[data-bee="trading-manager"].mood-fired-up-green {
  --wing-dur: 0.06s;
  --wing-flex: 0.25;
  --float-dist: 7px;
  --sprite-anim: trade-fired-up-bounce;
  --sprite-dur: 0.5s;
  filter: brightness(1.3) drop-shadow(0 0 8px #22c55e);
}
.bee[data-bee="trading-manager"].mood-fired-up-red {
  --wing-dur: 0.08s;
  --wing-flex: 0.3;
  --float-dist: 5px;
  --sprite-anim: trade-stress-shake;
  --sprite-dur: 0.18s;
  filter: brightness(1.1) drop-shadow(0 0 6px #ef4444);
}
.bee[data-bee="trading-manager"].mood-reporting {
  --wing-dur: 0.05s;
  --wing-flex: 0.2;
  --sprite-anim: bee-work-buzz;
  --sprite-dur: 0.45s;
}
.bee[data-bee="trading-manager"].mood-closed {
  --wing-anim: none;
  --float-dist: 0px;
  opacity: 0.45;
}

@keyframes trade-fired-up-bounce {
  0%, 100% { transform: translateY(0px); }
  40% { transform: translateY(-6px); }
  70% { transform: translateY(-3px); }
}
@keyframes trade-stress-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-3px); }
  50% { transform: translateX(3px); }
  80% { transform: translateX(-2px); }
}

/* On small screens, pull the legend out of its bottom-right overlay and let it
   flow below the hive as a horizontal wrap row (Joey wants it visible, not
   hidden). overflow:visible keeps the aspect-ratio-constrained stage from
   clipping the legend that now flows past its bottom edge. */
@media (max-width: 600px) {
  .hive-stage { overflow: visible; }
  .hud-legend {
    position: static;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 0.8rem;
    padding: 0.5rem 0.75rem;
    margin: 0.5rem auto 0;
    max-width: 100%;
  }
  .hud-clock { font-size: 0.7rem; padding: 0.3rem 0.4rem; }
}

/* --- Hover wave + tooltip (bee interaction) ---------------------------------
   Hovering a bee adds `.hovering` to its wrapper <g>. Inherited CSS custom
   properties cross the <use> shadow boundary exactly like the state machine:
   --wing-dur/flex drive an excited fast pump ("waving") and --sprite-anim swaps
   the idle hover bob for a cheerful bounce. office.js also shows a chat bubble. */

.bee.hovering {
  --wing-dur: 0.15s;
  --wing-flex: 0.10;          /* very wide pump = enthusiastic wave */
  --sprite-anim: bee-wave-bob;
  --sprite-dur: 0.35s;
}

@keyframes bee-wave-bob {
  0%   { transform: translateY(0); }
  25%  { transform: translateY(-11px); }
  55%  { transform: translateY(-5px); }
  75%  { transform: translateY(-10px); }
  100% { transform: translateY(0); }
}

/* Speech-bubble tooltip — absolutely positioned over .hive-stage. */
.bee-tooltip {
  position: absolute;
  pointer-events: none;
  z-index: 10;
  transform: translate(-50%, calc(-100% - 16px));
  white-space: nowrap;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.78rem;
  /* Fade in */
  animation: tooltip-appear 0.15s ease forwards;
}

@keyframes tooltip-appear {
  from { opacity: 0; transform: translate(-50%, calc(-100% - 22px)); }
  to   { opacity: 1; transform: translate(-50%, calc(-100% - 16px)); }
}

.bee-tooltip-bubble {
  background: rgba(8, 11, 20, 0.94);
  border: 1px solid var(--accent);
  border-radius: 8px;
  padding: 0.45rem 0.7rem;
  box-shadow: 0 0 16px rgba(40, 224, 255, 0.22);
  backdrop-filter: blur(4px);
  position: relative;
}

/* Downward arrow pointing toward the bee */
.bee-tooltip-bubble::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -7px;
  transform: translateX(-50%);
  border-left: 7px solid transparent;
  border-right: 7px solid transparent;
  border-top: 7px solid var(--accent);
}

.bee-tooltip-hi {
  margin: 0 0 0.18rem;
  color: var(--text, #e0e4ef);
  line-height: 1.3;
}

.bee-tooltip-hi strong {
  color: var(--accent);
}

.bee-tooltip-activity {
  margin: 0;
  color: var(--text-dim, #7a8ba5);
  font-size: 0.7rem;
}

/* Accessibility + a hard CPU floor: honor reduced-motion by stopping every
   keyframe loop (design doc §11). */
@media (prefers-reduced-motion: reduce) {
  .bee-sprite,
  .bee-wing-l,
  .bee-wing-r,
  .bee-antenna,
  .pollen,
  .hex-cell,
  .beam,
  .zzz text,
  .spec-orb,
  .spec-spark,
  .spec-scroll-lines,
  .gear-spin,
  .term-line,
  .term-cursor,
  .di-cursor,
  .chart-bar,
  .bolt-body,
  .spec-cmd-forearm,
  .spec-cmd-forearm-r,
  .spec-hammer-forearm,
  .spec-forearm-l,
  .spec-forearm-r,
  .spec-read-forearm,
  .spec-forearm-hack-l,
  .spec-forearm-hack-r,
  .bee-tooltip {
    animation: none !important;
  }
}
