/* GENERATED by make_mapcss.py from ../style.css. Do not hand-edit.

   The walk map's own rules, lifted away from the demo page's chrome so the
   renderer can be mounted inside the flight page without two stylesheets
   fighting over `body`. Self-sufficient: every var() a .wm- rule needs is
   declared inside .wm-root.

   The flight page is light, so it sets data-theme="light" and the renderer
   builds with `.wm-light` already on its root. */

body.wm-page-light {
  --page-bg:#f5f6f8; --page-fg:#1d232b; --page-dim:#68717e; --page-line:#e2e6eb;
  --page-card:#fff; --page-accent:#1a73e8;
  --good:#16a34a; --bad:#dc2626;
}
/* ---- classes the renderer emits that the visualizer never styled ---------------------
   .pill and .pill.ok/.bad are written by paintStatus; in the live tool .pill.ok simply did
   not exist, so a delivered run and a failed one looked identical. */
.pill {
  display:inline-block; padding:2px 9px; border-radius:100px; font-size: 14px; font-weight:650;
  letter-spacing:.02em; border:1px solid currentColor;
}
.pill.ok { color:var(--good); }
.pill.bad { color:var(--bad); }
.act { color:var(--ui-dim); font-style:italic; }
.loading { color:var(--page-dim); padding:20px; }
/* ==========================================================================
   nyc_geo walk map (v2). Tokens from WALKMAP_RENDER_SPEC.md section 2.1.
   No fill is written at a call site: the renderer only ever emits var(--token),
   so the shell's theme toggle drives the map for free.
   ========================================================================== */
.wm-root {
--ui-bg:#0b0e13; --ui-card:#12171f; --ui-line:#212a36; --ui-text:#e6edf5;
  --ui-dim:#8b97a8; --ui-accent:#4aa8ff;

  --ground:#0e1218; --beyond:#141b25;
  --block:#19202a;
  --bldg:#222c39; --bldg-2:#2a3648; --bldg-3:#354357; --bldg-lit:#46596f;
  --bldg-line:#0e1218; --bldg-shadow:#05080c; --bldg-hi:#8fb3d8;
  /* roof vocabulary */
  --roof:#2c3949; --roof-line:#18202b; --roof-glass:#3d5a74;
  --roof-accent:#4a6e8e; --roof-plant:#1e2733; --roof-well:#151c26;
  --roof-tank:#3a3026; --roof-tank-sh:#0d1116;
  --road:#28313f; --road-major:#323d4d; --road-casing:#141a22; --road-text:#7d8b9e;
  --water:#0d2029; --water-2:#123040; --water-line:#1e4356;
  --park:#16301f; --park-line:#1f4429;
  --struct:#1f2733; --struct-line:#2b3542; --struct-text:#7b8a9d;
  --label:#d5dee9; --label-dim:#8d9aab; --halo:#0e1218;

  --route:#38ccec; --route-ghost:#2a6f83;
  /* The IDEAL route is green and dotted; the WALKED route is blue and solid.
     It was drawn in --route-ghost, a desaturated blue, which read as a faded
     version of the walked path rather than as a different thing. */
  --optimal:#6ddf8e;
  /* The clear-map route needs to READ as a second route, not as a faded label.
     It borrowed --label-dim, a text colour tuned to sit back, and washed out
     against the roads. Warm amber-white: distinct from the green ideal and the
     blue walked path, bright enough to follow, still visibly secondary. */
  --optimal-clear:#e8c07a;
  /* The whole errand route is drawn in a darker leaf green as context, and only the
     leg currently being walked is lit in the bright --optimal. Both legs bright at
     once gave no clue which one the walker is actually on. */
  --optimal-dim:#2f7a48;
  --belief:#f0b429; --dest:#7ee787; --closed:#ef5f5f; --wrong:#ff7a7a;
  --shadow:0 1px 2px rgba(0,0,0,.5);
  /* category colours: a 12 px pin dot is the only place `cat` may appear (spec 2.2).
     These sat AFTER a stray closing brace, so they were orphaned declarations outside any
     rule: the parser discarded them and every var(--cat-*) in the dark map resolved to
     nothing. The light override below was fine, which is why only dark pins were wrong. */
  --cat-landmark:#c39bf0; --cat-transit:#8ab4f8; --cat-hotel:#e08bbd;
  --cat-food:#f0a15a;     --cat-health:#7fc8d6; --cat-park:#7ec98a;
  --cat-civic:#9fb4c9;    --glyph-shade:rgba(0,0,0,.45);
}
.wm-root.wm-light {
  --cat-landmark:#7c4dbd; --cat-transit:#2f6fd0; --cat-hotel:#b8548e;
  --cat-food:#c26a1c;     --cat-health:#2a8fa3; --cat-park:#2e8b45;
  --cat-civic:#5b6f85;    --glyph-shade:rgba(255,255,255,.55);
--ui-bg:#f5f6f8; --ui-card:#fff; --ui-line:#e2e6eb; --ui-text:#1d232b;
  --ui-dim:#68717e; --ui-accent:#1a73e8;

  --ground:#f2efe8; --beyond:#dcd7c9;
  --block:#e9e4d8;
  --bldg:#ded5c3; --bldg-2:#d1c7b1; --bldg-3:#c2b69c; --bldg-lit:#efe3c2;
  --bldg-line:#f2efe8; --bldg-shadow:#8d7f66; --bldg-hi:#fffdf5;
  --roof:#e3dbca; --roof-line:#bcb19b; --roof-glass:#b9cbd8;
  --roof-accent:#c9b78f; --roof-plant:#cec4ad; --roof-well:#c6bca6;
  --roof-tank:#a68e69; --roof-tank-sh:#b6a98f;
  --road:#fff; --road-major:#fff; --road-casing:#e0d9c9; --road-text:#8a9099;
  --water:#cfe1ea; --water-2:#bad5e3; --water-line:#a5c5d6;
  --park:#cfe0bc; --park-line:#b6cf9f;
  --struct:#ded8c8; --struct-line:#cec6b2; --struct-text:#8a8477;
  --label:#252b33; --label-dim:#6b7480; --halo:#fffdf8;

  --route:#0e8fc4; --route-ghost:#a7d3e6;
  --optimal:#1f9d4d; --optimal-clear:#b0761b; --optimal-dim:#9ccfaf;
  --belief:#b47c00; --dest:#2e8b40; --closed:#d33a3a; --wrong:#c93636;
  --shadow:0 1px 2px rgba(0,0,0,.13);
}
.wm-root { display:flex; flex-direction:column; gap:8px; }
.wm-bar { display:flex; gap:6px; align-items:center; flex-wrap:wrap; }
.wm-tile { font:inherit; font-size: 14px; padding:5px 11px; border-radius:8px; cursor:pointer;
  border:1px solid var(--ui-line); background:var(--ui-card); color:var(--ui-text); }
