/* ════════════════════════════════════════════════════════════════════
   CANVASS PRO · mobilenav.css
   The mobile-app shell: a native-feeling bottom tab bar (mobile), a slim
   left rail (desktop), the rapid-knock FAB, and the full-bleed map class.
   Turns the instrument into a thing you OPEN, not a page you scroll.

   TOKEN LAW: every color, space, radius, and motion value is a CSS variable
   from ../assets/tokens.css. Raw hex here is a defect. The one field color
   (the armed disposition hue on the FAB, the live-cell hue) arrives at
   runtime as --c via inline style from mobilenav.js, never written here.
   No em-dashes. Mobile-first; degrades to a desktop rail. Everything
   respects prefers-reduced-motion (the spring becomes an instant flip).
   ════════════════════════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════════════════════════
   0 · THE ROOT · a fixed shell chrome the integrator mounts into #mobileNav
   On mobile it is the bottom bar; on desktop it becomes a left rail. It
   never shows until the module marks it ready (so SSR/first-paint is clean).
   ════════════════════════════════════════════════════════════════════ */
.mobilenav {
  /* --mn-h (bar height) and --mn-rail-w (rail width) live at :root in
     app.css 16.0, the single source, so the page clearances below and the
     bar itself always read the same values. */
  --mn-glyph: 23px;                 /* tab glyph box */
  font-family: var(--body);
}
.mobilenav[hidden] { display: none; }

/* ════════════════════════════════════════════════════════════════════
   1 · MOBILE · the bottom tab bar (the SalesRabbit structural move)
   A fixed bar, safe-area padded, blurred header glass, hairline top edge.
   It owns the bottom edge; the integrator pads .view/.sheet/.map-foot so
   the map and sheets sit above it.
   ════════════════════════════════════════════════════════════════════ */
.mn-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 1185;
  display: flex; align-items: stretch; justify-content: space-around;
  height: calc(var(--mn-h) + env(safe-area-inset-bottom));
  padding: 0 4px env(safe-area-inset-bottom);
  background: var(--header-bg);
  -webkit-backdrop-filter: saturate(160%) blur(16px);
  backdrop-filter: saturate(160%) blur(16px);
  border-top: 1px solid var(--line);
  box-shadow: var(--e3);
}

/* a single tab · big thumb target, glyph over a mono micro-label */
.mn-tab {
  position: relative; flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; padding: 7px 2px 4px; background: none; border: none;
  color: var(--plat-faint); -webkit-tap-highlight-color: transparent;
  transition: color var(--m-fast) var(--ease);
}
.mn-tab:hover { color: var(--plat-dim); }
.mn-glyph {
  position: relative; width: var(--mn-glyph); height: var(--mn-glyph);
  display: flex; align-items: center; justify-content: center; line-height: 0;
  border-radius: var(--r-chip);
  transition: transform var(--m-pulse) var(--ease-spring),
              background var(--m-fast) var(--ease), box-shadow var(--m-fast) var(--ease);
}
.mn-glyph svg { display: block; width: 100%; height: 100%; }
.mn-lab {
  font-family: var(--mono); font-size: 8.5px; letter-spacing: .1em;
  text-transform: uppercase; line-height: 1;
}

/* ── active state · platinum glyph + label, a warm tint behind the glyph,
      an ember dot that springs in ── */
.mn-tab.on { color: var(--platinum); }
.mn-tab.on .mn-glyph {
  transform: translateY(-1px);
  background: var(--tint-active);
  box-shadow: var(--e-inset);
}
/* the indicator: a small ember pip riding under the active glyph */
.mn-ind {
  position: absolute; left: 50%; top: 2px; width: 5px; height: 5px;
  margin-left: -2.5px; border-radius: 50%; background: var(--ember);
  opacity: 0; transform: scale(0);
  transition: opacity var(--m-fast) var(--ease), transform var(--m-pulse) var(--ease-spring);
}
.mn-tab.on .mn-ind {
  opacity: 1; transform: scale(1);
  box-shadow: 0 0 0 3px var(--tint-ember);
}

/* press feel · a hardware tap that settles */
.mn-tab:active .mn-glyph { transform: scale(.9); }

/* ── the unread badge · an ember pip with a count, pulses once on bump ── */
.mn-badge {
  position: absolute; top: 3px; left: 50%; margin-left: 5px;
  min-width: 15px; height: 15px; padding: 0 4px; box-sizing: border-box;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-size: 9px; font-weight: 600; line-height: 1;
  color: var(--ember-ink); background: var(--ember);
  border: 1.5px solid var(--header-bg); border-radius: var(--r-pill);
  font-variant-numeric: tabular-nums;
}
.mn-badge[hidden] { display: none; }
.mn-badge.mn-bump { animation: mnBadgePop var(--m-pulse) var(--ease-spring); }
@keyframes mnBadgePop {
  0% { transform: scale(.4); } 60% { transform: scale(1.25); } 100% { transform: scale(1); }
}

