/* egregor.css v1 — the one design system for every Egregor page (USR-56).
   S9: system fonts, no CDN, no import. Until FE-2 lands (the server's static
   branch admits only /, /homes, /vendor/**) this file is inlined into each page
   between the markers `egregor.css v1 BEGIN/END`; keep this file the source and
   re-run the splice, never edit the copies. */

:root {
  /* palette: six colors and their surfaces. The belief ramp stays semantic
     (green cheap -> red dear, grey unknown) and is set in JS, not here. */
  --bg:#e7eeea; --card:#fff; --ink:#1b1b19; --mut:#6b6b66; --line:#e0dfd8;
  --acc:#0b6e4f; --warn:#b3541e; --sel:rgba(11,110,79,.10);
  /* USR-220(2): color with a purpose. --acc is reserved for the things you act on
     (Submit, Pay, Register); --save is the warm hue money-you-keep is printed in, and
     --conf the cool hue confidence is printed in, so a reader learns two meanings
     instead of reading one green everywhere. The price ramp (green cheap -> red dear)
     is untouched: it is the map's own encoding and is set in JS. */
  --save:#a5581c; --conf:#2a5d9f; --save-bg:rgba(165,88,28,.08); --conf-bg:rgba(42,93,159,.08);
  /* USR-107: one typeface, 15/24 body, 28/34 titles, tabular numerals (below) */
  --fs-xs:11px; --fs-sm:12px; --fs-md:15px; --fs-lg:17px; --fs-xl:28px;
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px;
  --r-1:4px; --r-2:8px; --tap:32px;
  --sh-1:0 1px 2px rgba(0,0,0,.06); --sh-2:0 1px 8px rgba(0,0,0,.05);
}
/* plan cards: the buy affordance (BE-7/R-9). A plan is a card, not a button, so the
   buy control can live inside it; a tier that cannot take money shows no button. */
.plan .act { display:block; margin-top:var(--sp-2); font-size:var(--fs-sm); }
.plan .act.cur { color:var(--acc); font-weight:650; }
.plan .act.free, .plan .act.lock { color:var(--mut); font-style:italic; }
button.act.buy { width:100%; padding:var(--sp-1) var(--sp-2); border-radius:var(--r-1);
  border:1px solid var(--acc); background:var(--acc); color:#fff; font-weight:650; cursor:pointer; }
button.act.buy:hover { filter:brightness(1.08); }
.buybar { display:flex; flex-wrap:wrap; gap:var(--sp-2); align-items:center; margin-bottom:var(--sp-2); }
.buybar input { min-width:14em; }
/* USR-124(2): the click a locked column or route used to be missing -- unlock() in
   common.js builds this link, one spot, so every lock ends the same way. */
.unlock { margin-left:.35em; font-weight:600; white-space:nowrap; }
/* USR-124(4): the item photo and its capture preview share one fixed-aspect box
   (BE's own display-contract note in egregor/photos.py) so a portrait or landscape
   phone photo never distorts the layout around it. */
.itemphoto { width:28px; height:28px; object-fit:cover; border-radius:var(--r-1); vertical-align:middle; margin-right:var(--sp-2); }
.photopreview { width:48px; height:48px; object-fit:cover; border-radius:var(--r-1); }
.scanvid { width:160px; height:120px; object-fit:cover; border-radius:var(--r-1); background:#000; }
.consent { display:flex; align-items:center; gap:.35em; font-size:var(--fs-sm); color:var(--mut); }
/* USR-98/GRW-2(3): the leaderboard's period toggle -- same tab language as `.nav`
   (border+card on the active one), scaled down since this one lives inside a card. */
.tabs { display:flex; gap:var(--sp-1); margin:var(--sp-1) 0 var(--sp-2); }
.tabs button { font-size:var(--fs-sm); color:var(--mut); padding:var(--sp-1) var(--sp-2);
  border:1px solid transparent; border-radius:var(--r-1); background:none; cursor:pointer; }
.tabs button.on { color:var(--ink); border-color:var(--line); background:var(--card); }
@keyframes egregor-unlock-flash { 0%, 100% { box-shadow:var(--sh-1); } 35% { box-shadow:0 0 0 3px var(--acc), var(--sh-2); } }
.plan.flash { animation:egregor-unlock-flash 1.2s ease; }
.banner { border:1px solid var(--line); border-left:3px solid var(--acc); background:var(--sel);
  border-radius:var(--r-1); padding:var(--sp-2) var(--sp-3); margin-bottom:var(--sp-2); font-size:var(--fs-sm); }
.banner.warn { border-left-color:var(--warn); background:transparent; }
/* USR-202: the callout -- one box for "the numbers show something here" and one for "they
   do not right now", used identically on goods, homes and routes. Accent rule and the pale
   accent tint for an opportunity; the muted rule and no tint for none-right-now. The tone
   is never the only signal (the sentence says which case it is), so the pair still reads
   without color. The option sits inside the box as a secondary button, so the next look is
   offered rather than instructed. */
.callout { display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2);
  border:1px solid var(--line); border-left:3px solid var(--acc); background:var(--sel);
  border-radius:var(--r-1); padding:var(--sp-2) var(--sp-3); margin:0 0 var(--sp-2); max-width:60em; }
.callout.none { border-left-color:var(--mut); background:var(--card); box-shadow:var(--sh-1); }  /* user 2026-09-14: a card on the green ground, not a wash that blends into it */
.callout .say { margin:0; flex:1 1 16em; font-size:var(--fs-md); font-weight:650; color:var(--ink); line-height:1.3; }
.callout.none .say { font-weight:600; }
.callout button { flex:0 0 auto; }
.callout .lock, .callout .chip { font-weight:400; }
td .callout { margin:0; text-align:left; }
.notadvice { margin:var(--sp-2) 0 0; }
/* USR-202: the field a callout's option sends you to says so for a moment. Focus alone is
   a caret a reader does not notice when the field was already on screen. */
@keyframes egregor-field-flash {
  0%, 100% { box-shadow:0 0 0 0 transparent; }
  30%      { box-shadow:0 0 0 3px var(--sel); border-color:var(--acc); }
}
.flashfield { animation:egregor-field-flash 1.3s ease; border-color:var(--acc); }
@media (prefers-reduced-motion: reduce) { .flashfield { animation:none; outline:2px solid var(--acc); } }
/* USR-198/200/205(1): the store mention. Two targets in one element -- the name selects
   and snaps the map, the arrow leaves the site -- so they are visibly two things, with the
   arrow given its own hit area rather than sitting flush against the last letter. The name
   is a button styled as text: it belongs to the table row it sits in, and a button chrome
   here would turn every table into a wall of controls. */
/* `display:inline-flex` made the mention an atomic flex box, so in a narrow table column the
   name shrank to min-content and "Union Sq. Green market" wrapped one character per line
   (seen in the beliefs table at 1280 px, 2026-09-12). It is plain inline text with an inline
   link after it; only genuinely unbreakable words break. */
.placeref { display:inline; }
.placeref .pick { all:unset; cursor:pointer; color:var(--ink); border-bottom:1px dotted var(--line);
  overflow-wrap:break-word; }
.placeref .pick:hover, .placeref .pick:focus-visible { border-bottom-color:var(--acc); color:var(--acc); }
.placeref .pick:focus-visible { outline:2px solid var(--acc); outline-offset:2px; }
.placeref.sel .pick { color:var(--acc); font-weight:650; border-bottom-color:var(--acc); }
.placeref .kind { font-size:.9em; }
.placeref .out { padding:0 .15em; color:var(--mut); text-decoration:none; font-size:.95em; }
.placeref .out:hover, .placeref .out:focus-visible { color:var(--acc); text-decoration:none; }
/* USR-198(d.1): the online rail -- the stores the map cannot draw, kept beside the map so a
   reader who looked for eBay among the pins finds it in the same glance. USR-213 addendum
   (user, 2026-09-12): it is part of the page LAYOUT, never a map overlay. The floating
   version covered markers as soon as the map grew (`.split`'s flex-filled #lmap runs to
   680 px and past it, while the rail's own cap was written against the old fixed 420 px box),
   and an annotation that hides the thing it annotates is worse than no annotation. So: at
   the map's right edge it is a real second column of `.maparea`; on phones it docks below the
   map as an ordinary block. Nothing here positions, floats or stacks it, which is why the
   USR-213 z-order (callout > rail > map controls > map) needs no z-index at all -- an
   in-flow element covers nothing. */
.rail { background:var(--card); border:1px solid var(--line); border-radius:var(--r-1);
  padding:var(--sp-2); font-size:var(--fs-sm); margin-top:var(--sp-2); }
.rail h3 { margin:0 0 var(--sp-1); font-size:var(--fs-sm); text-transform:uppercase;
  letter-spacing:.04em; color:var(--mut); font-weight:650; }
.rail h3 .lock { text-transform:none; letter-spacing:0; }
.rail-list { list-style:none; margin:0; padding:0; display:grid; gap:var(--sp-1); }
.rail-entry { border-left:3px solid var(--line); padding:var(--sp-1) var(--sp-2); border-radius:var(--r-1); }
.rail-entry.sel { border-left-color:var(--acc); background:var(--sel); }
.rail-entry .fee, .rail-entry .figs, .rail-entry .reach { color:var(--mut); }
.rail-entry .figs .none { font-style:italic; }
.rail-entry .reach.yes { color:var(--acc); }
.rail-entry .reach.unknown { font-style:italic; }
/* The two overlays the map does carry stay overlays: the window strip (`.window.strip`,
   absolute across the top at z-index 1100) and Leaflet's own controls, which is why the zoom
   control keeps its 54 px top margin while the strip is showing. Both belong to the map, so
   the strip is held to the map's own column and stops short of the rail -- `--rail-w` is
   written once and read by the column and by the strip's `right`, so the two cannot drift.
   The rail is a grid row of full height: it scrolls inside itself rather than stretching the
   card, and because the map column is `minmax(0,1fr)` the map keeps every pixel the rail does
   not take. The rule applies only when a rail is actually showing -- on every other page and
   every non-goods domain (USR-213) `.maparea` stays the single-column box it has always been,
   and Leaflet's attribution keeps its corner (R-1: the OpenStreetMap credit is a condition of
   using the tiles, not decoration). */
@media (min-width:760px) {
  .maparea:has(.rail:not([hidden])) { --rail-w:min(17rem, 34%);
    display:grid; grid-template-columns:minmax(0,1fr) var(--rail-w); gap:var(--sp-2);
    align-items:stretch; }
  .maparea:has(.rail:not([hidden])) > #lmap,
  .maparea:has(.rail:not([hidden])) > svg#map,
  .maparea:has(.rail:not([hidden])) > canvas#gl3d { grid-area:1 / 1; }
  /* align-self:start, not stretch: measured at 1280 px the stretched rail was a 1782 px
     tall card holding one entry, because `.split` grows the map row to the sidecol's height.
     It takes its content's height and scrolls only when the roster is longer than the map. */
  .maparea:has(.rail:not([hidden])) > .rail { grid-area:1 / 2; align-self:start;
    margin-top:0; overflow:auto; max-height:100%; }
  /* the strip spans the map, not the rail */
  .maparea:has(.rail:not([hidden])) .window.strip {
    right:calc(var(--rail-w) + var(--sp-2) + var(--sp-2)); }
}

@media (prefers-color-scheme: dark) {
  :root { --bg:#141413; --card:#1e1e1c; --ink:#ededea; --mut:#9c9c96; --line:#33332f;
          --acc:#4fc79c; --warn:#e6905a; --sel:rgba(79,199,156,.12);
          --sh-1:0 1px 2px rgba(0,0,0,.5); --sh-2:0 2px 14px rgba(0,0,0,.35); }
}
* { box-sizing:border-box; }
/* USR-124(1) grammar-parity screenshot pass, 2026-09-11: `[hidden]` alone did not hide
   a `.bar`-classed element -- `.bar { display:flex }` and the browser's own default
   `[hidden] { display:none }` tie on specificity, and the later author rule won, so
   observe mode's `.hidden = true` on #pricebar/#scanbar/#photobar/#submitbar left all
   four rendered (caught by a screenshot, not by `_scratch/observe_probe.js`, which only
   asserted the DOM property, never computed style). One rule, ahead of every class that
   sets its own `display`, makes `hidden` win everywhere it is set -- present and future. */
[hidden] { display:none !important; }
body { margin:0; padding:var(--sp-3); font:var(--fs-md)/1.4 system-ui,-apple-system,"Segoe UI",sans-serif;
       background:var(--bg); color:var(--ink); -webkit-text-size-adjust:100%; font-variant-numeric:tabular-nums; }
a { color:var(--acc); text-decoration:none; } a:hover { text-decoration:underline; }

/* header: wordmark, domain nav, tier line */
.top { display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--sp-2) var(--sp-4);
       padding-bottom:var(--sp-3); border-bottom:1px solid var(--line); margin-bottom:var(--sp-4); }