.wm-tile:hover { border-color:var(--ui-dim); }
.wm-tile.on { background:var(--route); border-color:var(--route); color:#04222c; font-weight:650; }
.wm-sep { width:1px; height:20px; background:var(--ui-line); margin:0 3px; }
.wm-grow { flex:1; }
.wm-chip { font-size: 14px; color:var(--ui-dim); font-variant-numeric:tabular-nums; }
.wm-stage { position:relative; border-radius:10px; overflow:hidden; background:var(--ground); }
.wm-svg { display:block; width:100%; aspect-ratio:16/10; max-height:62vh; cursor:grab; }
.wm-svg.drag { cursor:grabbing; }
.wm-scale { position:absolute; left:10px; bottom:10px; font-size: 14px; color:var(--label-dim);
  background:color-mix(in srgb, var(--ground) 72%, transparent); padding:3px 7px;
  border-radius:6px; display:flex; align-items:center; gap:6px; }
.wm-sbtrack { height:4px; border:1px solid var(--label-dim); border-top:none; }
.wm-status { color:var(--label); line-height:1.45; }
/* laid out below the map, see wm-over */
.wm-status b { color:var(--label); }
.wm-legend { display:flex; gap:12px; flex-wrap:wrap; font-size: 14px; color:var(--ui-dim); }
.wm-legend span { display:flex; align-items:center; gap:5px; }
.wm-legend i { width:11px; height:11px; border-radius:3px; display:inline-block; }
.wm-rail { display:flex; gap:6px; flex-wrap:wrap; }
.wm-say { font-size: 14px; color:var(--ui-dim); }
/* Step scrubber: walk the route without playing the call. Every stop is a real event from the
   trace, so stepping never invents a position the run did not visit. */
.wm-steps { display:flex; gap:6px; align-items:center; flex-wrap:wrap; }
.wm-range { flex:1; min-width:160px; accent-color:var(--route); }
/* ---- walk map: controls overlaid on the stage, status below it ------------------------
   The control row and the status read-out both used to eat the picture: the row took a band
   of height above the map and left white margins at the sides, and the status floated over
   the top-right corner, hiding several blocks of the very map it was describing. */
/* ONE panel behind the tiles rather than a translucent pill per tile. Individually-glassed
   buttons floating over the map picked up whatever was underneath them, so their colour shifted
   as the map moved and they read as debris. A single thin bar that hugs the row is stable, and
   the tiles inside it can drop their own backgrounds entirely. */
.wm-bar.wm-over { position:absolute; left:10px; top:10px; z-index:3; width:auto; right:auto;
  display:inline-flex; gap:2px; align-items:center; padding:4px;
  border-radius:10px;
  background:color-mix(in srgb, var(--ui-card) 88%, transparent);
  border:1px solid color-mix(in srgb, var(--ui-line) 85%, transparent);
  backdrop-filter:blur(10px) saturate(1.2); -webkit-backdrop-filter:blur(10px) saturate(1.2);
  box-shadow:0 2px 10px rgba(0,0,0,.28); }
.wm-bar.wm-over .wm-tile {
  background:transparent; border-color:transparent; box-shadow:none; }
.wm-bar.wm-over .wm-tile:hover {
  background:color-mix(in srgb, var(--ui-text) 12%, transparent); }
.wm-bar.wm-over .wm-tile.on {
  background:var(--ui-accent); border-color:transparent; }
.wm-bar.wm-over .wm-sep { width:1px; height:18px; margin:0 4px;
  background:color-mix(in srgb, var(--ui-line) 90%, transparent); }
.wm-over-chip { position:absolute; right:10px; bottom:34px; z-index:3;
  background:color-mix(in srgb, var(--ui-card) 72%, transparent);
  backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
  border-radius:7px; padding:3px 8px; }
/* The status line sits BETWEEN the map and the transport controls, and its text changes as the
   timeline moves - pills appear, "copilot belief diverges" comes and goes, per-leg counts grow
   a digit. Each reflow between one line and two moved the Play button 23px down the page, so
   the control you are aiming at shifted under the cursor mid-playback. Reserve two lines'
   worth up front: the row is allowed to fill, never to resize. */
.wm-status { position:static; max-width:none; margin:8px 0 0; display:flex; flex-wrap:wrap;
  gap:6px 16px; align-items:center; font-size: 14px;
  min-height:52px; align-content:flex-start; }
/* Same reasoning for the spoken line: it is one line of live transcript and must not push the
   rail below it around as the wording changes. */
.wm-say { min-height:19px; }
/* The re-centre tile carries the navigation glyph, so it reads as a map control rather than a
   checkbox. Filled when engaged, hollow when the view has been panned away from the walker. */
/* The re-centre control: a round glyph button floating on the map next to the scale bar, the
   convention every map application uses. Filled crosshair when engaged, hollow when the view
   has been panned away from the walker. */
.wm-locate { position:absolute; left:10px; bottom:34px; z-index:3;
  width:38px; height:38px; padding:0; border-radius:50%; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  background:color-mix(in srgb, var(--ui-card) 88%, transparent);
  border:1px solid color-mix(in srgb, var(--ui-line) 85%, transparent);
  backdrop-filter:blur(10px) saturate(1.2); -webkit-backdrop-filter:blur(10px) saturate(1.2);
  box-shadow:0 2px 10px rgba(0,0,0,.28); color:var(--ui-dim); }
.wm-locate:hover { color:var(--ui-text); }
.wm-locate.on { color:var(--ui-accent); }
.wm-locate svg { width:20px; height:20px; }
.wm-locate svg circle:first-of-type { fill:currentColor; }
.wm-locate svg circle:last-of-type { stroke:currentColor; stroke-width:1.7; }
.wm-locate svg path { stroke:currentColor; stroke-width:1.9; stroke-linecap:round; }
.wm-locate:not(.on) svg circle:first-of-type { fill:none; stroke:currentColor;
  stroke-width:1.7; }
/* Theme tile: glyph first, label after, matching the shell's own sun/moon button. The glyph
   carries the meaning and the label is the affordance, so the label is allowed to sit back. */
.wm-tile .wm-tlabel { margin-left:6px; }
/* Glyph-only tiles keep the row compact: the icon carries the meaning, the title carries the
   words for anyone who needs them. */
.wm-tile.wm-glyph { min-width:34px; padding-left:8px; padding-right:8px; font-size:14px; }
/* Leg 2 of a two-leg errand: the half of the walk the copilot only learns about mid-call.
   Violet reads as clearly distinct from the blue walked path without competing with the amber
   belief marker or the green ideal route. */
.wm-root { --leg2:#b98cff; }
.wm-root.wm-light { --leg2:#7a3fd0; }
/* ---- demo overrides -----------------------------------------------------------------
   The visualizer boxes the map into a 16:10 strip capped at 62vh, because there it shares
   a scrolling column with speech lanes, an audio player and two metric cards. Here the map
   IS the page, so it takes the whole column instead. */
.wm-root { flex:1 1 auto; min-height:0; gap:6px; }
.wm-stage { flex:1 1 auto; min-height:0; }
.wm-svg { width:100%; height:100%; aspect-ratio:auto; max-height:none; }
/* The status strip reserves two lines in the visualizer so the transport below it cannot
   shift under the cursor mid-playback. Same reasoning applies here and the read-out is
   shorter, so one line is enough. */
.wm-status { min-height:26px; margin:4px 0 0; }
/* ---- voice rail ---------------------------------------------------------------------
   Hidden by default. The silent map is the page; the transcript is what you open when
   somebody asks what was actually said. It takes width from the map rather than height,
   because the map loses far less by being narrower than by being shorter. */
.wm-body { display:flex; flex:1 1 auto; min-height:0; gap:8px; }
.wm-body > .wm-stage { flex:1 1 auto; min-width:0; }
.wm-rail { flex:0 0 clamp(280px, 27vw, 420px); display:flex; flex-direction:column;
  min-height:0; border:1px solid var(--ui-line); border-radius:10px;
  background:var(--ui-card); overflow:hidden; }
.wm-rail[hidden] { display:none; }
.wm-rail-head { padding:8px 10px; border-bottom:1px solid var(--ui-line);
  display:flex; flex-direction:column; gap:6px; }
.wm-rail-head > span:first-child { font-size: 14px; font-weight:650; color:var(--ui-text);
  letter-spacing:.02em; }
.wm-rail-head audio { width:100%; height:32px; }
.wm-rail-note { font-size: 14px; color:var(--ui-dim); }
.wm-utts { flex:1 1 auto; min-height:0; overflow-y:auto; padding:6px; scroll-behavior:smooth; }
.wm-utt { display:grid; grid-template-columns:38px 56px 1fr; gap:6px; align-items:baseline;
  padding:5px 6px; border-radius:6px; cursor:pointer; font-size: 14px; line-height:1.4;
  color:var(--ui-dim); border:1px solid transparent; }
.wm-utt:hover { background:color-mix(in srgb, var(--ui-accent) 9%, transparent); }
.wm-utt-t { font-variant-numeric:tabular-nums; font-size: 14px; opacity:.7; }
.wm-utt-w { font-size: 14px; font-weight:650; letter-spacing:.02em; }
.wm-utt.u .wm-utt-w { color:var(--route); }
.wm-utt.a .wm-utt-w { color:var(--ui-accent); }
.wm-utt.on { color:var(--ui-text); background:color-mix(in srgb, var(--ui-accent) 15%, transparent);
  border-color:color-mix(in srgb, var(--ui-accent) 45%, transparent); }
.wm-tile[disabled] { opacity:.4; cursor:not-allowed; }
/* ---- voice mode: a different mode, not a layer -----------------------------------------
   The walk transport steps aside and the call transport takes its place, because there are
   no "steps" in a recording, there is a clock. */
.wm-call { display:none; gap:6px; align-items:center; flex-wrap:wrap; }
.wm-root.wm-voice .wm-call { display:flex; }
/* The walk transport and the call transport are alternatives, never both. */
.wm-root.wm-voice .wm-steps { display:none; }
.wm-call .wm-chip { font-variant-numeric:tabular-nums; }
.wm-tl { display:flex; gap:8px; align-items:stretch; margin-top:2px; }
.wm-tl[hidden] { display:none; }
.wm-tl-keys { flex:0 0 62px; display:flex; flex-direction:column; justify-content:center;
  gap:20px; padding-top:15px; font-size: 14px; letter-spacing:.03em; color:var(--ui-dim); }
.wm-tl-keys .k-agent { color:var(--ui-accent); font-weight:650; }
.wm-tl-keys .k-user { color:var(--route);     font-weight:650; }
.wm-tl-stage { position:relative; flex:1 1 auto; min-width:0; cursor:pointer;
  border:1px solid var(--ui-line); border-radius:8px; overflow:hidden;
  background:var(--ground); }
.wm-tl-canvas { display:block; width:100%; }
.wm-tl-head { position:absolute; top:0; bottom:0; width:2px; margin-left:-1px;
  background:var(--label); box-shadow:0 0 6px rgba(0,0,0,.5); pointer-events:none; }
.wm-tl-head::before { content:""; position:absolute; top:0; left:-3px; width:8px; height:8px;
  border-radius:50%; background:var(--label); }
/* ---- compact: the gallery tile ---------------------------------------------------------
   Same instance, same walk, no furniture. Anything a viewer could press is hidden, so a tile
   cannot end up in a different state from the page it opens. */
.wm-root.wm-compact { gap:0; }
.wm-root.wm-compact .wm-bar,
.wm-root.wm-compact .wm-steps,
.wm-root.wm-compact .wm-status,
.wm-root.wm-compact .wm-legend,
.wm-root.wm-compact .wm-locate,
.wm-root.wm-compact .wm-scale,
.wm-root.wm-compact .wm-chip,
.wm-root.wm-compact .wm-rail,
.wm-root.wm-compact .wm-tl,
.wm-root.wm-compact .wm-call { display:none !important; }
.wm-root.wm-compact .wm-stage { border-radius:0; }
.wm-root.wm-compact .wm-svg { cursor:pointer; }
.tile-map .wm-root { flex:1 1 auto; min-height:0; }
/* The rail is a sibling of the map inside a flex row, so both need permission to shrink.
   Without min-width:0 the transport row's intrinsic width becomes the floor, the root grows
   past the viewport, and the rail's text runs off the right-hand edge of the page. */
#geo-board > .wm-root { flex:1 1 auto; min-width:0; max-width:100%; }
.wm-body { min-width:0; }
.wm-steps, .wm-call { min-width:0; }
.wm-utt-x { overflow-wrap:anywhere; }
/* Grid items default to min-width:auto, so a long unbroken utterance pushes the 1fr column
   past the rail instead of wrapping inside it. */
.wm-utt { min-width:0; }
.wm-utt-x { min-width:0; }
.wm-utts { overflow-x:hidden; }
/* The visualizer's own .wm-rail (its directions list) is copied in above and sets
   flex-wrap:wrap with a gap. Inherited by this rail, a wrapping COLUMN flex breaks the head
   and the transcript into two side-by-side columns, which is what pushed the text off the
   right edge of the page. Same class name, different component: reset both. */
.wm-rail { min-width:0; max-width:100%; flex-wrap:nowrap; gap:0; }
.pmap .wm-root { flex:1 1 auto; min-width:0; min-height:0; }


/* Focus. This sheet is extracted from the walk renderer's own styles, which carried none,
   so every control in the overlay fell back to the browser's default ring: visible, but
   inconsistent with the 2px ring the rest of the page uses. */
.wm-root :focus-visible {
  outline: 2px solid var(--ink, #17171f);
  outline-offset: 2px;
  border-radius: 4px;
}
.wm-tile:focus-visible, .wm-locate:focus-visible { outline-offset: 3px; }


/* Compact hides the timeline, the rail and the call transport, because a looping walk in a
   tile has no use for them. Voice mode does: it is the whole reason the tile has a play
   button. When both classes are on, voice wins - it is the more specific state. */
.wm-root.wm-compact.wm-voice .wm-tl { display: flex !important; }
.wm-root.wm-compact.wm-voice .wm-rail { display: block !important; }
.wm-root.wm-compact.wm-voice .wm-call { display: flex !important; }
.wm-root.wm-compact.wm-voice .wm-tl[hidden],
.wm-root.wm-compact.wm-voice .wm-rail[hidden],
.wm-root.wm-compact.wm-voice .wm-call[hidden] { display: none !important; }
