/* Plan Your Mailing — layout for the storefront's adaptation of the office mailing-map tool.
   Colours/radius reuse the site's tokens from style.css (--brand, --line, --radius, ...) so this
   reads as a storefront page, not the internal ops tool it's ported from. */

.mm-wrap input[type="checkbox"] { accent-color: var(--brand); }

.mm-wrap { max-width: none; padding: 0; }
.mm-wrap .wrap { max-width: 1180px; }
/* The databanner's .wrap container: fully collapse the generic .wrap padding (28px top /
   64px bottom — the bottom was showing as a grey band between the header and the map) so the
   row takes no space while the banner is empty; restore breathing room only when the banner
   actually has content to show. */
.mm-wrap > .wrap:first-child { padding-top: 0; padding-bottom: 0; }
.mm-wrap > .wrap:first-child:has(> :not(:empty)) { padding-top: 28px; padding-bottom: 16px; }

.mm-step1 { display: flex; flex-direction: column; }

.mm-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  margin-bottom: 16px; overflow: hidden;
}

.mm-card-header {
  padding: 12px 16px; border-bottom: 1px solid var(--line); font-weight: 700; font-size: 13px;
  color: var(--ink); display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.mm-card-header--split { flex-wrap: wrap; }
.mm-card-body { padding: 16px; font-size: 13px; color: var(--muted); }
.mm-card-body--flush { padding: 0; }

/* Full-bleed map: the map area spans the full viewport width regardless of the .wrap
   container around the rest of the page. */
.mm-map-full {
  position: relative; width: 100vw; margin-left: 50%; transform: translateX(-50%);
  /* Top border only — the map runs to the bottom of the window with nothing after it, so a
     bottom border has nothing to separate and its 1px is enough to start a page scroll. */
  border-top: 1px solid var(--line);
}
/* Leaflet numbers its panes up to 1000 (controls) while .leaflet-container itself has no
   z-index, so those numbers compete with the whole page instead of staying inside the map. A
   z-index here opens a stacking context: the map's internals still layer against each other,
   but the map as a whole becomes one layer the page can sit above. */
.leaflet-container { position: relative; z-index: 0; }

.mm-map-overlays {
  position: absolute; top: 14px; left: 16px; right: 16px; z-index: 500;
  display: flex; flex-direction: column; gap: 10px; pointer-events: none;
}
.mm-map-overlays > * { pointer-events: auto; }
/* ...but only the things that actually draw something. The rule above hands the pointer to the
   overlays' children, and the toolbar row is not a control — it is the GAP between two groups of
   them, stretched the full width of the map by justify-content: space-between. So a click
   anywhere across the top of the map landed on that gap instead of the map, and a polygon being
   drawn there simply would not take its next node. Same for the columns inside it that carry no
   surface of their own; the two cards keep the pointer, because they are surfaces. */
.mm-map-toolbar, .mm-map-toolbar-left, .mm-filter-bar, .mm-filter-chips { pointer-events: none; }
.mm-map-toolbar > *, .mm-map-toolbar-left > *,
.mm-filter-bar > *, .mm-filter-chips > * { pointer-events: auto; }

/* The Canada Post drop picker, sitting with the filter because it decides which walks exist to
   be filtered. Same card language as a filter chip so it reads as part of that column. */
.mm-cycle-bar {
  background: #fff; border: 1px solid #e5e7eb; border-radius: 8px; padding: 7px 10px;
  box-shadow: 0 1px 2px rgba(16,24,40,.05); pointer-events: auto; max-width: 230px;
}
/* Brand red, like the rest of the planner's own controls — this is a pricing decision, not a
   view option, so it should not read as neutral chrome. */
.mm-cycle-bar { border-left: 3px solid var(--brand, #BF2E1A); }
.mm-cycle-head {
  display: block; font-size: 9px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--brand, #BF2E1A); margin-bottom: 3px;
}
.mm-cycle-opts { display: flex; flex-direction: column; gap: 2px; }
.mm-cycle-opts label { display: flex; align-items: center; gap: 5px; font-size: 11px; color: #374151; cursor: pointer; }
.mm-cycle-opts input { margin: 0; accent-color: var(--brand, #BF2E1A); }
/* The chosen drop carries the colour too, so which one is live is readable at a glance rather
   than only from the radio. :has() is a progressive nicety — the accent above already says it. */
.mm-cycle-opts label:has(input:checked) { color: var(--brand, #BF2E1A); font-weight: 700; }
.mm-cycle-note { display: block; font-size: 9px; color: #9ca3af; font-style: italic; margin-top: 3px; }

/* Running filter-chip list — one chip per active filter type, each independently removable,
   plus a trailing "Add Map Filter" chip. Populated by updateFilterChips() in mailing-map.js. */
/* One card per active filter, stacked down the column rather than flowing across it, so the
   list grows toward empty map instead of toward the plan name on the other side. */
.mm-filter-chips { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.mm-filter-chips[hidden] { display: none; }
.mm-chip {
  display: inline-flex; align-items: center; gap: 12px;
  background: linear-gradient(to top, #ececec 0%, #fff 37.5%);
  border: none; border-radius: 10px; box-shadow: 0 0 4px rgba(0, 0, 0, .25);
  height: 28px; padding: 0 12px; font-size: 14px; font-weight: 500; color: #606060;
}
.mm-chip-label {
  background: none; border: none; padding: 0; margin: 0; font: inherit; color: inherit; cursor: pointer;
}
.mm-chip-label:hover { color: inherit; }
/* The × leads the chip, as in the design, and is the filled square icon rather than a typed
   character — masked so one file serves both its resting grey and the red it turns on hover. */
.mm-chip-x {
  flex: 0 0 auto; width: 16.25px; height: 16.25px; border: none; background-color: #606060;
  cursor: pointer; padding: 0; font-size: 0; line-height: 0;
  -webkit-mask: url('/public/images/map/shape.svg') center / contain no-repeat;
          mask: url('/public/images/map/shape.svg') center / contain no-repeat;
}
.mm-chip-x:hover { background-color: var(--brand); }

/* The map's floating chrome, from the nav_bar Figma (node 188:1240). One card treatment shared
   by every control that sits over the map, so they read as one family: a near-white vertical
   gradient, a 10px radius, and a tight ambient shadow rather than a drop shadow — the map moves
   under these, and a directional shadow makes them look stuck to it. */
.mm-card-surface {
  background: linear-gradient(to top, #ececec 0%, #fff 37.5%);
  border-radius: 10px;
  box-shadow: 0 0 4px rgba(0, 0, 0, .25);
}

/* The count banner stacks now rather than running across the top. Three products read as three
   rows far more naturally than as three columns, and stacked they leave the map's whole width
   free instead of a band across it. */
.mm-count-banner {
  display: flex; flex-direction: column; align-items: stretch; gap: 0;
  background: linear-gradient(to top, #ececec 0%, #fff 37.5%);
  border: 0; border-radius: 10px;
  padding: 10px 14px; box-shadow: 0 0 4px rgba(0, 0, 0, .25);
  min-width: 134px; max-width: 200px;
}
/* The product this number belongs to. Small and set in the brand red because it is a label, not
   a heading — it names the row without competing with the figure under it. */
.mm-count-banner-head {
  display: block; font-size: 10px; font-weight: 900; line-height: 1.3;
  letter-spacing: .02em; text-transform: uppercase; color: #961010;
  white-space: nowrap; margin-bottom: 1px;
}
.mm-count-banner-stat { display: flex; flex-direction: column; align-items: flex-start; gap: 0; }
.mm-count-banner-stat--main { flex-direction: column; align-items: flex-start; gap: 0; }
.mm-count-banner-stat-row { display: flex; align-items: baseline; gap: 10px; }
/* Clicking the count itself (not just the "Mail Plan Details" button) opens the same detail
   modal — see mm-count-banner-main-row/mm-count-banner-routes-row wiring in mailing-map.js. */
.mm-count-banner-clickable { cursor: pointer; margin: -4px -6px; padding: 4px 6px; border-radius: 6px; }
.mm-count-banner-clickable:hover { background: var(--brand-tint); }
.mm-count-banner-clickable:hover .mm-count-banner-value { color: var(--brand); }
/* Rules between rows now, not columns — the banner stacks. */
.mm-count-banner-stat--postal { padding-top: 8px; margin-top: 8px; border-top: 1px solid #d9d9d9; }
.mm-count-banner-stat--postal[hidden] { display: none; }
.mm-count-banner-stat--routes {
  flex-direction: column; align-items: flex-start; gap: 0;
  padding-top: 8px; margin-top: 8px; border-top: 1px solid #d9d9d9;
}
.mm-count-banner-stat--routes[hidden] { display: none; }
/* Hidden until hovering the neighbourhood-mail stat block, so the dwelling-type checkboxes
   don't clutter the banner at rest — they only matter once someone's looking at that count. */
/* The four dwelling types refine the Neighbourhood Mail count; they are not part of the card at
   rest. Hidden until the pointer is anywhere on the count banner, so the card reads as three
   numbers rather than three numbers and a form. This reverses an earlier call to pin them open
   for discoverability — the whole banner is the hover target rather than just the walk count,
   which is a wide enough surface that they are hard to miss once the mouse is near the numbers.
   focus-within keeps them reachable without a pointer at all. */
.mm-count-banner-type-filter {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; flex-wrap: nowrap;
  max-height: 0; opacity: 0; overflow: hidden; pointer-events: none; margin-top: 0;
  transition: max-height .18s ease, opacity .18s ease, margin-top .18s ease;
}
.mm-count-banner-type-filter[hidden] { display: none; }
.mm-count-banner:hover .mm-count-banner-type-filter,
.mm-count-banner:focus-within .mm-count-banner-type-filter {
  max-height: 120px; opacity: 1; pointer-events: auto; margin-top: 8px;
}
/* The reveal is a size change on a floating card — worth keeping, but not worth animating for
   anyone who has asked for less motion. */
@media (prefers-reduced-motion: reduce) {
  .mm-count-banner-type-filter { transition: none; }
}
.mm-count-banner-type-filter label {
  /* Matched to the sub-labels above them (10px) so the card reads as one type scale rather than
     three. The whole label is the hit target, so it stays comfortable to click at this size. */
  display: flex; align-items: center; gap: 6px; font-size: 10px; font-weight: 600;
  color: var(--muted); cursor: pointer;
}
.mm-count-banner-type-filter input { margin: 0; accent-color: var(--brand); }

/* The counts cut, revealed with the dwelling-type boxes because it answers the same shape of
   question — which delivery points am I paying for. Border and padding are applied only in the
   revealed state: the collapsed filter is max-height:0, so a permanent border would draw a
   stray rule across the card whenever the mouse is away. */
.mm-count-banner-cut { border-top: 0 solid #e5e7eb; padding-top: 0; }
.mm-count-banner:hover .mm-count-banner-cut,
.mm-count-banner:focus-within .mm-count-banner-cut {
  border-top-width: 1px; padding-top: 6px; margin-top: 8px;
}
.mm-count-banner-cut-head {
  font-size: 9px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: #9ca3af; margin-bottom: 1px;
}
/* Says what the choice above actually did, because "Consumers' Choice" is Canada Post's name
   for it and not self-explanatory to anyone who hasn't read their paperwork. */
.mm-count-banner-cut-note { font-size: 9px; color: #9ca3af; font-style: italic; margin-top: 1px; }

.mm-route-row--off { opacity: 0.45; }

.mm-basemap-toggle {
  background: var(--surface); color: var(--ink); border: 1px solid var(--line);
  border-radius: 8px; padding: 8px 12px; font-size: 12px; font-weight: 700; cursor: pointer;
  box-shadow: 0 2px 8px rgba(0,0,0,.12); margin: 0 10px 10px 0;
}
.mm-basemap-toggle:hover { border-color: var(--brand); color: var(--brand); }

/* Bump Leaflet's default 26x26 zoom buttons up to 36x36 to match the weight of the other
   bottom-right controls (Satellite toggle). Font-size/line-height scale with the box so the
   +/- glyphs stay centred rather than clipping or floating off-centre. */
.mm-map .leaflet-control-zoom a {
  width: 36px; height: 36px; line-height: 36px; font-size: 26px;
}

/* Both L.Control.Draw sub-toolbars (polygon/rectangle/circle, and edit/delete) hidden — see
   the comment above drawControl's setup in mailing-map.js for why removing them is safe: every
   action they offered is reachable elsewhere on the page. Elements stay in the DOM (not
   removed) since "Edit area" still forwards a real click to .leaflet-draw-edit-edit. */
.mm-map .leaflet-draw-toolbar { display: none; }

/* Standing FSA name inside each outline (renderFsaOutlines in mailing-map.js). Passing our own
   className to L.divIcon replaces Leaflet's default .leaflet-div-icon, so the white box and
   border it would otherwise draw are already gone — background/border are pinned to none
   anyway in case that default ever comes back. The white halo keeps the text readable over
   both the duotone basemap and the satellite imagery without needing a filled chip. */
.mm-fsa-label {
  background: none; border: none;
  font: 700 12px/16px -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  color: #1d4ed8; text-align: center; white-space: nowrap; pointer-events: none;
  text-shadow: 0 0 3px #fff, 0 0 3px #fff, 0 0 2px #fff;
}

/* Poll number inside each poll polygon (renderPollOutlines), in the same blue as the poll
   outlines. Smaller and lighter-weight than the FSA labels because a riding can hold well over
   a hundred polls — this has to stay legible without turning the riding into a wall of text. */
.mm-poll-label {
  background: none; border: none; pointer-events: none;
  display: flex; align-items: center; justify-content: center;
  font: 700 10px/12px -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  color: #1d4ed8; text-align: center; white-space: nowrap;
  text-shadow: 0 0 3px #fff, 0 0 3px #fff, 0 0 2px #fff;
}

/* Same idea for the ward / school-division overlays (createAreaPicker), in their own purple to
   match those outlines. Unlike a 3-character FSA these names wrap, so the icon box is a fixed
   size and centres its text both ways — that keeps a one-line and a two-line name sitting on
   the same point rather than drifting off it. */
.mm-area-label {
  background: none; border: none; pointer-events: none;
  display: flex; align-items: center; justify-content: center; text-align: center;
  font: 700 11px/13px -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  color: #6d28d9;
  text-shadow: 0 0 3px #fff, 0 0 3px #fff, 0 0 2px #fff;
}

/* Required tile-license credit (OSM/CARTO — see attributionControl.setPrefix(false) in
   mailing-map.js, which already drops the non-required "Leaflet" self-credit). Kept, just
   shrunk to a quiet corner note instead of Leaflet's default bar. */
.mm-map .leaflet-control-attribution {
  background: rgba(255,255,255,.7); font-size: 9px; padding: 1px 5px; line-height: 1.4;
  border-radius: 4px 0 0 0; box-shadow: none;
}
.mm-map .leaflet-control-attribution a { color: var(--muted); }

.mm-count-banner-value { font-size: 24px; font-weight: 900; color: #000; line-height: 1.15; white-space: nowrap; }
/* Wraps, unlike the figure above it: "addresses on 8 of 8 touched walks" is two lines in the
   design and truncating it would lose which of the two numbers is which. */
.mm-count-banner-label {
  font-size: 10px; font-weight: 400; color: #606060; line-height: 1.35; white-space: normal;
}
/* Stacked, so the figure sits above its description rather than beside it. */
.mm-count-banner-stat-row { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; }
.mm-count-banner--error .mm-count-banner-label { color: #991b1b; }
/* Bottom-centre map toolbar: the two actions for working with an already-drawn/selected
   area — adjust its shape, or switch between the two "what's inside it" views (unaddressed
   walks vs. individual civic addresses, which are mutually exclusive on the map — see
   hidePointsLayer/hideSelectLayer in mailing-map.js). Large and centred so it reads as the
   next step after drawing, not a buried option. */
/* One positioned container holding two stacked rows (filter bar on top, buttons below) —
   normal flex layout handles the stacking, so a row that wraps onto two lines on a narrow
   viewport pushes the other row down instead of overlapping it (the previous version used two
   independently `position: absolute` bars with a guessed pixel gap between them, which broke
   exactly that way). */
.mm-edit-toolbar {
  position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); z-index: 500;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  max-width: calc(100vw - 32px);
}
.mm-edit-toolbar[hidden] { display: none; }
.mm-edit-toolbar-buttons {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 12px;
  background: linear-gradient(to top, #ececec 0%, #fff 37.5%);
  border: 0; border-radius: 10px;
  padding: 8px 10px; box-shadow: 0 0 4px rgba(0, 0, 0, .25); max-width: 100%;
}
.mm-route-filter-bar {
  display: flex; align-items: center; justify-content: center; gap: 10px; flex-wrap: wrap;
  background: linear-gradient(to top, #ececec 0%, #fff 37.5%);
  border: 0; border-radius: 10px;
  padding: 8px 16px; box-shadow: 0 0 4px rgba(0, 0, 0, .25); max-width: 100%;
  font-size: 14px; font-weight: 700; color: #606060;
}
.mm-route-filter-bar[hidden] { display: none; }
/* Off until someone actually reaches for it: a fresh selection books every touched walk
   whatever its coverage, and a slider reading "50%" while nothing is being filtered claims
   otherwise. Greyed, deliberately NOT disabled — the click that turns it on has to land. */
.mm-route-filter-bar.is-off, .mm-routes-pct-row.is-off { opacity: .45; }
.mm-route-filter-bar.is-off:hover, .mm-routes-pct-row.is-off:hover { opacity: .7; }
.mm-route-filter-bar.is-off, .mm-route-filter-bar.is-off input[type="range"],
.mm-routes-pct-row.is-off, .mm-routes-pct-row.is-off input[type="range"] { cursor: pointer; }
.mm-route-filter-bar input[type="range"] { width: 140px; margin: 0; }
.mm-route-filter-bar button {
  background: var(--surface); color: var(--ink); border: 1px solid var(--line);
  border-radius: 7px; padding: 6px 12px; font-size: 12px; font-weight: 700; cursor: pointer;
}
.mm-route-filter-bar button:hover { border-color: var(--brand); color: var(--brand); }
.mm-edit-toolbar-btn {
  background: linear-gradient(to top, #f5f5f5 0%, #fff 37.5%);
  color: #606060; border: 1px solid #a2a2a2;
  border-radius: 10px; padding: 0 20px; height: 44px; font-size: 14px; font-weight: 500;
  cursor: pointer; white-space: nowrap;
}
.mm-edit-toolbar-btn:hover { border-color: var(--brand); color: var(--brand); }
.mm-edit-toolbar-btn:disabled { opacity: .4; cursor: not-allowed; }
.mm-edit-toolbar-btn:disabled:hover { border-color: var(--line); color: var(--ink); }
/* The Select: switcher is one unit -- label, segment and its trailing divider hide together,
   so a toolbar with no selectable conflict shows no orphaned label or stray rule. */
.mm-edit-toolbar-select { display: inline-flex; align-items: center; gap: 12px; }
.mm-edit-toolbar-select[hidden] { display: none; }
.mm-edit-toolbar-divider { width: 1px; align-self: stretch; background: var(--line); }
/* The view switcher. Named in the design ("VIEW: Addresses | Postal Codes | Routes") because
   three unlabelled pills next to an "Edit area" button read as three more actions rather than
   three states of one thing. */
.mm-edit-toolbar-view-label {
  font-size: 14px; font-weight: 900; color: #961010; letter-spacing: .02em;
  text-transform: uppercase; white-space: nowrap; align-self: center;
}
.mm-edit-toolbar-segment {
  display: flex; border: 1px solid #9c9c9c; border-radius: 10px; overflow: hidden;
}
/* height fixed rather than left to padding+line-height: <label> and <button> render at
   different intrinsic heights for the same padding/font (browser default UA box-model
   differs between them), so the shorter one's background used to fall short of the
   segment's full height, leaving a strip of the segment's own background showing below
   its text. */
.mm-edit-toolbar-segment label, .mm-edit-toolbar-segment button {
  display: flex; align-items: center; justify-content: center; gap: 6px; height: 44px; box-sizing: border-box;
  background: linear-gradient(to top, #f5f5f5 0%, #fff 37.5%);
  color: #606060; border: none; border-left: 1px solid #9c9c9c;
  padding: 0 18px; font-size: 14px; font-weight: 500; cursor: pointer; white-space: nowrap;
  /* style.css sets a global `label { margin-bottom: 6px }` for form fields — that extra margin
     was still counting toward this flex item's contribution to the row's cross-size even
     though the label itself was already the fixed 45px height above, which is what was
     actually inflating the segment 6px past its own children. */
  margin: 0;
}
.mm-edit-toolbar-segment label:first-child, .mm-edit-toolbar-segment button:first-child {
  border-left: none; border-radius: 8px 0 0 8px;
}
.mm-edit-toolbar-segment label:last-child, .mm-edit-toolbar-segment button:last-child {
  border-radius: 0 8px 8px 0;
}
/* Flat, not gradient: the selected view is the one control on the map that should read as
   pressed rather than as another raised surface. */
.mm-edit-toolbar-segment label:has(input:checked),
.mm-edit-toolbar-segment button[data-on] {
  background: #961010; color: #fff; font-weight: 700;
}
/* The checkbox stays in the DOM (mailing-map.js reads/sets .checked, and the label's
   :has(input:checked) rule above needs it) but is visually hidden — the pill's own
   background/text colour already carries the on/off state, same as the Addresses button
   next to it, so a visible checkbox square was redundant. */
.mm-edit-toolbar-segment input { position: absolute; opacity: 0; width: 0; height: 0; margin: 0; }
.mm-edit-toolbar-segment label[hidden], .mm-edit-toolbar-segment button[hidden] { display: none; }

/* Leaflet.draw's own Save/Cancel links (shown while dragging a shape's vertices, entered via
   "Edit area") default to tiny 11px text tucked next to the top-left toolbar icon — easy to
   miss entirely. Reposition them into the same large floating bar our own bottom toolbar uses
   (which EDITSTART/EDITSTOP in mailing-map.js hides/shows in its place), so the controls that
   matter while editing sit prominently over the map instead of in a corner. !important because
   leaflet.draw.css sets position/sizing directly on these classes and loads after this file. */
.leaflet-draw-actions {
  /* No `display` override here on purpose — Leaflet.draw toggles this element's own inline
     `display: block`/`none` to show/hide it, and an !important display here would win over
     that and force it permanently visible. Only position/appearance are overridden. */
  position: fixed !important; left: 50% !important; top: auto !important; right: auto !important;
  bottom: 20px !important; transform: translateX(-50%); z-index: 600 !important;
  text-align: center; background: none !important; border: none !important;
  white-space: nowrap;
}
.leaflet-draw-actions li { display: inline-block !important; float: none !important; margin: 0 5px; }
.leaflet-draw-actions a {
  display: block !important; height: auto !important; line-height: normal !important;
  padding: 14px 26px !important; font: 700 14px/1.2 -apple-system, system-ui, sans-serif !important;
  border-radius: 9px !important; border: none !important;
  box-shadow: 0 6px 24px rgba(0,0,0,.25) !important;
}
.leaflet-draw-actions li:first-child a { background: var(--brand) !important; color: #fff !important; }
.leaflet-draw-actions li:first-child a:hover { background: var(--brand-dark) !important; }
.leaflet-draw-actions li:last-child a { background: var(--surface) !important; color: var(--ink) !important; }
.leaflet-draw-actions li:last-child a:hover { background: #f3f4f6 !important; }

/* Numbered badge for a coordinate multiple addresses collapse onto — see drawPoints() in
   mailing-map.js. Leaflet's divIcon container carries no default sizing of its own. */
.mm-point-stack-dot {
  background: var(--brand); color: #fff; font-weight: 700; font-size: 10px;
  text-align: center; border-radius: 50%; box-shadow: 0 0 0 2px rgba(255,255,255,.75);
  white-space: nowrap;
}

/* Postal-code labels — see drawPostalCodes() in mailing-map.js. A label, not a pin: a postal
   code is an area, and a pin would claim a precision the data hasn't got. Leaflet sizes a
   divIcon from its content when iconSize is null, so the width has to come from the box itself.
   Pointer events off so labels never swallow a click meant for the map underneath. */
.mm-postal-label {
  display: flex !important; align-items: center; gap: 5px;
  width: max-content !important; padding: 2px 6px;
  background: rgba(255,255,255,.92); border: 1px solid rgba(0,0,0,.14); border-radius: 5px;
  box-shadow: 0 1px 3px rgba(0,0,0,.18);
  font-size: 10.5px; line-height: 14px; white-space: nowrap;
  pointer-events: none;
  /* Leaflet anchors a null-sized divIcon at its top-left; shift it so the label sits centred
     over the coordinate it belongs to rather than hanging down and to the right of it. */
  transform: translate(-50%, -50%);
}
.mm-postal-code { font-weight: 700; color: var(--ink); letter-spacing: .02em; }
.mm-postal-n { color: var(--brand); font-weight: 700; }
.mm-postal-n::before { content: '\00b7\00a0'; color: rgba(0,0,0,.3); font-weight: 400; }

.mm-map-toolbar {
  /* Both columns start at the top of the map. Centred, the right-hand column floated down by
     half the count banner's height — fine when that banner was a short horizontal strip, wrong
     now it is a tall stacked card, which left Save/PDF/Close hanging in the middle of the map. */
  display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; flex-wrap: wrap;
}
/* Two stacked rows, not one long one: the plan's name reads as a title over the actions that
   act on it, and moving "Add Map Filter" to the left column left this side short enough to
   stack without crowding the count banner opposite. */
/* Name and actions live in one card at the top of the map — the updated nav_bar frame
   (250:2406). Its geometry is the design's, and it adds up exactly: 13 top + 38 name + 12 gap
   + 36 pill + 9 bottom = the 108px the card is drawn at. */
.mm-map-toolbar-right {
  display: flex; flex-direction: column; align-items: flex-end; gap: 12px;
  background: linear-gradient(to top, #ececec 0%, #fff 37.5%);
  border-radius: 10px; box-shadow: 0 0 4px rgba(0, 0, 0, .25);
  padding: 13px 18px 9px; box-sizing: border-box;
  width: 277px; max-width: 100%;
}
/* One pill holding all three actions, as the design has it — three separate cards read as three
   unrelated controls that happen to be adjacent. The card lives on this container and the
   buttons inside it are plain text, so the group reads as one object with three labels. */
/* Actions as a line of text, not a second pill. The card is already the surface; a pill inside
   it was a surface on a surface, and at five actions it could not fit the narrower card without
   clipping. Pipe-separated and right-aligned under the name, so the two read as one block. */
.mm-map-toolbar-actions {
  display: flex; align-items: center; gap: 0; justify-content: flex-end;
  background: none; border-radius: 0; box-shadow: none;
}
/* Dividers, not content: aria-hidden in the markup so a screen reader hears five actions
   rather than "Save pipe Open pipe". */
.mm-toolbar-sep { color: #c0c0c0; font-size: 12px; user-select: none; }

/* The filter controls sit to the RIGHT of the count banner they change, not beneath it: the
   banner is a tall stacked card now, and a row underneath it pushed the chooser far enough
   down the map to read as unrelated to the numbers it drives. Column, so filters stack
   vertically as they are added. */
.mm-map-toolbar-left { display: flex; align-items: flex-start; gap: 14px; }
.mm-filter-bar { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }

/* Mail plan name — reads as a heading sitting on the map until you click into it, at which
   point it takes on the same card treatment as the buttons beside it so it's obviously an
   editable field. Sized in ch so a long name grows the box instead of scrolling inside it,
   with a max so it can't crowd the buttons. */
.mm-plan-name {
  /* Sized in px, and allowed to shrink ahead of the buttons (flex-shrink 1 against their 0).
     `ch` on an 800-weight face measured far wider than expected — the field came out ~306px
     and squeezed "Add Map Filter" until its label wrapped onto three lines. */
  /* Stretches to the width of the button row beneath it, so the name reads as a heading over
     those actions rather than a stray field floating beside them. */
  align-self: stretch; min-width: 7ch; width: auto;
  background: transparent; border: 1px solid transparent; border-radius: 8px;
  padding: 9px 10px; font-size: 15px; font-weight: 800; color: var(--ink);
  text-align: right; text-overflow: ellipsis; cursor: pointer;
}
/* The buttons keep their labels on one line and give up no width to the name field. */
.mm-map-toolbar-right .mm-filter-btn { flex: 0 0 auto; white-space: nowrap; }

/* SAVE / PDF / CLOSE. Inside the pill the buttons carry no surface of their own — the pill is
   the surface — so they are small, uppercase and red, reading as the map's own actions rather
   than as page furniture. */
.mm-map-toolbar-actions .mm-filter-btn {
  font-size: 12px; font-weight: 400; letter-spacing: 0; text-transform: none;
  color: #606060; height: auto; padding: 0 3px;
  background: none; border: 0; border-radius: 0; box-shadow: none;
}
/* The close control is a word now, not a glyph, so it must not keep the square button shape. */
.mm-map-toolbar-actions .mm-close-btn { width: auto; min-width: 0; aspect-ratio: auto; font-size: 12px; }
/* Underline on hover rather than a filled block: there is no button surface here to fill. */
.mm-map-toolbar-actions .mm-filter-btn:hover {
  background: none; color: #111; text-decoration: underline;
}
.mm-plan-name::placeholder { color: var(--muted); font-weight: 700; opacity: 1; }
.mm-plan-name:hover { border-color: var(--line); background: rgba(255,255,255,.75); }
.mm-plan-name:focus {
  outline: none; cursor: text; text-align: left;
  background: var(--surface); border-color: var(--brand);
  box-shadow: 0 2px 8px rgba(0,0,0,.12);
}
.mm-filter-btn {
  background: var(--surface); color: var(--ink); border: 1px solid var(--line);
  border-radius: 8px; padding: 10px 14px; font-size: 13px; font-weight: 700; cursor: pointer;
  box-shadow: 0 2px 8px rgba(0,0,0,.12);
}
.mm-filter-btn:hover { border-color: var(--brand); color: var(--brand); }
/* The chooser, per Figma 202:1514/202:1516: the same card as everything else floating on the
   map, Inter Black in brand red, with the filled plus square leading it. Masked like the chip's
   ×, so the icon takes its colour from the button rather than needing a second asset. */
#mm-filter-btn {
  display: inline-flex; align-items: center; gap: 12px; height: 36px; padding: 0 12px;
  background: linear-gradient(to top, #ececec 0%, #fff 37.5%);
  border: none; border-radius: 10px; box-shadow: 0 0 4px rgba(0, 0, 0, .25);
  font-size: 14px; font-weight: 900; letter-spacing: .02em; text-transform: uppercase;
  color: #961010; white-space: nowrap;
}
/* Same hover as Save/PDF/Close: a 7% brand wash and a darker red label. Stacked as a second
   gradient layer rather than replacing `background`, because these two carry the card's own
   gradient on themselves — the action buttons get to use a flat colour only because their card
   belongs to the pill wrapped around them. */
#mm-filter-btn:hover, .mm-chip:hover {
  background:
    linear-gradient(rgba(150, 16, 16, .07), rgba(150, 16, 16, .07)),
    linear-gradient(to top, #ececec 0%, #fff 37.5%);
  color: #7d0d0d;
}
.mm-chip:hover .mm-chip-x { background-color: #7d0d0d; }
.mm-filter-btn-icon {
  flex: 0 0 auto; width: 20.8px; height: 20.8px; background-color: currentColor;
  -webkit-mask: url('/public/images/map/add-filter.svg') center / contain no-repeat;
          mask: url('/public/images/map/add-filter.svg') center / contain no-repeat;
}
/* Square, so the × reads as a window control beside the two labelled actions rather than a
   third thing to do to the plan. */
.mm-close-btn { padding: 8px 12px; font-size: 18px; line-height: 1; font-weight: 700; }
.mm-close-btn:hover { border-color: var(--brand); color: var(--brand); }

/* Pulsing ring while no filter is applied — with nothing selected the page is just a map, and
   this is the one button that starts a plan. Toggled by updateFilterChips() in mailing-map.js,
   which already computes exactly that condition. The ring is an extra box-shadow layer rather
   than an outline/border so it can't shift the button's size or nudge the toolbar's layout.
   The base shadow is repeated in every keyframe because animating box-shadow replaces the
   property outright, and dropping it would make the button flicker flat on each cycle. */
@keyframes mm-filter-nudge {
  0%   { box-shadow: 0 0 4px rgba(0,0,0,.25), 0 0 0 0 rgba(191, 46, 26, .55); }
  70%  { box-shadow: 0 0 4px rgba(0,0,0,.25), 0 0 0 11px rgba(191, 46, 26, 0); }
  100% { box-shadow: 0 0 4px rgba(0,0,0,.25), 0 0 0 0 rgba(191, 46, 26, 0); }
}
.mm-filter-btn--nudge {
  border-color: var(--brand); color: var(--brand);
  animation: mm-filter-nudge 1.9s ease-out infinite;
}
/* Anything vestibular-triggering is opt-out: keep the emphasis, drop the motion. */
@media (prefers-reduced-motion: reduce) {
  .mm-filter-btn--nudge {
    animation: none;
    box-shadow: 0 0 4px rgba(0,0,0,.25), 0 0 0 3px rgba(191, 46, 26, .35);
  }
}
.mm-plan-btn { background: var(--brand); color: #fff; border-color: var(--brand); }
.mm-plan-btn:hover { background: var(--brand-dark); border-color: var(--brand-dark); color: #fff; }
/* Duotone retint (defs live in mailing-map.ejs as an inline SVG <filter>) — brand red in the
   shadows, warm yellow in the highlights, preserving whatever light/dark contrast the source
   tiles already had rather than crushing it the way the earlier sepia/hue-rotate attempt did. */
.mm-tile-branded {
  filter: url(#mm-map-duotone);
}
/* Toggled on #mm-map by setHover() in mailing-map.js whenever a route line is hovered (on the
   map or via its row in the table below) — signals the line under the pointer is clickable. */
.mm-map.mm-walk-hover .leaflet-interactive { cursor: pointer; }

/* Delivery route tooltip — translucent panel, but the route name and delivery-point figures
   stay fully opaque, so the map shows through without costing legibility. That's why the
   see-through lives here as a background alpha and NOT as Leaflet's own tooltip `opacity`
   option (which fades the text along with the panel; bindTooltip passes opacity: 1).
   Qualified with .leaflet-tooltip purely to win on specificity: leaflet.css is linked AFTER
   this file in mailing-map.ejs, so its `.leaflet-tooltip { background: #fff }` beat a bare
   `.mm-walk-tip` rule at equal specificity and the transparency never actually applied. */
.leaflet-tooltip.mm-walk-tip { background: rgba(255, 255, 255, 0.6); }
.leaflet-tooltip.mm-walk-tip::before { display: none; }

.mm-map { height: 560px; width: 100%; }
.mm-map--full { height: 78vh; min-height: 460px; }

/* Filter map by / Mail Plan Details: popups */
.mm-modal-overlay {
  position: fixed; inset: 0; z-index: 1000; background: rgba(17,17,17,.45);
  display: flex; align-items: flex-start; justify-content: center; padding: 90px 16px 16px;
  overflow-y: auto;
}
.mm-modal-overlay[hidden] { display: none; }
.mm-modal {
  background: var(--surface); border-radius: var(--radius); width: 100%; max-width: 420px;
  box-shadow: 0 20px 60px rgba(0,0,0,.35); overflow: hidden;
}
/* Wide enough for the two plan columns side by side; still capped by the overlay's own padding
   on smaller screens, where .mm-plan-grid drops back to one column. */
.mm-modal--wide { max-width: 1040px; }
.mm-modal-header {
  padding: 14px 16px; border-bottom: 1px solid var(--line); font-weight: 700; font-size: 14px;
  color: var(--ink); display: flex; align-items: center; justify-content: space-between;
}
/* Filter map by only — its header sits directly above the icon-tile grid/detail panel with no
   separating rule; Mail Plan Details keeps the divider above. */
#mm-filter-modal .mm-modal-header { border-bottom: none; }
.mm-modal-close {
  background: none; border: none; font-size: 20px; line-height: 1; color: var(--muted);
  cursor: pointer; padding: 2px 4px;
}
.mm-modal-close:hover { color: var(--ink); }
.mm-modal-header-left { display: flex; align-items: center; gap: 10px; }
.mm-modal-back {
  background: none; border: none; font-size: 16px; line-height: 1; color: var(--muted);
  cursor: pointer; padding: 2px 4px;
}
.mm-modal-back:hover { color: var(--brand); }
.mm-modal-back[hidden] { display: none; }
.mm-modal-body { padding: 16px; max-height: calc(100vh - 180px); overflow-y: auto; }

/* Filter-method switcher: 3x2 grid of icon tiles (Figma nav_bar, node 166:9). */
.mm-methods {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 16px;
}
/* `display: grid` above beats the UA stylesheet's `[hidden] { display: none }` on specificity,
   so toggling the `hidden` attribute alone silently did nothing — this reasserts it. */
.mm-methods[hidden] { display: none; }
/* Icon row is a fixed-height grid track (not flex) so the label sits at the same y on every
   tile regardless of each icon's own cropped height (59-70px, see .mm-method-icon--* below) —
   with flex + a fixed gap, a shorter icon left more/less space above the label per tile. */
.mm-method {
  display: grid; grid-template-rows: 76px auto; align-items: center; justify-items: center; gap: 8px;
  padding: 14px 8px; font-size: 12px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase;
  cursor: pointer; background: var(--surface); color: var(--muted);
  border: 2px solid var(--line); border-radius: 6px;
}
/* Border-width stays fixed (avoids layout shift) — the "thicker red border" look on hover comes
   from an outer box-shadow ring stacked on top of the solid border, plus a drop shadow. */
.mm-method:hover {
  border-color: var(--brand);
  box-shadow: 0 0 0 2px var(--brand), 0 6px 16px rgba(0,0,0,.15);
}
/* Persistent "this is the active filter" cue — distinct from the hover-only ring above. */
.mm-method[data-on] {
  border-color: var(--brand); color: var(--brand); background: var(--brand-tint);
}
/* Each source PNG is a square Midjourney render with generous whitespace padding around the
   subject — showing it whole (object-fit: contain) reads much smaller/emptier than the Figma
   design, which crops in on each subject individually. Sizes/offsets below are the design's own
   per-icon crop rectangles (Figma nav_bar 166:9, scaled 0.6x from its px dimensions), so the
   framing matches exactly rather than approximating one generic crop for all six. */
.mm-method-icon { position: relative; overflow: hidden; margin: 0 auto; }
.mm-method-icon img { position: absolute; max-width: none; }
.mm-method-icon--draw   { width: 85px; height: 59px; }
.mm-method-icon--draw img   { width: 110.67%; height: 160.16%; left: -5.06%;  top: -23.58%; }
.mm-method-icon--fsa    { width: 67px; height: 67px; }
.mm-method-icon--fsa img    { width: 146.92%; height: 146.92%; left: -27.69%; top: -26.92%; }
.mm-method-icon--address { width: 44px; height: 53px; }
.mm-method-icon--address img { width: 208.6%;  height: 170.18%; left: -54.84%; top: -32.46%; }
.mm-method-icon--polls  { width: 65px; height: 70px; }
.mm-method-icon--polls img  { width: 168.8%;  height: 156.3%;  left: -34.4%;  top: -28.89%; }
.mm-method-icon--ward   { width: 82px; height: 50px; }
.mm-method-icon--ward img   { width: 136.93%; height: 223.15%; left: -18.18%; top: -58.33%; }
.mm-method-icon--school { width: 69px; height: 54px; }
.mm-method-icon--school img { width: 159.06%; height: 204.04%; left: -29.13%; top: -51.52%; }

.mm-filter-draw { font-size: 12px; color: var(--muted); line-height: 1.6; }
.mm-draw-shapes { display: flex; gap: 8px; }
.mm-draw-shapes button {
  flex: 1; background: var(--surface); color: var(--ink); border: 1px solid var(--line);
  border-radius: 7px; padding: 10px 8px; font-size: 12px; font-weight: 700; cursor: pointer;
}
.mm-draw-shapes button:hover { border-color: var(--brand); color: var(--brand); }
/* The product picker in the save dialog. Three rows rather than a <select>: the counts beside
   the names are the whole point of the question, and a dropdown hides two thirds of the
   comparison behind a click. */
.mm-save-product { margin: 0 0 14px; padding: 0; border: 0; }
.mm-save-product legend {
  padding: 0; margin-bottom: 8px; font-size: 12px; font-weight: 700;
  color: var(--label); text-transform: uppercase; letter-spacing: .04em;
}
.mm-save-opt {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px; cursor: pointer;
  border: 1px solid #d9d9d9; border-radius: 8px; background: #fff;
}
.mm-save-opt + .mm-save-opt { margin-top: 6px; }
.mm-save-opt:has(input:checked) { border-color: var(--brand-deep); background: var(--brand-tint); }
.mm-save-opt input { margin: 0; accent-color: var(--brand-deep); }
.mm-save-opt-name { font-size: 14px; font-weight: 600; color: var(--ink); }
/* Right-aligned and tabular, so the three numbers stack into a column you read down. */
.mm-save-opt-qty { margin-left: auto; font-size: 13px; color: var(--label); font-variant-numeric: tabular-nums; }
.mm-save-opt:has(input:checked) .mm-save-opt-qty { color: var(--brand-deep); font-weight: 700; }

.mm-input, .mm-select {
  width: 100%; padding: 9px 10px; border: 1px solid var(--line); border-radius: 7px;
  font-size: 13px; color: var(--ink); box-sizing: border-box; background: var(--surface);
}
.mm-select-sm { padding: 6px 8px; font-size: 11px; font-weight: 600; width: auto; }
.mm-slider {
  width: 100%; margin: 6px 0 4px; accent-color: var(--brand); cursor: pointer;
}
.mm-row-between { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 10px; }
.mm-muted-strong { font-size: 11px; color: var(--muted); font-weight: 600; }
.mm-btn-sm {
  background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: 6px;
  padding: 5px 10px; font-size: 11px; font-weight: 600; cursor: pointer;
}
.mm-btn-sm:hover { border-color: var(--brand); color: var(--brand); }
/* Paired view toggles (Display Polls / Display Riding). Same visual weight as each other so
   neither reads as the primary action — the primary action in this panel is still selecting. */
.mm-toggle-row { display: flex; gap: 8px; margin-top: 10px; }
/* display:flex would otherwise win over the hidden attribute — same pairing every other
   flex-plus-[hidden] element in here needs. */
.mm-toggle-row[hidden] { display: none; }
.mm-row-between[hidden] { display: none; }
.mm-toggle {
  flex: 1; background: var(--surface); color: var(--ink); border: 1px solid var(--line);
  border-radius: 7px; padding: 9px 8px; font-size: 12px; font-weight: 700; cursor: pointer;
}
.mm-toggle:hover:not(:disabled) { border-color: var(--brand); color: var(--brand); }
.mm-toggle[data-on] { background: var(--brand); border-color: var(--brand); color: #fff; }
/* :hover:not(:disabled) above outranks [data-on] on specificity, so without this an ON toggle
   under the cursor (e.g. right after being clicked) rendered red text on its own red
   background — invisible. */
.mm-toggle[data-on]:hover:not(:disabled) { color: #fff; }

/* Secondary action under a primary mm-btn-block — same size and shape, no fill. */
.mm-btn-block--quiet {
  background: var(--surface); color: var(--ink); border: 1px solid var(--line); margin-top: 8px;
}
.mm-btn-block--quiet:hover { border-color: var(--brand); color: var(--brand); }
.mm-btn-block--quiet[hidden] { display: none; }

.mm-btn-block {
  display: block; width: 100%; margin-top: 10px; background: var(--brand); color: #fff; border: none;
  border-radius: 7px; padding: 9px 12px; font-size: 12px; font-weight: 600; cursor: pointer;
}
.mm-pick-list { max-height: 230px; overflow-y: auto; border: 1px solid var(--line); border-radius: 7px; margin-top: 8px; }
.mm-pick-list label {
  display: flex; align-items: center; gap: 8px; padding: 6px 10px; font-size: 12px; color: var(--ink);
  cursor: pointer; border-bottom: 1px solid var(--line);
}
.mm-pick-list label:last-child { border-bottom: none; }
.mm-checkline { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--muted); margin-top: 10px; cursor: pointer; }
.mm-checkline--inline { margin-top: 0; }
.mm-fine { font-size: 11px; color: #9ca3af; line-height: 1.5; margin-top: 8px; }
.mm-before-mailable div { margin-bottom: 8px; line-height: 1.6; }
.mm-before-mailable div:last-child { margin-bottom: 0; }
.mm-before-mailable b { color: var(--ink); }

/* Results panel — filled in by mailing-map.js */
.mm-count { font-size: 32px; font-weight: 800; color: var(--ink); line-height: 1.1; }
.mm-count-label { font-size: 11px; color: #9ca3af; font-weight: 700; text-transform: uppercase; letter-spacing: .4px; margin-bottom: 14px; }
.mm-bar-row { display: flex; justify-content: space-between; font-size: 12px; color: var(--muted); margin-bottom: 5px; }
.mm-bar { background: #f3f4f6; border-radius: 5px; height: 8px; overflow: hidden; margin-bottom: 8px; }
.mm-bar-fill { height: 100%; }
.mm-section { border-top: 1px solid var(--line); padding-top: 12px; margin-bottom: 12px; }
.mm-mini-table { width: 100%; font-size: 11px; margin-bottom: 8px; }
.mm-mini-table td { padding: 2px 12px 2px 0; border: none; background: none; }
/* Postal-code breakdown (postalPanel). Two columns rather than .mm-mini-table's default flow:
   the code is fixed-width and the count right-aligns against it, so the numbers form a column
   the eye can scan instead of sitting wherever the code's width leaves them. */
.mm-postal-list { margin-bottom: 4px; }
/* Expanded, the list is a scroll box: a thousand codes would otherwise push the walks column
   and the action buttons off the bottom of the dialog. Capped, it has no max-height so short
   selections don't get a scrollbar they don't need. */
.mm-postal-list--all { max-height: 220px; overflow-y: auto; }
.mm-postal-list .mm-mini-table { margin-bottom: 0; }
.mm-postal-row-code { font-variant-numeric: tabular-nums; letter-spacing: .3px; color: var(--muted); }
.mm-postal-row-n { text-align: right; font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
/* "of 43" on a clipped code — lighter than the count it qualifies, so the column still scans as
   a column of numbers and the denominator reads as an aside rather than a second figure. */
.mm-postal-row-of { color: var(--muted); font-weight: 400; }
.mm-postal-row--partial .mm-postal-row-code { font-style: italic; }
.mm-postal-more {
  background: none; border: none; padding: 0; margin-bottom: 6px;
  font: inherit; font-size: 11px; font-weight: 700; color: var(--brand);
  cursor: pointer; text-decoration: underline;
}
.mm-postal-more:hover { opacity: .75; }

.mm-extract-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 9px; padding-top: 9px; border-top: 1px solid #f9fafb; }
.mm-extract-row:first-child { border-top: none; padding-top: 0; }

/* Three columns, one per mail type. Equal tracks: they are presented as three equal options, so
   giving one a wider share would quietly rank them. minmax(0,…) on every track so the route
   table can shrink inside its column instead of forcing the grid wider than the dialog. */
.mm-plan-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px; align-items: start;
}
/* Two columns when the office sends no postal clusters, so the remaining pair still fills the
   dialog rather than leaving a third of it blank. */
.mm-plan-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.mm-plan-col { min-width: 0; }
/* A rule between the types rather than around them: they are three readings of one selection,
   not three cards. --walks keeps its name because other rules and the routes panel reference it. */
.mm-plan-col--rule { border-left: 1px solid var(--line); padding-left: 20px; }
.mm-col-head {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px;
  color: #9ca3af; margin-bottom: 10px;
}
/* .mm-section draws a divider above itself, which is right when sections stack but reads as a
   stray rule under a column heading. */
.mm-plan-col .mm-section:first-of-type { border-top: none; padding-top: 0; }
/* Only the walk list scrolls; the surrounding stats stay put (see renderRoutes). */
.mm-routes-scroll { max-height: 300px; overflow-y: auto; }
/* Mail Plan Details is draggable by its header (wiring in mailing-map.ejs). grab/grabbing on
   the header itself, and text selection suppressed mid-drag so pulling the dialog around
   doesn't highlight the title. */
#mm-plan-modal .mm-modal-header { cursor: grab; user-select: none; }
/* Once the dialog has been dragged, the point was to look at the map — so the dimmer goes and
   clicks pass through to it. The dialog itself keeps its own pointer events, and Escape and the
   × still close it; only click-outside-to-close stops working, which is what dragging it aside
   asked for. */
.mm-modal-overlay--moved { background: transparent; pointer-events: none; }
.mm-modal-overlay--moved .mm-modal { pointer-events: auto; }
#mm-plan-modal .mm-modal-header.mm-dragging { cursor: grabbing; }
#mm-plan-modal .mm-modal-close { cursor: pointer; }

/* Head of the preview / walk-summary views inside the dialog: back on the left, that view's
   own controls on the right. */
.mm-pane-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; margin-bottom: 12px;
}
.mm-pane-head-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* Long tables scroll within the view instead of growing the dialog past the viewport. */
.mm-pane-scroll { max-height: 60vh; overflow-y: auto; }

/* Sortable column headers on the route table (sortTh in mailing-map.js). */
.mm-routes-scroll th[data-sort]:hover { color: var(--brand); }

.mm-plan-actions {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  border-top: 1px solid var(--line); padding-top: 14px; margin-top: 16px;
}

@media (max-width: 860px) {
  .mm-plan-grid, .mm-plan-grid--2 { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  .mm-plan-col--rule { border-left: none; padding-left: 0; border-top: 1px solid var(--line); padding-top: 14px; margin-top: 6px; }
}
.mm-extract-title { font-size: 12px; font-weight: 700; color: var(--ink); }
.mm-extract-sub { font-size: 11px; color: var(--muted); }

/* Step 2/3 tables */
.mm-list-summary { padding: 12px 16px; border-bottom: 1px solid var(--line); font-size: 12px; color: var(--muted); }
/* Sits between the summary line and the table it filters, reading as a caption on the columns
   rather than a control bar of its own. */
.mm-walks-types {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 10px 16px; border-bottom: 1px solid var(--line);
}
.mm-walks-types-label { font-size: 11px; font-weight: 700; color: #9ca3af; text-transform: uppercase; letter-spacing: .04em; }
.mm-walks-types label {
  display: flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600;
  color: var(--muted); cursor: pointer;
}
.mm-walks-types input { margin: 0; accent-color: var(--brand); }
/* A column left out of the totals — greyed in the head as well as the body, so the excluded
   numbers still read as data rather than looking half-rendered. */
.mm-th-num--off { color: #d1d5db !important; }
/* Delivery points are editable per walk: Canada Post's number is the starting point, not the
   last word. Styled as a number that happens to be typeable — no box until hover/focus — so the
   column still reads as a total rather than a form. */
/* ── Per-column walk adjustments ───────────────────────────────────────────
   Each dwelling column is typed over directly, so the plan can say WHICH kind of address
   moved, not just that the total did. Canada Post's own figure sits under an edited cell. */
.mm-dp-total { font-size: 13px; font-weight: 700; color: var(--ink); }
.mm-dp-total--adj { color: var(--brand); }
.mm-tc { text-align: right; }
.mm-tc--off { color: #d1d5db; }
.mm-tc--off .mm-tc-input { color: #d1d5db; }
.mm-tc-input {
  width: 72px; text-align: right; font: inherit; font-size: 13px;
  color: var(--ink); background: transparent; border: 1px solid transparent; border-radius: 6px;
  padding: 3px 6px; -moz-appearance: textfield;
}
.mm-tc-input:hover { border-color: var(--line); background: #fff; }
.mm-tc-input:focus { outline: none; border-color: var(--brand); background: #fff; }
.mm-tc-input--adj { color: var(--brand); font-weight: 700; }
.mm-tc-cp { display: block; font-size: 10px; color: #9ca3af; padding-right: 7px; }

.mm-dp-cell { text-align: right; padding-right: 12px; }
.mm-dp-orig { font-size: 10px; color: #9ca3af; margin-top: 2px; white-space: nowrap; }
.mm-dp-reset {
  background: none; border: none; padding: 0 0 0 2px; font: inherit; font-size: 10px;
  color: var(--brand); text-decoration: underline; cursor: pointer;
}
.mm-table-wrap { overflow-x: auto; }
.mm-table { width: 100%; border-collapse: collapse; font-size: 13px; margin: 0; background: none; }
.mm-table th {
  text-align: left; padding: 9px 12px; color: #9ca3af; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .5px; border-bottom: 1px solid var(--line); background: #fafafa;
}
.mm-th-num { text-align: right; }
.mm-table td { padding: 8px 12px; border-bottom: 1px solid var(--line); color: var(--ink); }
.mm-table tr:last-child td { border-bottom: none; }
.mm-pager { display: flex; align-items: center; justify-content: center; padding: 16px; border-top: 1px solid var(--line); }
.mm-walks-note { padding: 12px 16px; border-top: 1px solid var(--line); font-size: 11px; color: var(--muted); line-height: 1.6; }

.mm-badge {
  border-radius: 4px; padding: 2px 8px; font-size: 11px; font-weight: 600; white-space: nowrap; display: inline-block;
}
.mm-badge--ok { color: #065f46; background: #ecfdf5; border: 1px solid #a7f3d0; }
.mm-badge--verify { color: #92400e; background: #fef3c7; border: 1px solid #fde68a; }
.mm-badge--bad { color: #991b1b; background: #fee2e2; border: 1px solid #fecaca; }
.mm-badge--unknown { color: var(--muted); background: #f3f4f6; border: 1px solid var(--line); }
.mm-badge--missing { color: #92400e; background: #fef3c7; }

/* The two ways out of Mail Plan Details — preview the addresses, or the walk summary. Equal
   actions, so equal styling: one class on both rather than a primary button beside a small
   secondary one, and the sizing lives here instead of an inline style on only one of them. */
.mm-plan-action { padding: 7px 14px; font-size: 12px; }

/* Address rows are view-only: no drag-select, no long-press callout on touch. Paired with the
   copy/cut/contextmenu guards in mailing-map.js. */
.mm-noselect {
  -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}

.mm-loadmore-wrap { display: flex; justify-content: center; padding: 16px; border-top: 1px solid var(--line); }
.mm-loadmore-wrap .btn { padding: 9px 22px; }

@media (max-width: 700px) {
  .mm-map { height: 380px; }
  .mm-map--full { height: 60vh; }
  .mm-map-overlays { left: 8px; right: 8px; }
  .mm-map-toolbar { flex-wrap: wrap; }
  .mm-count-banner { flex-wrap: wrap; }
}

/* mm-print-btn (mailing-map.js) fills this in and calls window.print() — letting the browser's
   own print/Save-as-PDF handle PDF generation rather than a server render or a client PDF lib,
   since the live map (tiles + the canvas-rendered route lines) already looks right on screen
   and prints as-is. Hidden at all other times; @media print below is the only place it shows. */
.mm-print-header { display: none; }

/* ── Print geometry ────────────────────────────────────────────────────────
   IMPORTANT: the map's print size is set by the body.mm-printing class BELOW, applied by
   mailing-map.js *before* it calls window.print() — deliberately NOT inside @media print.
   Verified against headless Chrome: print CSS has NOT been applied yet when the beforeprint
   event fires, so anything measuring/resizing there (Leaflet's invalidateSize/fitBounds) sees
   stale SCREEN dimensions. Sizing only in @media print therefore broke two ways at once:
     - fitBounds centred the selection for the wide on-screen box, then Chrome re-laid-out to a
       tall portrait page -> selection off-centre and cropped;
     - Leaflet had only ever requested tiles for the smaller screen viewport, so the extra area
       the print box exposed had no tiles at all -> route lines on a blank white page (the
       canvas overlay redraws from in-memory geometry, so it alone still showed up).
   Because CSS `in` units are exactly 96px on screen, the class produces the identical box in
   both contexts: Leaflet measures the true final geometry, loads the right tiles, and the
   print pass changes nothing about the map. Keep sizing out of @media print. */
body.mm-printing .mm-map-full {
  width: var(--mm-print-w); margin-left: 0; transform: none; border: none;
}
/* #mm-map's own width/height are set inline by the print prep in mailing-map.js, NOT here:
   sizeMapToViewport() already writes an inline height to snap the map to the viewport bottom,
   and an inline style beats any stylesheet rule short of !important. Rather than escalate to
   !important (which would then outrank the print prep too), both live in JS where the restore
   path can put the original inline value back verbatim. */
body.mm-printing .mm-print-header { display: block; }
/* THE blank-basemap fix. Leaflet fades new tiles in from opacity:0, and its 'load' event fires
   when the image bytes arrive — before that fade has run. Chrome would snapshot the page with
   the tiles still fully transparent, printing route lines onto blank white. (Racy, so it
   sometimes "worked": anything that delayed the snapshot let the fade finish.) Leaflet writes
   the fade as an inline style, so only !important can override it. */
body.mm-printing .leaflet-tile { opacity: 1 !important; }
/* Covers the momentary on-screen resize while tiles load for the print-sized box. */
.mm-print-veil {
  position: fixed; inset: 0; z-index: 3000; background: rgba(255,255,255,.92);
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 700; color: var(--ink);
}

.mm-print-header { padding: 0 0 10px; margin-bottom: 10px; border-bottom: 2px solid #000; }
/* Our logo, at the top of the printed page in place of the site masthead. The dark logo, not the
   white one the red band carries: white on white prints an empty rectangle. Living inside the
   print header rather than in the page's own bar is what lets mailing-map.js measure it along
   with everything else above the map, so the map's height stays measured rather than assumed. */
/* BOTH dimensions, not height:auto. The header's height is measured the moment it is built, and
   an image whose bytes have not arrived yet has no intrinsic size to lay out from — measured at
   that instant it reserves the wrong space, the map is sized against the wrong remainder, and the
   page spills onto a second sheet. 1.6 x 0.323in is logo.png's own 1870x377. */
/* ── Saved plans list ──────────────────────────────────────────────────────
   The customer's own plans. No folder or drag rules: filing plans into folders is the
   shop's console, where several people share one list. */
.mm-plans-bar { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.mm-plans-search {
  flex: 1 1 auto; min-width: 0; padding: 7px 10px; font: inherit; font-size: 13px;
  border: 1px solid var(--rule, #e5e7eb); border-radius: 8px; background: #fff; color: var(--ink);
}
.mm-plans-search:focus { outline: none; border-color: var(--brand, #BF2E1A); }
.mm-plans-count { font-size: 11.5px; color: var(--muted); white-space: nowrap; }
/* Capped and scrolled: a hundred plans should make the list scroll, not the dialog grow past
   the window. */
.mm-plans-list { display: flex; flex-direction: column; gap: 2px; max-height: 52vh; overflow-y: auto; }
.mm-plan-row {
  display: flex; align-items: baseline; gap: 10px; padding: 6px 9px;
  border: 1px solid transparent; border-radius: 7px; background: #fff;
}
.mm-plan-row:hover { background: var(--sunk, #f9fafb); border-color: var(--line); }
.mm-plan-row-name {
  flex: 0 1 auto; min-width: 0; font-size: 13px; font-weight: 700; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mm-plan-row-meta {
  flex: 1 1 auto; min-width: 0; font-size: 11px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mm-plan-row .mm-btn-sm { flex: 0 0 auto; align-self: center; }
.mm-plan-row-del:hover { border-color: #b91c1c; color: #b91c1c; }

.mm-print-logo { display: block; width: 1.6in; height: 0.323in; margin: 0 0 10px; }
.mm-print-header h1 { margin: 0 0 2px; font-size: 18px; }
.mm-print-header .mm-print-date { font-size: 11px; color: #555; margin-bottom: 8px; }
.mm-print-header .mm-print-stats { display: flex; gap: 28px; }
.mm-print-header .mm-print-stat-value { font-size: 22px; font-weight: 800; line-height: 1; }
.mm-print-header .mm-print-stat-label { font-size: 11px; color: #555; }
/* The caption sits between two stat rows, so it needs air above it or it reads as a third
   label belonging to the figure before it. */
.mm-print-header .mm-print-stats + .mm-print-sub { margin-top: 8px; }
/* The dwelling split under the two headline figures — smaller, because it explains the
   neighbourhood-mail number rather than competing with it. */
.mm-print-header .mm-print-stats--types { gap: 22px; margin-top: 5px; }
.mm-print-header .mm-print-stats--types .mm-print-stat-value { font-size: 15px; font-weight: 700; }
.mm-print-header .mm-print-stats--types .mm-print-stat-label { font-size: 10px; }
/* A type the job is not mailing to still shows its real count — the addresses are on the walk
   either way — but greyed and labelled, so it cannot be mistaken for part of the order. */
.mm-print-header .mm-print-stat--off .mm-print-stat-value,
.mm-print-header .mm-print-stat--off .mm-print-stat-label { color: #9ca3af; }

@media print {
  @page { size: letter portrait; margin: 0.4in; }
  body { background: #fff; }
  /* Chrome rasterizes the duotone-filtered tiles fine (verified), but only if it's told to
     print backgrounds/colours at all — without this the user's "Background graphics" checkbox
     silently decides whether the basemap appears. */
  * { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }
  /* Hide everything except the masthead, the map and our print header. The veil is screen-only
     feedback. (.brandbar is the old masthead, kept in this list because other pages still use
     it; the map page's own bar is .sh, handled just below.) */
  .brandbar, .foot, #mm-databanner,
  .mm-map-toolbar, .mm-edit-toolbar, .mm-modal-overlay, .mm-print-veil,
  .leaflet-control-zoom, .leaflet-control-attribution, .mm-basemap-toggle,
  .leaflet-draw, #mm-step2, #mm-step3 {
    display: none !important;
  }

  /* The masthead does not print at all. On screen it is a 150px band carrying the account row,
     the nav and an animated canvas — all navigation, useless in a PDF, and between them about an
     inch and a half of a letter page, which is what pushed the map onto a second sheet. What a
     printed plan needs from it is only our logo, and that is drawn into the print header instead
     (mm-print-logo below), where the JS that sizes the map can measure it. Trying to shrink the
     band in place is the version of this that does not work: the map is sized before print CSS
     applies, so its height would have to assume a number rather than measure one. */
  /* ── The walk summary as a page ──────────────────────────────────────────
     The map's print rules hide .mm-modal-overlay, because for that document a dialog on top is
     chrome in the way. Here the dialog IS the document, so this mode reverses that one rule and
     nothing else: the modal stops being a floating panel and becomes the page, the map goes, and
     the shared header stays where it is.

     Everything is scoped under body.mm-printing-walks, so a map print is untouched by all of it. */
  body.mm-printing-walks #mm-plan-modal {
    display: block !important;
    position: static; inset: auto; background: none; padding: 0; overflow: visible; z-index: auto;
  }
  body.mm-printing-walks #mm-plan-modal .mm-modal {
    position: static; width: auto; max-width: none; max-height: none;
    box-shadow: none; border: 0; border-radius: 0; padding: 0;
  }
  /* The letterhead — logo, plan name, date. It is built by the PDF button's handler either way,
     but .mm-print-header is display:none by default and the rule that reveals it is scoped to
     body.mm-printing, which is the MAP's print class. This document sets mm-printing-walks, so
     it never matched and the header was assembled and then hidden. Revealed here rather than by
     widening that rule: the map's copy lives outside @media print because preparePrint measures
     the header's height to size the map, and this document has no map to size — so on paper only,
     and no on-screen flash of a header nobody asked for. */
  body.mm-printing-walks .mm-print-header { display: block !important; }
  /* The map itself, and every control belonging to it. */
  body.mm-printing-walks #mm-map,
  body.mm-printing-walks .mm-map-overlays,
  body.mm-printing-walks .mm-modal-header,
  body.mm-printing-walks .mm-pane-head,
  body.mm-printing-walks #mm-walks-types,
  body.mm-printing-walks #mm-walks-summary,
  body.mm-printing-walks #mm-walks-note {
    display: none !important;
  }
  /* The summary line and the footnotes are not dropped — they are lifted into the print header
     (see the PDF button's handler), where they read as a standfirst rather than as two stray
     lines the table has already scrolled past. */

  /* On screen this pane is a fixed-height scroller inside a dialog. On paper it has to be as
     tall as it needs to be, or the PDF is one screenful of a longer table. */
  body.mm-printing-walks .mm-pane-scroll,
  body.mm-printing-walks .mm-table-wrap {
    max-height: none !important; height: auto !important; overflow: visible !important;
  }
  /* A manifest runs past one page whenever the selection is large, so the column headings repeat
     and no walk is split across the break. */
  body.mm-printing-walks .mm-table thead { display: table-header-group; }
  body.mm-printing-walks .mm-table tr { break-inside: avoid; page-break-inside: avoid; }
  body.mm-printing-walks .mm-table { width: 100%; font-size: 10.5px; }
  /* The per-walk reset link is an on-screen control; the adjusted NUMBER beside it is the point
     and stays. */
  body.mm-printing-walks .mm-dp-reset { display: none !important; }

  .sh {
    display: none !important;
  }
  /* Sizing intentionally omitted here — see the comment above body.mm-printing. */
}


/* Leaflet's zoom control and the satellite toggle, brought into the same card family as the rest
   of the map's chrome — see the nav_bar Figma (188:1240). Leaflet ships its own borders and
   shadow, so these override rather than add. */
.leaflet-touch .leaflet-bar,
.leaflet-control-zoom.leaflet-bar {
  background: linear-gradient(to top, #ececec 0%, #fff 37.5%);
  border: 0 !important; border-radius: 10px !important;
  box-shadow: 0 0 4px rgba(0, 0, 0, .25); overflow: hidden;
}
.leaflet-control-zoom a.leaflet-control-zoom-in,
.leaflet-control-zoom a.leaflet-control-zoom-out {
  width: 36px; height: 36px; line-height: 36px;
  background: transparent; border: 0; color: #606060;
  font-size: 20px; font-weight: 400;
}
.leaflet-control-zoom a.leaflet-control-zoom-in { border-bottom: 1px solid #d9d9d9 !important; }
.leaflet-control-zoom a:hover { background: rgba(150, 16, 16, .06); color: #961010; }

/* The basemap toggle. The icon is the exported asset from the design, not a redrawn one. */
.mm-basemap-toggle {
  display: inline-flex; align-items: center; gap: 8px; height: 40px; padding: 0 16px;
  background: linear-gradient(to top, #ececec 0%, #fff 37.5%);
  border: 0; border-radius: 10px; box-shadow: 0 0 4px rgba(0, 0, 0, .25);
  font-size: 14px; font-weight: 900; letter-spacing: .02em; text-transform: uppercase;
  color: #961010; cursor: pointer; font-family: inherit;
}
.mm-basemap-toggle:hover { color: #7d0d0d; }
.mm-basemap-toggle-icon { width: 18px; height: 16px; flex: 0 0 auto; }


/* The plan's name sits under the actions as a caption on the map. It carries a permanent
   translucent panel: the name is set over the basemap, and at 20px on a duotone map of streets
   and parcel outlines the glyphs collide with the linework behind them. The panel is white at
   60% rather than opaque so the map still reads through it and it stays a caption rather than
   becoming a second card competing with the pill above.
   (This reverses the original nav_bar treatment, which surfaced only on hover/focus — that kept
   the map clean but left the resting state, which is what you look at, the least legible one.)
   See the nav_bar Figma (188:1240). */
/* Qualified with the element and its container on purpose. style.css styles every text input
   with `input[type=text]` — one class cannot beat an element-plus-attribute selector, so a bare
   `.mm-plan-name` rule loses silently and the field keeps the generic white box and 16px text.
   That is why the previous 15px rule here never applied either; it has been overridden since it
   was written. */
/* A white field, full width of the card's inner measure — the design draws it at 277px inside a
   313px card, i.e. wider than the 216px pill below it, not matched to it. That is what stops a
   short name looking marooned in a box sized for something else. */
.mm-map-toolbar-right input.mm-plan-name {
  font-size: 16px; font-weight: 400; color: #606060; text-align: right;
  background: #fff; border: 0; border-radius: 6px;
  /* A ring rather than a border, so the field keeps its 24px box instead of growing by 2px. */
  box-shadow: 0 0 0 1px #00000014;
  width: 216px; max-width: 100%; box-sizing: border-box;
  height: 24px; padding: 0 10px;
}
.mm-map-toolbar-right input.mm-plan-name::placeholder { color: #606060; font-weight: 500; opacity: 1; }
.mm-map-toolbar-right input.mm-plan-name:hover {
  background: rgba(255, 255, 255, .8); border-radius: 6px;
}
.mm-map-toolbar-right input.mm-plan-name:focus {
  background: #fff; border-radius: 6px; border-color: transparent;
  box-shadow: 0 0 4px rgba(0, 0, 0, .25); outline: none;
}

/* ── One hover, one red, for every control on the map ───────────────────────────────────────
   The map had two of them. Controls restyled to the nav_bar design hover toward #961010, while
   everything older hovered toward style.css's --brand (#BF2E1A). Those are visibly different
   reds sitting inches apart on the same surface, which reads as a bug rather than a palette.

   The map gets its own tokens rather than changing --brand, which is correct everywhere else on
   the site. Scoped to the overlay containers so nothing outside the map is affected.

   Filled controls are excluded on purpose: a selected view pill and Mail Plan Details are
   already solid red, and washing them on hover would make them look like they had come unset. */
.mm-map-overlays, .mm-edit-toolbar, .leaflet-control-container {
  --mm-red: #961010;
  --mm-red-dark: #7d0d0d;
  --mm-red-wash: rgba(150, 16, 16, .08);
}

.mm-map-overlays .mm-filter-btn:hover,
.mm-map-toolbar-actions .mm-filter-btn:hover,
.mm-map-overlays .mm-close-btn:hover,
.mm-edit-toolbar .mm-edit-toolbar-btn:not(.mm-plan-btn):hover:not(:disabled),
.mm-edit-toolbar .mm-edit-toolbar-segment button:not([data-on]):hover,
.mm-edit-toolbar .mm-edit-toolbar-segment label:not(:has(input:checked)):hover,
.mm-route-filter-bar button:hover,
.mm-basemap-toggle:hover,
.mm-draw-shapes button:hover,
.leaflet-control-zoom a:hover {
  background: var(--mm-red-wash);
  color: var(--mm-red);
  border-color: var(--mm-red);
}

/* Already-red controls darken instead of washing — the same gesture, read the other way round. */
.mm-edit-toolbar .mm-plan-btn:hover,
.mm-edit-toolbar .mm-edit-toolbar-segment button[data-on]:hover,
.mm-edit-toolbar .mm-edit-toolbar-segment label:has(input:checked):hover {
  background: var(--mm-red-dark);
  border-color: var(--mm-red-dark);
  color: #fff;
}

/* The two count-banner rows that open the details modal follow the same wash. */
.mm-map-overlays .mm-count-banner-clickable:hover { background: var(--mm-red-wash); }
.mm-map-overlays .mm-count-banner-clickable:hover .mm-count-banner-value { color: var(--mm-red); }



/* Printing, under each product's own figure in the count banner. Third line of the stacked stat
   row, so it reads as "this many pieces, this much to print them" rather than competing with the
   count. Red, because it is the only money on the banner and the customer is looking for it.
   Hidden rather than blank when the visitor did not arrive from a product — see paintPrice. */
.mm-count-banner-price {
  display: flex; flex-direction: column; gap: 0; line-height: 1.3; white-space: nowrap;
  cursor: help;
}
/* Printing and postage together — the number someone sizes a mailing against. Red, because it is
   the only money on the banner and it is what they are looking for. */
.mm-price-total { font-size: 11px; font-weight: 900; color: #961010; }
/* The two halves under it, quiet: a total nobody can take apart is a total nobody trusts. */
.mm-price-note { font-size: 9px; font-weight: 400; color: #606060; }
.mm-count-banner-price[hidden] { display: none; }