.top h1 { font-size:var(--fs-xl); line-height:34px; margin:0; letter-spacing:-.01em; font-weight:650; }
.top h1 small { font-size:var(--fs-sm); color:var(--mut); font-weight:400; letter-spacing:0; }
/* USR-106: the landing pitch and the disclaimer footer, one copy for every page (market's words). */
.pitch { font-size:var(--fs-md); color:var(--ink); margin:0 0 var(--sp-2); max-width:60em; }
/* USR-124(5): the headline leads with today's best route and its profit, not the
   generic pitch below it -- bigger and bolder, same max-width so it wraps the same way. */
.headline { font-size:var(--fs-lg); font-weight:650; color:var(--ink); margin:0 0 var(--sp-2); max-width:60em; }
/* MKT-10(ii), USR-approved: the four "what it is not" lines as an always-visible 4-up
   row instead of a tap-to-expand <details> -- more tap-friendly than USR-98 asked for,
   not less, since there is nothing left to open. Copy is unchanged (marketing/landing.md
   section 2); only the presentation changed. */
.not { margin-bottom:var(--sp-3); }
.not .lbl2 { display:block; font-size:var(--fs-xs); font-weight:650; letter-spacing:.06em;
  text-transform:uppercase; color:var(--mut); margin-bottom:var(--sp-2); }
.notgrid { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--sp-3); }
.notgrid svg { display:block; margin-bottom:var(--sp-1); }
.notgrid b { display:block; font-size:var(--fs-sm); margin-bottom:2px; }
.notgrid span { color:var(--mut); font-size:var(--fs-sm); line-height:1.5; }

/* USR-120/SPEC 6.2a: the computation drawer (quantity, cost model) -- collapsed by
   default, native <details> so it needs no JS and stays keyboard/touch accessible. */
.drawer { margin:0 0 var(--sp-3); }
.drawer summary { cursor:pointer; min-height:var(--tap); display:flex; align-items:center;
  font-size:var(--fs-sm); color:var(--mut); list-style:none; }
.drawer summary::-webkit-details-marker { display:none; }
.drawer summary::before { content:'\25b8'; display:inline-block; margin-right:var(--sp-1);
  transition:transform 150ms ease; }
.drawer[open] summary::before { transform:rotate(90deg); }
.drawer[open] summary { color:var(--ink); }
.drawer .bar { margin-top:var(--sp-1); }
footer.site { margin-top:var(--sp-5); padding-top:var(--sp-3); border-top:1px solid var(--line); font-size:var(--fs-sm); }
footer.site a { color:var(--mut); }
footer.site #disclaimer { margin-top:var(--sp-2); max-width:60em; }
.nav { display:flex; gap:var(--sp-1); margin-left:auto; }
.nav a { font-size:var(--fs-sm); color:var(--mut); padding:var(--sp-1) var(--sp-2);
         border:1px solid transparent; border-radius:var(--r-1); }
.nav a.on { color:var(--ink); border-color:var(--line); background:var(--card); }
.nav a:hover { text-decoration:none; border-color:var(--line); }
.homepin { border:0; background:none; cursor:pointer; font-size:var(--fs-sm);
  color:var(--line); padding:0 0 0 var(--sp-1); line-height:1; vertical-align:middle; }
.homepin.set, .homepin:hover, .homepin:focus-visible { color:var(--acc); }
/* USR (2026-09-12): the star was invisible at --line on a light card and gave no feedback at
   all. Hollow = not pinned, filled = pinned; both readable, both a real tap target. */
.homepin { min-width:var(--tap); }
.homepin:not(.set) { color:var(--mut); }
.pinsay { font-size:var(--fs-sm); color:var(--mut); margin:var(--sp-1) 0 0; }
.coach { display:flex; flex-wrap:wrap; gap:var(--sp-2); align-items:center;
  background:var(--card); border:1px solid var(--line); border-radius:var(--r-1);
  padding:var(--sp-2) var(--sp-3); margin:0 0 var(--sp-2); font-size:var(--fs-sm); }

/* controls */
.bar { display:flex; flex-wrap:wrap; gap:var(--sp-2) var(--sp-3); align-items:center; margin:var(--sp-3) 0; }
label { color:var(--mut); font-size:var(--fs-sm); display:inline-flex; align-items:center; gap:var(--sp-1); }
select, input, button { font:inherit; font-size:var(--fs-md); min-height:var(--tap);
  padding:var(--sp-1) var(--sp-2); border:1px solid var(--line); border-radius:var(--r-1);
  background:var(--card); color:var(--ink); }