/* a live dot on a tab glyph (storms streaming) · a quiet amber heartbeat */
.mn-live {
  position: absolute; top: 1px; right: -1px; width: 7px; height: 7px;
  border-radius: 50%; background: var(--c, var(--amber));
  border: 1.5px solid var(--header-bg);
}
.mn-live[hidden] { display: none; }
/* the beat is a compositor-cheap ::after ring (transform + opacity, the
   mnFabPulse pattern), never an animated box-shadow over the blurred bar */
.mn-tab.mn-hot .mn-live::after {
  content: ""; position: absolute; inset: -2px; border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--c, var(--amber)) 55%, transparent);
  animation: mnLiveBeat 1.6s var(--ease) infinite; pointer-events: none;
}
@keyframes mnLiveBeat {
  0% { transform: scale(.64); opacity: 1; }
  70% { transform: scale(1.55); opacity: 0; }
  100% { transform: scale(1.55); opacity: 0; }
}

/* the You tab carries the rep coin instead of a stroke glyph */
.mn-coin {
  width: var(--mn-glyph); height: var(--mn-glyph); border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font: 700 9.5px var(--mono); letter-spacing: .02em;
  color: var(--platinum); background: color-mix(in srgb, var(--c, var(--plat-faint)) 26%, var(--graphite));
  border: 1.5px solid color-mix(in srgb, var(--c, var(--plat-faint)) 55%, var(--line-hi));
}
.mn-tab.on .mn-coin { border-color: var(--c, var(--ember)); }

/* ════════════════════════════════════════════════════════════════════
   2 · THE RAPID-KNOCK FAB · one-thumb knock, knock, knock
   Floats above the bar, bottom-right, thumb-reachable. Ember-ringed.
   When rapid is armed it carries the armed disposition color (--c inline)
   and pulses subtly (an active instrument, not a toy).
   ════════════════════════════════════════════════════════════════════ */
.mn-fab {
  position: fixed; right: 16px; z-index: 1186;
  bottom: calc(var(--mn-h) + env(safe-area-inset-bottom) + 16px);
  width: 56px; height: 56px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--grad-ember); color: var(--ember-ink);
  border: none; box-shadow: var(--e4), var(--e-ember);
  transition: transform var(--m-pulse) var(--ease-spring), box-shadow var(--m-fast) var(--ease);
}
.mn-fab svg { display: block; width: 25px; height: 25px; }
.mn-fab:active { transform: scale(.92); }
.mn-fab[hidden] { display: none; }

/* the armed read · a tinted ring in the armed disposition color, a soft
   pulse that says "every tap is a knock". The ring lives only while armed. */
.mn-fab.mn-armed {
  background: var(--c, var(--ember));
  color: var(--pin-ink, var(--platinum));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--c, var(--ember)) 30%, transparent), var(--e4);
}
.mn-fab.mn-armed::after {
  content: ""; position: absolute; inset: -3px; border-radius: 50%;
  border: 2px solid var(--c, var(--ember)); opacity: .7;
  animation: mnFabPulse 2s var(--ease) infinite; pointer-events: none;
}
@keyframes mnFabPulse {
  0% { transform: scale(1); opacity: .7; }
  70% { transform: scale(1.28); opacity: 0; }
  100% { opacity: 0; }
}
/* a small armed tick badge so the state reads even mid-pulse */
.mn-fab .mn-fab-tick {
  position: absolute; top: -2px; right: -2px; width: 14px; height: 14px;
  border-radius: 50%; background: var(--graphite); border: 1.5px solid var(--c, var(--ember));
  display: none;
}
.mn-fab.mn-armed .mn-fab-tick { display: block; }

/* ════════════════════════════════════════════════════════════════════
   3 · THE DESKTOP RAIL · the command console reads as a console
   On a wide viewport the bottom bar becomes a slim, fixed left rail of the
   same bespoke glyphs (icon + label). It is SECONDARY nav: the map command
   center (modes/storms/route/plan day) stays exactly as is. The FAB hides.
   ════════════════════════════════════════════════════════════════════ */