input::placeholder { color:var(--mut); }
select:focus-visible, input:focus-visible, button:focus-visible { outline:2px solid var(--acc); outline-offset:1px; }
button { cursor:pointer; } button:hover { border-color:var(--mut); }
button.primary { background:var(--acc); color:#fff; border-color:var(--acc); font-weight:600; }
button.primary:hover { filter:brightness(1.08); border-color:var(--acc); }
/* USR-124(1): one accent color for the conversion action only (Submit a reading, Pay/
   Buy); a capture/read-device button is secondary (explicit alias of the plain default,
   named so the hierarchy is a decision, not an accident); a recompute-the-display action
   (Refresh, admin's Refresh) is tertiary, the least visual weight of the three. */
button.secondary { background:var(--card); border:1px solid var(--line); color:var(--ink); }
button.secondary:hover { border-color:var(--mut); }
button.tertiary { background:none; border-color:transparent; color:var(--mut); font-weight:500; }
button.tertiary:hover { color:var(--ink); border-color:var(--line); }
input:disabled, select:disabled, button:disabled { opacity:.55; cursor:not-allowed; }

/* layout */
.grid { display:grid; grid-template-columns:minmax(280px,1fr) minmax(280px,1fr); gap:var(--sp-4); }
.card { background:var(--card); border-radius:var(--r-2); padding:var(--sp-3); box-shadow:var(--sh-1), var(--sh-2); }
/* CNS-1(iii): /terms and /privacy -- plain prose, no map chrome. */
.legal { max-width:64em; margin:0 auto; }
.legal h2 { margin-top:var(--sp-4); font-size:var(--fs-md); }
.legal p { max-width:70ch; line-height:1.6; }
.legal hr { border:none; border-top:1px solid var(--line); margin:var(--sp-4) 0; }
.card h2 { font-size:var(--fs-sm); margin:0 0 var(--sp-2); color:var(--mut);
           font-weight:650; letter-spacing:.04em; text-transform:uppercase; }
.card h2.mt { margin-top:var(--sp-4); }
.wrap { overflow-x:auto; }

/* tables */
table { width:100%; border-collapse:collapse; font-variant-numeric:tabular-nums; font-size:var(--fs-md); }
th, td { text-align:left; padding:var(--sp-1) var(--sp-2); border-bottom:1px solid var(--line); }
th { color:var(--mut); font-weight:650; font-size:var(--fs-sm); white-space:nowrap; }
tbody tr:last-child td { border-bottom:0; }
td.num, th.num { text-align:right; }
.pos { color:var(--acc); } .neg { color:var(--warn); }

/* state: loading, empty, locked */
.tier { font-size:var(--fs-sm); color:var(--mut); }
.lock { color:var(--mut); font-style:italic; font-size:var(--fs-sm); }
/* USR-397: a gatherer's light, colored as /api/admin/health serves it (admin.html). */
.light { display:inline-block; width:.7em; height:.7em; border-radius:50%; vertical-align:middle; margin-right:.4em; background:var(--mut); }
.light.green { background:var(--acc); } .light.amber { background:#d9a21b; } .light.red { background:var(--warn); } .light.grey { background:var(--mut); }
.state { color:var(--mut); font-size:var(--fs-sm); padding:var(--sp-3); text-align:center; }
.state.err { color:var(--warn); }

/* badges */
.demo, .rt, .crowtag { font-size:var(--fs-xs); white-space:nowrap; }
.demo { color:var(--warn); border:1px solid var(--warn); border-radius:3px; padding:0 3px; margin-left:var(--sp-1); }
.rt { background:var(--card); color:var(--acc); border:1px solid var(--acc); border-radius:3px;
      padding:1px 4px; font-weight:650; }
.rt.crow { color:var(--warn); border-color:var(--warn); }
.crowtag { color:var(--warn); margin-left:3px; }

/* map + legend */
#lmap { height:420px; border-radius:var(--r-1); } #lmap.off { display:none; }
/* R-37/SPEC 4.4: the 3-D scene overlays #lmap in place (same box, via .maparea's own
   position:relative) rather than duplicating every #lmap breakpoint rule above -- #lmap
   is never hidden (see switchView, web/index.html) so it keeps sizing the row the way it
   always has, and #gl3d just sits on top of it at whatever size that turns out to be.
   z-index:2 clears Leaflet's controls (already trapped under .herowrap's z-index:1,
   1843) but stays under the .window.strip quote (1100) so the price strip still reads
   over either view. */
#gl3d { position:absolute; inset:0; width:100%; height:100%; border-radius:var(--r-1);
  touch-action:none; cursor:grab; z-index:2; background:var(--bg); }
#gl3d[hidden] { display:none; }
svg#map { width:100%; height:auto; display:block; background:var(--bg); border-radius:var(--r-1); }
svg#map[hidden] { display:none; }
.lbl { font:var(--fs-xs) system-ui; background:var(--card); color:var(--ink);
       border:1px solid var(--line); border-radius:3px; padding:1px 4px; white-space:nowrap; }
.legend { display:flex; flex-wrap:wrap; gap:var(--sp-2) var(--sp-3); margin-top:var(--sp-2);
          font-size:var(--fs-xs); color:var(--mut); align-items:center; }
.legend span { display:inline-flex; align-items:center; gap:var(--sp-1); }
.legend i { display:inline-block; font-style:normal; }
.legend .ramp { width:56px; height:8px; border-radius:2px;
                background:linear-gradient(90deg,#1a9850,#f7e08a,#d73027); }
.legend .w1, .legend .w2 { height:8px; background:var(--mut); border-radius:2px; }
.legend .w1 { width:6px; } .legend .w2 { width:16px; }
.legend .fade { width:16px; height:8px; border-radius:2px; background:var(--mut); opacity:.35; }
.legend .fill1, .legend .fill2 { width:8px; height:8px; border-radius:50%; background:var(--mut); }
.legend .fill1 { opacity:.35; } .legend .fill2 { opacity:.9; }
.legend .solid, .legend .dash { width:26px; border-top:2px solid var(--acc); }

/* USR-107: 150-ms transitions on marker changes and the timeline scrub */
.leaflet-interactive { transition:r 150ms ease, opacity 150ms ease, fill-opacity 150ms ease; }
.window .quote, .verdict { transition:opacity 150ms ease; }
.legend .dash { border-top-style:dashed; border-color:var(--warn); }
/* USR-161/162: the position-uncertainty disk blends with multiply so overlapping disks
   darken into each other instead of occluding whichever was drawn last. */
.egr-disk { mix-blend-mode: multiply; }

/* plans */
.plans { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--sp-2); }
.plan { border-radius:var(--r-2); padding:var(--sp-2) var(--sp-3); box-shadow:var(--sh-1);
        cursor:pointer; background:var(--card); text-align:left; display:block; width:100%; min-height:0;
        transition:box-shadow 150ms ease; }
.plan:hover { box-shadow:var(--sh-2); }
.plan.on { box-shadow:0 0 0 2px var(--acc), var(--sh-2); background:var(--sel); }
.plan b { display:block; font-size:var(--fs-md); }
.plan .p { color:var(--acc); font-weight:650; } .plan .w { color:var(--mut); font-size:var(--fs-sm); display:block; margin-top:var(--sp-1); }

/* selectable rows */
#routes tr[data-i] { cursor:pointer; }
#routes tr[data-i]:hover td { background:var(--sel); }
#routes tr[data-i]:focus { outline:2px solid var(--acc); outline-offset:-2px; }
#routes tr.sel td { background:var(--sel); }
#routes tr.sel td:first-child { box-shadow:inset 2px 0 0 var(--acc); }

/* verdict (homes) */
.verdict { font-size:var(--fs-xl); margin:var(--sp-2) 0; font-weight:650; }
.verdict:empty { display:none; }   /* USR-374 stage 2b: the shell carries #verdict on every row; it takes no space until a listing is evaluated */
.above { color:var(--warn); } .below { color:var(--acc); }

/* BE-11 / USR-21: the catalog search box and its hit list. The nav tabs reuse `.nav`. */
.find { position:relative; }
.find input[type=search] { font:inherit; padding:var(--sp-1) var(--sp-2); min-height:var(--tap);
  border:1px solid var(--line); border-radius:var(--r-1); background:var(--card); color:var(--ink); }
.hits { position:absolute; z-index:1200; top:100%; left:0; right:0; margin-top:var(--sp-1);
  background:var(--card); border:1px solid var(--line); border-radius:var(--r-2);
  box-shadow:0 6px 20px rgba(0,0,0,.10); max-height:320px; overflow:auto; }
.hits button { display:block; width:100%; text-align:left; background:none; border:0;
  border-bottom:1px solid var(--line); padding:var(--sp-2) var(--sp-3); min-height:var(--tap);
  font:inherit; color:var(--ink); cursor:pointer; }
.hits button:last-child { border-bottom:0; }
.hits button:hover, .hits button:focus { background:var(--sel); outline:none; }
.hits .where { color:var(--mut); font-size:var(--fs-sm); }
.hits .state { display:block; }
.reqform { display:flex; flex-wrap:wrap; gap:var(--sp-1); padding:var(--sp-2) var(--sp-3); }
.reqform input { font:inherit; padding:var(--sp-1) var(--sp-2); min-height:var(--tap); flex:1 1 8em;
  border:1px solid var(--line); border-radius:var(--r-1); background:var(--card); color:var(--ink); }
.reqform button { min-height:var(--tap); padding:var(--sp-1) var(--sp-2); border-radius:var(--r-1);
  border:1px solid var(--acc); background:var(--acc); color:#fff; font-weight:600; cursor:pointer; }
.reqform button:disabled { opacity:.6; cursor:default; }

/* USR-84: the evidence trail panel, opened from a belief row. */
#evidence { position:relative; }
#evidence .close { position:absolute; top:var(--sp-2); right:var(--sp-2); min-height:var(--tap); min-width:var(--tap);
  border:0; background:none; font-size:var(--fs-xl); line-height:1; cursor:pointer; color:var(--mut); }
#evidence table .lock { display:table-row; }
/* USR-6: the contributor-trust panel shares the evidence panel's close-button chrome. */
#contributors { position:relative; }
#contributors .close { position:absolute; top:var(--sp-2); right:var(--sp-2); min-height:var(--tap); min-width:var(--tap);
  border:0; background:none; font-size:var(--fs-xl); line-height:1; cursor:pointer; color:var(--mut); }
#beliefs tr[data-store] { cursor:pointer; }
#beliefs tr[data-store]:hover, #beliefs tr[data-store]:focus { background:var(--sel); outline:none; }

/* BE-30: the registration form, same shape as .reqform. */
.regform { display:flex; flex-wrap:wrap; gap:var(--sp-1); align-items:center; margin-top:var(--sp-2); }
.regform .gsi { flex:1 1 100%; margin-top:var(--sp-1); }
.regform input { font:inherit; padding:var(--sp-1) var(--sp-2); min-height:var(--tap); flex:1 1 10em;
  border:1px solid var(--line); border-radius:var(--r-1); background:var(--card); color:var(--ink); }
.regform button { min-height:var(--tap); padding:var(--sp-1) var(--sp-2); border-radius:var(--r-1);
  border:1px solid var(--acc); background:var(--acc); color:#fff; font-weight:600; cursor:pointer; }
.regform button:disabled { opacity:.6; cursor:default; }
.regform .state { flex-basis:100%; }
/* IMP-32/R-26(2): registration led with its own case (not a trailing link after the
   anonymous form) and given the same button weight as the paid-tier CTAs. */
.regpromo { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between;
  gap:var(--sp-3); margin:var(--sp-2) 0 var(--sp-3); padding:var(--sp-2) var(--sp-3);
  border-radius:var(--r-2); background:var(--sel); border-left:3px solid var(--acc); }
.regpromo b { display:block; }
.regpromo button.primary { flex:0 0 auto; min-height:var(--tap); padding:var(--sp-1) var(--sp-3);
  border-radius:var(--r-1); font-weight:650; cursor:pointer; white-space:nowrap; }
.nav a.soon { opacity:.45; cursor:default; }

/* USR-67: the window quote strip — the price at a glance for what the map is showing. */
.window { display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--sp-2) var(--sp-3);
  padding:var(--sp-2) var(--sp-3); border:1px solid var(--line); border-radius:var(--r-2);
  background:var(--card); margin-bottom:var(--sp-3); }
.window .quote { font-size:var(--fs-lg); letter-spacing:-.01em; }
.window .quote b { font-size:var(--fs-sm); font-weight:600; color:var(--mut); text-transform:uppercase;
  letter-spacing:.04em; margin-left:var(--sp-2); }
.window .quote b:first-child { margin-left:0; }
.window .res { font-size:var(--fs-sm); color:var(--acc); border:1px solid var(--line);
  border-radius:var(--r-1); padding:0 var(--sp-1); }
.window .where { color:var(--mut); font-size:var(--fs-sm); }
.window .up { margin-left:auto; }

/* USR-85 (2): the quote sits on the map's top edge, not as a banner above it; the legend
   and the one-line help are toggles so the map keeps the space. */
.maparea { position:relative; }
.window.strip { position:absolute; top:var(--sp-2); left:var(--sp-2); right:var(--sp-2); z-index:1100;
  margin-bottom:0; box-shadow:0 1px 6px rgba(0,0,0,.18); padding:var(--sp-1) var(--sp-2); }
/* user, 2026-09-10: the strip hid the zoom control (Leaflet's own controls sit at z-index 1000
   in the top-left). The strip wins the stacking order and Leaflet's top controls drop below it,
   so neither covers the other. */
.maparea .leaflet-top .leaflet-control { margin-top:54px; }
/* nothing quoted, nothing to clear (ignored where :has is unsupported, which only
   restores the unconditional gap) */
.maparea:has(.window.strip:empty) .leaflet-top .leaflet-control { margin-top:var(--sp-2); }
.window.strip:empty { display:none; }
.window.strip .quote { font-size:var(--fs-md); }
.legendbtn, .helpbtn { font-size:var(--fs-sm); padding:2px var(--sp-2); border:1px solid var(--line);
  border-radius:var(--r-1); background:var(--card); color:var(--mut); cursor:pointer;
  /* self-caught before landing: .legendbtn is a direct child of .card, which the map/
     sidebar height-fill fix above (.split .herowrap .card) turns into a flex column --
     the flex default (align-items:stretch) would otherwise stretch this button to the
     card's full width, a plain button with no intrinsic width of its own. align-self is a
     no-op outside a flex/grid context, so this is harmless on every other page this rule
     already applies to. */
  align-self:flex-start; }
.legendbtn { margin-top:var(--sp-2); }
.help { margin:var(--sp-1) 0 var(--sp-2); }
.helptext { display:block; margin-top:var(--sp-1); color:var(--mut); font-size:var(--fs-sm); max-width:70ch; }
/* the `?` is a button, not a hover hint: a touch screen has no hover (user, 2026-09-10) */
button.q { font:inherit; font-size:var(--fs-xs); line-height:1.4; color:var(--mut); background:var(--card);
  border:1px solid var(--line); border-radius:50%; width:16px; height:16px; padding:0; margin-left:4px;
  cursor:pointer; vertical-align:middle; }
button.q:hover, button.q[aria-expanded="true"] { color:var(--acc); border-color:var(--acc); }
button.q:focus-visible { outline:2px solid var(--acc); outline-offset:1px; }
.termpop { position:absolute; z-index:2000; max-width:min(320px, calc(100vw - 16px));
  background:var(--card); color:var(--ink); border:1px solid var(--line); border-radius:var(--r-2);
  box-shadow:0 4px 14px rgba(0,0,0,.22); padding:var(--sp-2) var(--sp-3); font-size:var(--fs-sm);
  display:flex; gap:var(--sp-2); align-items:flex-start; }
.termpop .x { font:inherit; background:none; border:0; color:var(--mut); cursor:pointer;
  padding:0 2px; line-height:1; }

/* USR-107 firing 2: hero map full-bleed, domain tabs + controls pinned as one sticky
   region above it (direction: "map full-bleed at the top ... domain tabs overlaid,
   controls in one sticky bar"). .hero-controls holds the header (nav = domain tabs)
   and both control bars as a single sticky block; .herowrap breaks the map out to the
   page edge without touching #lmap's own JS-set size logic. */
/* USR-225 (defect, measured): sticky at 1,098px tall on a 375x812 phone, so the block
   pinned over everything below it. Nothing sticky may be taller than ~15% of the
   viewport; only .topbar (.top on pages not yet split) is sticky now, and this wrapper
   is ordinary flow. USR-227 folded in. */
.hero-controls { position:static; background:var(--bg);
  margin:calc(-1 * var(--sp-3)) calc(-1 * var(--sp-3)) 0; padding:0 var(--sp-3) 0;
  box-shadow:none; }
/* 2026-09-13 (frontend, measured): the full-bleed margins above must equal the body's own
   padding (--sp-3; --sp-2 under 768px, see the last block of this file), and read --sp-4 --
   4px of horizontal page scroll on /homes at every width, and 8px on a phone. */
/* 1654's own open item, closed here: neither #lmap nor .herowrap set a z-index, so they
   never opened a stacking context of their own -- Leaflet's own CSS puts its top/bottom
   control corners (vendor/leaflet/leaflet.css, .leaflet-top/.leaflet-bottom) at z-index:1000,
   which then compared directly against .hero-controls' 900 in the page's root stacking
   context and won, so the attribution control could pass over the sticky bar mid-scroll.
   Trapping the map's own z-index:1000 inside a low context here keeps it under everything
   the page stacks above 1, which is every z-index this file sets. */
.herowrap { position:relative; z-index:1; margin:0 calc(-1 * var(--sp-4)) var(--sp-4); background:var(--card);
  box-shadow:var(--sh-1), var(--sh-2); }
.herowrap .card { box-shadow:none; padding:var(--sp-3) var(--sp-4); border-radius:0; }
.herowrap .maparea { margin:0 calc(-1 * var(--sp-4)); }
.herowrap #lmap, .herowrap svg#map { border-radius:0; }
.herowrap #lmap { height:min(58vh, 520px); }

/* USR-123 (consultant, relaying the user): the full-bleed single column read too big
   on desktop; below 1024px this is unchanged (.herowrap stays exactly as 1654 landed
   it, full-bleed, map first). .sidecol carries what used to be loose .grid children
   (Beliefs, Routes) with the same visual gap .grid gave them. */
.sidecol { display:flex; flex-direction:column; gap:var(--sp-4); }
@media (min-width:1024px) {
  .split { display:grid; grid-template-columns:minmax(0,1fr) minmax(340px,400px);
    gap:var(--sp-4); align-items:stretch; }
  /* the map stops being full-bleed and becomes a normal card in its own column --
     every full-bleed rule above is undone here, at higher specificity, only at this
     width; nothing below 1024px reads any of these lines. */
  .split .herowrap { margin:0; border-radius:var(--r-2); overflow:hidden;
    display:flex; flex-direction:column; }
  .split .herowrap .card { padding:var(--sp-3); border-radius:var(--r-2);
    flex:1; display:flex; flex-direction:column; min-height:0; }
  .split .herowrap .maparea { margin:0; flex:1; min-height:0; }
  .split .herowrap #lmap, .split .herowrap svg#map { border-radius:var(--r-1); }
  /* USR reported (2026-09-11, live): with align-items:start (the previous rule here) a
     column noticeably shorter than its sibling left a large blank gap of bare page
     background below it -- on the goods page the sidecol's stack of cards (Beliefs,
     leaderboard, the reading form, Routes) routinely runs taller than the map card; on
     homes it goes the other way, the map running taller than the short Evaluate/Blocks
     column. align-items:stretch plus this flex chain (herowrap -> its card -> .maparea ->
     #lmap) lets the SHORTER column's map grow to fill the row height either page picks,
     rather than stopping at a fixed 680px and leaving the rest of its own column empty.
     min-height keeps the old floor so a very short sidecol never shrinks the map below
     what it already was; max-height stops an extreme sidecol from growing it absurdly tall. */
  /* no max-height here (an earlier version of this fix capped it at 900px and the user
     still saw a large gap live -- diagnosed: .maparea (flex:1) correctly grew to match
     the tall sidecol, but the cap then stopped #lmap short of it, recreating the same
     blank space one level in). The map is free to grow as large as the sidecol's own
     content makes the row, floored at the original 680px so a short sidecol never
     shrinks it. */
  /* consultant 2026-09-12 (user: "the map is huge"), folded: a fixed, generous height --
     min(62vh, 620px) -- and the map column sticks under the header while the right
     column scrolls beside it, instead of stretching to the table's full height. */
  .split .herowrap { align-self:start; position:sticky; top:calc(var(--topbar-h, 64px) + var(--sp-2));
    max-height:calc(100vh - var(--topbar-h, 64px) - var(--sp-3)); }
  .split .herowrap .card { flex:0 0 auto; }
  .split .herowrap #lmap { height:min(62vh, 620px); min-height:360px; }
  /* the rail takes what is left of the column and scrolls inside it, so the sticky column
     never outgrows the viewport (measured 1,056px on 800: the rail was unreachable). */
  /* USR-253(3) (consultant, 2026-09-13): measured at 1280x800 the rail was 10px tall --
     the sticky column gave the map its fixed 62vh and the rail the remainder, so a reader saw
     one lone store or none. When a rail is showing the map yields 16vh to it and the rail
     keeps a floor of one heading plus two entries; past that it scrolls, with `.rail-more`
     (Egregor.Rail) naming how many entries are below the fold. */
  .split #rail.rail { flex:1 1 auto; min-height:8.5rem; max-height:none; overflow:auto; }
  .split .herowrap:has(#rail:not([hidden])) #lmap { height:min(46vh, 560px); }
}

/* USR-178/USR-222: the currency and the estimate mark a money column carries once, in its
   own header, so the cells below it can stay bare figures with a symbol. Quieter than the
   label it follows -- it is the column's unit, not its name. */
.ccy { font-weight:400; font-size:var(--fs-sm); color:var(--mut); white-space:nowrap; }

/* USR-214(10): a thumb needs 44px, and the fraction of this audience on a touch screen is
   the fraction that contributes readings. It keys off the pointer, not the width, so a
   touch tablet in the two-column layout gets it too; a mouse keeps 32px, which is still
   above WCAG 2.5.8's 24px minimum. */
@media (pointer:coarse) {
  :root { --tap:44px; }
}

/* phone first: the contributor submits from a phone */
@media (max-width:760px) {
  :root { --tap:44px; }
  body { padding:var(--sp-3); }
  .grid { grid-template-columns:1fr; }
  .plans { grid-template-columns:1fr; }
  .notgrid { grid-template-columns:1fr 1fr; }
  .nav { margin-left:0; width:100%; flex-wrap:wrap; }
  .find, .find input[type=search] { width:100%; }
  .bar label, .bar input, .bar select { flex:1 1 auto; min-width:9em; }
  .bar button { flex:1 1 100%; }
  #lmap { height:300px; }
  .window .up { margin-left:0; width:100%; }
  .window.strip { position:static; margin-bottom:var(--sp-2); box-shadow:none; }
  .maparea .leaflet-top .leaflet-control { margin-top:var(--sp-2); }
  .top h1 { font-size:var(--fs-lg); }
  /* USR-222(1) (user on an iPhone, 2026-09-12): "two panels that are hard to scroll
     between". This was the second panel -- a 60vh scroll container holding the header,
     nav, search and controls, nested inside the page's own scroll. Two scrollers stacked
     on one screen means a drag lands in whichever one the thumb happened to start over,
     which is the whole of the report. On a phone the header is part of the one document
     flow and scrolls with it; it keeps the negative margins that make it full-bleed, and
     nothing else. Above 760px it is untouched (the sticky desktop region, USR-107). */
  .hero-controls { margin:calc(-1 * var(--sp-3)) calc(-1 * var(--sp-3)) 0;
    padding:var(--sp-2) var(--sp-3) 0; max-height:none; overflow:visible; }
  .hero-controls { margin-left:calc(-1 * var(--sp-2)); margin-right:calc(-1 * var(--sp-2)); }
  .herowrap { margin:0 calc(-1 * var(--sp-3)) var(--sp-3); }
  .herowrap .card { padding:var(--sp-2) var(--sp-3); }
  .herowrap .maparea { margin:0 calc(-1 * var(--sp-3)); }
  .herowrap #lmap { height:min(46vh, 340px); }
}

/* USR-157 step 1 (user, 2026-09-11): the OSM basemap was competing with the markers it is
   supposed to sit under -- the SPEC 3.3b encoding (disk size = position sd, saturation =
   price confidence, hue = the price ramp) only reads against a muted ground. Step 1 needs no
   ruling: the same OSM tiles R-1 already allows, rendered through a CSS filter so roads and
   water stay legible in light gray and every colored marker pops. Markers, disks, routes and
   captions are separate panes and are not filtered. Step 2 of USR-157 -- a real "roads only"
   tile style from a second host -- is a ruling request (R-1 amendment) and waits. */
.leaflet-tile-pane .egr-tiles { filter:grayscale(82%) saturate(1.1) brightness(1.06) contrast(.92); opacity:.9;  /* user 2026-09-14: the faintest hint of color */ }
@media (prefers-color-scheme: dark) {
  .leaflet-tile-pane .egr-tiles { filter:grayscale(85%) brightness(.62) contrast(.95); opacity:.8; }
}

/* ---- USR-214(1): a table you can read on a phone ---------------------------
   Three changes, all driven by Egregor.Tables' `data-label`/`.fold` stamping:
   a header row that stays put while you read down; a cue on the right edge when
   the table really does overflow, so the scroll is offered rather than hidden;
   and, under 760px, each row drawn as a card - one label/value line per cell -
   with the columns past the third behind one toggle that names how many there
   are. Above 760px the table is exactly what it was, plus the sticky header. */
.wrap { position:relative; }
.wrap table th { position:sticky; top:0; z-index:2; background:var(--card); }
.wrap[data-of]::after {
  content:""; position:sticky; right:0; top:0; float:right; width:24px; height:100%;
  pointer-events:none; background:linear-gradient(to right, rgba(0,0,0,0), rgba(0,0,0,.10));
}
.tbar { display:flex; justify-content:flex-end; margin:0 0 var(--sp-1); }
button.tmore { font-size:var(--fs-sm); min-height:var(--tap); }
.tbar[hidden] { display:none; }
table.cards tr.fullrow td { text-align:left; }

@media (max-width:760px) {
  /* No sideways scroll to discover: the row is the card. */
  .wrap { overflow-x:visible; }
  table.cards, table.cards tbody { display:block; }
  table.cards tr { display:block; border:1px solid var(--line); border-radius:var(--r-2);
    margin-bottom:var(--sp-2); padding:var(--sp-2); background:var(--card); }
  table.cards tr.hrow { display:none; }                     /* the header row is the labels */
  table.cards tr.fullrow { padding:var(--sp-2); }
  table.cards td { display:flex; justify-content:space-between; align-items:baseline;
    gap:var(--sp-4); border-bottom:0; padding:var(--sp-1) 0; min-height:var(--tap); }
  table.cards td.num { text-align:right; }
  table.cards td::before { content:attr(data-label); color:var(--mut);
    font-size:var(--fs-sm); font-weight:650; white-space:nowrap; }
  table.cards tr.fullrow td::before { content:none; }
  table.cards td.fold { display:none; }
  .wrap.allcols table.cards td.fold { display:flex; }
  /* the first cell of a card is its name; it reads as the card's title */
  table.cards tr:not(.fullrow) td:first-child { font-weight:650; padding-bottom:var(--sp-2);
    border-bottom:1px solid var(--line); margin-bottom:var(--sp-1); }
}
@media (prefers-color-scheme: dark) {
  .wrap[data-of]::after { background:linear-gradient(to right, rgba(0,0,0,0), rgba(0,0,0,.35)); }
}
@media (min-width:761px) {
  /* Above the card breakpoint every column is drawn, so the fold toggle would be a
     control that does nothing; the scroll cue is what the wide table gets instead. */
  .tbar { display:none; }
}

/* ---- USR-220 (user, 2026-09-12): less text above the fold, color with a purpose,
   and motion. All of it is CSS plus web/common.js's Motion helper -- no library, no
   build step, no network (S9). Tier: none new (S10); this renders what the tier
   already returns. ---- */

/* (3) the word budget. One line says what you are looking at; the paragraph and the
   "what Egregor is not" grid move into this disclosure, still one click away and still
   on /about in full. */
/* The lede sits in the header row, on its own line under the wordmark -- exactly where
   the <small> tagline it replaces sat, so the sticky block is no taller than before and
   "what am I looking at" is read before the callout and the controls, not after them. */
.top .lede { flex-basis:100%; order:9; margin:0; }
.lede { font-size:var(--fs-lg); font-weight:650; color:var(--ink); margin:var(--sp-2) 0;
  max-width:34em; line-height:1.35; }
.explain { margin:0 0 var(--sp-3); }
.explain > summary { cursor:pointer; font-size:var(--fs-sm); color:var(--mut);
  padding:var(--sp-1) 0; list-style:revert; }
.explain > summary:hover { color:var(--ink); }
.explain[open] > summary { margin-bottom:var(--sp-2); }

/* (2) color with a purpose. */
.callout.opportunity { border-left-color:var(--save); background:var(--save-bg); }
.callout.opportunity .say { color:var(--save); }
.callout .countup { font-variant-numeric:tabular-nums; }
.legend .fade { outline:1px solid var(--conf); }
.chip.conf, .conf { color:var(--conf); }

/* (1) motion. Every rule below is off under prefers-reduced-motion (bottom of this
   block), because a number that moves is a number some readers cannot read. */
@keyframes egr-in { from { opacity:0; transform:scale(.6); } to { opacity:1; transform:scale(1); } }
@keyframes egr-breathe { 0%,100% { transform:scale(1); } 50% { transform:scale(1.12); } }
@keyframes egr-draw { from { stroke-dashoffset:1200; } to { stroke-dashoffset:0; } }
@keyframes egr-rise { from { opacity:0; transform:translateY(6px); } to { opacity:1; transform:none; } }
path.egr-in, path.egr-mk, path.egr-foot { transform-box:fill-box; transform-origin:center; }
path.egr-in { animation:egr-in .45s cubic-bezier(.2,.8,.3,1) both; }
path.egr-mk { transition:stroke-width .15s ease, r .15s ease; }
path.egr-mk:hover { stroke-width:3; }
path.egr-route { stroke-dasharray:1200; animation:egr-draw 1.1s ease-out both; }
.egr-landed path.egr-disk { animation:egr-breathe 1.6s ease-in-out 2; }
.callout, .lede { animation:egr-rise .4s ease-out both; }
@media (prefers-reduced-motion: reduce) {
  path.egr-in, path.egr-route, .egr-landed path.egr-disk, .callout, .lede { animation:none; }
  path.egr-route { stroke-dasharray:none; }
}

/* USR-214 clause 2, the handle (web/common.js Egregor.MapHandle). Phones only: above
   760px the map's height comes from the layout row, not from a stored pixel value. The
   target is 44px tall even though the grip drawn inside it is 4px, because clause 10 asks
   for 44px and a 4px drag target is unusable with a thumb. */
.maphandle { display:none; }
@media (max-width:760px) {
  .maphandle { display:flex; align-items:center; justify-content:center;
    height:44px; margin:calc(-1 * var(--sp-1)) 0 var(--sp-1); cursor:ns-resize;
    touch-action:none; background:transparent; border:0; }
  .maphandle .grip { display:block; width:56px; height:4px; border-radius:999px;
    background:var(--line); transition:background .15s ease, width .15s ease; }
  .maphandle:hover .grip, .maphandle:focus-visible .grip, .maphandle.on .grip {
    background:var(--mut); width:72px; }
  .maphandle:focus-visible { outline:2px solid var(--acc); outline-offset:-4px; border-radius:var(--r-1); }
}
@media (prefers-reduced-motion: reduce) { .maphandle .grip { transition:none; } }

/* ---- USR-222(2): the way back ----------------------------------------------
   Tapping a store in a card scrolls the map to the reader (Egregor.MapFocus). The pill
   is what makes that a round trip rather than a one-way scroll: it sits on the map the
   reader was just taken to, and returns them to the card they tapped. Phones only --
   above 760px the map and the list are side by side and nothing moved.
   `.selcard` is the tapped row, marked so the card is still findable after the scroll. */
.backtolist { display:none; }
@media (max-width:760px) {
  .maparea { position:relative; }
  .backtolist { display:block; position:absolute; z-index:1100; left:50%; bottom:var(--sp-2);
    transform:translateX(-50%); min-height:var(--tap); padding:0 var(--sp-3);
    border:1px solid var(--line); border-radius:999px; background:var(--card);
    color:var(--ink); font:inherit; font-size:var(--fs-sm); font-weight:650;
    box-shadow:var(--sh-2); cursor:pointer; }
  .backtolist:focus-visible { outline:2px solid var(--acc); outline-offset:2px; }
  table.cards tr.selcard, li.selcard { border-color:var(--acc); background:var(--sel); }
}

/* ---- USR-226 / USR-230: the document order, every size -----------------------
   (1) header#topbar, sticky, short: wordmark, search, account, "?", the domain tabs and
   the chip row [item] [qty] [plan] (USR-230: the chips are IN the header so the item can
   be changed from anywhere on the page) (2) the context line (3) the callout (4) the map
   (5) #rail, a block under the map (6) the tables (7) the footer. Everything explanatory
   is behind #helpbtn (.guide); everything that tunes a computation is in a sheet opened
   from its chip. The consultant's 2026-09-12/13 blocks (USR-227/230/213/234/235) are
   folded in here at their numbers or tighter; nothing of theirs stands as an override. */
:root { --topbar-h:84px; }
.top, .topbar { position:sticky; top:0; z-index:900; background:var(--bg);
  display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-1) var(--sp-3);
  padding:6px 0; margin:0 0 var(--sp-2); border-bottom:1px solid var(--line); }
.top h1, .topbar h1 { font-size:22px; line-height:28px; margin:0; font-weight:650;
  letter-spacing:-.01em; }
/* USR-318 verify pass (2026-09-14, measured): /terms#photos landed with its first line under the
   sticky header (anchor y=0, header 63 px). Every in-page anchor clears the sticky bar. */
h2[id], h3[id], p[id], section[id] { scroll-margin-top:calc(var(--topbar-h, 84px) + var(--sp-3, 16px)); }
.topbar .nav, .topbar #nav { margin-left:auto; }
.nav a, .tabs button { text-align:center; }
.nav a .where { display:inline; white-space:nowrap; color:var(--mut); font-size:.85em; opacity:.85; }  /* count sits a space after the label (user, 2026-09-13) */
#helpbtn { min-height:28px; padding:0 10px; border-radius:999px; font-weight:650;
  line-height:26px; }