.mn-bar.mn-rail {
  left: 0; right: auto; top: 58px; bottom: 0;     /* sits under the 58px topbar */
  flex-direction: column; justify-content: flex-start;
  width: var(--mn-rail-w); height: auto; padding: 14px 0;
  gap: 4px;
  border-top: none; border-right: 1px solid var(--line);
  background: var(--graphite-2);
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.mn-rail .mn-tab {
  flex: 0 0 auto; gap: 5px; padding: 11px 4px;
  border-radius: var(--r-control); margin: 0 8px;
}
.mn-rail .mn-tab.on { background: var(--tint-active); }
/* on the rail the glyph stays flush in the tinted slot, no nested tier */
.mn-rail .mn-tab.on .mn-glyph { background: none; box-shadow: none; }
/* on the rail the active indicator becomes a left ember bar (console read) */
.mn-rail .mn-ind {
  left: -8px; top: 50%; width: 3px; height: 22px; margin: -11px 0 0;
  border-radius: var(--r-pill); box-shadow: none;
}
.mn-rail .mn-tab.on .mn-ind { transform: scaleY(1); box-shadow: none; }
.mn-rail .mn-ind { transform: scaleY(0); transform-origin: center; }
.mn-rail .mn-lab { font-size: 9px; }
.mn-rail .mn-badge { top: 6px; left: auto; right: 16px; margin-left: 0; }

/* ════════════════════════════════════════════════════════════════════
   4 · LAYOUT GLUE · the body classes the integrator toggles
   .mn-on-mobile  → the bottom bar is live; pad the bottom of the page so
                    content/sheets/the map foot clear the bar + FAB.
   .mn-on-desktop → the left rail is live; inset the main view by the rail.
   .mn-fullbleed  → (mobile) the map fills the viewport under the chrome.
   These live HERE (token-only) so the integrator only flips a class.
   ════════════════════════════════════════════════════════════════════ */

/* bottom clearance so the last controls + the map foot are never under the bar */
.mn-on-mobile .view {
  padding-bottom: calc(30px + var(--mn-h) + env(safe-area-inset-bottom));
}
/* the sheets already bottom-dock; lift their inner safe-area so the grab
   handle and primary action sit above the bar, not behind it */
.mn-on-mobile .sheet,
.mn-on-mobile .terr-panel {
  padding-bottom: calc(18px + var(--mn-h) + env(safe-area-inset-bottom));
}

/* the slim left rail insets the whole instrument on desktop */
@media (min-width: 721px) {
  .mn-on-desktop .view { padding-left: calc(18px + var(--mn-rail-w)); }
  .mn-on-desktop .topbar { padding-left: calc(18px + var(--mn-rail-w)); }
}

/* ── FULL-BLEED MAP (mobile, the map-first feel) ─────────────────────
   When the integrator adds .mn-fullbleed to <body> on a phone, the map
   stage fills the viewport between the topbar and the tab bar. The frame
   loses its card radius/border (it IS the screen now), and the map foot +
   legend tuck into the map's own readout. The rest of the chrome (HUD,
   toolbar, filters) still lives above it and scrolls. */
@media (max-width: 640px) {
  /* gated on .mn-on-mobile, and the phone topbar is 54px (app.css @640), not
     58px; the 641-720 band intentionally keeps the stacked (non-fullbleed)
     layout per app.css 16.9. The map fills the gap between the topbar and the
     tab bar; the Control Deck floats over its bottom edge. The .view gutter
     is 0 in the map-first read, so the stage needs no negative bleed. */
  .mn-fullbleed.mn-on-mobile .fieldmap {
    height: calc(100dvh - 54px - var(--mn-h) - env(safe-area-inset-bottom));
    border-radius: 0; border-left: none; border-right: none;
  }
  .mn-fullbleed.mn-on-mobile .map-stage { margin: 0; }
}

/* ════════════════════════════════════════════════════════════════════
   5 · REDUCED MOTION · the reward still registers, nothing springs
   ════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  .mn-glyph, .mn-ind, .mn-fab, .mn-tab:active .mn-glyph { transition: none; }
  .mn-tab.on .mn-ind { transform: scale(1); }
  .mn-rail .mn-tab.on .mn-ind { transform: scaleY(1); }
  .mn-badge.mn-bump,
  .mn-fab.mn-armed::after,
  .mn-tab.mn-hot .mn-live::after { animation: none; }
  .mn-fab.mn-armed::after { opacity: .5; transform: none; }
  .mn-tab.mn-hot .mn-live::after { content: none; }   /* the dot alone reads */
}

/* a focus ring that matches the instrument, never a glow */
.mn-tab:focus-visible,
.mn-fab:focus-visible { outline: 2px solid var(--ember-hi); outline-offset: 2px; }