/* USR-245: the settings menu -- one "⋯" at the right edge of the header on every width */
.settings { display:inline-flex; align-items:center; }
.setbtn { min-height:28px; min-width:32px; padding:0 8px; border-radius:999px; font-weight:700;
  font-size:18px; line-height:26px; letter-spacing:.05em; }
.setbtn[aria-expanded="true"] { background:var(--sel); border-color:var(--acc); color:var(--ink); }
.setrow { margin:0 0 var(--sp-1); }
.setrow label { display:flex; align-items:center; gap:var(--sp-2); }
.setrow select { flex:1; min-height:var(--tap); font:inherit; }
/* the chip row: the header's own last line on every width */
.chiprow { flex:0 0 100%; display:flex; gap:var(--sp-1); flex-wrap:nowrap; overflow-x:auto;
  scrollbar-width:none; padding:2px 0 4px; align-items:center; }
.chiprow::-webkit-scrollbar { display:none; }
.chiprow .chip, .tpick.chip { display:inline-flex; align-items:center; gap:4px; padding:2px 10px; border:1px solid var(--line);
  border-radius:999px; background:var(--card); color:var(--ink); font:inherit; font-weight:600;
  font-size:var(--fs-sm); line-height:22px; max-width:16em; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; cursor:pointer; min-height:28px; }
.chiprow .chip::after { content:" \25BE"; color:var(--acc); }
.chiprow .chip:first-child { border-color:var(--acc); }
.chiprow .chip[aria-expanded="true"] { background:var(--sel); border-color:var(--acc); }
/* USR-330: the side chip is a toggle, not a sheet -- no caret, and pressed = selling. */
.chiprow .chip.toggle::after { content:none; }
.chiprow .chip.toggle[aria-pressed="true"] { background:var(--sel); border-color:var(--acc); }
/* the sheets: one control each; bottom sheet under 768px, popover under the chip above */
.sheetback { position:fixed; inset:0; z-index:950; background:rgba(0,0,0,.28); }
.sheet { position:fixed; z-index:960; background:var(--card); border:1px solid var(--line);
  border-radius:var(--r-2); box-shadow:var(--sh-2); padding:var(--sp-2) var(--sp-3);
  max-height:70vh; overflow:auto; }
.sheethead { display:flex; align-items:center; justify-content:space-between; margin:0 0 var(--sp-1); }
.sheethead b { font-size:var(--fs-md); }
.sheetrow { display:flex; align-items:center; gap:var(--sp-2); margin:0 0 var(--sp-1); }
.sheetrow select, .sheetrow input { flex:1; min-height:var(--tap); font:inherit; }
.sheet .bar { margin:var(--sp-1) 0 0; }
.sheet .drawer { margin:var(--sp-1) 0 0; }
.skutree { margin-top:var(--sp-1); }
.tnode { margin:0 0 2px; }
.tnode summary { cursor:pointer; padding:4px 0; font-weight:600; text-transform:capitalize; }
.tnode .tnode { margin-left:var(--sp-3); }
.tleaf { list-style:none; margin:0 0 var(--sp-1) var(--sp-3); padding:0; }
.tpick { background:none; border:0; color:var(--acc); font:inherit; padding:4px 0; cursor:pointer;
  min-height:32px; text-align:left; }
.tpick.chip { color:var(--ink); padding:2px 10px; }
.recent { margin-top:var(--sp-1); display:flex; flex-wrap:wrap; gap:var(--sp-1); align-items:center; }
@media (max-width:767px) {
  .sheet { left:0; right:0; bottom:0; border-radius:var(--r-2) var(--r-2) 0 0; max-height:80vh;
    padding-bottom:calc(var(--sp-3) + env(safe-area-inset-bottom, 0px)); }
}
/* the rest of the order */
/* CNS-6: the first-visit "not" strip, one line above the fold, gone at the first tap or key. */
.notline { display:flex; align-items:center; gap:var(--sp-2); margin:0 0 var(--sp-2); padding:4px var(--sp-2);
  min-height:32px; max-height:44px; overflow:hidden; font-size:var(--fs-xs); line-height:1.3; color:var(--mut);
  border:1px solid var(--line); border-left:3px solid var(--acc); border-radius:6px; background:var(--card); }
.notline span { flex:1 1 auto; min-width:0; }
.notline b { color:var(--ink); font-weight:650; }
.notline button { flex:0 0 auto; min-height:24px; padding:0 8px; font-size:var(--fs-xs); }
.guide { margin:0 0 var(--sp-2); }
.guide .lede { margin:0 0 var(--sp-1); }
.context { margin:0 0 2px; font-size:var(--fs-sm); color:var(--mut); }
/* USR-208 / USR-327: the coverage strip and its "open next" field. */
.coverage { margin:0 0 2px; font-size:var(--fs-sm); color:var(--mut); line-height:1.4; }
.coverage b { color:var(--ink); font-weight:600; }
.coverage .openask { display:inline; }
.coverage .openask button.tertiary { min-height:var(--tap); padding:1px 6px; font-size:var(--fs-sm); }
.coverage .openform { display:inline-flex; flex-wrap:wrap; gap:6px; align-items:center; margin-top:4px; }
.coverage .openform input { width:12em; max-width:60vw; min-height:var(--tap); font-size:var(--fs-sm); }
.coverage .openform button.secondary { min-height:var(--tap); padding:1px 10px; font-size:var(--fs-sm); }
/* USR-331: the "Suggest a place" link and its form, in the places table foot and the online rail. */
.suggestplace { margin-top:var(--sp-1); font-size:var(--fs-sm); }
.suggestplace button.tertiary { min-height:var(--tap); padding:1px 6px; font-size:var(--fs-sm); }
.sp-form { display:grid; gap:6px; margin-top:6px; padding:var(--sp-1) var(--sp-2); border:1px solid var(--line); border-radius:var(--r-1); background:var(--card); }
.sp-form .sp-field { display:grid; grid-template-columns:5em 1fr; gap:6px; align-items:center; }
.sp-form .sp-field input, .sp-form .sp-field select { min-height:var(--tap); font-size:var(--fs-sm); width:100%; min-width:0; box-sizing:border-box; }
.sp-form .sp-lbl { width:5em; }
.sp-form .sp-check { display:inline-flex; align-items:center; gap:4px; min-height:var(--tap); }
.sp-form .sp-row { display:flex; flex-wrap:wrap; gap:6px; align-items:center; }
.sp-form .sp-row button.secondary { min-height:var(--tap); padding:1px 10px; font-size:var(--fs-sm); }
.rail .suggestplace { margin-top:var(--sp-2); }
.tabs { margin:0; }
.pitch, .headline { margin:0 0 var(--sp-1); font-size:var(--fs-md); line-height:1.3; }
.callout { padding:var(--sp-1) var(--sp-2); margin:0 0 var(--sp-1); gap:var(--sp-1) var(--sp-2); }
.callout .say { font-size:var(--fs-md); line-height:1.3; }
.bar { margin:var(--sp-1) 0; gap:var(--sp-1) var(--sp-2); }
.drawer { margin:0 0 var(--sp-1); }
.card { padding:var(--sp-2); }
.card h2 { margin:0 0 var(--sp-1); }
.card h2.mt { margin-top:var(--sp-2); }
th, td { padding:3px var(--sp-1); line-height:1.3; }
.herowrap { margin:0 calc(-1 * var(--sp-3)) var(--sp-2); }
.herowrap .card { padding:var(--sp-2) var(--sp-3); }
/* 2026-09-13 (frontend, measured at 768px): the map's full-bleed margin must equal the card
   padding just above, --sp-3, not the --sp-4 of the base rule -- 4px of horizontal scroll. */
.herowrap .maparea { margin:0 calc(-1 * var(--sp-3)); }
/* the timeline and the 3-D/help line are one slim row inside the map card (USR-230(4)) */
.mapbars { display:flex; flex-wrap:wrap; gap:0 var(--sp-3); align-items:center; }
.mapbars #timebar { flex:1 1 300px; }
.mapbar { margin:var(--sp-1) 0 0; min-height:0; }
.mapbar:empty { display:none; }
#timebar { grid-template-columns:auto 1fr auto; }
@media (min-width:768px) and (max-width:1023px) {
  /* tablet: the chips share the header's second line with the tabs */
  .chiprow { flex:0 1 auto; order:5; max-width:60%; }
  .top .nav, .top #nav, .topbar .nav, .topbar #nav { order:6; flex:1 1 0; min-width:0; display:flex; flex-wrap:nowrap;
    overflow-x:auto; overflow-y:hidden; scrollbar-width:none; justify-content:flex-end;
    mask-image:linear-gradient(to right, transparent 0, #000 24px, #000 100%);
    -webkit-mask-image:linear-gradient(to right, transparent 0, #000 24px, #000 100%); }
  .top .nav a, .topbar .nav a { flex:0 0 auto; padding:2px 6px; font-size:var(--fs-sm); white-space:nowrap; }
  /* USR-245: the settings button closes the chips+tabs line on both headers (.top is /homes) */
  .top .settings, .topbar .settings { order:7; }
}
/* USR-213 (consultant), folded: the rail is a block under the map card on every width. */
.rail, #rail.rail { position:static; width:auto; max-height:none; margin:var(--sp-2) 0 0;
  padding:var(--sp-1) var(--sp-2); }
.maparea:has(.rail:not([hidden])) { grid-template-columns:1fr; }
.rail-list { gap:2px; }
.state { padding:var(--sp-2); }
#mapcard h2 { margin:0 0 var(--sp-1); }
#help { margin:0; }
.legend { gap:var(--sp-1) var(--sp-2); margin-top:var(--sp-1); font-size:var(--fs-xs);
  line-height:1.25; }
@media (min-width:1024px) { #rail.rail { max-height:40vh; overflow:auto; } }
/* USR-253(3): the count in the heading and a cue that the list continues. The cue sticks to
   the rail's bottom edge and is removed by Egregor.Rail once the reader is at the end. */
.rail h3 .count { text-transform:none; letter-spacing:0; font-weight:400; color:var(--mut); }
.rail-more { position:sticky; bottom:0; margin:0 calc(-1 * var(--sp-2)) calc(-1 * var(--sp-1));
  padding:var(--sp-1) var(--sp-2); text-align:center; font-size:var(--fs-xs); color:var(--mut);
  background:linear-gradient(to bottom, transparent, var(--card) 45%); pointer-events:none; }
.rail .state.none { font-style:italic; color:var(--mut); padding:var(--sp-1) 0; }
/* USR-226(d): under 1024px the right column dissolves (display:contents) so the context
   line, the callout and the banner (.lead) can sit between the header and the map. */
@media (max-width:1023px) {
  .split { display:flex; flex-direction:column; }
  .sidecol { display:contents; }
  .sidecol > .lead { order:-1; }
  .sidecol > .card, .sidecol > details { margin-bottom:var(--sp-3); }
}
@media (max-width:767px) {
  :root { --topbar-h:100px; }
  body { padding:var(--sp-2); }
  /* the header is three short rows on a phone: wordmark/search/account/"?", the tabs
     (full width, one line, visibly scrollable: right-edge fade and a chevron), the chips.
     Measured target: under 130px (USR-225(d)5). A sticky element is its own containing
     block, so .navmore positions against it without position:relative (which would undo
     the sticky -- the defect the consultant's 2026-09-13 block carried). */
  /* USR-355 pass (2026-09-15): "Egregor · happiness" was 13 px wider than the phone row and the
     whole header grid overflowed (scrollWidth 380 at 375). The wordmark and search columns may
     shrink (17 px wordmark, 6 px gaps); the buttons and tabs keep their size; ellipsis is the last resort. */
  .top, .topbar { display:grid; grid-template-columns:minmax(0,auto) minmax(0,1fr) auto auto auto;
    grid-template-areas:"h1 find acct help set" "nav nav nav nav nav" "chips chips chips chips chips";
    column-gap:6px; row-gap:2px; padding:3px 0; }
  .topbar #find input, .find input[type=search] { min-height:30px; }
  .chiprow .chip { min-height:26px; line-height:20px; padding:1px 9px; }
  .chiprow { padding:0 0 1px; }
  .top h1, .topbar h1 { grid-area:h1; font-size:17px; letter-spacing:-.01em; line-height:24px; white-space:nowrap; min-width:0; overflow:hidden; text-overflow:ellipsis; }
  .top .lede, .topbar .lede { display:none; }
  .topbar .find, .topbar #find { grid-area:find; margin:0; }
  .topbar #find input { padding:4px 8px; font-size:var(--fs-sm); }
  #helpbtn { grid-area:help; }
  .top .settings, .topbar .settings { grid-area:set; }
  .chiprow { grid-area:chips; padding:2px 0 2px; }
  .top .tier, .top #acct, .topbar .tier, .topbar #acct { grid-area:acct; align-self:center;
    justify-self:end; font-size:var(--fs-xs); white-space:nowrap; max-width:10ch;
    overflow:hidden; text-overflow:ellipsis; }
  .top .nav, .top #nav, .topbar .nav, .topbar #nav { grid-area:nav; display:flex;
    flex-wrap:nowrap; overflow-x:auto; overflow-y:hidden; gap:2px; -webkit-overflow-scrolling:touch;
    scrollbar-width:none; margin:0; padding-right:24px; align-items:center; height:28px;
    touch-action:pan-x; overscroll-behavior-x:contain; scroll-snap-type:x proximity;
    mask-image:linear-gradient(to right, #000 0, #000 calc(100% - 30px), transparent 100%);
    -webkit-mask-image:linear-gradient(to right, #000 0, #000 calc(100% - 30px), transparent 100%); }
  .top .nav a, .top #nav a, .topbar .nav a, .topbar #nav a { flex:0 0 auto; white-space:nowrap;
    line-height:24px; padding:1px 10px; min-width:5em; text-align:center; font-size:var(--fs-sm);
    scroll-snap-align:start; }
  .tabs button { flex:0 0 auto; padding:2px 8px; font-size:var(--fs-sm); }
  .navmore { position:absolute; right:0; top:33px; height:28px; width:36px; border:0; background:transparent;
    color:var(--acc); font-size:22px; line-height:1; display:flex; align-items:center; justify-content:center;
    cursor:pointer; padding:0; }
  .navmore[hidden] { display:none; }
  .herowrap { margin:0 calc(-1 * var(--sp-2)) var(--sp-2); }
  #lmap, .leaflet-container { height:45vh !important; min-height:240px; }
  /* USR-226(3): the callout is one paragraph and one line of buttons, under 96px */
  .callout { gap:var(--sp-1) var(--sp-2); padding:var(--sp-1) var(--sp-2); }
  .callout .say { font-size:13.5px; line-height:1.3; flex:1 1 100%; font-weight:600; letter-spacing:-.015em; }
  .callout button, .callout .tertiary { min-height:26px; line-height:22px; padding:1px 10px; font-size:var(--fs-sm); }
  .coach { padding:var(--sp-1) var(--sp-2); font-size:var(--fs-sm); line-height:1.3;
    margin:0 0 var(--sp-1); }
  .coach .primary, .coach .tertiary { padding:2px 10px; min-height:28px; }
  .bar { display:grid; grid-template-columns:1fr 1fr; gap:var(--sp-1); align-items:center; }
  .bar select, .bar input { width:100%; padding:4px 6px; font-size:var(--fs-sm); min-height:30px; }
  .bar .tier, .bar #tierinfo { grid-column:1 / -1; font-size:var(--fs-xs); margin:0; }
  .bar .tertiary { padding:2px 8px; }
  #timebar { grid-template-columns:auto 1fr; margin:var(--sp-1) 0 0; }
  #mapcard h2 { font-size:var(--fs-xs); margin:0 0 2px; }
  #help .tertiary, #help button { padding:1px 8px; min-height:26px; font-size:var(--fs-xs); }
  .legend { display:none; }              /* the "?" guide explains the encoding on phones */
  .drawer summary { font-size:var(--fs-sm); }
}
@media (min-width:768px) { .navmore { display:none; } }

/* USR-226(e): a place card was 154px tall on a phone because every cell carried the
   44px tap floor -- but the tap target is the row (the card), not each cell inside it.
   The title takes its own line; the figures sit inline after it. 12 cards: 1,848px -> ~900. */
@media (max-width:760px) {
  table.cards tr:not(.fullrow):not(.hrow) { display:flex; flex-wrap:wrap; align-items:baseline;
    gap:0 var(--sp-3); min-height:var(--tap); padding:var(--sp-1) var(--sp-2);
    margin-bottom:var(--sp-1); }
  table.cards tr:not(.fullrow):not(.hrow) td { min-height:0; padding:1px 0; gap:var(--sp-1);
    flex:0 1 auto; }
  table.cards tr:not(.fullrow):not(.hrow) td:first-child { flex:0 0 100%; padding-bottom:2px;
    margin-bottom:2px; }
}
abbr.q90 { text-decoration:underline dotted; cursor:help; font-weight:500; }
/* USR-235: the confidence words wrap inside a table cell ("highly / confident") so the
   column fits the 400px right column instead of scrolling off it. */
td abbr.q90 { white-space:normal; display:inline-block; max-width:6.5em; line-height:1.15; text-align:right; }
@media (min-width:1024px) { .sidecol #beliefs th { white-space:normal; line-height:1.15; } }
/* logo mark (consultant 2026-09-13) */
h1 .mark { vertical-align:-5px; margin-right:6px; color:var(--acc); }
.coach .mark { vertical-align:-4px; margin-right:2px; }
/* consultant 2026-09-13: Leaflet's zoom control sits below the strip banner so a two-row
   banner never covers it; the control stacks above the strip's z-index. */
.maparea .leaflet-top.leaflet-left { top:auto; bottom:12px; }
.maparea .leaflet-bottom.leaflet-left { bottom:48px; }
/* consultant 2026-09-13: tab labels vertically centered; chips show an ellipsis, never a hard cut. */
.nav a, .topbar .nav a, .top .nav a { display:inline-flex; align-items:center; justify-content:center; gap:.35em; }
#options .chip, .chiprow .chip { max-width:18em; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
@media (max-width:767px) { #options .chip, .chiprow .chip { max-width:11em; } }

/* consultant 2026-09-13 (user): the "Prices by place" head sat with its link mid-line; one row, title left, link right. */
.card h2.rowhead { display:flex; align-items:baseline; justify-content:space-between; gap:var(--sp-2); flex-wrap:wrap; }
.card h2.rowhead > span { display:inline-flex; align-items:center; gap:var(--sp-1); }
.card h2.rowhead a.tier { margin-left:auto; white-space:nowrap; }
#contributors .lede { margin:0 0 var(--sp-2); color:var(--mut); font-size:var(--fs-sm); }

/* consultant 2026-09-13 (user, phone): collapsible heads read as run-on text. One shape for
   every <details> head: a boxed row, chevron, title in ink, any note on its own line below. */
.drawer summary, .explain > summary {
  display:flex; flex-wrap:wrap; align-items:center; gap:0 var(--sp-1);
  padding:var(--sp-1) var(--sp-2); border:1px solid var(--line); border-radius:8px;
  background:var(--card); color:var(--ink); font-weight:600; font-size:var(--fs-sm); list-style:none; }
.explain > summary::-webkit-details-marker { display:none; }
.explain > summary::before { content:'\25b8'; display:inline-block; margin-right:var(--sp-1); transition:transform 150ms ease; }
.explain[open] > summary::before { transform:rotate(90deg); }
.drawer summary .lock, .explain > summary .lock, .drawer summary small, .explain > summary small {
  flex-basis:100%; display:block; margin-left:1.4em; margin-top:2px; font-weight:400; color:var(--mut); line-height:1.35; }
.drawer[open] summary, .explain[open] > summary { border-bottom-left-radius:0; border-bottom-right-radius:0; }
.rankrow { display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-1) var(--sp-2); margin-bottom:var(--sp-2); }
.rankrow #rankmsg:empty { display:none; }
.rankrow #rankmsg { flex-basis:100%; }
/* consultant 2026-09-13 (user): the plans drawer sat in one grid column on a wide window, leaving the other white. */
#plansdrawer, .grid > .drawer { grid-column:1 / -1; }
/* consultant 2026-09-13 (user): lat and lon sat in separate, diagonal columns. One "Where" component on
   every form: the pair stays side by side, accuracy and the location button ride with it. */
fieldset.geo { display:inline-flex; flex-wrap:wrap; align-items:center; gap:var(--sp-1) var(--sp-2);
  margin:0; padding:var(--sp-1) var(--sp-2) var(--sp-2); border:1px solid var(--line); border-radius:8px; min-width:0; max-width:100%; }
fieldset.geo legend { font-size:var(--fs-sm); color:var(--mut); padding:0 4px; }
fieldset.geo input { flex:0 0 auto; }
fieldset.geo #locmsg:empty { display:none; }
fieldset.geo #locmsg { flex-basis:100%; }
@media (max-width:767px) { fieldset.geo { width:100%; } }

/* USR-258: observable and evaluate forms. One row per concern: labels above inputs, the
   button at the end of the row; on a phone the row stacks full width. `.tap` is the one
   44 px button that reads the device; `.faces` the happiness row. */
.evalrow { display:grid; grid-template-columns:repeat(auto-fit, minmax(6.5em, 1fr)); gap:var(--sp-2); align-items:end; margin:var(--sp-2) 0; }
.evalrow .fld { display:block; font-size:var(--fs-sm); color:var(--mut); }
.evalrow .fld input, .evalrow .fld select, .evalrow .fld output { display:block; width:100%; box-sizing:border-box; margin-top:2px; }
.evalrow > button { align-self:end; }
.evalrow #locmsg { grid-column:1/-1; }
.evalrow #locmsg:empty { display:none; }
/* USR-374 stage 3: the shell's homes form stacks each label above its field (was homes.html's .evalrow .fld). */
.bar .fld { display:block; font-size:var(--fs-sm); color:var(--mut); }
.bar .fld input { display:block; margin-top:2px; }
@media (max-width:600px) { .evalrow { grid-template-columns:1fr; } }
button.tap { min-height:44px; width:100%; font-size:var(--fs-md); margin:var(--sp-2) 0 var(--sp-1); }
.tier.warn { color:var(--warn); }
.faces { display:flex; gap:var(--sp-1); margin:var(--sp-2) 0 var(--sp-1); }
.faces .face { flex:1; min-height:44px; font-size:1.6rem; line-height:1; padding:var(--sp-1) 0; }
.faces .face.sel { outline:2px solid var(--acc); outline-offset:1px; }
a.typeit { display:inline-block; margin-top:var(--sp-1); }
/* User 2026-09-14: the top spacing differed between pages -- those wrapped in
   .hero-controls (homes, pricing, register, me) bled the header to the window edge with
   negative margins; goods, about, terms did not. One rule for all: the header sits
   inside the body's own padding on every page, and the wrapper is inert. */
.hero-controls { margin:0 !important; padding:0 !important; }
/* USR-301: zoom by tier -- the teaser button on the map and its note under it */
button.zoomtease { background:var(--bg); border:1px solid var(--line); border-radius:999px; padding:4px 10px; font:inherit; font-size:var(--fs-sm); cursor:pointer; }
.zoomnote { font-size:var(--fs-sm); color:var(--mut); margin:var(--sp-1) 0 0; }
/* USR-277: price over time */
.history .histsvg { width:100%; height:auto; display:block; margin-top:var(--sp-1); }
.history .grid { stroke:var(--line); stroke-width:1; }
.history .ax { font-size:11px; fill:var(--mut); }
.history .band { fill:var(--acc); opacity:.12; }
.history .line { fill:none; stroke:var(--acc); stroke-width:2; }
.history .fband { fill:var(--mut); opacity:.14; }
.history .fline { fill:none; stroke:var(--ink); stroke-width:1.5; stroke-dasharray:5 4; }
.history .now { stroke:var(--mut); stroke-width:1; stroke-dasharray:2 3; }
.trend { font-weight:650; font-size:var(--fs-md); }
.trend.bad { color:var(--warn, #b45309); } .trend.good { color:var(--ok, #15803d); } .trend.flat { color:var(--mut); }   /* which way is good is the page's call (user, 2026-09-14) */
/* User 2026-09-14 (USR-124(e) phone check): pricing, sign in and my account overflowed
   390 px because the h1's tagline would not wrap. On a phone the tagline drops under the
   wordmark and the header wraps; nothing else changes. */
@media (max-width:767px) {
  .top { flex-wrap:wrap; }
  .top h1 { flex:1 1 100%; white-space:normal; min-width:0; }
  .top h1 small { display:block; margin-top:2px; }
  .top .nav { flex:1 1 100%; }
}

/* USR-324: the "Other" tab is a button that opens the every-domain sheet; it dresses as a tab
   and takes the tab's own rules at every breakpoint (the phone header's tab strip included). */
.nav .navother { font:inherit; font-size:var(--fs-sm); color:var(--mut); padding:var(--sp-1) var(--sp-2); background:none;
  border:1px solid transparent; border-radius:var(--r-1); cursor:pointer; display:inline-flex; align-items:center; gap:.35em; white-space:nowrap; }
.nav .navother:hover, .nav .navother[aria-expanded="true"] { border-color:var(--line); color:var(--ink); }
@media (max-width:767px) {
  .top .nav .navother, .topbar .nav .navother { flex:0 0 auto; white-space:nowrap; line-height:24px; padding:1px 10px;
    min-width:5em; min-height:0; height:28px; text-align:center; font-size:var(--fs-sm); scroll-snap-align:start; }
}
.domlist { display:flex; flex-direction:column; gap:2px; }
.domlist .domrow { display:flex; justify-content:space-between; align-items:baseline; gap:var(--sp-2); padding:var(--sp-1) var(--sp-2);
  border-radius:var(--r-1); color:var(--ink); text-decoration:none; min-height:var(--tap); }
.domlist .domrow:hover { background:var(--bg); text-decoration:none; }
.domlist .domrow.on { background:var(--bg); font-weight:600; }
.domlist .domrow.soon { opacity:.45; }
.domlist .domrow .where { color:var(--mut); font-size:var(--fs-sm); text-align:right; }

/* user 2026-09-15: the "?" pulses twice after the first-visit guide folds away (Egregor.Guide) */
@keyframes helppulse { 0%,100% { box-shadow:0 0 0 0 var(--acc); } 50% { box-shadow:0 0 0 6px transparent; } }
#helpbtn.pulse { animation:helppulse 1.6s ease-out 2; border-color:var(--acc); color:var(--acc); }
@media (prefers-reduced-motion: reduce) { #helpbtn.pulse { animation:none; outline:2px solid var(--acc); } }

/* user 2026-09-16: the one-tap location banner on the map (ZoomGate.open) */
.egr-locate { background:var(--card); border-radius:var(--r-2); box-shadow:var(--sh-1); padding:4px 6px; display:flex; gap:4px; align-items:center; }
.egr-locate button.secondary { padding:6px 10px; font-size:var(--fs-sm); }
.egr-locate button.tertiary { padding:4px 8px; }
.egr-locate .egr-locnote { max-width:220px; font-size:var(--fs-sm); line-height:1.3; padding:2px 4px; }
/* USR-401: /admin -- the status strip (one light, one word, opens its tab), tabs that
   scroll on a phone, and the row count a collapsed panel carries in its heading. */
.strip { display:flex; flex-wrap:wrap; gap:var(--sp-1) var(--sp-2); margin:0 0 var(--sp-2); }
.strip .dot { display:inline-flex; align-items:center; gap:.35em; font-size:var(--fs-sm); color:var(--ink);
  padding:var(--sp-1) var(--sp-2); border:1px solid var(--line); border-radius:999px; background:var(--card); cursor:pointer; }
.strip .dot .light { margin-right:0; } .strip .dot span:last-child { color:var(--mut); }
.strip:empty::after { content:'reading the site\2026'; color:var(--mut); font-size:var(--fs-sm); }
.admtabs { overflow-x:auto; flex-wrap:nowrap; -webkit-overflow-scrolling:touch; scrollbar-width:none; }
.admtabs::-webkit-scrollbar { display:none; }
.admtabs button { white-space:nowrap; flex:0 0 auto; }
.pane > details.explain { margin:0 0 var(--sp-2); }
.pane > details.explain > .wrap, .pane > details.explain > .state, .pane > details.explain > .tier { margin-top:var(--sp-1); }
summary .cnt { font-weight:400; color:var(--mut); }
