/* Wayfinder — chart-derived palette. Magenta is the colour real nautical
   charts reserve for cautions, so it is spent only on warnings and the
   active state, never as decoration. */
:root{
  --ground:#0B1116;
  --panel:#131E27;
  --panel-2:#1B2A36;
  --line:#26353F;
  --ink:#E6E2D6;
  --ink-2:#9BA6B0;
  --ink-3:#85919C;
  --datum:#6FB8D6;
  --magenta:#FF74B0;
  --ok:#5FBF8F;
  --warn:#D6B25A;
  --orange:#E08A4E;
  /* Ink on a filled accent or caution. Dark here, where the fills are pale
     on a dark ground; white under Holiday, where they are deep on a light one. */
  --on-accent:#06131A;
  --on-magenta:#1A0610;
  /* Shadows and scrims are mixed from these, so a light theme can soften
     them rather than drop black smudges under every floating panel. */
  --shadow:#000;
  --scrim:rgba(0,0,0,.6);
  --font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --r:10px;
  --nav:62px;
  --safe-b:env(safe-area-inset-bottom,0px);
  /* How much of the viewport the on-screen keyboard is covering, written by
     shell.js from `visualViewport`. Zero whenever there is no keyboard, so
     every `max()` below reduces to what it was. */
  --kb:0px;
}
*{box-sizing:border-box}
/* ID selectors below outrank the UA [hidden] rule; make it win anyway. */
[hidden]{display:none!important}
html,body{height:100%}
body{
  margin:0; background:var(--ground); color:var(--ink);
  font:15px/1.55 var(--font);
  overscroll-behavior:none; -webkit-font-smoothing:antialiased;
}
.mono,.v,.k{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}

#shell{position:fixed;inset:0;display:flex;flex-direction:column-reverse}

/* ---------- nav ---------- */
#nav{
  flex:0 0 auto; display:flex; background:var(--panel);
  border-top:1px solid var(--line);
  padding-bottom:var(--safe-b);
}
.navbtn{
  flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:3px; height:var(--nav); background:none; border:0; cursor:pointer;
  color:var(--ink-3); font-size:11px; letter-spacing:.02em;
  -webkit-tap-highlight-color:transparent; transition:color .15s;
}
.navbtn svg{width:22px;height:22px;fill:currentColor}
.navbtn.is-active{color:var(--magenta)}
.navbtn:focus-visible{outline:2px solid var(--datum);outline-offset:-3px}

/* With the keyboard up the nav bar is behind it: drawn, unreachable, and
   eating the space the sheet needs. Put it away until the keyboard goes. */
html.kb-up #nav{display:none}

/* ---------- views ---------- */
#main{flex:1 1 auto;position:relative;min-height:0}
.view{position:absolute;inset:0;display:none;overflow:auto;overscroll-behavior:contain}
.view.is-active{display:block}
/* The colour of a tile that has not arrived. See applyProjection(). */
#map{position:absolute;inset:0;background:#EDE8E0}
#map.globe{background:#04060B}

.pad{padding:26px 20px 40px;max-width:64ch;margin:0 auto}
h1{font-size:1.6rem;line-height:1.15;margin:0 0 6px;letter-spacing:-.01em}
h3{font-size:1rem;margin:0 0 6px}
.lede{color:var(--ink-2);margin:0 0 20px}
.fine{font-size:.85rem;color:var(--ink-3);margin:8px 0 0}
.card{
  background:var(--panel); border:1px solid var(--line);
  border-left:3px solid var(--magenta); border-radius:var(--r);
  padding:16px 18px; margin:0 0 14px;
}
.card p{margin:0 0 8px} .card p:last-child{margin:0}
.card.warn{border-left-color:var(--warn)}

/* ---------- HUD ---------- */
#hud{
  position:absolute; top:64px; left:12px; z-index:5;
  background:color-mix(in srgb,var(--ground) 82%,transparent); backdrop-filter:blur(8px);
  border:1px solid var(--line); border-radius:var(--r);
  padding:9px 12px; font-size:11px; line-height:1.7;
  pointer-events:none;
}
.hud-row{display:flex;gap:10px}
.hud-row .k{color:var(--ink-3);width:44px}
.hud-row .v{color:var(--ink);font-variant-numeric:tabular-nums}

/* ---------- map chrome above the sheet ----------
 *
 * MapLibre pins the zoom buttons, the scale bar and the attribution to the
 * bottom of the map container, and the sheet sits on top of that container —
 * so they were underneath it in *every* state, collapsed included. Measured on
 * a 390x844 phone: the zoom stack occupies y 652-781 and the collapsed sheet
 * starts at y 720, so its bottom third was always hidden and the whole thing
 * disappeared the moment anything opened. The attribution was covered
 * outright, which is not merely untidy — the tile licence requires it to be
 * visible.
 *
 * `--sheet-h` is written by the sheet itself on every height change, so the
 * bottom chrome rides above it the way the controls do in every native map
 * app. The transition matches the sheet's own so they move together rather
 * than one chasing the other.
 */
:root{ --sheet-h:0px; }

.maplibregl-ctrl-bottom-left,
.maplibregl-ctrl-bottom-right{
  /* max(), not a sum: once the sheet is up the controls sit above *it*, not
     above the screen edge, so adding the home-indicator inset on top would
     float them needlessly. Whichever is the greater obstruction wins. */
  bottom:calc(max(var(--sheet-h), env(safe-area-inset-bottom, 0px)) + 10px);
  transition:bottom .22s ease;
}
/* At full height the sheet is the screen; chrome hovering on its last visible
   strip is clutter, not a control. Driven from the root element because the
   sheet and the map are not siblings — it lives outside the map's view. */
html[data-sheet="full"] .maplibregl-ctrl-bottom-left,
html[data-sheet="full"] .maplibregl-ctrl-bottom-right{
  opacity:0; pointer-events:none;
}

/* The corner stacks its controls itself, and the scale bar landed on top of
   the zoom buttons — invisible while the sheet covered both, obvious the
   moment they were lifted clear. A column with a gap cannot overlap. */
.maplibregl-ctrl-bottom-left{
  display:flex; flex-direction:column; align-items:flex-start; gap:6px;
}
.maplibregl-ctrl-bottom-left .maplibregl-ctrl{ margin:0 0 0 10px; }
/* The credit line, while it shows in full, wrapped right across a phone and
   over the zoom buttons in the other corner. It wraps beside them instead:
   10px margin + 44px buttons + a gap, kept clear on the left. */
.maplibregl-ctrl-bottom-right .maplibregl-ctrl-attrib.maplibregl-compact-show{
  max-width:calc(100vw - 76px - env(safe-area-inset-left, 0px));
}
.maplibregl-ctrl-bottom-left .maplibregl-ctrl-scale{ margin-bottom:2px; }

/* The attribution collapses, but not immediately — and through MapLibre's own
 * class rather than a second mechanism beside it.
 *
 * The OpenStreetMap Foundation's guidelines permit folding the credit down to
 * an info button, and are specific about when: on a dismiss, on a map
 * interaction such as panning or zooming, or automatically after five seconds.
 * They are equally specific that seeing it on *initial* presentation must take
 * no interaction at all. So app.js removes `maplibregl-compact-show` on
 * whichever of those comes first, and MapLibre's own ⓘ button puts it back —
 * that class is the single switch its stylesheet already keys off.
 *
 * A parallel `wf-attrib-*` pair lived here and did not work: MapLibre's button
 * toggles its class, this toggled that one, and after a tap both were in the
 * state that hides the text. Two mechanisms for one piece of state is the bug,
 * not the fix.
 */

/* Touch targets on the map's own buttons.
 *
 * MapLibre draws them at 29 px. WCAG 2.2 puts the AA floor at 24x24 and the
 * AAA level at 44x44; Material asks for 48dp with 8dp between. 29 px clears
 * the bare minimum and nothing else, on the controls most likely to be jabbed
 * at one-handed on a moving bus. Enlarged only where the pointer is coarse, so
 * a mouse still gets the compact ones. */
@media (pointer:coarse){
  .maplibregl-ctrl-group button{
    width:44px; height:44px;
  }
  .maplibregl-ctrl-group button .maplibregl-ctrl-icon{
    background-size:22px 22px;
  }
}

/* A position that has stopped arriving must look stopped. Greyed and faded,
   with the accuracy ring going with it — the ring is a claim about precision
   and an old fix has no business making one. */
.user-puck.is-stale{ opacity:.45; filter:grayscale(1); }
.user-puck.is-stale svg{ animation:none; }

/* ---------- controls ---------- */
#mapctl{position:absolute;right:14px;bottom:18px;z-index:5;display:flex;flex-direction:column;gap:10px}
.fab{
  width:52px;height:52px;border-radius:50%;border:1px solid var(--line);
  background:var(--panel);color:var(--datum);cursor:pointer;
  display:grid;place-items:center;box-shadow:0 4px 16px color-mix(in srgb,var(--shadow) 45%,transparent);
}
.fab svg{width:24px;height:24px;fill:currentColor}
.fab.fab-sm{width:44px;height:44px;color:var(--ink-2)}
.fab.fab-sm svg{width:20px;height:20px}
.fab:active{transform:scale(.94)}
.fab.tracking{color:var(--magenta);border-color:var(--magenta)}
/* Tracking, but the map has been panned off the puck. Still lit, because
   the watch is live, and hollowed out, because the next tap re-centres
   rather than switches off. */
.fab.adrift{color:var(--magenta);border-color:var(--magenta);opacity:.62}

#btn-src{
  position:absolute;top:15px;right:14px;z-index:6;
  background:color-mix(in srgb,var(--ground) 82%,transparent);backdrop-filter:blur(8px);
  border:1px solid var(--line);border-radius:999px;
  color:var(--ink-2);font-size:11px;letter-spacing:.06em;text-transform:uppercase;
  padding:7px 13px;cursor:pointer;font-family:ui-monospace,monospace;
}

/* ---------- offline download ---------- */
#dl{
  position:absolute;left:12px;right:12px;bottom:18px;z-index:6;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
  padding:12px 14px;
}
.dl-head{display:flex;align-items:center;gap:10px;margin-bottom:8px}
#dl-label{flex:1 1 auto;min-width:0;font-size:12px;color:var(--ink-2);font-family:ui-monospace,monospace}
#dl-bar{height:4px;background:var(--panel-2);border-radius:2px;overflow:hidden}
#dl-bar i{display:block;height:100%;width:0;background:var(--datum);transition:width .2s}

/* ---------- sheet ---------- */
#basemap-sheet,#offline-sheet{position:absolute;inset:0;z-index:20;background:var(--scrim);display:grid;place-items:end stretch}
.offline-list{list-style:none;margin:0;padding:0}
.offline-list .off-row{padding:11px 0;border-bottom:1px solid var(--line)}
.offline-list .off-row:last-child{border-bottom:0}
.offline-row-main{display:flex;flex-direction:column;gap:2px;min-width:0}
.offline-row-main strong{overflow-wrap:anywhere}
.offline-row-btns{display:flex;gap:7px;flex-wrap:wrap;margin-top:8px}
.offline-here{font-size:11px;color:var(--datum);font-weight:600}
.offline-warn{color:var(--magenta)}
.offline-detail{color:var(--ink-2)}
/* What a saved area knows besides its map (areapack.js). */
.offline-data{color:var(--ink-2)}
.offline-info{margin-top:10px;padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:var(--panel-2)}
.offline-info .pack-h{margin:10px 0 4px;font-weight:600}
.offline-info .pack-h:first-child{margin-top:0}
.pack-days{display:flex;flex-direction:column;gap:3px}
.pack-day{display:grid;grid-template-columns:7.5em 1fr auto auto;gap:8px;align-items:baseline;font-size:13px}
.pack-day-t{font-variant-numeric:tabular-nums}
.pack-note{padding:5px 0;border-bottom:1px solid var(--line)}
.pack-note:last-child{border-bottom:0}
.pack-note.is-urgent strong,.pack-note.is-warn strong{color:var(--magenta)}
.pack-guide summary{cursor:pointer;padding:4px 0}
.pd-offline{color:var(--datum);font-weight:600;margin-bottom:4px}
.sheet-inner{background:var(--panel);border-top:1px solid var(--line);border-radius:16px 16px 0 0;padding:22px 20px calc(22px + var(--safe-b));max-height:80%;overflow:auto}
.sheet-inner h2{margin:0;font-size:1.2rem}
.sheet-inner-head{position:sticky;top:-22px;z-index:1;display:flex;align-items:center;gap:8px;
  margin:-22px -20px 6px;padding:16px 8px 10px 20px;background:var(--panel);
  border-bottom:1px solid var(--line)}
.sheet-inner-head h2{flex:1 1 auto;min-width:0}
.sheet-inner-x{flex:0 0 auto;width:44px;height:44px;display:grid;place-items:center;
  background:none;border:0;border-radius:9px;color:var(--ink-2);font-size:24px;line-height:1;
  cursor:pointer;font-family:inherit;padding:0}
.sheet-inner-x:active{background:var(--panel-2)}
label{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.1em;color:var(--ink-3);margin:16px 0 6px}
input[type=text]{
  width:100%;padding:11px 13px;border-radius:8px;border:1px solid var(--line);
  background:var(--ground);color:var(--ink);font-family:ui-monospace,monospace;font-size:14px;
}
input:focus-visible{outline:2px solid var(--datum);outline-offset:1px}
/* iPhone draws date and time boxes at their own native width and ignores
   width:100% / min-width:0 while they keep the native look, so in a two-up
   row (Starts | Ends) one ran into the box beside it. Every form, not just one.
   An empty one also collapses to no height on iOS: the min-height keeps it a box. */
:where(input[type=date],input[type=time],input[type=datetime-local],input[type=month],input[type=week]){
  -webkit-appearance:none;appearance:none;min-width:0;max-width:100%;min-height:2.6em}
input[type=date]::-webkit-date-and-time-value,input[type=time]::-webkit-date-and-time-value,
input[type=datetime-local]::-webkit-date-and-time-value{text-align:left}
/* Every box shrinks with its column rather than pushing out of it.
   :where() keeps this at zero weight, so any form's own width rules still win. */
:where(select,textarea,input:not([type=checkbox],[type=radio])){min-width:0;max-width:100%}
.sheet-btns{display:flex;gap:9px;margin-top:16px;flex-wrap:wrap}
.btn{padding:10px 16px;border-radius:8px;border:1px solid var(--line);background:var(--panel-2);color:var(--ink);cursor:pointer;font-size:14px}
.btn.primary{background:var(--datum);border-color:var(--datum);color:var(--on-accent);font-weight:600}

/* ---------- toast ---------- */
#toast{
  position:absolute;left:50%;bottom:calc(var(--nav) + 24px);transform:translateX(-50%) translateY(12px);
  background:var(--panel-2);border:1px solid var(--line);border-radius:999px;
  padding:9px 17px;font-size:13px;z-index:30;opacity:0;pointer-events:none;
  transition:opacity .2s,transform .2s;max-width:88vw;text-align:center;
}
#toast.show{opacity:1;transform:translateX(-50%) translateY(0)}

/* ---------- wide screens: nav becomes a rail ---------- */
@media (min-width:900px){
  #shell{flex-direction:row}
  #nav{
    flex-direction:column; width:88px; height:100%;
    border-top:0; border-right:1px solid var(--line); padding:14px 0 0;
  }
  .navbtn{flex:0 0 auto;height:70px}
  #toast{bottom:28px}
}

/* ---------- foldables: keep content out of the hinge ----------
   Viewport Segments API. Where the browser reports two side-by-side
   segments, pin the HUD into the left one so the fold never cuts it. */
@media (horizontal-viewport-segments:2){
  #hud{left:calc(env(viewport-segment-right 0 0) - 100% - 12px)}
  #btn-src{right:calc(100% - env(viewport-segment-left 1 0) + 14px)}
}
@media (vertical-viewport-segments:2){
  /* Tabletop-ish: keep controls on the lower (flat) segment. */
  #mapctl{bottom:calc(100% - env(viewport-segment-top 0 1) + 18px)}
}

/* The tool sheet on a foldable.
 *
 * The rest of this file decides between a phone's bottom sheet and a
 * desktop's right-hand drawer on width alone, at 900px. A book-style
 * foldable opened flat is about 880 CSS pixels across, which lands on the
 * phone side of that line — so the sheet spanned the whole screen and the
 * hinge ran straight down the middle of the tool grid, the header and its
 * close cross. Width was never the question on these devices; where the
 * screen is continuous is.
 *
 * Unfolded with the hinge vertical, the sheet moves wholly into the right
 * segment. That is the drawer pattern the desktop already uses, it leaves
 * the map readable on the left, and nothing it contains crosses the fold.
 *
 * Folded shut the phone rules apply untouched: one segment, one sheet. */
@media (horizontal-viewport-segments:2){
  #sheet{
    left:calc(env(viewport-segment-left 1 0) + 10px);
    right:10px;
    border-radius:16px 16px 0 0;
  }
  /* The launcher grid has half the width it had; ask for narrower cells
     rather than letting one column of very wide buttons happen. */
  .toolgrid{grid-template-columns:repeat(auto-fill,minmax(84px,1fr))}
}
@media (vertical-viewport-segments:2){
  /* Hinge across the middle: the sheet lives on the lower, flat half and
     stops at the fold rather than bending over it. */
  #sheet{
    max-height:calc(100dvh - env(viewport-segment-top 0 1)
                    - max(calc(var(--nav) + var(--safe-b)), var(--kb)) - 8px);
  }
}

@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* map failure state — one screen degrades, the app keeps working */
.mapfail{max-width:42ch;margin:0 auto;padding:16% 24px 0;text-align:center;color:var(--ink-2)}
.mapfail h3{color:var(--ink);font-size:1.15rem;margin:0 0 8px}
.mapfail p{margin:0 0 8px}

/* ---------------- boot splash ---------------- */
/* Above the gate, because it is what covers it. The mark does not spin: a
   session check takes a few hundred milliseconds and a spinner that appears
   and vanishes inside that reads as a flicker, which is the thing this exists
   to remove. It fades in instead, so a fast answer shows nothing at all. */
#boot{position:fixed;inset:0;z-index:61;display:grid;place-items:center;
  background:var(--ground);animation:boot-in .5s ease both}
#boot .brand-mark{width:64px;height:64px}
@keyframes boot-in{from{opacity:0}to{opacity:1}}
@media (prefers-reduced-motion:reduce){#boot{animation:none}}

/* ---------------- auth gate ---------------- */
#gate{position:fixed;inset:0;z-index:60;display:grid;place-items:center;background:var(--ground);padding:24px}
.gate-card{width:100%;max-width:400px}
.gate-brand{display:flex;gap:14px;align-items:center;margin-bottom:26px}
.gate-brand .brand-mark{width:52px;height:52px;flex:0 0 auto}
.gate-brand h1{font-size:1.5rem;margin:0;letter-spacing:-.01em}
.gate-brand p{margin:2px 0 0;color:var(--ink-3);font-size:.87rem}
#gate-logo{width:52px;height:52px;flex:0 0 auto;object-fit:contain;border-radius:12px}
.gate-home{display:block;margin-top:18px;text-align:center;color:var(--ink-2);font-size:.9rem;text-decoration:none}
.gate-home:hover{color:var(--ink)}
.gate-tabs{display:flex;gap:4px;background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:4px;margin-bottom:20px}
.gate-tab{flex:1;padding:9px;border:0;border-radius:7px;background:none;color:var(--ink-3);cursor:pointer;font-size:14px}
.gate-tab.is-on{background:var(--panel-2);color:var(--ink)}
#auth-form label{margin-top:14px}
#auth-form input{width:100%;padding:12px 13px;border-radius:8px;border:1px solid var(--line);background:var(--panel);color:var(--ink);font-size:15px}
#auth-form input:focus-visible{outline:2px solid var(--datum);outline-offset:1px}
.gate-hint{font-size:.8rem;color:var(--ink-3);margin:12px 0 0;line-height:1.5}
.gate-err{font-size:.85rem;color:var(--magenta);margin:12px 0 0;padding:9px 12px;background:color-mix(in srgb,var(--magenta) 9%,transparent);border-radius:7px;border:1px solid color-mix(in srgb,var(--magenta) 25%,transparent)}
.btn.wide{width:100%;margin-top:16px;padding:13px}
.navbtn-out{color:var(--ink-3);opacity:.65}

/* ---------------- advisories ---------------- */
.wide-pad{max-width:760px}
#adv-search{width:100%;padding:11px 14px;border-radius:9px;border:1px solid var(--line);background:var(--panel);color:var(--ink);font-size:15px;margin-bottom:10px}
#adv-search:focus-visible{outline:2px solid var(--datum);outline-offset:1px}
#adv-meta{margin-bottom:16px}
.adv{display:flex;gap:13px;align-items:flex-start;padding:13px 2px;border-bottom:1px solid var(--line)}
.adv:last-child{border-bottom:0}
.lvl{flex:0 0 auto;width:26px;height:26px;border-radius:6px;display:grid;place-items:center;font-size:12px;font-weight:700;font-family:ui-monospace,monospace}
.lvl-1{background:color-mix(in srgb,var(--ok) 16%,transparent);color:var(--ok)}
.lvl-2{background:color-mix(in srgb,var(--warn) 16%,transparent);color:var(--warn)}
.lvl-3{background:color-mix(in srgb,var(--orange) 18%,transparent);color:var(--orange)}
.lvl-4{background:color-mix(in srgb,var(--magenta) 16%,transparent);color:var(--magenta)}
.lvl-x{background:var(--panel-2);color:var(--ink-3)}
.adv-body{min-width:0;flex:1}
.adv-country{font-weight:600;font-size:.97rem}
.adv-sum{font-size:.84rem;color:var(--ink-3);margin-top:2px;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.adv-date{font-size:.72rem;color:var(--ink-3);font-family:ui-monospace,monospace;white-space:nowrap;padding-top:5px}

.fab.on{color:var(--magenta);border-color:var(--magenta);background:color-mix(in srgb,var(--magenta) 10%,transparent)}
#btn-open3d{margin-bottom:18px}

/* ---------------- vault ---------------- */
.vault-bar{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;padding-bottom:12px;border-bottom:1px solid var(--line)}
.btn.sm{padding:6px 12px;font-size:13px}
.btn.danger{color:var(--magenta);border-color:color-mix(in srgb,var(--magenta) 30%,transparent)}
.vrow{display:flex;gap:10px;align-items:center;padding:12px 0;border-bottom:1px solid var(--line)}
.vmeta{flex:1;min-width:0}
.vname{font-weight:600;font-size:.95rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.filedrop{display:flex;flex-direction:column;gap:3px;align-items:center;justify-content:center;
  margin-top:18px;padding:26px;border:1.5px dashed var(--line);border-radius:12px;
  cursor:pointer;color:var(--ink-2);text-align:center;transition:border-color .15s,color .15s}
.filedrop:hover{border-color:var(--datum);color:var(--ink)}
#vault-form input{width:100%;padding:12px 13px;border-radius:8px;border:1px solid var(--line);background:var(--panel);color:var(--ink);font-size:15px}
#vault-form{margin-bottom:20px}

/* ---------------- SOS / emergency card ---------------- */
.navbtn-sos.is-active{color:var(--magenta)}
.sos-head{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap}
#sos-country{background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:8px;padding:9px 12px;font-size:14px;min-width:170px}
#sos-country:focus-visible{outline:2px solid var(--datum);outline-offset:1px}
.sos-pick{display:inline-flex;align-items:center;gap:10px;justify-content:space-between;min-width:200px;min-height:44px;
  background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:10px;padding:9px 14px;font-size:15px;cursor:pointer}
.sos-pick svg{color:var(--ink-3);flex:none}
.sos-pick:hover{border-color:var(--datum)}
.sos-pick:focus-visible{outline:2px solid var(--datum);outline-offset:1px}
.sos-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin:6px 0 22px}
.sos-num{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--magenta);border-radius:10px;padding:14px 16px;text-decoration:none;display:block}
.sos-num .lbl{font-size:.7rem;text-transform:uppercase;letter-spacing:.11em;color:var(--ink-3)}
.sos-num .num{font-size:1.75rem;font-weight:700;font-family:ui-monospace,monospace;color:var(--ink);line-height:1.2;margin-top:3px}
.facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:1px;background:var(--line);border:1px solid var(--line);border-radius:10px;overflow:hidden;margin-bottom:20px}
.fact{background:var(--panel);padding:12px 14px}
.fact .lbl{font-size:.68rem;text-transform:uppercase;letter-spacing:.1em;color:var(--ink-3)}
.fact .val{font-size:.95rem;margin-top:3px;font-weight:600}
.val.bad{color:var(--magenta)} .val.good{color:var(--ok)}
.sec{margin-bottom:20px}
.sec h3{display:flex;align-items:center;gap:8px;margin-bottom:9px}
.sec ul{margin:0;padding-left:19px}
.sec li{margin-bottom:7px;font-size:.92rem;color:var(--ink-2)}
.sec p{font-size:.92rem;color:var(--ink-2);margin:0}
.tag{font-size:.62rem;text-transform:uppercase;letter-spacing:.1em;padding:2px 7px;border-radius:3px;font-weight:600}
.tag-legal{background:color-mix(in srgb,var(--magenta) 14%,transparent);color:var(--magenta)}
.tag-scam{background:color-mix(in srgb,var(--warn) 14%,transparent);color:var(--warn)}
.adv{cursor:pointer} .adv:hover{background:var(--panel)}
#adv-detail{margin-top:4px}
.back{background:none;border:0;color:var(--datum);cursor:pointer;padding:6px 0;font-size:.9rem}
.stale{color:var(--warn)}

/* pinned destinations */
#pinned h4{font-size:.7rem;text-transform:uppercase;letter-spacing:.11em;color:var(--ink-3);margin:4px 0 8px}
.pins{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:18px}
.pin{display:flex;align-items:center;gap:7px;background:var(--panel);border:1px solid var(--line);
  border-radius:999px;padding:5px 13px 5px 6px;color:var(--ink);cursor:pointer;font-size:.88rem}
.pin:hover{border-color:var(--datum)}
.pin .lvl{width:20px;height:20px;font-size:11px}
/* 19x25 as drawn, which is under the 24x24 floor WCAG 2.2 puts on a target
   and well under anything a thumb hits reliably on a moving train. The glyph
   stays the size it was; the box around it grows. */
.pinbtn{background:none;border:0;color:var(--ink-3);font-size:17px;cursor:pointer;
  line-height:1;padding:0;min-width:44px;min-height:44px;display:grid;place-items:center;
  border-radius:9px;flex:0 0 auto}
.pinbtn:active{background:var(--panel-2)}
.pinbtn.on{color:var(--warn)}
.pinbtn:hover{color:var(--ink)}

/* Offscreen advisory rows cost nothing to lay out until scrolled into view. */
.adv{content-visibility:auto;contain-intrinsic-size:auto 62px}
#map{contain:strict}

/* The assistant's working, under its answer. Closed by default; see
   renderTrail() in ai.js for why it is kept at all. */
.ai-trail{margin-top:10px;border-top:1px solid var(--line);padding-top:8px}
.ai-trail>summary{cursor:pointer;color:var(--ink-3,var(--ink-2));font-size:.82rem;
  list-style:none;padding:2px 0}
.ai-trail>summary::-webkit-details-marker{display:none}
.ai-trail>summary::before{content:"\25B8 ";display:inline-block;transition:transform .15s}
.ai-trail[open]>summary::before{content:"\25BE "}
.ai-trail>summary:hover{color:var(--datum)}
.ai-trail-did{font-size:.82rem;color:var(--ink-2);margin:5px 0 0 12px;
  padding-left:10px;border-left:2px solid var(--line)}
/* What it concluded, as against what it went and looked at. */
.ai-trail-think{font-size:.82rem;color:var(--ink-3,var(--ink-2));font-style:italic;
  line-height:1.5;margin:6px 0 2px 12px;padding-left:10px;
  border-left:2px solid var(--datum);white-space:pre-wrap}
/* The same distinction while it is still running. */
.ai-status .ai-think{font-style:italic;opacity:.8}

/* The way out of the solar-system diagram. Top-left, clear of the search bar
   in the middle and the map controls on the right. */
#solar-back{position:absolute;left:12px;top:12px;z-index:7;
  background:color-mix(in srgb,var(--panel) 92%,transparent);backdrop-filter:blur(10px);
  border:1px solid var(--datum);border-radius:999px;color:var(--datum);
  font-size:13px;padding:8px 14px;cursor:pointer;box-shadow:0 3px 14px color-mix(in srgb,var(--shadow) 40%,transparent)}
#solar-back:hover{background:var(--datum);color:var(--on-accent)}
#solar-back:focus-visible{outline:2px solid var(--datum);outline-offset:2px}

/* The day/night Earth's switch.
 *
 * `top` and `right` are written from the draw loop, because only the draw
 * knows how big the disc came out on this screen and the button sits beside
 * it. Quieter than "Back to Earth" on purpose: that is the way out and this is
 * a preference, and two equally loud pills in one view is one too many. */
#solar-earth{
  position:absolute;z-index:7;
  background:color-mix(in srgb,var(--panel) 86%,transparent);backdrop-filter:blur(10px);
  border:1px solid var(--line);border-radius:999px;color:var(--ink-2);
  font-size:11px;letter-spacing:.04em;padding:6px 11px;cursor:pointer;
  font-family:inherit;white-space:nowrap;line-height:1;
}
#solar-earth:hover{color:var(--ink);border-color:var(--datum)}
/* On: a solid sun-gold pill with dark text. The old pale-yellow text on the
   translucent panel vanished on every light look and was faint on the dark
   one. A filled pill carries its own contrast, so it reads the same in all
   looks (literal colours are fine here: they never depend on the panel). */
#solar-earth[aria-pressed="true"]{background:#F2B33D;color:#1B1405;border-color:#F2B33D;font-weight:600}
#solar-earth[aria-pressed="true"]:hover{background:#FFC24F;color:#1B1405;border-color:#FFC24F}
#solar-earth.is-off{color:var(--ink-3);opacity:.8}
#solar-earth:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
/* A thumb needs more than 11px of text to aim at. */
@media (pointer:coarse){ #solar-earth{padding:10px 13px;font-size:12px} }

/* ---------------- place search ---------------- */
#searchwrap{position:absolute;top:12px;left:50%;transform:translateX(-50%);z-index:7;width:min(420px,calc(100% - 130px))}
#searchbar{position:relative;display:flex;align-items:center}
#place-search{width:100%;padding:11px 44px 11px 15px;border-radius:999px;border:1px solid var(--line);
  background:color-mix(in srgb,var(--panel) 94%,transparent);backdrop-filter:blur(10px);color:var(--ink);font-size:14px;
  box-shadow:0 3px 14px color-mix(in srgb,var(--shadow) 35%,transparent)}
#place-search:focus-visible{outline:2px solid var(--datum);outline-offset:1px}
/* Inside the field rather than beside it: the bar is already as wide as a
   phone allows, and a button taking 44 px off the text would cost more than
   it gives. */
#place-go{position:absolute;right:4px;top:50%;transform:translateY(-50%);
  width:34px;height:34px;display:flex;align-items:center;justify-content:center;
  background:none;border:0;border-radius:999px;color:var(--ink-2);cursor:pointer;padding:0}
#place-go:hover,#place-go:focus-visible{color:var(--datum);background:var(--panel-2)}
/* While the real search is still running behind results that came from this
   machine. A moving bar rather than a spinner, because what it is saying is
   "there is more coming", not "nothing has happened yet". */
#place-results.searching{border-color:var(--datum)}
.pres-more{display:block;height:2px;background:linear-gradient(90deg,
  transparent, var(--datum), transparent);background-size:42% 100%;
  background-repeat:no-repeat;animation:presmore 1.1s linear infinite}
@keyframes presmore{from{background-position:-45% 0}to{background-position:145% 0}}
@media (prefers-reduced-motion:reduce){.pres-more{animation:none;background-position:0 0;opacity:.5}}
#place-results{margin-top:7px;background:var(--panel);border:1px solid var(--line);border-radius:12px;
  overflow:hidden;max-height:46vh;overflow-y:auto;box-shadow:0 6px 22px color-mix(in srgb,var(--shadow) 45%,transparent)}
.pres{display:block;width:100%;text-align:left;background:none;border:0;border-bottom:1px solid var(--line);
  padding:10px 15px;color:var(--ink);cursor:pointer}
.pres:last-child{border-bottom:0}
.pres:hover,.pres:focus-visible{background:var(--panel-2)}
.pres-name{font-size:.93rem;font-weight:600}
.pres-empty{padding:12px 15px}
/* The name on the sign, one line under the name you searched for. Its own line
   rather than a suffix: this is the string that gets held up to a taxi driver
   and burying it behind a separator hid the half of the row that works. */
.pres-local{font-size:.88rem;color:var(--ink-2);line-height:1.25}
/* Pinyin is a reading, not a name: lighter than the script it is
   reading, and italic so the eye does not take it for a second name. */
.pres-spoken{color:var(--ink-3,var(--ink-2));font-style:italic}
/* The street. On four rows all reading "Hanting Hotel" this is the only line
   that answers the question being asked, so it is set in the body colour
   rather than the fine-print grey the rest of the sub-line uses. */
.pres-area{color:var(--ink-2);line-height:1.25}
/* What the box actually asked, when that was not what was typed. */
.pres-said{padding:9px 15px;border-bottom:1px solid var(--line);color:var(--datum)}
.pres-hint{display:block;width:100%;text-align:left;padding:10px 15px;background:none;
  border:0;border-bottom:1px solid var(--line);color:var(--ink-2);cursor:pointer;
  font-family:inherit;line-height:1.35}
.pres-hint:hover{background:var(--panel-2);color:var(--datum)}
/* A guess at what is being typed — the chain, or the kind of place — above
   the places themselves, with an icon so it does not read as one of them. */
.pres-sug{display:flex;gap:11px;align-items:center}
.pres-sug-i{flex:0 0 auto;width:26px;text-align:center;font-size:1.15rem}
.pres-sug-t{min-width:0}
.pres-sug .pres-name{color:var(--datum)}
.pres-sug-local{color:var(--ink-2);font-weight:400}
.pres.is-active{background:var(--panel-2);box-shadow:inset 3px 0 0 var(--datum)}
/* The empty box: kinds of place, then the places searched for before. */
.pres-chips{display:flex;flex-wrap:wrap;gap:7px;padding:11px 13px;border-bottom:1px solid var(--line)}
.pres-chip{border:1px solid var(--line);background:var(--panel-2);color:var(--ink);border-radius:999px;
  padding:6px 11px;font:inherit;font-size:.86rem;cursor:pointer;min-height:34px}
.pres-chip:hover,.pres-chip:focus-visible{border-color:var(--datum);color:var(--datum)}
.pres-head{display:flex;justify-content:space-between;align-items:center;padding:8px 15px 4px}
.pres-clear{background:none;border:0;color:var(--ink-2);font:inherit;cursor:pointer;padding:4px 0}
.pres-clear:hover{color:var(--datum)}
@media (max-width:520px){ #searchwrap{width:calc(100% - 120px);left:12px;transform:none} }

/* ---------------- measure ---------------- */
#measure-panel{position:absolute;left:12px;bottom:18px;z-index:7;display:flex;gap:12px;align-items:center;
  background:color-mix(in srgb,var(--panel) 94%,transparent);backdrop-filter:blur(10px);border:1px solid var(--line);
  border-left:3px solid var(--magenta);border-radius:10px;padding:10px 14px}
#measure-total{font-family:ui-monospace,monospace;font-size:1.15rem;font-weight:600;font-variant-numeric:tabular-nums}

/* ---------------- phrasebook ---------------- */
.tag-lang{background:color-mix(in srgb,var(--datum) 14%,transparent);color:var(--datum)}
.phrases{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);border-radius:10px;overflow:hidden}
.phrase{background:var(--panel);padding:12px 15px;display:flex;align-items:center;gap:12px}
.ph-words{flex:1;min-width:0}
.ph-say{flex:none;min-width:48px;min-height:48px;font-size:1.2rem}
.ph-say.is-on,.ph-pace.is-on{background:var(--datum);border-color:var(--datum);color:var(--on-accent)}
.ph-pace{margin:0 0 10px}
.dc-say{min-width:72px;min-height:56px;font-size:1.6rem}
.ph-en{font-size:.72rem;text-transform:uppercase;letter-spacing:.08em;color:var(--ink-3)}
.ph-native{font-size:1.35rem;line-height:1.45;margin-top:4px;color:var(--ink)}
.ph-rom{font-size:.82rem;color:var(--ink-3);font-style:italic;margin-top:2px}

.switch{display:flex;gap:11px;align-items:flex-start;margin:18px 0 4px;cursor:pointer;
  text-transform:none;letter-spacing:normal;color:var(--ink);font-size:.95rem}
.switch input{margin-top:3px;width:17px;height:17px;accent-color:var(--datum);flex:0 0 auto}
.switch strong{display:block;font-weight:600}
.switch .fine{margin-top:2px}

/* ---------------- cities ---------------- */
.tag-city{background:var(--panel-2);color:var(--ink-3)}
.cities{display:flex;flex-wrap:wrap;gap:7px}
.city{display:inline-flex;align-items:center;gap:5px;background:var(--panel);border:1px solid var(--line);
  border-radius:999px;padding:6px 13px;color:var(--ink);cursor:pointer;font-size:.87rem}
.city:hover,.city:focus-visible{border-color:var(--datum);color:var(--datum)}
.city-local{color:var(--ink-3);font-size:.88em}
.city-dot{color:var(--warn);font-size:1.1em;line-height:0}
.city-notes{margin-top:14px;display:grid;gap:1px;background:var(--line);border:1px solid var(--line);border-radius:10px;overflow:hidden}
.city-note{background:var(--panel);padding:11px 14px}
.city-note-n{font-size:.7rem;text-transform:uppercase;letter-spacing:.1em;color:var(--warn)}
.city-note-t{font-size:.9rem;color:var(--ink-2);margin-top:3px}

/* ---------------- routing ---------------- */
#route-panel{position:absolute;left:12px;right:12px;bottom:18px;z-index:8;
  background:color-mix(in srgb,var(--panel) 96%,transparent);backdrop-filter:blur(10px);border:1px solid var(--line);
  border-left:3px solid var(--datum);border-radius:12px;padding:12px 14px;max-height:46vh;overflow-y:auto}
/* ---- the two ends ----
   A stack with the swap button between them, so the shape on screen matches
   the shape of the question: from here, to there, and a way to turn it round. */
.route-ends{position:relative;display:grid;grid-template-columns:1fr auto;gap:6px 8px;
  align-items:center;margin-bottom:10px}
.route-end{display:flex;align-items:center;gap:8px;background:var(--panel-2);
  border:1px solid var(--line);border-radius:9px;padding:4px 8px;min-width:0}
.route-end input{flex:1;min-width:0;background:transparent;border:0;color:var(--ink);
  font:inherit;font-size:.9rem;padding:5px 0;outline:none}
.route-end input::placeholder{color:var(--ink-3)}
.route-pin{flex:0 0 auto;width:20px;height:20px;border-radius:999px;display:grid;
  place-items:center;font-size:11px;font-weight:700;color:#0B1116}
.route-pin.is-a{background:var(--ok)}
.route-pin.is-b{background:var(--magenta)}
.route-mini{flex:0 0 auto;background:transparent;border:0;color:var(--ink-2);cursor:pointer;
  font-size:15px;line-height:1;padding:4px 5px;border-radius:7px}
.route-mini:hover{color:var(--datum);background:color-mix(in srgb,var(--datum) 12%,transparent)}
.route-swap{grid-column:2;grid-row:1 / span 2;align-self:center;
  border:1px solid var(--line);background:var(--panel-2)}
.route-sugg{grid-column:1 / -1;position:absolute;top:100%;left:0;right:0;z-index:6;
  background:var(--panel);border:1px solid var(--line);border-radius:10px;
  max-height:44vh;overflow-y:auto;box-shadow:0 10px 30px color-mix(in srgb,var(--shadow) 45%,transparent)}
.route-sugg-row{display:block;width:100%;text-align:left;background:transparent;border:0;
  border-bottom:1px solid var(--line);color:var(--ink);padding:8px 11px;cursor:pointer}
.route-sugg-row:last-child{border-bottom:0}
.route-sugg-row:hover{background:var(--panel-2)}
.route-sugg-n{display:block;font-size:.92rem}
.route-sugg-sub{display:block;line-height:1.25}
/* The A and B on the map itself, so the line has visible ends. */
.route-marker{width:22px;height:22px;border-radius:999px;display:grid;place-items:center;
  background:var(--pin);color:#0B1116;font-weight:700;font-size:12px;
  border:2px solid #0B1116;box-shadow:0 2px 6px color-mix(in srgb,var(--shadow) 50%,transparent)}
.route-head{display:flex;gap:10px;align-items:center;justify-content:space-between}
/* Prompts and progress read as text; only a finished route's figures are set
   in the monospace (was bold monospace throughout, three lines at 375 px). */
#route-summary{font-size:.9rem;line-height:1.35;color:var(--ink-2);min-width:0}
#route-summary.is-result{font-family:ui-monospace,monospace;font-size:1.02rem;font-weight:600;color:var(--ink)}
#route-mode{background:var(--panel-2);color:var(--ink);border:1px solid var(--line);border-radius:7px;padding:6px 9px;font-size:13px}
.route-btns{display:flex;gap:8px;margin-top:10px}
/* Driving/cycling: the steering is handed to the phone's navigation app. */
.route-handoff{margin-top:10px}
.route-drive-note{margin:8px 0 0;padding:8px 10px;border:1px solid var(--line);border-left:3px solid var(--warn);color:var(--ink);
  border-radius:8px;background:var(--panel);font-size:13px;line-height:1.4}
.route-handoff .row-btns{flex-wrap:wrap}
.route-handoff a.btn{text-decoration:none}
#route-steps{margin:12px 0 0;padding-left:0;list-style:none;font-size:.86rem;
  color:var(--ink-2);display:grid;gap:2px}
.route-step{display:grid;grid-template-columns:20px 1fr auto;gap:9px;align-items:baseline;
  padding:5px 7px;border-radius:8px;border-left:2px solid transparent}
.route-step.is-tappable{cursor:pointer}
.route-step.is-tappable:hover{background:var(--panel-2)}
.route-step-i{color:var(--datum);font-size:1rem;line-height:1;text-align:center}
.route-step-t{min-width:0;line-height:1.3}
.route-step-d{white-space:nowrap;font-variant-numeric:tabular-nums}
/* Which line is now. The one thing a written list of turns could not say. */
.route-step.is-now{background:color-mix(in srgb,var(--ok) 12%,transparent);border-left-color:var(--ok);color:var(--ink)}
.route-step.is-now .route-step-i{color:var(--ok)}
@media (min-width:900px){ #route-panel{right:auto;width:380px} }

/* ---------------- settings ---------------- */
#view-settings input[type=text],#view-settings input[type=password]{width:100%;padding:11px 13px;border-radius:8px;
  border:1px solid var(--line);background:var(--panel);color:var(--ink);font-size:14px;font-family:ui-monospace,monospace}
#view-settings select{width:100%;padding:10px 12px;border-radius:8px;border:1px solid var(--line);
  background:var(--panel);color:var(--ink);font-size:14px}
.row-btns{display:flex;gap:9px;align-items:center;flex-wrap:wrap;margin-top:10px}
.switch.inline{margin:0}
.found{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--ok);
  border-radius:10px;padding:12px 14px;margin-top:10px}
.found-h{font-weight:600;font-size:.95rem;margin-bottom:2px}
.found .btn{margin-top:9px}
#set-status{color:var(--ink-3);font-size:.85rem}

/* ---------------- assistant ----------------
 * A floating window, not a sheet panel, and deliberately short: it is anchored
 * to the bottom edge and capped at a little over half the viewport, so the map
 * — or whatever view you asked the question from — is still on screen behind
 * the answer. Folded down it is its own title bar and nothing else.
 *
 * Bottom offsets use `max(nav, keyboard)` for the same reason the sheet does:
 * the nav bar and the on-screen keyboard cover the same edge, they never stack.
 */
:root{
  /* Where the bottom of the assistant sits: above the nav bar, or above the
     keyboard when that is up instead, and above whatever height the tool sheet
     currently is — so opening the assistant never buries the Tools launcher. */
  --ai-bottom:calc(max(calc(var(--nav) + var(--safe-b)), var(--kb)) + var(--sheet-h) + 10px);
}
/* Off the map the tool sheet is hidden, but --sheet-h kept its last height, so
   the companion button floated ~90px above a sheet nobody could see: right on
   top of the Interpreter's Translate button, the chevrons of the Settings rows
   and the counts on Country brief (measured 2026-10-05). No sheet, no term. */
html:not([data-view="map"]){--ai-bottom:calc(max(calc(var(--nav) + var(--safe-b)), var(--kb)) + 10px)}
#ai-fab{position:fixed;right:14px;z-index:44;
  bottom:calc(var(--ai-bottom) + 8px);
  width:54px;height:54px;border-radius:50%;border:1px solid var(--magenta);
  background:var(--panel);color:var(--magenta);cursor:pointer;display:grid;place-items:center;
  box-shadow:0 6px 20px color-mix(in srgb,var(--shadow) 50%,transparent);transition:bottom .22s ease}
#ai-fab svg{width:26px;height:26px;fill:currentColor;pointer-events:none}
/* Parked somewhere by hand. The transition goes with the dock it was for —
   animating `bottom` while a finger is dragging `top` fights the finger — and
   `touch-action:none` is what stops a drag on the button panning the map
   underneath it. */
#ai-fab.is-moved{transition:none}
/* A press and hold is a gesture here, so none of the browser's own must
   fire on top of it: no text selection, no iOS save-image callout, and no
   pan of the map underneath. */
#ai-fab{touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
#ai-fab.is-dragging{cursor:grabbing;box-shadow:0 10px 28px color-mix(in srgb,var(--shadow) 60%,transparent);transform:scale(1.06)}
/* Two buttons for one thing on the same screen is one button too many. */
html[data-ai="open"] #ai-fab{display:none}
/* The same once the Companion screen (or the Agents hub carrying its chat
   card) is showing its own "Talk to …" box: the round button sat right on
   that box's Send on every phone height measured (2026-10-05). */
html[data-view="agents"]:has(#view-agents .ag-sub.is-on .cmp-chat) #ai-fab{display:none}

#ai-panel{position:fixed;right:10px;left:10px;z-index:45;
  bottom:var(--ai-bottom);transition:bottom .22s ease;
  background:var(--panel);border:1px solid var(--line);border-radius:16px;
  display:flex;flex-direction:column;overflow:hidden;
  /* A height, not just a ceiling. Sized to content the window grew and shrank
     under every answer, which on a phone means the composer you are typing in
     moves while you type in it. The log takes the slack instead.
     The last term is what matters when the tool sheet is raised underneath:
     whatever the others allow, the window stops short of the search bar rather
     than growing off the top of the screen. */
  height:min(52vh,520px);
  height:min(52dvh,520px,calc(100dvh - var(--ai-bottom) - 64px));
  box-shadow:0 12px 38px color-mix(in srgb,var(--shadow) 60%,transparent)}

.ai-head{display:flex;gap:9px;align-items:center;padding:9px 8px 9px 13px;
  border-bottom:1px solid var(--line);cursor:pointer}
.ai-head strong{font-size:.95rem;flex:0 0 auto;margin-right:auto}
.ai-mark{width:19px;height:19px;fill:var(--magenta);flex:0 0 auto}
.ai-head .fine{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-family:ui-monospace,monospace;text-align:right}
.ai-hbtn{flex:0 0 auto;width:38px;height:38px;display:grid;place-items:center;
  background:none;border:0;border-radius:9px;color:var(--ink-3);cursor:pointer}
.ai-hbtn svg{width:19px;height:19px;fill:currentColor;transition:transform .18s ease}
.ai-hbtn:active{background:var(--panel-2)}
#ai-panel.is-folded #ai-min svg{transform:rotate(180deg)}
#ai-panel.is-folded #ai-log,#ai-panel.is-folded .ai-compose,#ai-panel.is-folded #ai-quota{display:none}
/* Folded: a bubble where the round button lives, not a bar across the map.
   It says what the chat last did ("Pinned 5 places") and the first two lines
   of the last answer, with an edge in the companion's colour so it reads as
   something to tap. The whole bubble unfolds it (ai.js); the small × on its
   corner closes it. It rides on --ai-bottom like the button, so a raised
   place card or tool panel keeps it above the panel's top, never over it. */
.ai-peek{display:none}
#ai-panel.is-folded{left:auto;right:calc(14px + env(safe-area-inset-right,0px));
  bottom:calc(var(--ai-bottom) + 8px);height:auto;
  width:min(330px,calc(100vw - 72px));
  border-radius:22px;overflow:visible;cursor:pointer;
  border-color:color-mix(in srgb,var(--magenta) 55%,var(--line));
  box-shadow:0 8px 24px color-mix(in srgb,var(--shadow) 50%,transparent)}
#ai-panel.is-folded #ai-max,#ai-panel.is-folded #ai-new{display:none}
#ai-panel.is-folded .ai-head{position:relative;display:grid;border-bottom:0;
  grid-template-columns:auto auto minmax(0,1fr) auto;
  grid-template-areas:"face name did min" "face t t min";
  column-gap:8px;row-gap:1px;align-items:center;padding:6px 4px 6px 10px;line-height:1.25}
#ai-panel.is-folded .ai-head:focus-visible{outline:2px solid var(--datum);outline-offset:2px;border-radius:22px}
#ai-panel.is-folded .ai-face{grid-area:face;margin:0}
#ai-panel.is-folded #ai-name{grid-area:name;margin:0;font-size:.86rem}
#ai-panel.is-folded .ai-peek{display:contents}
.ai-peek-did{grid-area:did;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:.76rem;font-weight:600;color:var(--magenta)}
.ai-peek-did::before{content:'· ';color:var(--ink-3);font-weight:400}
.ai-peek-did[hidden]{display:none}
.ai-peek-t{grid-area:t;min-width:0;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;
  -webkit-line-clamp:2;line-clamp:2;font-size:.8rem;line-height:1.25;color:var(--ink-2);overflow-wrap:anywhere}
#ai-panel.is-folded #ai-min{grid-area:min}
/* The × sits on the bubble's corner, small to look at and finger-sized to hit. */
#ai-panel.is-folded #ai-close{position:absolute;top:-9px;right:-7px;width:24px;height:24px;
  min-width:0;min-height:0;border-radius:50%;background:var(--panel);border:1px solid var(--line);
  color:var(--ink-2);box-shadow:0 2px 6px color-mix(in srgb,var(--shadow) 40%,transparent)}
#ai-panel.is-folded #ai-close svg{width:12px;height:12px}
#ai-panel.is-folded #ai-close::after{content:'';position:absolute;inset:-10px}
/* An answer came in while it was folded. */
#ai-panel.is-folded.is-unread .ai-head::before{content:'';position:absolute;z-index:1;left:34px;top:5px;
  width:10px;height:10px;border-radius:50%;background:var(--datum);border:2px solid var(--panel)}
/* Off the map every screen keeps the bottom-right corner clear for the round
   button and no wider (the Translate, Check and chip rows measured 10-05),
   so there the bubble is the button's own size: the character, and the dot.
   For a few seconds after the chat did something or answered (.is-told) it
   opens out to say so. */
html:not([data-view="map"]) #ai-panel.is-folded:not(.is-told){width:60px;height:60px;border-radius:50%;
  overflow:hidden;border-width:2px;background:var(--panel-2)}
html:not([data-view="map"]) #ai-panel.is-folded:not(.is-told) .ai-head{display:flex;justify-content:center;
  align-items:center;height:100%;padding:0}
html:not([data-view="map"]) #ai-panel.is-folded:not(.is-told) :is(#ai-name,.ai-peek,#ai-min,#ai-close){display:none}
html:not([data-view="map"]) #ai-panel.is-folded:not(.is-told) .ai-face{transform:scale(1.6);border:0}
html:not([data-view="map"]) #ai-panel.is-folded.is-unread:not(.is-told) .ai-head::before{left:auto;right:7px;top:7px}
/* Nothing to sit beside: the sheet is the screen, or the keyboard is up for
   something that is not the chat (a folded chat has no box to type in). */
html.kb-up #ai-panel.is-folded{display:none}
@media (max-width:899px) and (min-height:501px){
  /* On the map, as the button does, it stands over the ⓘ map credit. */
  html[data-view="map"] #ai-panel.is-folded{bottom:calc(var(--ai-bottom) + 44px)}
  html[data-view="map"][data-sheet="full"] #ai-panel.is-folded{display:none}
}
/* Landscape phones: beside the right-hand map column, as the button docks,
   and left of the side drawer once a panel is open in it. */
@media (orientation:landscape) and (max-height:500px) and (max-width:899px){
  #ai-panel.is-folded{right:calc(76px + env(safe-area-inset-right,0px));
    bottom:calc(max(calc(var(--nav) + var(--safe-b)), var(--kb)) + 10px);
    width:min(330px,calc(100vw - 170px))}
  html[data-sheet]:not([data-sheet="peek"]) #ai-panel.is-folded{
    right:calc(var(--drawer-w) + 22px + env(safe-area-inset-right,0px));
    width:min(300px,calc(100vw - var(--drawer-w) - 110px))}
}
/* The keyboard is up: the tool sheet is under it, so the window sits on the
   keyboard rather than a sheet's height above it — that gap was the room
   the conversation was missing while typing. */
html.kb-up{--ai-bottom:calc(var(--kb) + 8px)}
/* On a phone the town pill and a passing heads-up sit over the top of the
   window once it is tall (keyboard up, maximised) and hide its title bar and
   close button. They wait while the chat is open; an urgent alert does not. */
@media (max-width:899px){
  html[data-ai="open"]:not(:has(#ai-panel.is-folded)) .wf-pill,
  html[data-ai="open"]:not(:has(#ai-panel.is-folded)) #notices .ntc:not(.is-urgent){display:none}
}

/* Maximised: as tall as the screen allows, which is not the same as the whole
   screen. Only `top` is claimed; `bottom` stays on `--ai-bottom`, so the
   window grows upward and stops above the navigation bar rather than over it.
   That is deliberate. The bottom bar is how you leave the assistant, and a
   window that covers the way out in order to be twenty per cent taller has
   made a bad trade — the height was never the scarce thing, the reading area
   was. Stopping short still turns 422px of log into 732px on a 812px phone.

   Pinned rather than given a height, because the top inset is the real limit
   on a phone with a notch, and asking for 100dvh puts the header under it. */
#ai-panel.is-max{
  top:calc(env(safe-area-inset-top,0px) + 8px);
  height:auto}
#ai-panel.is-max #ai-max svg{transform:rotate(180deg)}
/* Reading width. 88% of a phone is right for a chat bubble and wrong for a
   page of prose with citations, which is what this state is for. */
#ai-panel.is-max .ai-msg{max-width:min(96%,64ch)}

#ai-log{flex:1;overflow-y:auto;padding:14px;display:flex;flex-direction:column;gap:11px;min-height:120px}
.ai-msg{max-width:88%}
.ai-user{align-self:flex-end}
.ai-user .ai-body{background:var(--datum);color:var(--on-accent);border-radius:14px 14px 3px 14px;padding:9px 13px;font-size:.92rem}
.ai-bot .ai-body{background:var(--panel-2);border-radius:14px 14px 14px 3px;padding:10px 13px;
  font-size:.92rem;white-space:pre-wrap;line-height:1.55}
.ai-meta{font-size:.68rem;color:var(--ink-3);margin-top:4px;font-family:ui-monospace,monospace}

.ai-compose{position:relative;flex:0 0 auto;border-top:1px solid var(--line)}
#ai-form{display:flex;gap:8px;padding:10px 12px}
#ai-input{flex:1;min-width:0;padding:10px 13px;border-radius:999px;border:1px solid var(--line);
  background:var(--ground);color:var(--ink);font-size:16px}
#ai-input:focus-visible{outline:2px solid var(--datum);outline-offset:1px}
/* "New chat started. Undo" — the one line left after the header's new-chat button. */
.ai-fresh{align-self:center;font-size:13px;color:var(--ink-2);padding:2px 0 6px}
.ai-fresh button{background:none;border:0;padding:4px 6px;color:var(--datum);font:inherit;font-weight:600;
  text-decoration:underline;cursor:pointer}
.ai-plus{flex:0 0 auto;width:40px;height:40px;border-radius:50%;border:1px solid var(--line);
  background:var(--ground);color:var(--ink-2);cursor:pointer;display:grid;place-items:center}
.ai-plus svg{width:20px;height:20px;fill:currentColor;transition:transform .18s ease}
.ai-plus[aria-expanded="true"]{border-color:var(--datum);color:var(--datum)}
.ai-plus[aria-expanded="true"] svg{transform:rotate(45deg)}
#ai-send{flex:0 0 auto;white-space:nowrap}

/* The assistant's viewfinder. It sits in the composer, above the text box,
   because the note typed there goes with the picture and the two belong in
   the same place. */
.ai-cam{margin:10px 12px 0;border:1px solid var(--line);border-radius:12px;overflow:hidden;background:#000}
/* The whole frame, never a crop of it. This was once `cover` in a box capped
   at 230px, and a phone's camera streams portrait, so the viewfinder showed a
   thin band across the middle while Capture sent the full frame — the model
   was asked about things the person never saw they had photographed. With
   `contain` what is on screen is what is sent, bars and all. */
#ai-cam-video{width:100%;display:block;object-fit:contain;background:#000;
  max-height:34vh;max-height:min(34dvh,230px)}
.ai-cam-btns{display:flex;gap:8px;flex-wrap:wrap;padding:9px 10px;background:var(--panel-2)}
.ai-cam-btns .btn{flex:0 0 auto}
/* While the viewfinder is up it is what is being looked at, so the window
   grows to nearly the whole screen and the picture takes the room: the log
   keeps a strip, the composer keeps its text box and Ask, and the video
   shrinks into whatever is left rather than pushing either off the bottom.
   That last part is done with flex, not a height sum, so it holds on every
   screen and with the keyboard up. */
#ai-panel:has(#ai-cam:not([hidden])){
  height:min(88vh,calc(100vh - var(--ai-bottom) - 64px));
  height:min(88dvh,calc(100dvh - var(--ai-bottom) - 64px))}
#ai-panel:has(#ai-cam:not([hidden])) #ai-log{flex:0 1 auto;min-height:0;max-height:18%}
#ai-panel:has(#ai-cam:not([hidden])) .ai-compose{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
#ai-panel:has(#ai-cam:not([hidden])) .ai-compose > *{flex:0 0 auto}
#ai-panel:has(#ai-cam:not([hidden])) .ai-cam{flex:1 1 auto;min-height:150px;display:flex;flex-direction:column}
#ai-panel:has(#ai-cam:not([hidden])) .ai-cam-btns{flex:0 0 auto}
#ai-panel:has(#ai-cam:not([hidden])) #ai-cam-video{flex:1 1 0;min-height:0;height:auto;max-height:none}

/* What Ask is about to do, when it is not the ordinary thing. */
.ai-armed{display:flex;align-items:center;gap:7px;margin:9px 12px 0;padding:5px 6px 5px 10px;
  border:1px solid var(--magenta);border-radius:999px;background:color-mix(in srgb,var(--magenta) 10%,transparent);
  color:var(--magenta);font-size:.8rem;width:max-content;max-width:calc(100% - 24px)}
.ai-armed > svg{width:15px;height:15px;fill:currentColor;flex:0 0 auto}
.ai-armed button{width:24px;height:24px;display:grid;place-items:center;border:0;border-radius:50%;
  background:none;color:inherit;cursor:pointer;flex:0 0 auto}
.ai-armed button svg{width:11px;height:11px;fill:currentColor}
.ai-armed button:active{background:color-mix(in srgb,var(--magenta) 25%,transparent)}

/* The composer's menu. Opens upward, because it hangs off a control that is
   already at the bottom of a window that is already at the bottom. */
.ai-menu{position:absolute;left:10px;right:10px;bottom:calc(100% + 6px);z-index:2;
  background:var(--panel);border:1px solid var(--line);border-radius:13px;
  box-shadow:0 -6px 26px color-mix(in srgb,var(--shadow) 50%,transparent);padding:6px;
  /* Capped, because the window clips it: left to its natural height it grew
     over the title bar, and a menu that hides the close button of the thing it
     belongs to is a trap. This is the fallback — the real ceiling is measured
     against the window when the menu opens, since how much room there is
     depends on how tall the window happens to be. */
  max-height:min(44vh,330px);overflow-y:auto;overscroll-behavior:contain}
.ai-mi{display:flex;gap:11px;align-items:flex-start;width:100%;text-align:left;
  background:none;border:0;border-radius:9px;padding:9px 10px;color:var(--ink);cursor:pointer}
.ai-mi:hover,.ai-mi:focus-visible{background:var(--panel-2)}
.ai-mi > svg{width:20px;height:20px;fill:var(--ink-3);flex:0 0 auto;margin-top:1px}
.ai-mi span{display:flex;flex-direction:column;gap:1px;min-width:0}
.ai-mi b{font-size:.9rem;font-weight:600}
.ai-mi i{font-style:normal;font-size:.76rem;color:var(--ink-3);line-height:1.4}

@media (min-width:900px){
  /* Clear of the right-hand drawer (400px at right:16px), so the two never
     overlap and neither has to be shut to read the other. */
  #ai-fab{bottom:22px;right:432px}
  #ai-panel{left:auto;right:432px;bottom:22px;width:min(400px,calc(100vw - 464px));
    height:min(68vh,620px);height:min(68dvh,620px)}
  /* Maximised beside the drawer rather than over it: on a wide screen the
     drawer is the other half of the work, and covering it to read an answer
     about it would be the wrong trade. Wider as well as taller, because a
     400px column is the shape that made the long answers hard to read. */
  #ai-panel.is-max{top:22px;height:auto;
    width:min(720px,calc(100vw - 464px))}
  /* Folded, the bubble docks where the button does, beside the drawer. */
  #ai-panel.is-folded{right:432px;bottom:22px;width:min(340px,calc(100vw - 464px))}
  /* The drawer is pinned top and bottom here, so there is no sheet height to
     ride above — only the drawer to sit beside, which the offsets above do. */
}
@media (max-width:420px){
  /* Something has to give at this width, and it is the model id — the mode
     matters while you are choosing it, the model name does not. */
  .ai-head .fine{display:none}
}

/* user position: puck sized to imply nothing about precision */
/* An arrow, so the puck answers "which way am I facing" as well as "where am
   I". With no heading to show it collapses to the old dot rather than pointing
   somewhere invented — see .no-heading. */
.user-puck{width:26px;height:26px;display:grid;place-items:center;
  filter:drop-shadow(0 0 3px color-mix(in srgb,var(--shadow) 80%,transparent))}
.user-puck svg{width:26px;height:26px;fill:#FF74B0;stroke:#0B1116;stroke-width:1.4;
  stroke-linejoin:round;transition:opacity .18s}
.user-puck::before{content:'';position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);width:16px;height:16px;border-radius:50%;
  background:#FF74B0;border:2.5px solid #0B1116;box-shadow:0 0 0 4px color-mix(in srgb,var(--magenta) 25%,transparent);
  opacity:0;transition:opacity .18s}
.user-puck.no-heading svg{opacity:0}
.user-puck.no-heading::before{opacity:1}

/* ---------------- transit ---------------- */
#transit-panel{position:absolute;left:12px;right:12px;bottom:18px;z-index:7;
  background:color-mix(in srgb,var(--panel) 96%,transparent);backdrop-filter:blur(10px);border:1px solid var(--line);
  border-left:3px solid var(--magenta);border-radius:12px;padding:11px 14px}
.transit-head{display:flex;justify-content:space-between;align-items:baseline;gap:10px;margin-bottom:9px}
.transit-head .fine{font-family:ui-monospace,monospace}
.tks{display:flex;flex-wrap:wrap;gap:6px 12px}
.tk-l{display:inline-flex;align-items:center;gap:6px;font-size:.84rem;color:var(--ink-2);cursor:pointer}
.tk-l input{accent-color:var(--datum);width:15px;height:15px}
.tk-d{width:9px;height:9px;border-radius:50%;display:inline-block}
@media (min-width:900px){ #transit-panel{right:auto;width:360px} }

/* ---------------- places ---------------- */
#places-panel{position:absolute;left:12px;right:12px;bottom:18px;z-index:7;
  background:color-mix(in srgb,var(--panel) 96%,transparent);backdrop-filter:blur(10px);border:1px solid var(--line);
  border-left:3px solid #8AB4F8;border-radius:12px;padding:11px 14px;max-height:52vh;overflow-y:auto}
#places-list{margin-top:10px;display:grid;gap:1px;background:var(--line);border:1px solid var(--line);border-radius:9px;overflow:hidden}
#places-list:empty{display:none}
.place-row{display:flex;gap:9px;align-items:center;background:var(--panel);border:0;
  padding:9px 12px;text-align:left;cursor:pointer;color:var(--ink);width:100%}
.place-row:hover{background:var(--panel-2)}
.place-body{display:flex;flex-direction:column;min-width:0}
.place-n{font-size:.9rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (min-width:900px){ #places-panel{right:auto;width:380px} }

/* ---------------- currency ---------------- */
.fx-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px}
#fx-amount{flex:1;min-width:96px;padding:10px 12px;border-radius:8px;border:1px solid var(--line);
  background:var(--panel);color:var(--ink);font-size:15px;font-family:ui-monospace,monospace}
#fx-from,#fx-to{padding:10px 10px;border-radius:8px;border:1px solid var(--line);
  background:var(--panel);color:var(--ink);font-size:14px;font-family:ui-monospace,monospace}
.fx-arrow{color:var(--ink-3)}
#fx-result{font-family:ui-monospace,monospace;font-size:1.6rem;font-weight:700;color:var(--datum);
  font-variant-numeric:tabular-nums}
#fx-unit{margin-top:2px}

/* ---------------- tap-anywhere place card ---------------- */
#place-card{position:absolute;left:12px;right:12px;bottom:18px;z-index:9;
  background:color-mix(in srgb,var(--panel) 97%,transparent);backdrop-filter:blur(10px);border:1px solid var(--line);
  border-left:3px solid var(--magenta);border-radius:12px;padding:14px 16px}
.pc-close{position:absolute;top:6px;right:8px;background:none;border:0;color:var(--ink-3);font-size:22px;cursor:pointer;line-height:1}
.pc-title{font-weight:700;font-size:1.08rem;padding-right:26px}
.pc-sub{color:var(--ink-2);font-size:.9rem;margin-top:2px}
.pc-list{margin-top:8px;display:grid;gap:3px}
.pc-item{font-size:.84rem;color:var(--ink-3)}
.pc-coords{font-family:ui-monospace,monospace;font-size:.72rem;color:var(--ink-3);margin-top:8px}
.pc-actions{display:flex;gap:8px;margin-top:10px;flex-wrap:wrap;align-items:center}
.pc-actions .ui-more{min-width:34px;height:32px;margin-left:auto}
.pc-addr{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#live-panel{position:absolute;left:12px;right:12px;bottom:18px;z-index:7;
  background:color-mix(in srgb,var(--panel) 96%,transparent);backdrop-filter:blur(10px);border:1px solid var(--line);
  border-left:3px solid #6FB8D6;border-radius:12px;padding:11px 14px}
#live-notes{margin-top:8px}
@media (min-width:900px){ #place-card,#live-panel{right:auto;width:380px} }

/* ---------------- weather ----------------
   Carries the same free-standing-panel geometry as its neighbours (the sheet
   strips it back out again — see the `#sheet-body > [id]` rule), and the same
   coloured spine, in the radar's blue. */
#weather-panel{position:absolute;left:12px;right:12px;bottom:18px;z-index:7;
  background:color-mix(in srgb,var(--panel) 96%,transparent);backdrop-filter:blur(10px);border:1px solid var(--line);
  border-left:3px solid #4FA3D1;border-radius:12px;padding:11px 14px}
@media (min-width:900px){ #weather-panel{right:auto;width:380px} }

/* The one sentence the whole tool exists for. Big, first, and coloured when
   the answer is "yes, and soon". */
.wx-verdict{
  font-size:1.05rem; font-weight:600; margin:8px 0 2px; color:var(--ink);
  line-height:1.3;
}
.wx-verdict.is-wet{color:#8AB4F8}
.wx-now{color:var(--ink-2);font-size:.86rem;line-height:1.5;margin-bottom:8px}
.wx-now .fine{color:var(--ink-3,var(--ink-2))}

/* Two hours of rain, fifteen minutes to a bar. Bars grow from the bottom, so
   the shape of a shower reads left to right the way a chart does. */
.wx-strip{display:flex;gap:3px;align-items:flex-end;height:58px;margin:4px 0 2px}
.wx-cell{
  flex:1 1 0; min-width:0; height:100%;
  display:flex; flex-direction:column; justify-content:flex-end; align-items:stretch; gap:2px;
}
.wx-cell i{display:block;width:100%;border-radius:2px 2px 0 0;background:var(--line)}
.wx-cell i.is-dry{background:var(--line);opacity:.5}
.wx-cell i.is-light{background:#6FB8D6;opacity:.6}
.wx-cell i.is-rain{background:#4FA3D1}
.wx-cell i.is-heavy{background:#8AB4F8}
.wx-cell span{
  font-size:12px; color:var(--ink-3,var(--ink-2)); text-align:center;
  font-variant-numeric:tabular-nums; white-space:nowrap; overflow:hidden;
}
/* On a narrow phone nine timestamps do not fit; every other one does, and the
   bars still carry the shape. */
@media (max-width:420px){ .wx-cell:nth-child(even) span{visibility:hidden}
  /* At 12 px a time is a shade wider than its bar; the hidden neighbour's
     space is free, so it may spill into it. */
  .wx-cell:nth-child(odd) span{overflow:visible} }

/* The transport for the loop. The slider is the control people reach for — it
   is the timeline — so it gets the room and the button stays small. */
/* Rain around you, at a fixed distance across.
   Square because it is a range display and a ring has to stay a ring; capped
   because past about 300px it stops telling you anything a smaller one did
   not, and on a phone the panel it sits in is the scarce thing. */
.wx-around{margin:10px 0 0;padding:0;display:flex;flex-direction:column;gap:5px}
.wx-around canvas{width:100%;max-width:300px;aspect-ratio:1;align-self:center;display:block;
  border:1px solid var(--line);border-radius:10px;background:var(--ground)}
.wx-around figcaption{text-align:center}

.wx-loop{display:flex;align-items:center;gap:10px;margin-top:10px}
.wx-loop input[type=range]{flex:1 1 auto;min-width:0;accent-color:#4FA3D1}
.wx-loop .fine{flex:0 0 auto;font-variant-numeric:tabular-nums}
#wx-kindrow{margin-top:8px;align-items:center;gap:10px}
#wx-note{margin-top:10px}

.cam-title{font-weight:600;font-size:.9rem;margin:10px 0 6px}
.cam-img{width:100%;border-radius:8px;border:1px solid var(--line);display:block;margin-bottom:8px;background:#000}
.radio-player{width:100%;margin:6px 0 8px}

/* The camera wall. Tiles are a fixed aspect so the grid does not reflow every
   time a camera hands back a picture of a different shape — which, across
   seven networks and a few thousand cameras, is constantly. */
#cams-panel{max-height:78vh;overflow-y:auto}
#cam-wall{display:grid;gap:6px;margin-top:10px;
  grid-template-columns:repeat(auto-fill,minmax(150px,1fr))}
.cam-tile{position:relative;padding:0;border:1px solid var(--line);border-radius:8px;
  overflow:hidden;background:#000;cursor:pointer;aspect-ratio:4/3;display:block}
.cam-tile img{width:100%;height:100%;object-fit:cover;display:block}
/* A live tile fills the same box a still would. `cover` rather than `contain`
   because the grid is a fixed 4:3 and these streams run 352x288 to 1080p —
   letterboxing every one of them turns the wall into a wall of black bars. */
.cam-tile video{width:100%;height:100%;object-fit:cover;display:block;background:#000;
  pointer-events:none}
.cam-tile.is-on{border-color:#5FBF8F;box-shadow:0 0 0 1px #5FBF8F}
/* A stream-only camera waiting for a player slot. Without this it is a black
   square, which reads as a camera that is down rather than one that is queued. */
.cam-tile.is-queued::after{content:"live · scroll to play";position:absolute;
  inset:auto 0 46% 0;text-align:center;font-size:.68rem;color:var(--ink-3);
  letter-spacing:.03em}
/* A camera that stopped answering keeps its last good frame on screen, which
   is the one failure that genuinely misleads. So it is dimmed and labelled. */
.cam-tile.is-dead img{opacity:.25;filter:grayscale(1)}
.cam-tile.is-dead::after{content:"no picture";position:absolute;inset:auto 0 42% 0;
  text-align:center;font-size:.72rem;color:var(--ink-3);letter-spacing:.04em}
.cam-cap{position:absolute;left:0;right:0;bottom:0;padding:10px 6px 4px;
  font-size:.68rem;line-height:1.25;color:#fff;text-align:left;
  background:linear-gradient(transparent,rgba(0,0,0,.82));
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
#cam-big{margin:10px 0;padding:10px;border:1px solid var(--line);border-radius:10px;
  background:var(--panel-2)}
.cam-big-head{display:flex;flex-direction:column;gap:2px;margin-bottom:8px;align-items:flex-start}

/* Live video, where a network publishes it. Same box as the still it
   replaces, so the panel does not jump when a stream fails over to one. */
.cam-video{width:100%;border-radius:8px;border:1px solid var(--line);display:block;
  margin-bottom:8px;background:#000;aspect-ratio:16/9;object-fit:contain}
.mp-cam-video{width:100%;aspect-ratio:16/9;object-fit:contain;display:block;
  border:1px solid var(--line);border-radius:8px;background:#000}

/* Which cameras move. A wall of stills with a handful of live streams hidden
   in it is, to anyone looking at it, a wall of stills. */
.cam-badge{font-size:.6rem;font-weight:700;letter-spacing:.08em;line-height:1;
  padding:3px 5px;border-radius:4px;color:#0B0D0F;background:#5FBF8F}
.cam-badge.is-clip{background:var(--ink-3);color:#0B0D0F}
.cam-tile .cam-badge{position:absolute;top:5px;left:5px;z-index:1}
/* On the tiles it is a status light, so it pulses; in a heading it is a word
   and holding still is the point. */
.cam-tile .cam-badge.is-live{animation:cam-pulse 2.4s ease-in-out infinite}
@keyframes cam-pulse{0%,100%{opacity:1}50%{opacity:.55}}
@media (prefers-reduced-motion:reduce){
  .cam-tile .cam-badge.is-live{animation:none}
}
/* The local-script name on a place card. Larger than the fine print because
   it is meant to be shown to someone, not just read. */
.pd-local{font-size:1.05rem;margin:2px 0 4px;color:var(--ink)}
.pd-spoken{color:var(--ink-3);font-style:italic;font-size:.9rem}
/* The same line wherever a place is listed (names.js): the sign's name, a
   speaker that says it in the local voice, and how to say it yourself. The
   reading wraps under the name on a narrow phone rather than squeezing it. */
.pres-local,.pd-local{display:flex;flex-wrap:wrap;align-items:center;column-gap:6px;row-gap:1px}
.pn-spoken{color:var(--ink-3,var(--ink-2));font-style:italic}
.pd-local .pn-spoken{font-size:.9rem}
.pn-say{display:inline-flex;align-items:center;justify-content:center;flex:none;
  width:28px;height:28px;margin:-4px 0;border-radius:50%;color:var(--magenta);cursor:pointer;
  vertical-align:middle;-webkit-tap-highlight-color:transparent}
.pn-say[hidden]{display:none}
.pn-say svg{width:18px;height:18px}
.pn-say:hover,.pn-say:focus-visible{background:var(--panel-2)}
.pn-say.on{background:var(--magenta);color:var(--on-magenta)}
.near-sub .pn-say{width:24px;height:24px;margin:-3px 2px}
.near-sub .pn-say svg{width:16px;height:16px}
/* The same line under a transit name (10-10): a stop on the board, in the
   stop finder and down a line, a run's destination, the stops to get on and
   off at in a journey. Smaller than the English heading above it, and
   wrapping rather than cut off — the reading is the part a traveller needs. */
.dep-pn,.sf-pn,.bl-pn,.jstep-pn{display:flex;flex-wrap:wrap;align-items:center;column-gap:6px;row-gap:1px;
  font-size:.8rem;color:var(--ink-2);white-space:normal;overflow:visible}
.jstep-pn{margin-top:2px}
.jstep-pn>.fine:first-child{min-width:2em}
.dep-pn .pn-say,.sf-pn .pn-say,.bl-pn .pn-say,.jstep-pn .pn-say{width:24px;height:24px;margin:-3px 0}
.dep-pn .pn-say svg,.sf-pn .pn-say svg,.bl-pn .pn-say svg,.jstep-pn .pn-say svg{width:16px;height:16px}
.dep-towards .pn-local,.dep-alt .pn-local,.bl-dirs .pn-local{color:var(--ink-2)}

/* ---- booking ---------------------------------------------------------- *
   The comparison links are the answer to "which is cheapest", so they are the
   ones that look like buttons; the agencies below them read as a list. */
.pd-book-dates{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;margin:4px 0 10px}
.pd-book-field{display:flex;flex-direction:column;gap:2px}
.pd-book-field input{background:var(--panel);color:var(--ink);border:1px solid var(--line);
  border-radius:7px;padding:5px 7px;font:inherit;font-size:.85rem}
.pd-book-nights{padding-bottom:6px}
.pd-book-h{font-size:.8rem;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-2);
  margin:12px 0 3px}
.pd-book-hint{margin:0 0 7px}
.pd-book-links{display:flex;flex-wrap:wrap;gap:7px}
/* The platform name and what tapping it lands on, on one line. */
.pd-book-top{display:flex;align-items:baseline;gap:7px;flex-wrap:wrap}
/* Four words, and the only one that is emphasised is the one that means the
   link goes where the reader expects. The rest are a quiet qualification, not
   a warning: a city-wide list is a perfectly good page to be sent to, as long
   as nobody was promised the hotel. */
.pd-book-lands{font-size:.7rem;letter-spacing:.03em;color:var(--ink-3,var(--ink-2));
  border:1px solid var(--line);border-radius:999px;padding:0 6px;line-height:1.5;white-space:nowrap}
.pd-book-lands[data-lands="property"]{color:var(--datum);border-color:var(--datum)}
.pd-book-link.is-exact{border-color:var(--datum)}
.pd-book-more{background:none;border:0;color:var(--datum);cursor:pointer;padding:8px 0 2px;
  text-align:left;text-decoration:underline;text-underline-offset:3px}
/* The name, to paste into the ones that only open a search. */
.pd-book-copy{display:flex;flex-wrap:wrap;align-items:center;gap:7px;margin:12px 0 2px}
.pd-copy{background:var(--panel-2);border:1px solid var(--line);border-radius:7px;
  color:var(--ink);cursor:pointer;padding:4px 9px;font-size:.84rem;max-width:32ch;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pd-copy:hover{border-color:var(--datum)}
.pd-copy.is-done{color:var(--datum);border-color:var(--datum)}
.pd-book-link{display:flex;flex-direction:column;gap:1px;text-decoration:none;color:var(--ink);
  background:var(--panel);border:1px solid var(--line);border-radius:9px;padding:7px 11px;
  max-width:100%;min-width:0}
.pd-book-link:hover{border-color:var(--datum)}
.pd-book-link.is-compare{border-color:var(--datum);background:color-mix(in srgb,var(--datum) 10%,transparent)}
.pd-book-name{font-weight:600;font-size:.9rem}
.pd-book-note{max-width:30ch;line-height:1.25}
.pd-book-compare{margin:14px 0 4px}
.pd-book-foot{margin-top:10px}


/* "What works here": one row per layer, the reason under the name. A tick
   with no explanation teaches nothing and a cross with no explanation reads
   as a fault rather than as an absence of data. */
.cov-list{display:flex;flex-direction:column;gap:8px;margin:8px 0 10px}
.cov-row{display:flex;gap:8px;align-items:flex-start}
.cov-row > div{display:flex;flex-direction:column;gap:1px;min-width:0}
.cov-mark{flex:0 0 1.1em;line-height:1.4;color:var(--ok);font-weight:700}
.cov-row.is-off .cov-mark{color:var(--magenta)}
.cov-row.is-off strong{color:var(--ink-3)}
.cam-embed{width:100%;aspect-ratio:16/9;border:0;border-radius:8px;background:#000;display:block}
#eye-side{max-height:40vh;overflow-y:auto}
select.mini{background:var(--panel-2);color:var(--ink);border:1px solid var(--line);border-radius:7px;padding:6px 9px;font-size:13px}
#live-panel{max-height:70vh;overflow-y:auto}

/* ==================================================================
   REDESIGN: one surface for tools.
   Mobile: a bottom sheet above the nav (peek / half / full).
   Desktop: a right-hand drawer. Exactly one panel is visible at a time,
   so nothing can cover anything else.
   ================================================================== */
#sheet{
  /* `max()`, not a sum, and for the same reason the map's bottom chrome uses
     one: the nav bar and the on-screen keyboard are two things covering the
     same edge, never two things stacked on each other. With the keyboard up
     the nav is behind it and adding both would float the sheet in mid-air. */
  position:fixed; top:auto; left:0; right:0; z-index:35;
  inset:auto 0 max(calc(var(--nav) + var(--safe-b)), var(--kb)) 0;
  background:var(--panel); border-top:1px solid var(--line); border-radius:16px 16px 0 0;
  display:flex; flex-direction:column; box-shadow:0 -8px 30px color-mix(in srgb,var(--shadow) 45%,transparent);
  /* A slight overshoot-free ease-out: it settles where the finger left it
     rather than sliding in at a constant speed (10-03). */
  transition:height .26s cubic-bezier(.22,.9,.3,1), transform .22s ease, opacity .18s ease; will-change:height;
  max-height:calc(100vh - var(--nav) - var(--safe-b) - 8px);
  max-height:calc(100dvh - max(calc(var(--nav) + var(--safe-b)), var(--kb)) - 8px);
}
#sheet.is-peek{height:auto}
/* Tapping a place opens at card height, not half the screen.
   Half a phone screen of panel for "you tapped a building" is why the sheet
   felt like it was in the way: the thing you tapped was under it. A card is
   enough for a name, a line of detail and two buttons, and the handle drags it
   up to the full thing when you want that. */
/* Heights in `dvh`, not `vh`, and a ceiling the sheet can never exceed.
 *
 * `100vh` on iOS Safari is the *large* viewport — the height the page would
 * have if the address bar were hidden — while a `position:fixed` element
 * anchored to `bottom` sits above the address bar that is actually on screen.
 * So a sheet 100vh tall anchored to the visible bottom hangs off the top of
 * the screen by exactly the height of the browser chrome, and what hangs off
 * the top is `#sheet-head`: the title, the height chevron and the close
 * cross. The tool opened full-screen with no visible way out of it, which is
 * the "cannot see the close or minimise" on iPhone.
 *
 * `dvh` tracks the viewport that is really there, address bar and all, and
 * shrinks and grows as that bar retracts. The plain `vh` line above each one
 * is the fallback for a browser that does not know `dvh` — it keeps today's
 * behaviour rather than collapsing the sheet to nothing.
 *
 * `max-height` on the sheet itself is the belt to that braces: whatever a
 * state asks for, the sheet stops at the top of the visible viewport, so the
 * header is reachable even if a future height is written carelessly. */
#sheet.is-card{height:min(34vh,250px); height:min(34dvh,250px)}
#sheet.is-half{height:46vh; height:46dvh}
#sheet.is-full{height:calc(100vh - var(--nav) - var(--safe-b) - 8px);
               height:calc(100dvh - max(calc(var(--nav) + var(--safe-b)), var(--kb)) - 8px)}
#sheet.is-peek .sheet-body{display:none}
/* The grip.
 *
 * The bar people are aiming at is 40x4 px, and it stays that size because a
 * fat grey bar across the top of a sheet is noise. What changed is the target
 * *around* it: 22px of padding above and below makes the button itself 44px
 * tall, which is the floor every other control in this app clears and the
 * reason dragging the sheet down used to need two or three attempts. The bar
 * is centred in that space, so nothing looks different and everything within
 * a thumb's width of it now works.
 *
 * `touch-action:none` is what lets the drag happen at all on a touchscreen:
 * without it the browser claims a vertical drag as a page scroll before the
 * pointermove handler ever sees it. */
.sheet-handle{
  flex:0 0 auto; width:100%; background:none; border:0; padding:20px 0 16px; cursor:grab;
  touch-action:none; user-select:none; -webkit-user-select:none;
  margin-bottom:-14px;                /* the target grows, the layout does not */
}
.sheet-handle:active{cursor:grabbing}
.sheet-handle span{display:block;width:40px;height:4px;border-radius:2px;background:var(--ink-3);margin:0 auto;opacity:.7;
  transition:width .15s ease, opacity .15s ease}
/* Something to aim at while you are dragging, and a hint that the strip is
   draggable at all when a mouse is over it. */
.sheet-handle:hover span,#sheet.is-dragging .sheet-handle span{width:56px;opacity:1}

/* While a finger owns the height, nothing else may animate it: a 220ms ease
   on `height` and a pointermove writing a new height every frame are two
   things driving one number, and the sheet lags a finger's width behind. */
#sheet.is-dragging{transition:none !important}

/* ---------------- the sheet's header ----------------
 * The old sheet could only be resized by dragging a 40x4 px bar and only be
 * closed by finding a small cross inside whichever panel happened to be open.
 * Both are still there; neither is required any more. The header says what you
 * are looking at and gives the two things you want to do to it as 44px
 * targets, which is what stops the sheet feeling like something you have to
 * wrestle up and down to use.
 */
.sheet-head{
  flex:0 0 auto; display:flex; align-items:center; gap:4px; padding:0 6px 6px 14px;
  border-bottom:1px solid var(--line); margin-bottom:6px;
  /* The second half of the "hard to slide it down" fix: the whole title strip
     is a drag surface, so the gesture is aimed at a bar the width of the
     screen instead of at a 40px grip. The buttons inside opt out in JS. */
  touch-action:none; user-select:none; -webkit-user-select:none; cursor:grab;
}
.sheet-head:active{cursor:grabbing}
.sheet-head .sheet-hbtn{cursor:pointer;touch-action:manipulation}
.sheet-head strong{flex:1 1 auto; font-size:.95rem; letter-spacing:.01em;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.sheet-hbtn{
  flex:0 0 auto; width:44px; height:44px; display:grid; place-items:center;
  background:none; border:0; border-radius:9px; color:var(--ink-2); cursor:pointer;
}
.sheet-hbtn svg{width:20px;height:20px;fill:currentColor;transition:transform .18s ease}
.sheet-hbtn.is-up svg{transform:rotate(180deg)}
.sheet-hbtn:active{background:var(--panel-2)}

/* ---------------- the launcher strip ----------------
 * Replaces a thirteen-item horizontal scroller. One button opens everything as
 * a labelled grid; the rest of the strip is what is switched on right now, so
 * the collapsed sheet answers "what is my map doing" instead of showing a menu.
 */
.sheet-bar{
  flex:0 0 auto; display:flex; align-items:center; gap:8px; padding:2px 12px 10px; min-width:0;
}
/* The strip is a drag surface too (10-03): sideways still scrolls the chips,
   up and down moves the sheet. touch-action is not inherited, so every
   element in it says so. */
.sheet-bar,.sheet-bar *{touch-action:pan-x}
.tools-btn{
  flex:0 0 auto; display:flex; align-items:center; gap:7px; height:38px; padding:0 14px;
  user-select:none; -webkit-user-select:none;
  border-radius:999px; border:1px solid var(--line); background:var(--panel-2);
  color:var(--ink); font-size:.87rem; font-weight:600; cursor:pointer; font-family:inherit;
}
.tools-btn svg{width:16px;height:16px;fill:currentColor;opacity:.8}
.tools-btn:active{background:var(--line)}
.sheet-live{
  flex:1 1 auto; display:flex; gap:6px; overflow-x:auto; scrollbar-width:none; min-width:0;
  align-items:center;
}
.sheet-live::-webkit-scrollbar{display:none}
.sheet-hint{color:var(--ink-3);font-size:.8rem;white-space:nowrap}
.livechip{
  flex:0 0 auto; height:32px; padding:0 12px; border-radius:999px; cursor:pointer;
  border:1px solid var(--datum); background:color-mix(in srgb,var(--datum) 16%,transparent); color:var(--datum);
  font-size:.82rem; font-weight:600; white-space:nowrap; font-family:inherit;
}
.livechip.is-showing{background:var(--datum);color:var(--on-accent)}

/* ---------------- the tool grid ---------------- */
.toolgrid{
  display:grid; grid-template-columns:repeat(auto-fill,minmax(92px,1fr)); gap:8px; padding:6px 0 2px;
}
.toolcell{
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:7px;
  min-height:78px; padding:10px 6px; border-radius:12px; cursor:pointer; font-family:inherit;
  border:1px solid var(--line); background:var(--panel-2); color:var(--ink); font-size:.79rem;
  text-align:center; line-height:1.2;
}
.toolcell svg{width:23px;height:23px;fill:var(--ink-2)}
.toolcell:active{background:var(--line)}
.toolcell.is-on{border-color:var(--datum);background:color-mix(in srgb,var(--datum) 12%,transparent)}
.toolcell.is-on svg{fill:var(--datum)}
#tools-note{margin:12px 0 2px}

/* ---------------- grouped tools, layer chips, map only (10-03) ----------------
 * "Those options look lump sum together": the grid was one block of fifteen
 * cells. It is now what is on the map first, then the tools in four labelled
 * groups. The cross on a panel only puts it away; a layer is switched off by
 * the switch in the panel's header or the small cross on its chip. */
.tg-h,.lk-h{margin:16px 0 7px;font-size:.72rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-3)}
.tg-group:first-child .tg-h{margin-top:4px}
.tg-group .toolgrid{grid-template-columns:repeat(auto-fill,minmax(74px,1fr));gap:6px;padding:0}
.tg-group .toolcell{min-height:70px;padding:8px 4px;gap:5px;font-size:.76rem;position:relative}
.toolcell.is-on::after{content:'';position:absolute;top:7px;right:7px;width:7px;height:7px;border-radius:50%;background:var(--datum)}
.tg-on{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.tg-alloff{background:none;border:0;padding:6px 4px;color:var(--datum);font:inherit;font-size:.82rem;font-weight:600;cursor:pointer}
.livechip{display:inline-flex;align-items:center;gap:4px;padding:0 3px 0 12px}
.lc-open{background:none;border:0;padding:0;height:100%;color:inherit;font:inherit;font-weight:600;cursor:pointer;
  max-width:190px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lc-x{flex:0 0 auto;width:26px;height:26px;border-radius:50%;border:0;padding:0;display:grid;place-items:center;cursor:pointer;
  background:color-mix(in srgb,var(--datum) 22%,transparent);color:inherit}
.lc-x svg{width:12px;height:12px;fill:currentColor}
.livechip.is-showing .lc-x{background:color-mix(in srgb,var(--on-accent) 25%,transparent)}
.sheet-onoff{margin:0 6px;touch-action:manipulation}
.sheet-onoff[hidden]{display:none}
#sheet-back[hidden]{display:none}
#sheet-head #sheet-back{margin-left:-8px}

/* Live layers as switch rows, in groups. */
.lk-groups .tk-l{display:flex;width:100%;min-height:48px;gap:12px;padding:6px 0;margin:0;border-bottom:1px solid var(--line);
  font-size:.92rem;color:var(--ink);text-transform:none;letter-spacing:normal;font-weight:400}
.lk-groups .tk-l input.ui-toggle{order:3;margin-left:auto;width:46px;height:28px;flex:0 0 auto}
.lk-groups .tk-d{width:12px;height:12px;flex:0 0 auto}
.lk-groups .tk-l:not(:has(input:checked)) .tk-d{opacity:.45}
.lk-group:not(:has(.tk-l:not([hidden]))){display:none}
.lk-groups .lk-group:first-child .lk-h{margin-top:6px}
html[data-theme] .lk-groups label.tk-l{letter-spacing:normal;font-weight:400;color:var(--ink);text-transform:none}

/* The way back from map only. */
#sheet-pill{position:fixed;left:50%;transform:translateX(-50%);z-index:36;
  bottom:calc(var(--nav) + var(--safe-b) + 14px);
  display:flex;align-items:center;gap:7px;height:42px;padding:0 16px;border-radius:999px;
  border:1px solid var(--line);background:var(--panel);color:var(--ink);font:inherit;font-size:.86rem;font-weight:600;
  box-shadow:0 4px 16px color-mix(in srgb,var(--shadow) 40%,transparent);cursor:pointer}
#sheet-pill svg{width:16px;height:16px;fill:currentColor}
#sheet-pill .sp-up{opacity:.7}
#sheet-pill[hidden]{display:none}
@media (max-width:899px){
  /* Sinks a little and fades rather than sliding its full height: the nav
     bar is in the page flow under a fixed sheet, so a full slide passed over
     the top of it. */
  html[data-chrome="min"] #sheet.is-peek{transform:translateY(28px);opacity:0;visibility:hidden;pointer-events:none;
    transition:transform .22s ease, opacity .18s ease, visibility 0s linear .22s}
}
@media (min-width:900px){ #sheet-pill{display:none !important} }

/* The route chip (10-04): a route left on the map once Directions is put away. */
#route-chip{position:fixed;left:50%;transform:translateX(-50%);z-index:37;
  /* Clear of the scale bar and the ⓘ, which sit on the sheet's top edge. */
  bottom:calc(var(--nav) + var(--safe-b) + var(--sheet-h) + 40px);
  display:flex;align-items:stretch;height:42px;max-width:min(420px,calc(100vw - 96px));
  border:1px solid var(--line);border-radius:999px;background:var(--panel);color:var(--ink);
  box-shadow:0 4px 16px color-mix(in srgb,var(--shadow) 40%,transparent);transition:bottom .22s ease}
#route-chip[hidden]{display:none}
html[data-view]:not([data-view="map"]) #route-chip{display:none}
/* Map only: the sheet is tucked away and its pill sits where the sheet was. */
@media (max-width:899px){
  html[data-chrome="min"] #route-chip{bottom:calc(var(--nav) + var(--safe-b) + 66px)}
}
#route-chip button{display:flex;align-items:center;gap:7px;border:0;background:none;color:inherit;font:inherit;
  font-size:.86rem;font-weight:600;cursor:pointer;min-width:0}
#route-chip-open{padding:0 6px 0 14px;flex:1 1 auto}
#route-chip-open svg{flex:0 0 auto;width:16px;height:16px;fill:var(--datum)}
#route-chip-t{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
#route-chip-m{flex:0 0 auto;white-space:nowrap;margin-left:-3px}
#route-chip-m:empty{display:none}
#route-chip-x{flex:0 0 auto;padding:0 14px 0 10px;border-left:1px solid var(--line) !important;
  border-radius:0 999px 999px 0;color:var(--ink-2)}
#route-chip-x svg{width:16px;height:16px;fill:currentColor}
#route-chip-x:active,#route-chip-open:active{background:var(--panel-2)}
#route-chip .rc-undo{display:none}
#route-chip.is-undo .rc-undo{display:inline;color:var(--datum)}
#route-chip.is-undo .rc-x,#route-chip.is-undo #route-chip-open svg{display:none}
#route-chip.is-undo #route-chip-open{color:var(--ink-2);font-weight:500}

.sheet-chips{
  flex:0 0 auto; display:flex; gap:6px; padding:4px 12px 10px; overflow-x:auto; scrollbar-width:none;
}
.sheet-chips::-webkit-scrollbar{display:none}
.chip{
  flex:0 0 auto; padding:7px 13px; border-radius:999px; border:1px solid var(--line);
  background:var(--panel-2); color:var(--ink-2); font-size:.84rem; cursor:pointer; white-space:nowrap;
}
.chip.is-on{background:var(--datum);border-color:var(--datum);color:var(--on-accent);font-weight:600}
.chip-ai{border-color:color-mix(in srgb,var(--magenta) 50%,transparent);color:var(--magenta)}
.chip-ai.is-on{background:var(--magenta);border-color:var(--magenta);color:var(--on-magenta)}
.chip.is-showing{box-shadow:0 0 0 2px color-mix(in srgb,var(--datum) 45%,transparent)}
.chip-reset{margin-left:auto;border-style:dashed;color:var(--ink-3)}
.chip-reset.is-on{background:var(--panel-2);color:var(--ink-3);font-weight:400}
#sheet.off-map .chip:not(.chip-ai){display:none}
/* Off the map there is nothing for the collapsed sheet to launch. On a phone
   it was a bare 27 px handle whose tap opened the last map panel over the
   view (the SOS card's emergency numbers included). On a desktop it was a
   400x24 strip pinned top right, holding only the Assistant chip, or nothing
   at all with the assistant off, and it sat on Family's "New group" and took
   its clicks. The assistant button still floats over every view. */
#sheet.off-map.is-peek{display:none}
.chip-ai{display:inline-flex;align-items:center;gap:6px}
.chip-ai svg{width:15px;height:15px;fill:currentColor;flex:0 0 auto}

/* On a phone the chip scroller is replaced by the launcher strip. It stays in
   the markup because the desktop drawer still uses it — there it is a wrapped
   grid with room to read every label at once, which was never true in a
   two-line strip on a phone. */
@media (max-width:899px){
  .sheet-chips{display:none}
  /* The handle is redundant once a panel has a header with real buttons, and
     two grab affordances stacked on top of each other read as clutter. */
  #sheet:not(.is-peek) .sheet-handle{padding:5px 0 0}
  #sheet:not(.is-peek) .sheet-handle span{opacity:.35}
  /* The launcher belongs to the map. Looking at a tapped place or the
     assistant, it is just a second row of chrome above the thing you opened —
     and while the grid it opens is on screen, it is the button for the thing
     you are already looking at. */
  /* 10-03: with a panel up the header has ← and the layer's switch, so the
     strip under it was the same controls twice. It shows with the sheet
     down, where it is the whole sheet. */
  #sheet:not(.is-peek) .sheet-bar,
  #sheet.off-map .sheet-bar,
  html[data-panel="tools"] .sheet-bar{display:none}

  /* The sheet's header already names the panel, so the panel's own title is
     the same word twice, eleven pixels apart. The count beside it is not
     duplicated and stays. */
  #sheet .near-head > div > strong,
  #sheet .transit-head > strong{display:none}
  #sheet .near-head,#sheet .transit-head{margin-top:0}
}
@media (min-width:900px){
  .sheet-bar{display:none}
}

/* ---------------- public-transport journeys ---------------- */
#transit-opts{margin:8px 0;display:grid;gap:8px}
#transit-opts input[type=datetime-local]{background:var(--ground);color:var(--ink);
  border:1px solid var(--line);border-radius:8px;padding:5px 8px;font-size:.82rem}
#journey-list{margin-top:10px;display:grid;gap:8px}
#journey-list:empty{display:none}
.journey-row{display:grid;gap:6px;text-align:left;width:100%;cursor:pointer;color:var(--ink);
  background:var(--panel-2);border:1px solid var(--line);border-radius:10px;padding:9px 11px}
.journey-row.is-on{border-color:var(--datum);background:color-mix(in srgb,var(--datum) 10%,transparent)}
.journey-head{display:flex;justify-content:space-between;align-items:baseline;gap:10px}
.journey-legs{display:flex;flex-wrap:wrap;gap:5px;align-items:center}
.journey-foot{opacity:.85}
.journey-off{opacity:.9;line-height:1.3}
.leg-badge{font-size:.76rem;font-weight:600;padding:2px 7px;border-radius:6px;
  background:var(--datum);color:var(--on-accent);white-space:nowrap}
.leg-badge.is-walk{background:none;border:1px dashed var(--line);color:var(--ink-3);font-weight:400}
#route-steps .route-step.is-off{color:var(--magenta)}

/* ---------------- flight radar ---------------- */
#flights-panel{position:absolute;left:12px;right:12px;bottom:18px;z-index:7;
  background:color-mix(in srgb,var(--panel) 96%,transparent);backdrop-filter:blur(10px);border:1px solid var(--line);
  border-left:3px solid #6FB8D6;border-radius:12px;padding:11px 14px;max-height:52vh;overflow-y:auto}
#fr-search{flex:1 1 160px;min-width:0;background:var(--ground);color:var(--ink);
  border:1px solid var(--line);border-radius:8px;padding:6px 9px;font-size:.84rem}
#fr-card{margin-top:10px;background:var(--panel-2);border:1px solid var(--line);
  border-left:3px solid var(--magenta);border-radius:10px;padding:10px 12px;position:relative}
.fr-head{display:flex;justify-content:space-between;align-items:baseline;gap:10px}
.fr-head strong{font-size:1.02rem;letter-spacing:.02em}
/* The leg, drawn rather than written. Two airport codes with the places
   under them and an arrow between reads at a glance in a way that
   "Dalaman to London Gatwick" does not, and it is the first thing anyone
   looks for when they tap an aeroplane. */
.fr-route{display:flex;align-items:center;gap:10px;margin:9px 0 4px;
  padding:8px 10px;border:1px solid var(--line);border-radius:9px;background:var(--panel-2)}
.fr-end{display:flex;flex-direction:column;min-width:0;flex:1}
.fr-end.to{text-align:right;align-items:flex-end}
.fr-end strong{font-size:1.05rem;letter-spacing:.04em}
.fr-end .fine{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.fr-arrow{color:var(--ink-3);flex:0 0 auto}
/* When there is no route to draw, say why rather than leaving a gap where the
   leg should be. */
.fr-noroute{margin:9px 0 4px;padding:8px 10px;border:1px dashed var(--line);
  border-radius:9px;font-size:.8rem;color:var(--ink-3);line-height:1.45}

/* A photograph of this exact tail, not a stock shot of the type. */
.fr-photo{display:block;margin:8px 0;border-radius:9px;overflow:hidden;
  border:1px solid var(--line);background:#000}
.fr-photo img{display:block;width:100%;aspect-ratio:3/2;object-fit:cover}
.fr-grid{margin:8px 0;display:grid;gap:2px}
.fr-row{display:flex;justify-content:space-between;gap:12px;font-size:.82rem}
.fr-row .k{color:var(--ink-3)}
.fr-row .v{font-family:ui-monospace,monospace;text-align:right}
.fr-alert{margin-top:7px;padding:5px 8px;border-radius:7px;font-size:.82rem;
  background:color-mix(in srgb,var(--magenta) 14%,transparent);border:1px solid color-mix(in srgb,var(--magenta) 45%,transparent);color:var(--magenta)}
#fr-list{margin-top:10px;display:grid;gap:1px;background:var(--line);
  border:1px solid var(--line);border-radius:9px;overflow:hidden}
#fr-list:empty{display:none}
.fr-listrow{display:flex;justify-content:space-between;gap:10px;align-items:baseline;
  background:var(--panel);border:0;padding:8px 12px;text-align:left;cursor:pointer;
  color:var(--ink);width:100%;font-size:.85rem}
.fr-listrow.is-on{background:color-mix(in srgb,var(--datum) 14%,transparent)}
/* The leg sits with the flight number rather than among the numbers to its
   right: "where is it going" is the question, and it should be readable
   without moving your eye across the row. */
.fr-leg{color:var(--datum);font-variant-numeric:tabular-nums;letter-spacing:.02em;
  white-space:nowrap;font-size:.95em}
@media (min-width:900px){ #flights-panel{right:auto;width:380px} }
.sheet-body{flex:1 1 auto; min-height:0; overflow-y:auto; overscroll-behavior:contain; padding:0 14px 14px}

/* Panels lose their floating geometry inside the sheet.
 *
 * Every panel here is also a free-standing overlay on the map in its own
 * right, so each carries `position:absolute; bottom:18px; z-index:7` from
 * that life. Inside the sheet that is not cosmetic. An absolutely positioned
 * child of `#sheet-body` is out of the flow and anchored to the sheet's
 * bottom edge, so it grows *upward* as results arrive and paints straight
 * over `#sheet-head` — and `#sheet-head` is where the close cross and the
 * height chevron live. Open Near me or Flights on a phone, wait for the list,
 * and every tap meant for those two buttons landed on the panel instead:
 * there was no way left to shut the tool.
 *
 * Written as `#sheet-body > [id]` rather than as a list of panel ids, for two
 * reasons. Two ids outrank the single one in `#near-panel`, so a panel
 * declared further down this file — which is exactly how Near me and Flights
 * escaped the old list — cannot quietly win again whatever the source order.
 * And a panel added tomorrow is covered without anyone having to remember
 * that this rule exists.
 *
 * `overflow:visible` is part of it: each panel brought its own `overflow-y`
 * and its own `max-height` in viewport units, which inside a sheet that is
 * already a scroller made a second scroller within the first. One surface,
 * one scrollbar — `#sheet-body` owns it.
 */
#sheet-body > [id]{
  position:static; left:auto; right:auto; bottom:auto; top:auto;
  width:auto; max-width:none; height:auto; max-height:none; z-index:auto;
  background:transparent; border:0; border-radius:0; box-shadow:none;
  backdrop-filter:none; overflow:visible; padding:6px 0 0;
}
/* The place card carries its own close cross, positioned against itself. */
#sheet-body > #place-card{position:relative;padding-right:0}

/* the two one-tap actions stay on the map, out of the sheet's way */
#mapquick{position:absolute;right:14px;top:64px;z-index:5;display:flex;flex-direction:column;gap:10px}
#mapctl{display:none}

/* ---------- clean map ----------
 *
 * A phone screen is mostly chrome: search across the top, the basemap pill,
 * the readout, three FABs down one side, and MapLibre's scale, zoom, compass
 * and pitch stack down the other. All of it useful, none of it the map. This
 * takes the lot away for as long as somebody wants to just look.
 *
 * Two rules keep it from becoming a trap:
 *
 * The button that does it never goes anywhere. It is the one thing exempt
 * from its own effect, so the way back is always exactly where the way out
 * was, and it swaps its arrows around to say which it will do next.
 *
 * The attribution stays. MapLibre folds it to an ⓘ, which the OSMF guidelines
 * allow, but hiding it outright is a licence breach and not ours to make — so
 * it is deliberately absent from the list below.
 *
 * Confined to the phone layout, and not merely because that is where the
 * clutter is: the button itself only exists under this breakpoint, so hiding
 * chrome at desktop widths would leave nothing to bring it back with. Letting
 * the rules lapse above 900px means a phone left in this state and reopened
 * on a laptop comes back to a full set of controls rather than a bare map.
 */
@media (max-width:899px){
  html[data-chrome="min"] #hud,
  html[data-chrome="min"] #btn-src,
  html[data-chrome="min"] #searchwrap,
  html[data-chrome="min"] #legend,
  html[data-chrome="min"] #ai-fab,
  html[data-chrome="min"] #mapquick > .fab:not(#btn-clean),
  html[data-chrome="min"] .maplibregl-ctrl-bottom-left{
    opacity:0;
    pointer-events:none;
  }
  #hud,#btn-src,#searchwrap,#legend,#mapquick > .fab,
  .maplibregl-ctrl-bottom-left{ transition:opacity .18s ease; }
}
/* A desktop window has room for all of it, and the rules above lapse there —
   so the button would promise something it could no longer deliver. */
@media (min-width:900px){ #btn-clean{display:none} }
/* Whichever arrow describes what the next tap does, never both. */
#btn-clean .ico-show{display:none}
html[data-chrome="min"] #btn-clean .ico-hide{display:none}
html[data-chrome="min"] #btn-clean .ico-show{display:block}
/* Quieter than the tools it hid — it is a way back, not a fourth control
   competing with them — but never so faint that it cannot be found again. */
html[data-chrome="min"] #btn-clean{background:color-mix(in srgb,var(--ground) 72%,transparent);backdrop-filter:blur(8px)}
@media (prefers-reduced-motion:reduce){
  #hud,#btn-src,#searchwrap,#legend,#mapquick > .fab,
  .maplibregl-ctrl-bottom-left{ transition:none; }
}

/* compact readout: tap to expand */
#hud{pointer-events:auto;cursor:pointer;text-align:left;font-family:ui-monospace,monospace;color:var(--ink);border:1px solid var(--line)}
#hud .hud-row{display:none}
#hud .hud-row.hud-key{display:flex}
#hud.open .hud-row{display:flex}
/* The left column (app.js): the readout and the key step down under the top
   stack and slide back when a banner goes. Pushed into the sheet, the readout
   waits out of sight; visibility, not display, so it can still be measured. */
#hud,#legend{transition:top .2s ease,opacity .18s ease}
#hud.is-crowded{visibility:hidden;opacity:0;pointer-events:none}
@media (prefers-reduced-motion:reduce){ #hud,#legend{transition:none} }

/* toast sits above the sheet — whatever height the sheet currently is. The
   84px here was the peek height at the time it was written, so the toast sat
   under anything taller and floated in mid-air over anything shorter. */
#toast{bottom:calc(var(--nav) + var(--safe-b) + var(--sheet-h) + 14px);z-index:60;
  transition:bottom .22s ease}

/* ---- settings tabs ---- */
.set-who-row{display:flex;align-items:center;justify-content:space-between;gap:8px 12px;flex-wrap:wrap;margin:0 0 20px}
.set-who-row #set-who{margin:0;min-width:0;overflow-wrap:anywhere}
.set-who-row .btn{flex:0 0 auto}
.set-tabs{display:flex;gap:4px;background:var(--panel);border:1px solid var(--line);border-radius:10px;
  padding:4px;margin:6px 0 18px;overflow-x:auto;scrollbar-width:none}
.set-tabs::-webkit-scrollbar{display:none}
.set-tabs:empty{display:none}
.set-tab{flex:1 0 auto;padding:9px 12px;border:0;border-radius:7px;background:none;color:var(--ink-3);cursor:pointer;font-size:.86rem;white-space:nowrap}
.set-tab.is-on{background:var(--panel-2);color:var(--ink);font-weight:600}
.set-pane{display:none}
.set-pane.is-on{display:block}
.set-pane>h3:first-child{margin-top:4px}

/* ---- desktop: drawer, not sheet ---- */
@media (min-width:900px){
  #sheet{
    left:auto; right:16px; top:16px; bottom:16px; width:400px; border-radius:14px;
    border:1px solid var(--line); box-shadow:0 10px 34px color-mix(in srgb,var(--shadow) 50%,transparent); transition:none;
    /* The drawer is pinned top and bottom, so its height is already bounded.
       The phone's ceiling — which exists to keep a bottom-anchored sheet from
       hanging off the top of an iOS viewport — would only shorten it here. */
    max-height:none;
  }
  #sheet.is-peek{bottom:auto; height:auto}
  #sheet.is-card,#sheet.is-half,#sheet.is-full{height:auto}
  #sheet.is-card .sheet-chips{display:flex}
  .sheet-handle{display:none}
  /* Nothing drags here: the drawer's height is the window's. The grab cursor
     the phone layout puts on this strip would be a promise it cannot keep. */
  .sheet-head{padding-left:12px; cursor:default; touch-action:auto; user-select:auto; -webkit-user-select:auto}
  .sheet-chips{flex-wrap:wrap;padding:12px 12px 10px}
  /* Centred in the map that is left of the drawer (400px + 16px) and the
     button column beside it (436px + its 50px), not in the whole map: the
     map starts after the side menu, and the old 50%-of-the-map placement
     ran the box's right end under the drawer. */
  #searchwrap{width:min(420px,calc(100% - 510px));transform:none;
    left:calc((100% - 486px - min(420px,calc(100% - 510px))) / 2)}
  #btn-src{right:436px}
  #mapquick{right:436px}
  #toast{bottom:28px}
  /* With a panel open the drawer runs to the bottom of the window, over the
     map's bottom-right corner — and the credit there has to stay visible.
     Left of the assistant button too, which docks at right:432px. */
  html[data-sheet]:not([data-sheet="peek"]) .maplibregl-ctrl-bottom-right{right:494px}
}

/* ==================================================================
   DESKTOP DESIGN. Below 900px everything above stands (phone). From 900px
   the app becomes a workspace: a real sidebar, full-width views, and a
   desktop pattern per view instead of one centred column.
   ================================================================== */
.nav-brand,.nav-foot{display:none}
#adv-empty{display:none}

@media (min-width:900px){
  /* ---- sidebar ---- */
  #nav{width:88px;padding:14px 0 0;justify-content:flex-start}
  .navbtn{height:64px}
  .nav-foot{display:block;margin-top:auto;padding:14px 10px;border-top:1px solid var(--line);
    font-size:.7rem;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center}

  /* ---- content views: full workspace, not a phone column ---- */
  .pad,.wide-pad{max-width:none;margin:0;padding:32px 40px 48px}
  .pad p.lede{max-width:70ch}
  .card{max-width:70ch}

  /* ---- Settings: vertical tabs on the left, a label | field form on the right ---- */
  #view-settings .pad{display:grid;grid-template-columns:220px minmax(0,1fr);column-gap:44px;align-items:start}
  #view-settings h1,.set-who-row{grid-column:1/-1}
  #set-tabs{grid-column:1;grid-row:3 / span 4;position:sticky;top:24px;
    flex-direction:column;gap:2px;padding:6px;background:transparent;border:0;overflow:visible}
  .set-tab{flex:0 0 auto;text-align:left;padding:10px 14px;border-radius:8px;font-size:.92rem}
  .set-tab.is-on{background:var(--panel-2)}
  #admin-moved,#view-settings .pad>.set-pane{grid-column:2}
  /* A form of label | field pairs. Everything spans both columns by default
     and only a label and its own field opt into the two-column pair — the
     inverse of listing each block that must span, which silently squeezed
     every newly added card into the 200px label column. */
  .set-pane.is-on{display:grid;grid-template-columns:200px minmax(0,560px);gap:14px 22px;
    align-items:center;max-width:880px}
  .set-pane.is-on>*{grid-column:1/-1;margin:0;min-width:0}
  .set-pane.is-on>label:not(.switch){grid-column:1;text-align:right;color:var(--ink-2);
    text-transform:none;letter-spacing:0;font-size:.9rem;align-self:center}
  .set-pane.is-on>label:not(.switch) .fine{display:block;font-size:.72rem;margin-top:2px}
  .set-pane.is-on>input,.set-pane.is-on>select{grid-column:2}
  .set-pane.is-on>.row-btns:has(>select),.set-pane.is-on>.row-btns:has(>input){grid-column:2}
  .set-pane.is-on>.row-btns>select{width:auto;flex:1}
  .set-pane>h3{font-size:1.25rem;margin-top:14px}
  .set-pane>h3:first-child{margin-top:0}
  .set-pane>p.fine{margin-bottom:2px;max-width:70ch}
  /* the grid zeroes margins, so subsection headings buy their air back */
  .set-pane.is-on>h4.sub{margin:20px 0 0;padding-top:16px;border-top:1px solid var(--line)}
  .set-pane.is-on>h4.sub:first-of-type{border-top:0;padding-top:0}
  .set-pane.is-on>details.advanced{margin:6px 0 4px}
  .set-pane.is-on>.switch{padding:4px 0}
  .set-pane.is-on>.row-btns{margin-top:4px}
  #pw-form{display:grid;grid-template-columns:200px minmax(0,560px);gap:12px 22px;align-items:center}
  #pw-form>label{grid-column:1;margin:0;text-align:right;text-transform:none;letter-spacing:0;font-size:.9rem;color:var(--ink-2)}
  #pw-form>input{grid-column:2;margin:0}
  #pw-form>p,#pw-form>.row-btns{grid-column:1/-1}

  /* ---- Brief: master (list) | detail ---- */
  #view-brief .pad{display:grid;grid-template-columns:400px minmax(0,1fr);column-gap:40px;height:100%;box-sizing:border-box;
    grid-template-areas:"title detail" "lede detail" "search detail" "pinned detail" "meta detail" "list detail";
    grid-template-rows:auto auto auto auto auto minmax(0,1fr);padding-bottom:0}
  #view-brief h1{grid-area:title}
  #view-brief .lede{grid-area:lede}
  #adv-search,.sx:has(>#adv-search){grid-area:search}
  #pinned{grid-area:pinned}
  #adv-meta{grid-area:meta}
  #adv-list{grid-area:list;overflow-y:auto;padding-right:6px;padding-bottom:32px}
  #adv-detail,#adv-empty{grid-area:detail;overflow-y:auto;padding:0 0 32px;align-self:stretch}
  #adv-detail[hidden]{display:none}
  #adv-detail:not([hidden]) ~ #adv-empty{display:none}
  #adv-empty{display:grid;place-items:center;text-align:center;color:var(--ink-3);border:1px dashed var(--line);border-radius:14px;min-height:320px}
  #adv-empty p{max-width:34ch;margin:0}
  .empty-mark{font-size:2.4rem;color:var(--datum);margin-bottom:8px}
  #adv-detail .back{display:none}
  #adv-detail h2{font-size:1.6rem}
  #adv-detail .facts{grid-template-columns:repeat(4,minmax(0,1fr))}

  /* ---- SOS: the numbers on the left, held in view; help near you and
     the country guides on the right ---- */
  #view-sos .pad{display:grid;grid-template-columns:400px minmax(0,1fr);column-gap:40px;
    grid-template-areas:"head head" "lede lede" "top body" "top know";grid-template-rows:auto auto auto 1fr;align-items:start}
  .sos-head{grid-area:head}
  #sos-sub{grid-area:lede}
  #sos-top{grid-area:top;position:sticky;top:24px}
  #sos-top .sos-grid{grid-template-columns:1fr 1fr}
  #sos-body{grid-area:body;max-width:760px}
  #sos-know{grid-area:know;max-width:760px}
  #sos-body>.ui-head:first-child{margin-top:0}

  /* ---- Vault: wider, table-like ---- */
  #view-vault .pad{max-width:980px}
  .vrow{padding:14px 12px;border-radius:8px}
  .vrow:hover{background:var(--panel)}
  .filedrop{max-width:520px}
}

@media (min-width:1200px){
  /* ---- full sidebar with labels ---- */
  #nav{width:232px;padding:0}
  .nav-brand{display:flex;align-items:center;gap:10px;padding:20px 18px 16px;font-weight:700;font-size:1.05rem;letter-spacing:-.01em;border-bottom:1px solid var(--line);margin-bottom:8px}
  .nav-brand .brand-mark{width:26px;height:26px}
  .navbtn{flex-direction:row;justify-content:flex-start;gap:12px;height:44px;padding:0 18px;margin:0 8px;border-radius:9px;font-size:.92rem;letter-spacing:0}
  .navbtn svg{width:20px;height:20px}
  .navbtn.is-active{background:var(--panel-2)}
  .navbtn-sos.is-active,.navbtn.is-active{color:var(--ink)}
  .navbtn.is-active svg{fill:var(--magenta)}
  .nav-foot{text-align:left;padding:14px 18px}
  #view-brief .pad{grid-template-columns:440px minmax(0,1fr)}
  #view-sos .pad{grid-template-columns:440px minmax(0,1fr)}
  .set-pane.is-on{grid-template-columns:220px minmax(0,600px)}
}
.adv.is-sel{background:var(--panel);box-shadow:inset 3px 0 0 var(--datum)}

/* ---- cloud key box ---- */
.cloud-box{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--magenta);
  border-radius:12px;padding:16px;margin:14px 0 18px;display:grid;gap:10px}
/* This is the pane's primary action, not a field label in a list of twelve. */
.cloud-box>label{margin:0;font-size:1rem;font-weight:600;color:var(--ink);
  text-transform:none;letter-spacing:0}
/* The key gets a line of its own. Sharing one no-wrap row with a provider
   list — which sizes itself to its longest option — left the key field a
   box a few characters wide. */
.cloud-box input#cloud-key{width:100%;font-family:ui-monospace,monospace;font-size:.86rem;padding:11px 12px}
.cloud-box .cloud-row{display:flex;gap:9px;align-items:center;flex-wrap:wrap}
.cloud-box .cloud-row>select{flex:0 1 300px;min-width:0;max-width:320px}
.cloud-box .cloud-row>.btn{flex:0 0 auto}
.cloud-box .cloud-row>.fine{flex:1 1 100%}
.cloud-box p.fine{margin:0}
#cloud-result:not(:empty){margin-top:8px;color:var(--ink)}
details.advanced{margin:8px 0 16px}
details.advanced>summary{cursor:pointer;color:var(--ink-3);font-size:.9rem;padding:6px 0}
@media (min-width:900px){
  .cloud-box{padding:18px 20px}
}

/* ---- model profiles ---- */
h4.sub{font-size:.72rem;text-transform:uppercase;letter-spacing:.12em;color:var(--ink-3);margin:22px 0 8px}
#profiles{display:grid;gap:8px;margin-bottom:6px}
.prof{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:10px 14px;align-items:center;
  background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--ok);border-radius:10px;padding:10px 14px}
.prof.off{border-left-color:var(--ink-3);opacity:.7}
.prof-main{min-width:0}
.prof-name{background:none;border:0;border-bottom:1px dashed transparent;color:var(--ink);font-weight:600;font-size:.98rem;padding:2px 0;width:100%}
.prof-name:hover,.prof-name:focus{border-bottom-color:var(--line);outline:0}
.prof-main .fine{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.prof-roles{display:flex;gap:5px}
.prof-acts{display:flex;gap:6px;align-items:center}
select.route{width:100%;padding:10px 12px;border-radius:8px;border:1px solid var(--line);background:var(--panel);color:var(--ink);font-size:14px}
@media (min-width:900px){
  .set-pane>#profiles,.set-pane>h4.sub{grid-column:1/-1}
  .set-pane>select.route{grid-column:2;margin:0}
  .set-pane>#route-hint{grid-column:2}
}
@media (max-width:640px){ .prof{grid-template-columns:1fr} .prof-acts{justify-content:flex-start} }

/* ---- scan (camera) ---- */
#scan-stage{position:relative;border-radius:12px;overflow:hidden;background:#000;margin-bottom:10px}
#scan-stage:empty,#scan-stage:has(video[hidden]):has(img[hidden]){background:transparent}
#scan-video,#scan-shot{width:100%;display:block;max-height:44vh;max-height:44dvh;
  object-fit:contain;background:#000}
#scan-langrow{align-items:center;margin-bottom:8px}
#scan-target{background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:7px;padding:7px 10px;font-size:13px}
#scan-result{margin-top:10px}
.scan-h{font-size:.68rem;text-transform:uppercase;letter-spacing:.11em;color:var(--ink-3);margin:12px 0 4px}
.scan-b{white-space:pre-wrap;font-size:.95rem;line-height:1.55}
.scan-tr{color:var(--ink);background:var(--panel-2);border-radius:9px;padding:11px 13px}
.scan-orig{color:var(--ink-2);font-size:.9rem}
.scan-notes{color:var(--warn)}
.ai-media{width:100%;border-radius:10px;display:block;background:#000}
.prof-model{display:flex;gap:6px;align-items:center;margin:4px 0;flex-wrap:wrap}
.prof-model-sel{flex:1;min-width:120px;max-width:100%;background:var(--panel-2);color:var(--ink);border:1px solid var(--line);border-radius:7px;padding:5px 8px;font-size:.82rem;font-family:ui-monospace,monospace}
.prof-filter{width:90px;background:var(--ground);color:var(--ink);border:1px solid var(--line);border-radius:7px;padding:5px 8px;font-size:.8rem}
.prof-kind{background:var(--panel-2);color:var(--ink-2);border:1px solid var(--line);border-radius:7px;padding:5px 8px;font-size:.78rem}

/* ---- saved finds ---- */
#finds-list{display:grid;gap:10px;grid-template-columns:repeat(auto-fill,minmax(240px,1fr))}
.find{display:flex;gap:12px;align-items:center;background:var(--panel);border:1px solid var(--line);
  border-radius:12px;padding:10px;cursor:pointer;text-align:left;color:var(--ink);width:100%}
.find:hover{border-color:var(--datum)}
.find img{width:58px;height:58px;object-fit:cover;border-radius:8px;flex:0 0 auto;background:var(--panel-2)}
.find-t{font-weight:600;font-size:.95rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.find-s{font-size:.8rem;color:var(--ink-3);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
#find-detail{margin-top:6px}
.fd-head{display:flex;gap:14px;align-items:flex-start;margin-bottom:12px}
.fd-head img{width:120px;height:120px;object-fit:cover;border-radius:12px}
.fd-title{font-size:1.35rem;font-weight:700;line-height:1.2}
.fd-sum{color:var(--ink-2);margin-top:4px}
/* section chooser: the reader opens only what they want */
.fd-chips{display:flex;flex-wrap:wrap;gap:6px;margin:12px 0}
.fd-chip{padding:6px 12px;border-radius:999px;border:1px solid var(--line);background:var(--panel-2);
  color:var(--ink-2);font-size:.82rem;cursor:pointer}
.fd-chip.is-on{background:var(--datum);border-color:var(--datum);color:var(--on-accent);font-weight:600}
.fd-chip.key{border-color:var(--magenta);color:var(--magenta)}
.fd-chip.key.is-on{background:var(--magenta);border-color:var(--magenta);color:var(--on-magenta)}
.fd-body{white-space:pre-wrap;font-size:.94rem;line-height:1.6;background:var(--panel);
  border:1px solid var(--line);border-radius:12px;padding:14px 16px}
.fd-body:empty{display:none}
.ai-photo-thumb{max-width:150px;border-radius:10px;display:block;margin-bottom:6px}
/* an analysis card in the chat log is a panel, not a speech bubble */
.ai-find{max-width:100%;align-self:stretch;background:var(--panel-2);border:1px solid var(--line);
  border-radius:14px;padding:14px}
.ai-find .fd-head img{width:92px;height:92px}
#ai-photo{flex:0 0 auto;font-size:15px;line-height:1}
@media (min-width:900px){ #view-finds .pad{display:block} #finds-list{grid-template-columns:repeat(auto-fill,minmax(280px,1fr))} }

/* ---- rich place detail: photos, facts, story, the view from the street ---- */
.pd-strip{display:flex;gap:6px;overflow-x:auto;padding-bottom:4px;margin:8px 0 2px;scrollbar-width:thin}
.pd-strip-n{margin:0 0 4px;font-size:.76rem}
.pd-strip img{height:96px;width:128px;object-fit:cover;border-radius:8px;cursor:zoom-in;
  background:var(--panel-2);flex:0 0 auto;border:1px solid var(--line)}
.pd-body{margin-top:8px}
/* "Not here any more?" — one quiet line at the foot of the place card. */
/* "May have closed" on a place card (stillopen.py) */
.pd-still{display:flex;flex-wrap:wrap;align-items:center;gap:4px 8px;margin:10px 0;padding:8px 10px;border-left:3px solid var(--warn);border-radius:8px;background:color-mix(in srgb,var(--warn) 10%,transparent);font-size:.85rem}
.pd-still strong{color:var(--warn)}
.pd-still .btn{margin-left:auto}
.pd-gone{margin-top:14px;font-size:.8rem;color:var(--ink-3)}
.pd-gone .linkish{background:none;border:0;color:var(--datum);cursor:pointer;font:inherit;font-size:.8rem;padding:2px 0}
.pd-gone .linkish:disabled{opacity:.6;cursor:default}
#pd-gone-dialog textarea{width:100%;padding:10px 12px;border-radius:8px;border:1px solid var(--line);
  background:var(--ground);color:var(--ink);font-size:15px;font-family:inherit;box-sizing:border-box;resize:vertical;margin-top:8px}
.pd-body:empty{display:none}
.pd-facts{display:grid;gap:5px}
.pd-fact{display:grid;grid-template-columns:minmax(96px,34%) 1fr;gap:10px;font-size:.86rem;align-items:baseline}
.pd-k{color:var(--ink-3)}
.pd-v{color:var(--ink);overflow-wrap:anywhere}
a.pd-v{color:var(--datum)}
.pd-story p{font-size:.9rem;line-height:1.6;margin:0 0 6px}
.pd-street .pd-stage{height:190px;border-radius:10px;background:var(--panel-2) center/cover no-repeat;
  border:1px solid var(--line);margin-bottom:6px}
.pd-street .pd-stage.is-pano{cursor:grab;background-size:auto 100%;touch-action:none}
.pd-street .pd-stage.is-pano:active{cursor:grabbing}
.pd-nav{display:flex;gap:6px;margin-top:6px;align-items:center}
/* `cursor:zoom-out` says "tap anywhere to close" to a mouse and says nothing
   at all to a thumb, which is why the lightbox read as a photograph the app
   had got stuck on. The backdrop still dismisses; the cross is what says so.
   Padded clear of the status bar and the notch. */
.pd-light{position:fixed;inset:0;z-index:80;background:rgba(4,8,11,.92);display:flex;
  flex-direction:column;align-items:center;justify-content:center;gap:10px;
  padding:max(20px,calc(env(safe-area-inset-top,0px) + 56px)) 20px
          max(20px,calc(env(safe-area-inset-bottom,0px) + 20px));cursor:zoom-out}
.pd-light-x{position:absolute;top:max(12px,env(safe-area-inset-top,0px));right:12px;
  width:44px;height:44px;display:grid;place-items:center;border-radius:50%;
  border:1px solid var(--line);background:color-mix(in srgb,var(--panel) 92%,transparent);color:var(--ink);
  font-size:22px;line-height:1;cursor:pointer;font-family:inherit;padding:0}
.pd-light-x:active{background:var(--panel-2)}
.pd-light img{max-width:min(96vw,1200px);max-height:78vh;max-height:72dvh;
  object-fit:contain;border-radius:8px}
.pd-light-cap{max-width:min(96vw,1200px);color:var(--ink-2);font-size:.85rem;text-align:center}
@media (min-width:900px){.pd-street .pd-stage{height:240px}}

.field-note{font-size:.72rem;color:var(--datum);margin-left:2px;font-family:ui-monospace,monospace}
.field-note.bad{color:var(--magenta)}

/* ==================================================================
   v51: richer reference, place media, research, pagination, overlays
   ================================================================== */
/* ---- pager ---- */
.pager{display:flex;align-items:center;gap:4px;flex-wrap:wrap;margin:10px 0 2px}
.pager[hidden]{display:none}
.pager-btn{min-width:30px;height:30px;padding:0 8px;border-radius:7px;border:1px solid var(--line);
  background:var(--panel-2);color:var(--ink-2);font-size:.82rem;cursor:pointer;font-family:ui-monospace,monospace}
.pager-btn:disabled{opacity:.4;cursor:default}
.pager-btn.is-on{background:var(--datum);border-color:var(--datum);color:var(--on-accent);font-weight:700;opacity:1}
.pager-gap{color:var(--ink-3);padding:0 2px}
.pager-info{margin-left:auto;font-size:.74rem;color:var(--ink-3);font-family:ui-monospace,monospace}
.pager-list:empty{display:none}
#adv-list .pager-list{display:block}
#finds-list .pager-list{display:contents}

/* ---- search suggestions (Brief + SOS) ---- */
.suggest-box{position:absolute;left:0;right:0;top:calc(100% + 6px);z-index:12;background:var(--panel);border:1px solid var(--line);
  border-radius:12px;overflow:hidden;box-shadow:0 8px 26px color-mix(in srgb,var(--shadow) 45%,transparent);max-height:44vh;overflow-y:auto}
.suggest{display:flex;justify-content:space-between;gap:12px;width:100%;text-align:left;background:none;border:0;
  border-bottom:1px solid var(--line);padding:10px 14px;color:var(--ink);cursor:pointer;font-size:.92rem}
.suggest:last-child{border-bottom:0}
.suggest:hover,.suggest:focus-visible{background:var(--panel-2)}
.suggest-l{font-weight:600}
.suggest-r{color:var(--ink-3);font-size:.82rem;white-space:nowrap}
.suggest-none{padding:10px 14px}
#adv-list .suggest{border:1px solid var(--line);border-radius:9px;margin:6px 0;background:var(--panel)}
.adv-matches{display:flex;flex-wrap:wrap;gap:6px;margin:2px 0 10px}
.adv-match{font-size:.76rem;background:color-mix(in srgb,var(--datum) 14%,transparent);color:var(--datum);border-radius:999px;padding:3px 10px}
.adv-flag{margin-right:6px}
.adv-notes{display:inline-block;margin-top:3px;font-size:.75rem;text-transform:uppercase;letter-spacing:.1em;
  color:var(--ok);background:color-mix(in srgb,var(--ok) 12%,transparent);border-radius:3px;padding:1px 6px}
.adv-synthetic .lvl{opacity:.5}

/* ---- SOS card ---- */
.sos-country-line{display:flex;align-items:baseline;gap:8px;margin:2px 0 8px}
.sos-flag{font-size:1.6rem;line-height:1}
.sos-name{font-weight:700;font-size:1.1rem}
.help-list{display:grid;gap:8px;margin-top:8px}
.help-item{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:10px 12px}
.help-t{font-size:.95rem}
.help-item .row-btns{margin-top:8px}
.help-h{font-size:.78rem;letter-spacing:.04em;text-transform:uppercase;color:var(--ink-3);margin:10px 0 2px}
.help-t .tag{margin-left:6px}
.sos-where-en{font-size:1rem;color:var(--ink)}
.sos-where-local{font-size:1.15rem;color:var(--ink);margin-top:2px}
.sos-where .row-btns{margin-top:8px}
.sos-others{margin-top:10px}
.sos-others summary{cursor:pointer;font-size:.9rem;color:var(--ink-2);padding:4px 0}
.home-ask{background:var(--panel-2);border:1px solid var(--line);border-radius:10px;padding:10px 12px;margin-bottom:8px}
.home-ask p{margin:0 0 8px;font-size:.9rem}
.home-ask select{max-width:100%}
.driver-card{position:fixed;inset:0;z-index:9999;background:var(--ground);color:var(--ink);display:flex;flex-direction:column;justify-content:center;align-items:center;gap:14px;padding:24px 20px;text-align:center;overflow:auto}
.dc-phrase{font-size:clamp(2rem,9vw,3.6rem);line-height:1.2;font-weight:700}
.dc-rom{font-size:1.05rem;color:var(--ink-2)}
.dc-place{font-size:clamp(1.6rem,7vw,2.6rem);line-height:1.25;font-weight:600;margin-top:10px}
.dc-addr{font-size:1.2rem;color:var(--ink-2)}
.dc-en{font-size:.9rem;color:var(--ink-3);margin-top:8px}
.dc-close{margin-top:18px;min-width:140px}
/* City guide (placecard.js pdGuide): in the card, a clamped intro and a grid
   of topic tiles; each topic opens as its own full page (.pd-gt). */
.pd-guide-intro{font-size:.9rem;line-height:1.6;margin:0 0 4px;color:var(--ink-2)}
.pd-guide-intro.is-clamped{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-clamp:3;overflow:hidden}
.pd-guide-more{background:none;border:0;padding:2px 0;color:var(--datum);font:inherit;font-size:.84rem;cursor:pointer;margin:0 0 10px}
.pd-guide-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:8px 0 6px}
.pd-guide-tile{display:flex;flex-direction:column;align-items:flex-start;gap:3px;text-align:left;
  padding:10px 12px;min-height:44px;border-radius:12px;border:1px solid var(--line);background:var(--panel-2);
  color:var(--ink);font:inherit;cursor:pointer}
.pd-guide-tile:hover,.pd-guide-tile:focus-visible{border-color:var(--datum)}
.pd-guide-tile:focus-visible{outline:2px solid var(--datum);outline-offset:1px}
.pd-guide-tile-h{font-weight:600;font-size:.9rem}
.pd-guide-tile-h::after{content:" \203A";color:var(--datum)}
.pd-guide-tile-p{font-size:.78rem;line-height:1.4;color:var(--ink-3);display:-webkit-box;-webkit-box-orient:vertical;
  -webkit-line-clamp:2;line-clamp:2;overflow:hidden}
@media (max-width:340px){ .pd-guide-grid{grid-template-columns:1fr} }
.pd-gt-nav{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;margin:0 0 12px;padding-bottom:2px}
.pd-gt-nav::-webkit-scrollbar{display:none}
.pd-gt-nav .fd-chip{flex:0 0 auto;white-space:nowrap}
.pd-gt-acts{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 12px}
.pd-gt-part{border-top:1px solid var(--line);padding:2px 0}
.pd-gt-part:last-of-type{border-bottom:1px solid var(--line);margin-bottom:10px}
.pd-gt-part>summary{cursor:pointer;padding:11px 0;font-weight:600;font-size:.92rem;color:var(--ink);list-style:none;
  display:flex;justify-content:space-between;align-items:center;gap:10px}
.pd-gt-part>summary::-webkit-details-marker{display:none}
.pd-gt-part>summary::after{content:"+";color:var(--datum);font-weight:400;font-size:1.1rem}
.pd-gt-part[open]>summary::after{content:"\2212"}
.pd-gt-part>.pd-guide-part{margin:0 0 10px}
.pd-guide-part{margin:0 0 14px}
.pd-guide-part h4{font-size:.92rem;margin:0 0 4px;color:var(--ink)}
.pd-guide-part p{font-size:.88rem;line-height:1.6;margin:0 0 6px;color:var(--ink-2)}
.pd-guide-credit{margin-top:6px}
.pd-guide-credit a{color:inherit}
.help-item .fine{margin-top:2px}

/* ---- plugs ---- */
.plug-row{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-start}
.plug-item{display:flex;flex-direction:column;align-items:center;gap:3px;background:var(--panel);border:1px solid var(--line);
  border-radius:10px;padding:8px 10px 6px;cursor:pointer;min-width:78px;max-width:180px}
.plug-item:hover{border-color:var(--datum)}
.plug-face{fill:var(--panel-2);stroke:var(--line);stroke-width:2}
.plug-pins{fill:var(--ink)}
.plug-pins .pin-out{fill:var(--datum)}
.plug-letter{fill:var(--ink-3);font:700 13px ui-monospace,monospace}
.plug-cap{font-size:.72rem;color:var(--ink-2);font-family:ui-monospace,monospace}
.plug-more{font-size:.74rem;color:var(--ink-3);text-align:center;margin-top:4px;line-height:1.4}
.plug-volts{flex:1 1 160px;align-self:stretch;background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:10px 12px;font-size:.9rem}
.plug-volts .fine{margin-top:4px;font-size:.76rem}

/* ---- Brief detail ---- */
.brief-sub{margin:-2px 0 8px}
.brief-hero:empty{display:none}
.brief-hero{margin:4px 0 16px}
.brief-hero img{width:100%;max-height:260px;object-fit:cover;border-radius:12px;border:1px solid var(--line);display:block;background:var(--panel-2)}
.brief-hero .fine{margin-top:6px}
.city-strip{display:flex;gap:8px;overflow-x:auto;padding:2px 0 6px;margin:0 0 10px;scrollbar-width:thin}
.city-card{flex:0 0 auto;width:132px;background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:0;overflow:hidden;
  cursor:pointer;color:var(--ink);text-align:left}
.city-card img{width:100%;height:84px;object-fit:cover;display:block;background:var(--panel-2)}
.city-card-n{display:block;padding:6px 8px;font-size:.78rem;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.city-card:hover{border-color:var(--datum)}
.city-notes .pager{padding:8px 12px;background:var(--panel)}
.city-notes .pager-list{display:grid;gap:1px}

/* ---- place card media ---- */
.pd-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(96px,1fr));gap:6px;margin:8px 0 2px}
.pd-grid img{width:100%;aspect-ratio:4/3;object-fit:cover;border-radius:8px;cursor:zoom-in;background:var(--panel-2);border:1px solid var(--line)}
.pd-loading{padding:6px 0}
.pd-links{margin-top:10px}
/* Photographs under an assistant answer. A row that scrolls rather than a
   grid that wraps: on a phone two 140px tiles fit and a third says, by being
   half visible, that there is more. */
.ai-shots{display:flex;gap:6px;margin-top:9px;overflow-x:auto;scrollbar-width:none;
  -webkit-overflow-scrolling:touch;padding-bottom:2px}
.ai-shots::-webkit-scrollbar{display:none}
.ai-shots img{flex:0 0 auto;width:140px;height:100px;object-fit:cover;border-radius:9px;
  border:1px solid var(--line);background:var(--panel-2);cursor:zoom-in;display:block}
.shop-h{font-size:.68rem;text-transform:uppercase;letter-spacing:.11em;color:var(--ink-3);margin:12px 0 6px}
.shop-links{display:flex;flex-wrap:wrap;gap:6px}
.shop-links .btn{text-decoration:none;font-size:.8rem;padding:5px 11px}
.pd-player:empty{display:none}
.pd-player{aspect-ratio:16/9;border-radius:10px;overflow:hidden;background:#000;margin-bottom:8px;border:1px solid var(--line)}
.pd-player iframe{width:100%;height:100%;border:0;display:block}
.pd-vgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:8px}
.pd-vthumb{background:var(--panel);border:1px solid var(--line);border-radius:9px;padding:0;overflow:hidden;cursor:pointer;color:var(--ink);text-align:left}
.pd-vthumb img{width:100%;aspect-ratio:16/9;object-fit:cover;display:block;background:var(--panel-2)}
.pd-vthumb.is-on{border-color:var(--magenta)}
.pd-vtitle{display:block;padding:6px 8px;font-size:.76rem;line-height:1.35;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.pd-near-row{display:flex;gap:10px;align-items:center;width:100%;background:var(--panel);border:1px solid var(--line);border-radius:9px;
  padding:6px 8px;margin-bottom:6px;cursor:pointer;color:var(--ink);text-align:left}
.pd-near-row:hover{border-color:var(--datum)}
.pd-near-row img,.pd-near-blank{width:56px;height:42px;object-fit:cover;border-radius:6px;flex:0 0 auto;background:var(--panel-2)}
.pd-near-blank{display:grid;place-items:center;color:var(--ink-3)}
.pd-near-t{display:flex;flex-direction:column;min-width:0}
.pd-near-n{font-weight:600;font-size:.9rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pd-near-t .fine{margin:0}
.pd-near-row-s{padding-top:8px;padding-bottom:8px}
.pd-near-row-s .pd-near-t .fine{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pd-around-top{display:flex;flex-direction:column;gap:8px;margin:2px 0 6px}
.pd-around-r{align-self:flex-start;margin:0}
.pd-around-r .seg-b{white-space:nowrap;padding:6px 14px}
.pd-around-find{position:relative;display:flex;align-items:center;border:1px solid var(--line);border-radius:999px;background:var(--panel-2)}
.pd-around-find:focus-within{border-color:var(--datum);box-shadow:0 0 0 3px color-mix(in srgb,var(--datum) 22%,transparent)}
.pd-around-find .sx{flex:1 1 auto}
.pd-around-find input{width:100%;box-sizing:border-box;min-height:42px;padding:9px 40px 9px 14px;border:0;border-radius:999px;
  background:transparent;color:var(--ink);font:inherit;font-size:16px;-webkit-appearance:none;appearance:none}
.pd-around-find input::placeholder{color:var(--ink-3);opacity:1}
.pd-around-find input:focus{outline:none}
.pd-around-find .sx-x{right:8px}
.pd-around-s{margin:0 0 8px}
.pd-around-n{margin:0 0 6px}

/* ---- sources + shopping ---- */
.src-list{display:grid;gap:6px;margin-top:4px}
.src{display:grid;grid-template-columns:auto 1fr;column-gap:8px;background:var(--panel);border:1px solid var(--line);border-radius:9px;
  padding:8px 10px;color:var(--ink);text-decoration:none;font-size:.84rem}
.src:hover{border-color:var(--datum)}
.src-n{color:var(--datum);font-family:ui-monospace,monospace;font-weight:700}
.src-t{font-weight:600;grid-column:2}
.src-u{grid-column:2;color:var(--ink-3);font-size:.74rem;font-family:ui-monospace,monospace}
.src-s{grid-column:2;color:var(--ink-2);font-size:.8rem;margin-top:2px}
.src:not(:has(.src-n)){grid-template-columns:1fr}
.src:not(:has(.src-n)) .src-t,.src:not(:has(.src-n)) .src-u,.src:not(:has(.src-n)) .src-s{grid-column:1}
.ai-sources{margin-top:8px;max-width:100%}
.ai-status{font-size:.78rem;color:var(--ink-3);font-family:ui-monospace,monospace;padding:4px 0 6px;display:grid;gap:2px}
.ai-status:empty{display:none}
.fd-brand{font-size:.9rem;color:var(--datum);font-family:ui-monospace,monospace;margin-top:2px}
/* Which one of them it is, and how the model knows. Three lines under the
   name, in descending confidence: the variant is part of the answer, the
   printed codes are the evidence, and the last line is the model saying how
   sure it is. Monospace on the codes because they are meant to be read
   character by character and typed into a search. */
.fd-variant{font-size:.86rem;color:var(--ink-2);margin-top:2px}
.fd-ids{font-size:.78rem;color:var(--ink-3);font-family:ui-monospace,monospace;
  margin-top:3px;word-break:break-word}
.fd-how{font-size:.76rem;color:var(--ink-3);margin-top:4px;font-style:italic}
/* Not an error state. The analysis was cut short, which is a different thing
   from the analysis failing, and the border says "read the rest with care"
   rather than "this went wrong". */
.fd-warn{margin-top:10px;padding:8px 11px;border-radius:9px;font-size:.8rem;
  color:var(--ink-2);background:var(--panel-2);border-left:3px solid var(--warn)}
/* Genuine or not: a badge with its reasons folded under it (finds.js). */
.fd-auth{margin-top:10px;border:1px solid var(--line);border-left:4px solid var(--ink-3);border-radius:10px;
  padding:0 12px;background:var(--panel);font-size:.88rem}
.fd-auth.is-ok{border-left-color:var(--ok)}
.fd-auth.is-warn{border-left-color:var(--warn)}
.fd-auth-badge{padding:9px 0;cursor:pointer;font-weight:600}
.fd-auth.is-ok .fd-auth-badge{color:var(--ok)}
.fd-auth.is-warn .fd-auth-badge{color:var(--warn)}
.fd-auth.is-unsure .fd-auth-badge{color:var(--ink-2)}
.fd-auth-h{font-weight:600;margin:6px 0 3px;font-size:.84rem}
.fd-auth-list{margin:0 0 6px;padding-left:20px;display:grid;gap:3px;line-height:1.4}
.fd-sure{font-style:normal;font-weight:600;color:var(--ink-2)}
.fd-idev{font-size:.78rem;color:var(--ink-3);margin-top:4px}
.fd-idev summary{cursor:pointer}
/* Photos waiting to be analysed together (ai.js, up to three). Not
   .ai-shots: that is the sideways-scrolling photo row under an answer, and
   sharing it laid the tray out as one row with a hidden scrollbar, which put
   Analyse and "Add another angle" off the right edge of a phone. */
.ai-tray{margin:8px 12px 0;padding:8px 10px;border:1px solid var(--line);border-radius:12px;background:var(--panel-2)}
.ai-shots-row{display:flex;gap:8px;flex-wrap:wrap}
.ai-shot{position:relative}
.ai-shot img{display:block;width:64px;height:64px;object-fit:cover;border-radius:8px;border:1px solid var(--line)}
.ai-shot button{position:absolute;top:-8px;right:-8px;width:28px;height:28px;border-radius:50%;
  border:1px solid var(--line);background:var(--panel);color:var(--ink);cursor:pointer}
.ai-tray .row-btns{margin-top:8px}
/* While shooting another angle the viewfinder's own Capture and Cancel are
   the buttons; the tray shrinks to its thumbnails so the picture keeps the
   room, and a second Analyse/Cancel row does not crush the camera box (and
   its Capture button) off the bottom of a short phone. */
#ai-panel:has(#ai-cam:not([hidden])) .ai-tray .fine,
#ai-panel:has(#ai-cam:not([hidden])) .ai-tray .row-btns{display:none}
#ai-panel:has(#ai-cam:not([hidden])) .ai-tray{padding:6px 8px}
#ai-panel:has(#ai-cam:not([hidden])) .ai-shot img{width:48px;height:48px}
#ai-panel:has(#ai-cam:not([hidden])) .ai-shot button{display:none}

/* ---- translation drawn on the photo ---- */
#scan-overlay{position:absolute;inset:0;pointer-events:none}
#scan-overlay:empty{display:none}
#scan-shot:not([hidden])~#scan-overlay{pointer-events:auto}
#scan-stage:has(#scan-shot:not([hidden])){display:inline-block;width:100%}
#scan-shot{width:100%;max-height:60vh;object-fit:contain}
/* A label is painted in the sign's own colours (read off the photo by the
   server: --ov-bg the surface, --ov-fg the ink), opaque, over the outline the
   text detector found — so it covers the words it translates. The type size
   is set by scan.js fitText. */
.ov-block{position:absolute;box-sizing:border-box;display:flex;align-items:center;justify-content:center;text-align:center;
  background:var(--ov-bg,var(--panel));color:var(--ov-fg,var(--ink));border-radius:2px;
  box-shadow:0 0 0 1px color-mix(in srgb,var(--ov-fg,var(--ink)) 22%,transparent);
  padding:0 2px;overflow:hidden;line-height:1.08;font-weight:600;cursor:pointer;
  white-space:normal;word-break:normal;overflow-wrap:normal;transform-origin:50% 50%}
.ov-block.is-tight{overflow-wrap:anywhere}
.ov-block.is-est{outline:1px dashed color-mix(in srgb,var(--datum) 70%,transparent)}
.ov-block.is-lifted{background:transparent;color:transparent;box-shadow:0 0 0 2px var(--magenta)}
/* Saved translations (scan.js openSaved): a grid of the kept photos. */
.scan-saved-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:10px;margin:8px 0}
.scan-tile{position:relative}
.scan-tile-open{display:flex;flex-direction:column;gap:4px;width:100%;padding:0;border:1px solid var(--line);border-radius:10px;
  background:var(--panel);color:inherit;overflow:hidden;cursor:pointer;text-align:left;font:inherit}
.scan-tile-open img{display:block;width:100%;aspect-ratio:4/3;object-fit:cover;background:var(--line)}
.scan-tile-open .fine{padding:0 8px 6px}
.scan-tile-x{position:absolute;top:4px;right:4px;width:26px;height:26px;border-radius:50%;border:0;padding:0;cursor:pointer;
  background:color-mix(in srgb,var(--panel) 85%,transparent);color:var(--ink);font-size:18px;line-height:26px}
.yd-privacy h2{font-size:1rem;margin:14px 0 4px}
.yd-privacy p,.yd-privacy li{font-size:.92rem}
.tr-list{margin-top:6px}
.tr-row{background:var(--panel);border:1px solid var(--line);border-radius:8px;padding:8px 10px;margin-bottom:6px}
.tr-t{font-size:.95rem}
.tr-o{font-size:.8rem;color:var(--ink-3);margin-top:2px}
.tr-line{display:flex;align-items:flex-start;gap:8px}
.tr-line+.tr-line{margin-top:4px}
.tr-body{flex:1;min-width:0}
.tr-p{font-size:.85rem;color:var(--ink-2);margin-top:1px}
.tr-line .tr-o+.tr-p{font-size:.78rem}
.tr-say{flex:none;min-width:34px;padding-left:6px;padding-right:6px}
.tr-say.is-on,#scan-result .btn.is-on{background:var(--datum);border-color:var(--datum);color:var(--on-accent)}

/* ---- place card: conditions and country essentials ---- */
.pd-cond{display:flex;flex-wrap:wrap;gap:1px;background:var(--line);border:1px solid var(--line);
  border-radius:10px;overflow:hidden;margin:10px 0}
.pd-cond-item{flex:1 1 120px;background:var(--panel);padding:8px 11px;min-width:0}
.pd-cond-l{display:block;font-size:.75rem;text-transform:uppercase;letter-spacing:.1em;color:var(--ink-3)}
.pd-cond-v{display:block;font-size:.92rem;font-weight:600;margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pd-country{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--datum);
  border-radius:10px;padding:9px 12px;margin-bottom:10px}
.pd-country-head{display:flex;align-items:center;gap:8px;width:100%;background:none;border:0;padding:0;
  color:var(--ink);cursor:pointer;text-align:left}
.pd-country-head:hover .pd-country-n{color:var(--datum)}
.pd-flag{font-size:1.3rem;line-height:1}
.pd-country-n{font-weight:700;font-size:.98rem}
.pd-country-head .fine{margin:0 0 0 auto;white-space:nowrap}
.pd-country-facts{display:flex;flex-wrap:wrap;gap:10px 18px;margin-top:7px}
.pd-cf{min-width:84px}
@media (max-width:420px){ .pd-country-head .pd-country-n ~ .fine{display:none} }

/* ---- key verification ---- */
.key-verdict{font-size:.8rem;line-height:1.45;margin-top:6px;color:var(--ok);
  background:color-mix(in srgb,var(--ok) 10%,transparent);border:1px solid color-mix(in srgb,var(--ok) 28%,transparent);border-radius:8px;padding:7px 10px}
.key-verdict.bad{color:var(--magenta);background:color-mix(in srgb,var(--magenta) 9%,transparent);border-color:color-mix(in srgb,var(--magenta) 30%,transparent)}
.key-test{margin-top:6px}
@media (min-width:900px){
  .set-pane.is-on>.key-verdict,.set-pane.is-on>.key-test{grid-column:2}
}

/* ---- routing pickers ---- */
.route-tools{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:6px 0 2px}
.route-filter{flex:1 1 150px;min-width:110px;background:var(--ground);color:var(--ink);
  border:1px solid var(--line);border-radius:7px;padding:6px 10px;font-size:.82rem}
.route-count{margin:0;white-space:nowrap}
select.route optgroup{background:var(--panel);color:var(--ink-3);font-style:normal;font-weight:600}
select.route option{background:var(--panel);color:var(--ink);font-family:ui-monospace,monospace;font-size:.85rem}
@media (min-width:900px){ .set-pane.is-on>.route-tools{grid-column:2} }

/* ---- compass and turn-by-turn ---- */
#btn-compass.on{color:var(--magenta);border-color:var(--magenta);background:color-mix(in srgb,var(--magenta) 10%,transparent)}
#compass-dial{transform-origin:12px 12px;transition:transform .25s ease-out}
#nav-live{margin-top:10px;background:var(--panel);border:1px solid var(--line);
  border-left:3px solid var(--ok);border-radius:12px;padding:12px 14px}
#nav-live.is-off{border-left-color:var(--magenta)}
/* Arrow, distance, instruction — in that order of size, because that is the
   order they are read in at a junction. */
.nav-now{display:flex;gap:12px;align-items:center}
.nav-icon{flex:0 0 auto;font-size:2.1rem;line-height:1;color:var(--ok);width:40px;text-align:center}
#nav-live.is-off .nav-icon{color:var(--magenta)}
.nav-now-text{min-width:0}
#nav-instruction{font-size:1.02rem;font-weight:600;line-height:1.3;color:var(--ink-2)}
#nav-distance{font-family:ui-monospace,monospace;font-size:1.9rem;font-weight:700;
  color:var(--ok);line-height:1.05;font-variant-numeric:tabular-nums}
#nav-live.is-off #nav-distance{color:var(--magenta)}
/* The turn after this one. Small on purpose: it is a warning, not the
   instruction, and it must never be mistaken for what to do now. */
.nav-then{margin-top:7px;padding-top:7px;border-top:1px solid var(--line)}
.nav-safety{margin:8px 0 0}
.navlive-foot{display:flex;justify-content:space-between;gap:10px;margin-top:6px;flex-wrap:wrap}
.nav-eta{font-variant-numeric:tabular-nums;color:var(--ok)}
.nav-ctl{margin-top:10px;display:flex;gap:10px;align-items:center;flex-wrap:wrap}
#nav-recompute{margin-left:auto}

/* ---- air quality, forecast, Google panorama ---- */
.aqi-ok{color:var(--ok)} .aqi-mid{color:var(--warn)} .aqi-bad{color:var(--magenta)}
.pd-forecast{display:flex;gap:1px;background:var(--line);border:1px solid var(--line);
  border-radius:10px;overflow:hidden;margin:0 0 10px}
.pd-fc{flex:1;background:var(--panel);padding:8px 10px;min-width:0}
.pd-fc-t{display:block;font-family:ui-monospace,monospace;font-weight:600;font-size:.9rem;margin:2px 0}
.pd-fc .fine{margin:0;font-size:.72rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ---------------- map popups ----------------
   MapLibre's own stylesheet paints every popup white and sets no text colour,
   so the bubble inherited the app's light-on-dark ink and came out as pale
   grey on white — the bus-stop card was effectively unreadable. The popup is
   part of this app's surface, not the library's, so it is themed like the
   panels: dark panel, cream ink, and a tip that matches on all eight anchors. */
/* Every selector here is one class more specific than the vendor rule it
   replaces, so the theme holds even if the two stylesheets ever load in the
   other order again. */
.maplibregl-popup{z-index:8}
.maplibregl-popup .maplibregl-popup-content{
  background:var(--panel); color:var(--ink);
  border:1px solid var(--line); border-left:3px solid var(--datum);
  border-radius:10px; padding:10px 13px;
  font:13px/1.5 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  box-shadow:0 10px 28px color-mix(in srgb,var(--shadow) 45%,transparent);
  max-width:74vw; white-space:pre-line; word-break:break-word;
}
@media (min-width:900px){ .maplibregl-popup .maplibregl-popup-content{max-width:330px} }
.maplibregl-popup .maplibregl-popup-close-button{
  color:var(--ink-2); font-size:17px; line-height:1; padding:3px 7px;
  border-radius:0 9px 0 9px;
}
.maplibregl-popup .maplibregl-popup-close-button:hover{background:var(--panel-2);color:var(--ink)}
/* The tip is a CSS triangle whose colour lives on a different border edge for
   each anchor; all eight have to be restated or one side keeps a white arrow. */
.maplibregl-popup.maplibregl-popup-anchor-top .maplibregl-popup-tip,
.maplibregl-popup.maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
.maplibregl-popup.maplibregl-popup-anchor-top-right .maplibregl-popup-tip{border-bottom-color:var(--panel)}
.maplibregl-popup.maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
.maplibregl-popup.maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
.maplibregl-popup.maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip{border-top-color:var(--panel)}
.maplibregl-popup.maplibregl-popup-anchor-left .maplibregl-popup-tip{border-right-color:var(--panel)}
.maplibregl-popup.maplibregl-popup-anchor-right .maplibregl-popup-tip{border-left-color:var(--panel)}

/* Structured popups (built as DOM, not a text blob) read as a small card. */
.mp-t{display:block;font-weight:700;font-size:.95rem;color:var(--ink);margin-bottom:2px}
.mp-s{display:block;font-size:.78rem;color:var(--ink-2)}
.mp-k{display:inline-block;font-size:.66rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ground);background:var(--datum);border-radius:4px;padding:1px 6px;margin-bottom:5px}
.mp-l{display:block;font-size:.8rem;color:var(--ink);margin-top:5px;font-family:ui-monospace,monospace}
/* A camera's popup carries the picture, because the picture is the layer.
   Fixed aspect so the bubble does not jump around the map as frames of
   different shapes arrive from seven different networks. */
/* "Also here" only appears when there is something named to list. */
.pc-list-head{font-size:.72rem;letter-spacing:.05em;text-transform:uppercase;
  color:var(--ink-3);margin:10px 0 3px}
.mp-cam{margin-top:8px}
.mp-cam-img,.mp-cam-embed{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;
  border:1px solid var(--line);border-radius:8px;background:#000}
.mp-cam-embed{aspect-ratio:16/9;border:0}
.mp-b{margin-top:8px;display:flex;gap:6px;flex-wrap:wrap}
.mp-b button{background:var(--panel-2);color:var(--ink);border:1px solid var(--line);
  border-radius:7px;padding:5px 9px;font-size:.76rem;cursor:pointer}
.mp-b button:hover{border-color:var(--datum);color:var(--datum)}

/* ---------------- near me ----------------
   Anchored on a point rather than a viewport, so the panel leads with where
   it is searching and how far, and every row ends with the two numbers that
   decide whether you go: distance and whether the door is open. */
#near-panel{position:absolute;left:12px;right:12px;bottom:18px;z-index:7;
  background:color-mix(in srgb,var(--panel) 96%,transparent);backdrop-filter:blur(10px);border:1px solid var(--line);
  border-left:3px solid var(--ok);border-radius:12px;padding:11px 14px;
  max-height:58vh;overflow-y:auto;overscroll-behavior:contain}
@media (min-width:900px){ #near-panel{right:auto;width:376px} }
.near-head{display:flex;justify-content:space-between;align-items:baseline;gap:10px;margin-bottom:9px}
.near-head .fine{font-family:ui-monospace,monospace}
.near-head>div{min-width:0}
#near-anchor{display:block;margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#near-count{flex:0 0 auto;white-space:nowrap}

/* A horizontal reel: fourteen categories will not fit on a phone as a grid,
   and a dropdown hides the one thing the panel is for. */
/* The reel is scrollable and there are more chips than fit; the fade at the
   right edge is the only thing that says so on a touch screen with no bar. */
.near-cats{display:flex;gap:6px;overflow-x:auto;padding-bottom:4px;scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
  -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 26px),transparent);
  mask-image:linear-gradient(to right,#000 calc(100% - 26px),transparent)}
.near-cats::-webkit-scrollbar{display:none}
.near-cat{flex:0 0 auto;display:flex;align-items:center;gap:6px;cursor:pointer;
  background:var(--panel);color:var(--ink-2);border:1px solid var(--line);
  border-radius:999px;padding:7px 12px;font-size:.82rem;white-space:nowrap;
  min-height:36px;transition:border-color .12s,color .12s,background .12s}
.near-cat-i{font-size:1rem;line-height:1}
.near-cat.is-on{color:var(--ground);background:var(--cat);border-color:var(--cat);font-weight:600}
.near-cat:focus-visible{outline:2px solid var(--datum);outline-offset:2px}

.near-controls{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:9px 0 4px}
.seg{display:inline-flex;background:var(--ground);border:1px solid var(--line);border-radius:8px;padding:2px}
.seg button{background:none;border:0;color:var(--ink-3);font-size:.78rem;padding:5px 10px;
  border-radius:6px;cursor:pointer;font-family:ui-monospace,monospace}
.seg button.is-on{background:var(--panel-2);color:var(--ink)}

#near-list{margin-top:10px}
.near-google:not(:empty){margin:10px 0 2px}
.near-gframe{display:block;width:100%;height:min(75vh,720px);min-height:420px;border:0}
.near-row{background:var(--panel);border:1px solid var(--line);border-radius:10px;
  margin-bottom:7px;overflow:hidden}
.near-main{display:flex;gap:10px;align-items:center;width:100%;background:none;border:0;
  padding:10px 12px;text-align:left;color:var(--ink);cursor:pointer}
.near-main:hover{background:var(--panel-2)}
.near-i{flex:0 0 auto;width:28px;height:28px;border-radius:8px;display:grid;place-items:center;
  font-size:15px;background:color-mix(in srgb,var(--cat) 18%,transparent);
  border:1px solid color-mix(in srgb,var(--cat) 45%,transparent)}
.near-body{display:flex;flex-direction:column;min-width:0;flex:1}
.near-n{font-size:.92rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.near-sub{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.near-right{flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;gap:0;text-align:right;
  max-width:11ch}
.near-right .fine{font-size:.7rem;white-space:nowrap}
.near-d{font-family:ui-monospace,monospace;font-size:.9rem;font-weight:700;color:var(--datum);
  font-variant-numeric:tabular-nums}
.near-open{font-size:.7rem;letter-spacing:.04em;text-transform:uppercase;font-weight:700}
.near-still{font-size:.75rem;color:var(--warn);margin-top:2px}
.near-open.is-open{color:var(--ok)} .near-open.is-shut{color:var(--magenta)}
.near-hours{max-width:14ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.near-acts{display:flex;gap:6px;flex-wrap:wrap;padding:0 12px 10px}
.near-act{background:var(--panel-2);color:var(--ink-2);border:1px solid var(--line);
  border-radius:7px;padding:5px 10px;font-size:.76rem;cursor:pointer;text-decoration:none;
  display:inline-block;line-height:1.3}
.near-act:hover{border-color:var(--datum);color:var(--datum)}

/* The way out of the Stay list. Separated by a rule rather than dropped in as
   another row, because it is not a place — it is the admission that a list of
   positions cannot say which position is worth sleeping in. */
.near-advice{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding:10px 12px 4px;margin-top:6px;border-top:1px solid var(--line)}
.near-advice .fine{flex:1 1 12rem;min-width:0}

/* ---------------- inside a venue ----------------
   Shares the shape of the Near me row deliberately: the same eye is reading
   both, and a park's toilet and a street's toilet are the same row with a
   different origin. What it adds is the second name line, because in China
   the name on the sign is the half of the row that gets you there. */
.venue-title{font-size:1.05rem;font-weight:700;line-height:1.25;margin-top:2px}
.venue-local{font-size:1rem;color:var(--ink-2);line-height:1.3;margin-bottom:3px}
.venue-acts{display:flex;gap:6px;flex-wrap:wrap;margin:9px 0 2px}
.venue-act{background:var(--panel-2);color:var(--ink-2);border:1px solid var(--line);
  border-radius:7px;padding:5px 10px;font-size:.76rem;cursor:pointer;text-decoration:none;
  display:inline-block;line-height:1.3}
.venue-act:hover{border-color:var(--datum);color:var(--datum)}

.venue-find{display:flex;gap:7px;align-items:center;margin:10px 0 8px}
#venue-filter{flex:1;min-width:0;background:var(--ground);color:var(--ink);
  border:1px solid var(--line);border-radius:8px;padding:9px 11px;font-size:.86rem;
  font-family:inherit;min-height:38px}
#venue-filter:focus{outline:none;border-color:var(--datum)}

.venue-chips{display:flex;gap:6px;overflow-x:auto;padding-bottom:4px;scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
  -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 26px),transparent);
  mask-image:linear-gradient(to right,#000 calc(100% - 26px),transparent)}
.venue-chips::-webkit-scrollbar{display:none}
.venue-chip{flex:0 0 auto;cursor:pointer;background:var(--panel);color:var(--ink-2);
  border:1px solid var(--line);border-radius:999px;padding:7px 12px;font-size:.8rem;
  white-space:nowrap;min-height:36px}
.venue-chip.is-on{color:var(--ground);background:var(--cat,var(--datum));
  border-color:var(--cat,var(--datum));font-weight:600}
.venue-chip:focus-visible{outline:2px solid var(--datum);outline-offset:2px}

#venue-list{margin-top:10px}
.venue-row{background:var(--panel);border:1px solid var(--line);border-radius:10px;
  margin-bottom:7px;overflow:hidden}
.venue-main{display:flex;gap:10px;align-items:center;width:100%;background:none;border:0;
  padding:10px 12px;text-align:left;color:var(--ink);cursor:pointer}
.venue-main:hover{background:var(--panel-2)}
.venue-i{flex:0 0 auto;width:28px;height:28px;border-radius:8px;display:grid;place-items:center;
  font-size:15px;background:color-mix(in srgb,var(--cat) 18%,transparent);
  border:1px solid color-mix(in srgb,var(--cat) 45%,transparent)}
.venue-body{display:flex;flex-direction:column;min-width:0;flex:1}
.venue-n{font-size:.92rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.venue-l{font-size:.86rem;color:var(--ink-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.venue-f{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.venue-right{flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;text-align:right;
  max-width:11ch}
.venue-right .fine{font-size:.7rem;white-space:nowrap}
.venue-d{font-family:ui-monospace,monospace;font-size:.9rem;font-weight:700;color:var(--datum);
  font-variant-numeric:tabular-nums}
.venue-rowacts{display:flex;gap:6px;flex-wrap:wrap;padding:0 12px 10px}
.venue-main:focus-visible,.venue-act:focus-visible{outline:2px solid var(--datum);outline-offset:-2px}

/* ---------------- departures ----------------
   The three columns are the three questions: which one, going where, when. */
#dep-board{margin-top:11px;border-top:1px solid var(--line);padding-top:10px}
.dep-head{display:flex;justify-content:space-between;align-items:baseline;gap:10px;margin-bottom:8px}
.dep-head .fine{font-family:ui-monospace,monospace}
#dep-sub{display:block}
.dep-row{display:flex;gap:10px;align-items:center;padding:7px 0;border-bottom:1px solid var(--line)}
.dep-row:last-child{border-bottom:0}
.dep-row.is-cancelled{opacity:.55;text-decoration:line-through}
.dep-line{flex:0 0 auto;min-width:38px;text-align:center;font-family:ui-monospace,monospace;
  font-weight:700;font-size:.82rem;padding:3px 7px;border-radius:6px;
  color:var(--ground);background:var(--m)}
.dep-to{display:flex;flex-direction:column;min-width:0;flex:1}
.dep-towards{font-size:.88rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dep-to .fine{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dep-when{flex:0 0 auto;font-family:ui-monospace,monospace;font-weight:700;font-size:.95rem;
  color:var(--ink-2);font-variant-numeric:tabular-nums}
/* A live minute and a timetable minute look identical and mean different
   things, so the live one is marked — this is the whole point of the board. */
.dep-when.is-live{color:var(--ok);position:relative;padding-left:12px}
.dep-when.is-live::before{content:'';position:absolute;left:0;top:50%;width:6px;height:6px;
  margin-top:-3px;border-radius:50%;background:var(--ok);animation:dep-pulse 2s ease-in-out infinite}
@keyframes dep-pulse{0%,100%{opacity:1}50%{opacity:.25}}
@media (prefers-reduced-motion:reduce){ .dep-when.is-live::before{animation:none} }
.dep-alt{display:block;width:100%;text-align:left;background:var(--panel);color:var(--ink-2);
  border:1px solid var(--line);border-radius:7px;padding:6px 9px;margin-top:6px;
  font-size:.78rem;cursor:pointer}
.dep-alt:hover{border-color:var(--datum);color:var(--datum)}
.mp-dep .dep-row{padding:5px 0}
.mp-dep{margin-top:8px;border-top:1px solid var(--line);padding-top:6px}

/* ---------------- clocks ---------------- */
#hud .clock-row .v{font-weight:600}
#hud.tz-split #hud-here{color:var(--datum)}
#hud .v.is-other-day{color:var(--warn)}
#hud .v.is-other-day::after{content:'*';margin-left:2px}
.tz-cards{display:flex;gap:10px;margin:10px 0 14px;flex-wrap:wrap}
.tz-card{flex:1 1 150px;background:var(--panel);border:1px solid var(--line);
  border-left:3px solid var(--datum);border-radius:10px;padding:11px 13px;
  display:flex;flex-direction:column;gap:2px}
.tz-card strong{font-family:ui-monospace,monospace;font-size:1.7rem;line-height:1.1;
  font-variant-numeric:tabular-nums}
.tz-card:last-child{border-left-color:var(--ok)}
#tz-home{min-width:min(320px,100%);max-width:100%}

/* ---------------- keyboard focus ----------------
   Everything clickable had a hover state and, outside the nav bar and the text
   inputs, nothing at all for the keyboard: tabbing through the sheet moved an
   invisible cursor across the chips, the map controls, the place rows and the
   pager. :focus-visible only fires for keyboard and assistive navigation, so a
   pointer still gets the quiet surface the design is built around.

   One rule with a shared outline rather than per-component styles, because the
   failure to avoid is a *new* control landing without one. */
.chip:focus-visible,
.fab:focus-visible,
.btn:focus-visible,
.set-tab:focus-visible,
.sos-tab:focus-visible,
.gate-tab:focus-visible,
.sheet-handle:focus-visible,
.place-row:focus-visible,
.near-main:focus-visible,
.near-act:focus-visible,
.pager-btn:focus-visible,
.journey-row:focus-visible,
.dep-alt:focus-visible,
.fr-listrow:focus-visible,
.city:focus-visible,
.pin:focus-visible,
.pinbtn:focus-visible,
.pc-close:focus-visible,
.back:focus-visible,
.prof-name:focus-visible,
#hud:focus-visible,
.pd-near-row:focus-visible,
.near-cat:focus-visible,
select:focus-visible,
textarea:focus-visible,
[role="tab"]:focus-visible {
  outline: 2px solid var(--datum);
  outline-offset: 2px;
  /* The chips sit in a horizontally scrolling strip that clips at the edges;
     a ring drawn outside the element would be cut off there. */
  border-radius: 8px;
}
.sheet-chips .chip:focus-visible { outline-offset: -2px; }

/* A keyboard user has to be able to reach the map's tools without tabbing
   through the whole chip strip first. Visible only when focused. */
.skip-link {
  position: fixed; top: 8px; left: 8px; z-index: 100;
  transform: translateY(-200%);
  background: var(--panel-2); color: var(--ink);
  border: 1px solid var(--datum); border-radius: 8px;
  padding: 10px 14px; font-size: .9rem; text-decoration: none;
}
.skip-link:focus { transform: translateY(0); }

/* ---------------- ferries ----------------
   A crossing is a line of text before it is a line on the map: the name of
   both ends, how long it takes and whether a car can come. Rows are buttons
   because both ends of a ferry route are usually off screen at the zoom you
   found it at, and tapping one fits the map to it. */
.transit-sub{
  margin:12px 0 5px; font-size:.68rem; text-transform:uppercase;
  letter-spacing:.12em; color:var(--ink-3,var(--ink-2)); font-weight:600;
}
#ferry-list{display:grid;gap:3px;margin-top:6px}
.ferry-row{
  display:flex; gap:8px; align-items:flex-start; width:100%; text-align:left;
  background:none; border:0; border-radius:8px; padding:7px 8px; cursor:pointer;
  color:var(--ink); font-family:inherit; font-size:.86rem; line-height:1.35;
}
.ferry-row:hover{background:var(--panel-2)}
.ferry-row:active{background:var(--line)}
.ferry-row:focus-visible{outline:2px solid var(--datum);outline-offset:-2px}
.ferry-dot{flex:0 0 auto;width:8px;height:8px;border-radius:2px;margin-top:5px}
.ferry-txt{display:flex;flex-direction:column;gap:1px;min-width:0}
.ferry-txt strong{font-weight:600;overflow-wrap:anywhere}
.ferry-txt .fine{color:var(--ink-3,var(--ink-2))}

/* ---------------- map legend ----------------
   Twelve layers can be drawn at once — nine live ones plus places, transit and
   "near me" — each as a coloured dot, and there was no key anywhere. Sits
   under the readout, collapses to its heading, and never appears with nothing
   in it. */
#legend{
  position:absolute; left:12px; z-index:5; max-width:min(220px,45vw);
  background:color-mix(in srgb,var(--ground) 86%,transparent); backdrop-filter:blur(8px);
  border:1px solid var(--line); border-radius:var(--r);
  padding:6px 8px; font-size:12px; line-height:1.5;
  /* below the compact readout; JS moves it when the readout expands */
  top:96px;
}
#legend-toggle{
  background:none; border:0; color:var(--ink-3); cursor:pointer; padding:1px 2px;
  font-size:.66rem; text-transform:uppercase; letter-spacing:.11em; font-weight:600;
}
#legend-toggle:hover{color:var(--ink)}
#legend.is-shut #legend-items{display:none}
#legend-items{display:grid; gap:3px; margin-top:4px}
.lg-row{display:flex; gap:6px; align-items:center; color:var(--ink-2); white-space:nowrap}
.lg-dot{width:9px; height:9px; border-radius:50%; flex:0 0 auto;
  border:1px solid color-mix(in srgb,var(--ground) 90%,transparent)}
.lg-dot.is-line{width:14px; height:3px; border-radius:1px}
@media (max-width:520px){ #legend{font-size:12px; max-width:44vw} }

/* ==================================================================
   ACCOUNT AND SECURITY (Settings)
   ================================================================== */
/* Password strength. A meter, not a gate: the server's only hard rules are
   length and the breach list, and a bar that explains beats a rule that
   rejects — the person choosing the passphrase is the one who has to
   remember it. */
#au-strength{margin:6px 0 10px}
.pwbar{height:4px;border-radius:2px;background:var(--panel-2);overflow:hidden}
.pwbar i{display:block;height:100%;width:0;border-radius:2px;background:var(--magenta);
  transition:width .2s ease,background .2s ease}
.pwbar i[data-score="2"]{background:var(--warn)}
.pwbar i[data-score="3"]{background:var(--datum)}
.pwbar i[data-score="4"]{background:var(--ok)}
#au-pwlabel{display:block;margin-top:4px}

.gate-step{font-size:1.05rem;margin:4px 0 8px}
#mfa-form .btn.wide,#gate-pending .btn.wide{margin-top:8px}

/* The setup and recovery blocks. `user-select:all` on the code so a long
   base32 secret or ten recovery codes can be copied in one gesture on a
   phone, where selecting text by dragging is miserable. */
.code{background:var(--ground);border:1px solid var(--line);border-radius:8px;
  padding:10px 12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.86rem;line-height:1.9;overflow-wrap:anywhere;user-select:all;margin:8px 0}
#mfa-qr{margin:10px 0;display:inline-block;background:#fff;padding:8px;border-radius:10px}
#mfa-qr svg{display:block}
#mfa-box,#account-box{margin-bottom:6px}

/* One row per live session. The device and where it was last used are the two
   things somebody needs to recognise their own, so they lead. */
.sess-row{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:11px 13px;border:1px solid var(--line);border-radius:10px;
  background:var(--panel);margin-bottom:7px}
.sess-row.is-current{border-left:3px solid var(--ok)}
.pill-now{display:inline-block;margin-left:7px;padding:1px 7px;border-radius:999px;
  font-size:.72rem;background:color-mix(in srgb,var(--ok) 14%,transparent);border:1px solid color-mix(in srgb,var(--ok) 45%,transparent);
  color:var(--ok)}


/* ---------- thumbs ----------
 *
 * An audit of every control in the app at 320, 375 and 844 px found a dozen
 * sitting between 29 and 38 px tall. WCAG 2.2 puts the AA floor at 24x24 and
 * these clear it, so nothing here is a compliance fix; they are simply small
 * for a thumb on a moving train, which is where this app is used. Material
 * asks for 48dp and Apple for 44pt, and the sheet's own header buttons were
 * already built to 44.
 *
 * Scoped to a coarse pointer so a mouse keeps the compact controls — the same
 * condition the map's own zoom buttons are enlarged under, a few hundred
 * lines above. Growing them unconditionally would put 44px pills through the
 * middle of the desktop console.
 */
@media (pointer:coarse){
  /* The assistant's own controls. Closing it and folding it are the two
     somebody reaches for in a hurry, and the composer is what a thumb is on. */
  #ai-close,#ai-min{min-width:44px;min-height:44px}
  #ai-send,#ai-plus,#ai-input{min-height:42px}
  .ai-mi{min-height:44px}
  /* The emergency card's tabs and its country picker: the SOS view is the one
     screen in here that gets used one-handed under stress. The settings tabs
     are the same control in a different room. */
  .sos-tab,.set-tab{min-height:42px}
  #sos-country{min-height:44px}
  /* Page numbers on the advisory and place lists. 30x30 between two
     neighbours 4px away is a coin-toss. */
  .pager-btn{min-width:40px;height:40px}
  /* The strip of switched-on layers, and the small buttons inside panels. */
  .livechip{height:38px}
  .btn.sm{min-height:38px}
  /* Time-zone shortcuts in settings. */
  #tz-home-auto,#tz-home-here{min-height:38px}
  /* Disclosure rows and the model-routing filter, in the settings view. Not
     traveller-facing, but they are still tapped with the same thumb.
     Native checkboxes are left alone on purpose: their `label.switch` wrapper
     is the target and it is already the width of the panel.
     Not MapLibre's attribution button: in MapLibre 5 its ⓘ is a <summary>
     drawn at 24x24 from a background image, and 40px tall tiled that image
     into a second "i" under the first. */
  summary:not(.maplibregl-ctrl-attrib-button){min-height:40px;display:flex;align-items:center}
  #route-filter{min-height:38px}

  /* iOS Safari zooms the page in when a text field it is about to focus has a
     computed font-size below 16px — and, the part that does the damage, it
     does not zoom back out when the field is blurred. Search for something,
     press Enter, and the page is left at roughly 1.14x for ever: everything
     is wider than the screen, and the sheet's tool sections and the map's own
     controls sit outside the visual viewport with no way to reach them. It
     reads as a broken layout and it is a zoom nobody asked for.
     Reported on iPhone against the search box, which was 14px.

     The fix is 16px, not `maximum-scale=1`. Pinning the scale in the viewport
     meta would also stop the zoom, by taking pinch-to-zoom away from everyone
     permanently — an accessibility failure, and one recent Safari ignores
     anyway. Making the text big enough removes the reason for the zoom
     instead, and costs a couple of pixels on a phone where the fields are
     already full width.

     `!important` because these are ID-scoped rules (`#auth-form input`,
     `#place-search`) that a bare element selector cannot outrank, and the
     failure mode of missing one is invisible on a desktop and unusable on a
     phone. Typed here once rather than as six edits that the seventh field
     added next year would not inherit.

     Selects and checkboxes are left alone: they open a native picker rather
     than a keyboard, and neither zooms. */
  input:not([type=checkbox]):not([type=radio]):not([type=file]),
  textarea{font-size:16px!important}
}

/* ---- what is above you, under the Live panel ----
   A readout rather than a layer legend: the map says where each body is
   overhead on Earth, which is not the same question as whether the person
   reading can see it from where they are standing. */
#sky-now{margin-top:10px;padding-top:9px;border-top:1px solid var(--line)}
.sky-head{color:var(--datum);margin-bottom:5px}
.sky-row{line-height:1.5;color:var(--ink-2)}
.sky-row b{color:var(--ink)}
.sky-mag{font-variant-numeric:tabular-nums;font-style:normal;color:var(--ink-3,var(--ink-2))}
/* The chart wheel, centred in the Sky readout. */
.sky-wheel{display:block;margin:6px auto 4px}
.sky-cap{color:var(--ink-3,var(--ink-2));text-align:center;margin:0 0 8px;line-height:1.4}

/* What is known about one thing in the sky. Floats over the map at the size a
   photograph is worth showing at, and never wider than a phone. */
#sky-card{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  z-index:6;width:min(330px,calc(100vw - 32px));max-height:min(78vh,620px);overflow:auto;
  background:var(--panel,#131A21);border:1px solid var(--line);border-radius:12px;
  padding:14px 16px 16px;box-shadow:0 18px 48px color-mix(in srgb,var(--shadow) 67%,transparent)}
.sky-card-x{position:absolute;right:8px;top:6px;background:none;border:0;
  color:var(--ink-2);font-size:1.3rem;line-height:1;cursor:pointer;padding:4px 8px}
.sky-card-t{font-size:1.02rem;font-weight:600;padding-right:22px;margin-bottom:8px}
.sky-card-img{display:block;width:100%;border-radius:8px;margin:0 0 10px}
.sky-card-facts{color:var(--datum);margin-bottom:8px}
.sky-card-p{color:var(--ink-2);line-height:1.5;margin-bottom:8px}
.sky-card-link{color:var(--datum)}
/* The live half of a card — where a planet is right now, as against what it
   is always — set apart in the colour this app uses everywhere for a reading
   rather than a description. */
.sky-card-live{color:var(--datum);line-height:1.5;margin-bottom:3px}

/* Pointing at something, as against tapping it. Narrow, quiet, and never in
   the way: no pointer events of its own, so moving towards it never makes it
   flicker, and it follows the cursor rather than anchoring to the object. */
#sky-tip{position:absolute;z-index:6;pointer-events:none;
  width:max-content;max-width:min(270px,calc(100vw - 28px));
  background:var(--panel,#131A21);border:1px solid var(--line);border-radius:9px;
  padding:8px 11px 9px;box-shadow:0 10px 30px color-mix(in srgb,var(--shadow) 60%,transparent);font-size:.78rem;line-height:1.45}
.sky-tip-t{font-weight:600;font-size:.86rem;margin-bottom:4px}
.sky-tip-l>div{color:var(--ink-2);margin-top:2px}
.sky-tip-l>.sky-tip-live{color:var(--datum)}
.sky-tip-l>.sky-tip-more{color:var(--ink-3,var(--ink-2));opacity:.7;margin-top:5px;font-style:italic}
@media (pointer:coarse){#sky-tip{display:none}}


/* The track bar: whose track is on screen, and how far back to look. Sits over
   the map rather than in a panel, because it belongs to what is drawn. */
#track-bar{position:absolute;left:50%;transform:translateX(-50%);bottom:calc(var(--nav) + 14px);
  z-index:5;display:flex;flex-direction:column;gap:6px;
  width:max-content;max-width:min(560px,94vw);padding:8px 10px;border-radius:12px;box-sizing:border-box;
  background:var(--panel);border:1px solid var(--line);box-shadow:0 6px 20px color-mix(in srgb,var(--shadow) 35%,transparent)}
#track-bar .tb-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:center}
#track-bar strong{font-size:13.5px;color:var(--ink-1)}
#track-bar .tb-n{font-size:12.5px;color:var(--ink-3);margin-right:4px}
#track-bar .tb-row button{padding:5px 10px;font-size:13px;border-radius:8px;cursor:pointer;
  background:var(--ground);color:var(--ink-2);border:1px solid var(--line)}
#track-bar .tb-row button.on{background:var(--magenta);border-color:var(--magenta);color:var(--on-magenta);font-weight:700}
@media (min-width:900px){#track-bar{bottom:18px}}

/* The itinerary above the bar: numbered stops in the order they were made,
   and between each pair how far and how long the way took. Scrolls inside
   itself so a week of stops never pushes the bar off the map. */
#track-bar .tb-list{width:min(440px,calc(94vw - 22px));max-height:min(38vh,340px);overflow-y:auto;
  overscroll-behavior:contain;border-bottom:1px solid var(--line);padding-bottom:6px}
#track-bar .tb-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:0 0 4px}
#track-bar .tb-title{font-size:12px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-3)}
#track-bar .tb-tools{display:flex;gap:6px;flex:0 0 auto}
#track-bar .tb-fold{font-size:12px;padding:3px 10px;border-radius:999px;cursor:pointer;
  background:var(--ground);color:var(--ink-1);border:1px solid var(--line);font-weight:600}
#track-bar .tb-row button.tb-more{color:var(--ink-1);font-weight:600}
@media (max-width:899px){#track-bar .tb-list{max-height:min(30vh,260px)}}
#track-bar .tb-names{font-size:12px;padding:3px 9px;border-radius:999px;cursor:pointer;
  background:none;color:var(--datum);border:1px solid color-mix(in srgb,var(--datum) 45%,transparent)}
#track-bar .tb-names.on{background:color-mix(in srgb,var(--datum) 14%,transparent)}
#track-bar .tb-note{font-size:12px;color:var(--ink-3);margin:2px 0 6px;line-height:1.4}
#track-bar .tb-stops{list-style:none;margin:0;padding:0}
#track-bar .tb-day{font-size:11.5px;font-weight:700;color:var(--ink-2);margin:8px 0 2px;padding-left:2px}
#track-bar .tb-leg{font-size:11.5px;color:var(--ink-3);margin:0 0 0 13px;padding:3px 0 3px 17px;
  border-left:2px dotted color-mix(in srgb,var(--magenta) 55%,transparent)}
#track-bar .tb-stop{display:flex;align-items:center;gap:10px;width:100%;text-align:left;cursor:pointer;
  padding:6px 4px;border:0;border-radius:8px;background:none;color:var(--ink)}
#track-bar .tb-stop:hover,#track-bar .tb-stop.sel{background:var(--panel-2)}
#track-bar .tb-num{flex:0 0 26px;height:26px;border-radius:50%;display:grid;place-items:center;
  font-size:12.5px;font-weight:800;background:var(--panel);color:var(--magenta);border:2px solid var(--magenta);box-sizing:border-box}
#track-bar .tb-num.last{background:var(--magenta);color:var(--on-magenta)}
#track-bar .tb-txt{flex:1 1 auto;min-width:0;display:flex;flex-direction:column}
#track-bar .tb-place{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#track-bar .tb-when{font-size:12px;color:var(--ink-2);font-variant-numeric:tabular-nums}
#track-bar .tb-dur{flex:0 0 auto;font-size:12px;color:var(--ink-2);text-align:right;max-width:34%}

/* A numbered stop on the track. Same round badge as in the list, so the two
   read as one thing; the latest is filled. */
.trk-stop{width:26px;height:26px;border-radius:50%;padding:0;display:grid;place-items:center;cursor:pointer;
  font-family:inherit;font-size:12.5px;font-weight:800;line-height:1;background:var(--panel);color:var(--magenta);border:2px solid var(--magenta);
  box-shadow:0 2px 8px color-mix(in srgb,var(--shadow) 45%,transparent)}
.trk-stop.last{background:var(--magenta);color:var(--on-magenta)}
.trk-stop.sel{outline:3px solid color-mix(in srgb,var(--magenta) 40%,transparent);outline-offset:2px;z-index:2}

/* Family phones on the map. HTML markers, not a symbol layer: there are three
   or four, each needs its name readable at every zoom, and none may be dropped
   for collision. Colour is the reading — live, gone quiet, not sharing. */
.fam-pin{display:flex;align-items:center;gap:6px;padding:5px 10px 5px 7px;
  border-radius:999px;background:var(--panel);color:var(--ink-1);
  border:2px solid var(--magenta);box-shadow:0 3px 10px color-mix(in srgb,var(--shadow) 45%,transparent);
  font-size:13px;font-weight:700;white-space:nowrap;cursor:pointer;
  transform:translateY(-6px)}
.fam-pin svg{width:15px;height:15px;flex:0 0 15px;fill:currentColor;color:var(--magenta)}
.fam-pin.stale{border-color:#D6B25A}
.fam-pin.stale svg{color:#D6B25A}
.fam-pin.off{border-color:#6B7076;opacity:.8}
.fam-pin.off svg{color:#6B7076}
.fam-pin:hover{filter:brightness(1.12)}

/* The name beside a searched place's pin, for a place the basemap does not
   label there itself (app.js dropPlacePin). Tokens only, so every look. */
.pin-name{position:absolute;left:calc(100% + 2px);top:3px;max-width:180px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  padding:2px 8px;border-radius:999px;background:var(--panel);color:var(--ink-1);
  font-size:12px;font-weight:700;line-height:1.35;pointer-events:none;
  box-shadow:0 2px 6px color-mix(in srgb,var(--shadow) 40%,transparent)}

/* ======================================================================
 * Views with a header: Family and the agents. The back arrow is the way
 * to the map on a phone; on a desktop the nav is always beside the view,
 * so the arrow is hidden there and the title sits flush.
 * ====================================================================== */
.view-head{display:flex;align-items:flex-start;gap:10px;margin:0 0 18px}
.view-head-t{flex:1 1 auto;min-width:0}
.view-head-t h1{margin:0 0 2px}
.view-head-t .lede{margin:0}
.view-head-a{flex:0 0 auto;display:flex;gap:8px;align-items:center;padding-top:4px}
.back-btn{flex:0 0 auto;width:40px;height:40px;margin:-4px 0 0 -8px;border:0;border-radius:10px;
  background:none;color:var(--datum);cursor:pointer;display:grid;place-items:center;
  -webkit-tap-highlight-color:transparent}
.back-btn svg{width:26px;height:26px;fill:currentColor}
.back-btn:active{background:var(--panel-2)}
@media (min-width:900px){ .back-btn[data-goto="map"]{display:none} .view-head-t{padding-left:0} }
.view-head-wrap{padding-top:18px}
@media (max-width:899px){ .view-head-wrap{padding-left:14px;padding-right:14px} }

/* A dialog in the app's own clothes. */
.app-dialog{max-width:min(560px,calc(100vw - 24px));width:100%;border:1px solid var(--line);border-radius:14px;
  background:var(--panel);color:var(--ink);padding:20px;box-sizing:border-box;margin:auto}
.app-dialog::backdrop{background:var(--scrim);backdrop-filter:blur(3px)}
.app-dialog h2{font-size:1.15rem;margin:0 0 8px}
.app-dialog h3{margin:16px 0 6px}
.app-dialog input[type=password],.app-dialog input:not([type]){width:100%;padding:11px 13px;border-radius:8px;
  border:1px solid var(--line);background:var(--ground);color:var(--ink);font-size:15px;box-sizing:border-box}
.app-dialog .row-btns{margin-top:14px}
@media (max-width:520px){
  .app-dialog{position:fixed;inset:auto 0 0 0;max-width:none;border-radius:16px 16px 0 0;
    max-height:calc(100vh - 40px);overflow:auto;padding-bottom:calc(20px + var(--safe-b))}
}

/* The AI agreement (aiconsent.js): which features, and the ID-document line. */
.aiconsent-list{margin:0 0 10px;padding-left:20px;line-height:1.55}
.aiconsent-id{border-left:3px solid var(--warn);padding:6px 10px;border-radius:0 8px 8px 0;
  background:color-mix(in srgb,var(--warn) 12%,transparent)}

/* Ask.confirm / Ask.text (dialog.js): the app's own question box, in place
   of the browser's confirm() and prompt(). */
.app-dialog.ask{max-width:min(420px,calc(100vw - 24px));padding:22px 22px 18px;box-shadow:0 18px 48px -16px var(--shadow)}
.ask h2{font-size:1.12rem;line-height:1.35;margin:0 0 10px}
.ask .ask-p{margin:0 0 8px;color:var(--ink-2);font-size:.94rem;line-height:1.5}
.ask .ask-input{width:100%;margin-top:6px;padding:12px 13px;border-radius:10px;border:1px solid var(--line);
  background:var(--ground);color:var(--ink);font-size:16px;box-sizing:border-box}
.ask .ask-input:focus{outline:2px solid var(--datum);outline-offset:1px;border-color:transparent}
.ask-btns{display:flex;gap:10px;justify-content:flex-end;margin-top:18px}
.ask-btns .btn{min-height:44px;padding:0 18px;border-radius:10px;font:inherit;font-size:15px}
.ask-btns .btn.ask-danger{background:var(--magenta);border-color:var(--magenta);color:var(--on-magenta);font-weight:600}
@media (max-width:520px){
  .app-dialog.ask{max-width:none;padding:26px 18px calc(16px + var(--safe-b))}
  .app-dialog.ask::before{content:"";position:absolute;top:8px;left:50%;width:36px;height:4px;margin-left:-18px;
    border-radius:2px;background:var(--line)}
  .ask-btns{flex-direction:column-reverse;gap:8px}
  .ask-btns .btn{width:100%;min-height:48px}
}

/* The nav badge: unread notices. */
.navbtn{position:relative}
.nav-badge{position:absolute;top:8px;left:calc(50% + 6px);min-width:17px;height:17px;padding:0 5px;border-radius:9px;
  background:var(--magenta);color:var(--on-magenta);font-size:10.5px;font-weight:700;line-height:17px;text-align:center;
  font-style:normal}
/* Eight items on a narrow phone: smaller type, tighter letters, same targets. */
@media (max-width:430px){ .navbtn{font-size:10px;letter-spacing:0;gap:2px} .navbtn svg{width:21px;height:21px} }
@media (max-width:359px){ .navbtn span{display:none} .navbtn svg{width:24px;height:24px} }

/* ---------------- Family ---------------- */
.fam-group{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:16px;margin:0 0 16px}
.fam-group-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;flex-wrap:wrap;margin-bottom:12px}
.fam-group-t h2{font-size:1.15rem;margin:0}
.fam-group-t .fine{display:block;margin:2px 0 0}
.fam-key{display:inline-flex;align-items:center;gap:6px;font-size:.78rem;padding:5px 10px;border-radius:999px;
  border:1px solid var(--line);color:var(--ink-2);white-space:nowrap}
.fam-key svg{width:14px;height:14px;fill:currentColor}
.fam-key.is-ok{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 40%,transparent);background:color-mix(in srgb,var(--ok) 8%,transparent)}
.fam-key.is-off{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 40%,transparent);background:color-mix(in srgb,var(--warn) 8%,transparent)}
.fam-unlock{background:var(--panel-2);border:1px solid color-mix(in srgb,var(--warn) 35%,transparent);border-left:3px solid var(--warn);
  border-radius:10px;padding:14px;margin:0 0 14px}
.fam-unlock h3{margin:0 0 4px}
.fam-unlock .fine{margin:0 0 10px}
.fam-row{display:flex;gap:8px;align-items:center;margin:0}
.fam-row input{flex:1 1 auto;min-width:0;padding:11px 12px;border-radius:8px;border:1px solid var(--line);
  background:var(--ground);color:var(--ink);font-size:15px}
.fam-paste{margin-top:10px}
.fam-paste summary{cursor:pointer;color:var(--datum);font-size:.9rem}
.fam-paste .fam-row{margin-top:8px}
.fam-backup{display:flex;gap:12px;align-items:center;background:var(--panel-2);border:1px solid var(--line);
  border-radius:10px;padding:12px 14px;margin:0 0 14px}
.fam-backup>div{flex:1 1 auto;min-width:0}
.fam-backup .fine{margin:2px 0 0}
.fam-backup-ok{color:var(--ok);margin:0}
.fam-members{display:flex;flex-direction:column;gap:10px}
.fam-none{padding:10px 0}
.fam-member{display:grid;grid-template-columns:44px 1fr;gap:12px;align-items:start;background:var(--ground);
  border:1px solid var(--line);border-radius:12px;padding:12px}
.fam-member.is-off{opacity:.65}
.fam-avatar{width:44px;height:44px;border-radius:50%;display:grid;place-items:center;font-weight:700;font-size:1.1rem;
  background:hsl(var(--h) 45% 32%);color:#fff;border:2px solid hsl(var(--h) 55% 55%)}
.fam-main{min-width:0}
.fam-line{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.fam-name{font-size:1.02rem}
.fam-pill{font-size:.72rem;padding:2px 8px;border-radius:999px;border:1px solid;text-transform:uppercase;letter-spacing:.06em}
.fam-pill.is-ok{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 50%,transparent)}
.fam-pill.is-warn{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 50%,transparent)}
.fam-pill.is-off{color:var(--ink-3);border-color:var(--line)}
.fam-meta{display:flex;gap:12px;flex-wrap:wrap;align-items:center;font-size:.82rem;color:var(--ink-3);margin-top:3px}
.fam-bat{display:inline-flex;align-items:center;gap:6px}
.fam-bat b{display:inline-block;width:26px;height:11px;border:1px solid var(--ink-3);border-radius:3px;position:relative;padding:1px}
.fam-bat b::after{content:"";position:absolute;right:-4px;top:3px;width:2px;height:5px;background:var(--ink-3);border-radius:1px}
.fam-bat i{display:block;height:100%;background:var(--ok);border-radius:1px}
.fam-bat.is-low i{background:var(--magenta)}
.fam-model{opacity:.8}
.fam-protect{display:inline-flex;align-items:center;gap:4px}
.fam-protect svg{width:13px;height:13px;fill:currentColor}
.fam-protect.is-on{color:var(--ok)}
.fam-protect.is-locked{color:var(--datum)}
.fam-protect.is-off{color:var(--ink-3)}
.fam-protect-state{display:flex;align-items:center;gap:8px;margin:2px 0 12px;padding:10px 12px;
  border:1px solid var(--line);border-radius:10px;background:var(--panel-2);font-size:.9rem;color:var(--ink-2)}
.fam-protect-state svg{width:20px;height:20px;fill:currentColor;flex:0 0 auto}
.fam-protect-state.is-on{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 40%,transparent)}
.fam-protect-state.is-locked{color:var(--datum);border-color:color-mix(in srgb,var(--datum) 40%,transparent)}
.fam-protect-state.is-off{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 40%,transparent)}
.fam-steps{margin:4px 0 12px;padding-left:20px;font-size:.86rem;color:var(--ink-2);line-height:1.5}
.fam-steps li{margin:5px 0}
.fam-input{width:100%;margin:8px 0 0;padding:11px 12px;border:1px solid var(--line);border-radius:10px;
  background:var(--panel-2);color:var(--ink);font:15px/1.4 var(--font)}
.fam-input:focus{outline:none;border-color:color-mix(in srgb,var(--datum) 55%,transparent)}
.btn.is-danger{color:var(--magenta);border-color:color-mix(in srgb,var(--magenta) 45%,transparent)}
.fam-code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:2.4rem;
  font-weight:700;letter-spacing:.12em;text-align:center;color:var(--ink);margin:10px 0 8px;
  font-variant-numeric:tabular-nums}
.fam-code-bar{height:4px;border-radius:999px;background:var(--panel-2);overflow:hidden;margin:0 0 6px}
.fam-code-bar i{display:block;height:100%;width:100%;background:var(--datum);
  transition:width 1s linear}
.fam-guard-phones{margin:6px 0 12px;padding-left:18px;font-size:13.5px;line-height:1.45;color:var(--ink-2)}
.fam-guard-phones li{margin:4px 0}
.fam-guard-phones li.is-warn{color:var(--warn)}
.fam-where{font-size:.88rem;color:var(--ink-2);margin-top:6px;font-variant-numeric:tabular-nums;line-height:1.45}
.fam-place{color:var(--ink)}
.fam-dist{color:var(--datum)}
.fam-acts{grid-column:1 / -1;display:grid;grid-template-columns:repeat(auto-fit,minmax(48px,1fr));gap:6px;margin-top:2px}
.fam-act{min-width:0;display:flex;flex-direction:column;align-items:center;gap:3px;padding:8px 6px;
  border:1px solid var(--line);border-radius:10px;background:var(--panel);color:var(--ink-2);cursor:pointer;
  font-size:.74rem;-webkit-tap-highlight-color:transparent}
.fam-act svg{width:20px;height:20px;fill:currentColor}
.fam-act.is-primary{color:var(--datum);border-color:color-mix(in srgb,var(--datum) 45%,transparent)}
.fam-act:active{background:var(--panel-2)}
.fam-act[disabled]{opacity:.5}
.fam-group-foot{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:14px}
.fam-group-foot .btn svg{width:16px;height:16px;fill:currentColor;vertical-align:-3px}
.fam-foot{margin-top:6px}
.fam-empty{text-align:center;padding:36px 16px;border:1px dashed var(--line);border-radius:14px}
.fam-empty-ico{width:44px;height:44px;fill:var(--ink-3);margin-bottom:6px}
.fam-empty h3{margin:0 0 6px}
.fam-empty .fine{max-width:44ch;margin:0 auto 16px}
.fam-menu{display:flex;flex-direction:column;gap:6px;margin:12px 0}
.fam-mi{display:flex;gap:12px;align-items:center;text-align:left;padding:11px 12px;border:1px solid var(--line);
  border-radius:10px;background:var(--panel-2);color:var(--ink);cursor:pointer;font:inherit}
.fam-mi svg{width:20px;height:20px;fill:var(--ink-2);flex:0 0 auto}
.fam-mi b{display:block;font-weight:600}
.fam-mi i{display:block;font-style:normal;font-size:.82rem;color:var(--ink-3)}
.fam-mi.is-danger{color:var(--magenta)} .fam-mi.is-danger svg{fill:var(--magenta)}
.fam-key-code{display:block;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;word-break:break-all;
  padding:12px;border:1px solid var(--line);border-radius:8px;background:var(--ground);margin:12px 0}
.fam-code{width:100%;box-sizing:border-box;font-family:ui-monospace,monospace;font-size:12px;word-break:break-all;
  padding:10px;border:1px solid var(--line);border-radius:8px;background:var(--ground);color:var(--ink);margin:8px 0}
.fam-steps{padding-left:20px;margin:6px 0 10px;color:var(--ink-2);font-size:.92rem}
.fam-qr-wrap{display:flex;justify-content:center;margin:12px 0 6px}
.fam-qr{width:min(320px,74vw);height:auto;image-rendering:pixelated;background:#fff;padding:12px;border-radius:12px}
.fam-qr.fam-qr-sm{width:min(200px,56vw)}
.fam-qr-label{margin:16px 0 0;font-weight:600;text-align:center}
.fam-hist{max-height:42vh;overflow-y:auto;border:1px solid var(--line);border-radius:10px;margin:8px 0 14px;background:var(--ground)}
.fam-hist-row{display:flex;gap:12px;padding:7px 10px;font-size:13.5px;border-bottom:1px solid var(--line);align-items:center}
.fam-hist-row:last-child{border-bottom:0}
.fam-hist-t{flex:0 0 100px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.fam-hist-p{flex:1;background:none;border:0;color:var(--datum);text-align:left;padding:0;cursor:pointer;font:inherit;font-variant-numeric:tabular-nums}
span.fam-hist-p{color:var(--ink-2)}
.fam-hist-n+.fam-hist-t{flex-basis:128px}
.fam-hist-head{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}
.fam-hist-head h3{margin:0}
.fam-hist-day{padding:8px 10px 3px;font-size:12px;font-weight:700;color:var(--ink-2);border-bottom:1px solid var(--line)}
.fam-hist-leg{padding:3px 10px 3px 44px;font-size:12px;color:var(--ink-3);border-bottom:1px solid var(--line)}
.fam-hist-n{flex:0 0 22px;height:22px;border-radius:50%;display:grid;place-items:center;font-size:11.5px;font-weight:800;
  color:var(--magenta);border:2px solid var(--magenta);box-sizing:border-box}

/* ---------------- Agents hub ---------------- */
.ag-sub{display:none} .ag-sub.is-on{display:block}
.ag-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:12px}
.ag-card{display:flex;flex-direction:column;align-items:flex-start;gap:8px;text-align:left;padding:16px;
  background:var(--panel);border:1px solid var(--line);border-radius:14px;color:var(--ink);cursor:pointer;font:inherit;
  -webkit-tap-highlight-color:transparent;position:relative}
.ag-card:active{background:var(--panel-2)}
.ag-ico{width:40px;height:40px;border-radius:11px;display:grid;place-items:center}
.ag-ico svg{width:22px;height:22px;fill:currentColor}
.ag-ico-notice{background:color-mix(in srgb,var(--magenta) 14%,transparent);color:var(--magenta)}
.ag-ico-voice{background:color-mix(in srgb,var(--datum) 14%,transparent);color:var(--datum)}
.ag-ico-plan{background:color-mix(in srgb,var(--ok) 14%,transparent);color:var(--ok)}
.ag-ico-watch{background:color-mix(in srgb,var(--warn) 14%,transparent);color:var(--warn)}
.ag-ico-camera{background:color-mix(in srgb,var(--orange) 14%,transparent);color:var(--orange)}
/* The Camera agent: two big doors, stacked, each a whole-card tap target. */
.cam-pick{display:grid;gap:12px;max-width:560px}
.cam-opt{display:grid;grid-template-columns:40px 1fr;gap:4px 14px;align-items:start;text-align:left;padding:16px;min-height:88px;
  background:var(--panel);border:1px solid var(--line);border-radius:14px;color:var(--ink);cursor:pointer;font:inherit;
  -webkit-tap-highlight-color:transparent}
.cam-opt[hidden]{display:none}
.cam-opt .ag-ico{grid-row:1/3}
.cam-opt-t{font-weight:600;font-size:1.02rem;align-self:center}
.cam-opt:active{background:var(--panel-2)}
.cam-opt:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.ag-t{font-weight:600;font-size:1.02rem;display:flex;align-items:center;gap:8px}
.ag-count{min-width:20px;height:20px;padding:0 6px;border-radius:10px;background:var(--magenta);color:var(--on-magenta);font-size:11px;
  font-weight:700;line-height:20px;text-align:center}
.ag-d{font-size:.86rem;color:var(--ink-2);line-height:1.4}
#ag-hub-foot{margin-top:18px}
.ag-empty{border:1px dashed var(--line);border-radius:12px;padding:18px;text-align:center}
.ag-empty p{margin:0 0 12px;color:var(--ink-2)}
.ag-sys{margin:0 0 16px;padding:12px 14px;background:var(--panel);border:1px solid var(--line);border-radius:12px}
.ag-sys .fine{display:block}

/* One verified item. The quote is the point; the summary is the model's
   restatement of it, and the source is where to check. */
.ag-item{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--ink-3);border-radius:12px;
  padding:12px 14px;margin:0 0 10px}
.ag-item.is-urgent{border-left-color:var(--magenta)}
.ag-item.is-warn{border-left-color:var(--warn)}
.ag-item.is-note{border-left-color:var(--datum)}
.ag-item.is-good{border-left-color:var(--ok)}
.ag-item.is-focus{box-shadow:0 0 0 2px var(--datum)}
.ag-item-h{display:flex;gap:10px;align-items:flex-start}
.ag-item-ico{font-size:1.25rem;line-height:1.2;flex:0 0 auto}
.ag-item-t{min-width:0}
.ag-item-t strong{display:block;font-size:1rem;line-height:1.3}
.ag-item-t .fine{display:block;margin:1px 0 0}
.ag-item-s{margin:8px 0 6px;color:var(--ink-2);font-size:.93rem;line-height:1.5}
.ag-quote{margin:0 0 8px;padding:8px 12px;border-left:2px solid var(--line);background:var(--ground);border-radius:0 8px 8px 0;
  font-size:.86rem;color:var(--ink-2);font-style:italic;line-height:1.45}
.ag-src{display:flex;gap:8px;align-items:baseline;flex-wrap:wrap;font-size:.82rem}
.ag-src-a{color:var(--datum);text-decoration:none;word-break:break-all}
.ag-src-a:hover{text-decoration:underline}
.ag-src-t{margin:0;flex:1 1 100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ag-trust{font-size:.66rem;text-transform:uppercase;letter-spacing:.08em;padding:1px 6px;border-radius:3px;font-weight:600}
.ag-trust.is-official{background:color-mix(in srgb,var(--ok) 16%,transparent);color:var(--ok)}
.ag-trust.is-press{background:color-mix(in srgb,var(--datum) 16%,transparent);color:var(--datum)}
.ag-trust.is-web,.ag-trust.is-model{background:var(--panel-2);color:var(--ink-3)}
.ag-item .row-btns{margin-top:10px}
/* Notices: a short card, the rest behind Read more. */
.ag-item{cursor:pointer}
.ag-item-s{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.ag-more{display:flex;justify-content:space-between;align-items:baseline;width:100%;margin:2px 0 0;padding:6px 0 0;
  background:none;border:0;border-top:1px solid var(--line);color:var(--datum);font:inherit;font-size:.86rem;
  font-weight:600;cursor:pointer;text-align:left}
.ag-more .fine{font-weight:400}
.nt-showall{margin:4px 0 12px}
.nt-detail{padding:0 20px 18px}
.nt-d-head{position:sticky;top:0;z-index:1;display:flex;align-items:flex-start;gap:8px;margin:0 -20px 10px;
  padding:14px 8px 10px 20px;background:var(--panel);border-bottom:1px solid var(--line)}
.nt-d-head h2{flex:1 1 auto;min-width:0;margin:8px 0 0;font-size:1.1rem;line-height:1.35;outline:none}
.nt-d-chips{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 4px}
.nt-chip{font-size:.8rem;padding:3px 9px;border-radius:999px;border:1px solid var(--line);color:var(--ink-2);background:var(--panel-2)}
.nt-chip.is-urgent{border-color:var(--magenta);color:var(--magenta);background:color-mix(in srgb,var(--magenta) 12%,transparent)}
.nt-chip.is-warn{border-color:var(--warn);color:var(--warn);background:color-mix(in srgb,var(--warn) 12%,transparent)}
.nt-chip.is-good{border-color:var(--ok);color:var(--ok);background:color-mix(in srgb,var(--ok) 12%,transparent)}
.nt-d-sec h3{margin:16px 0 4px;font-size:.72rem;text-transform:uppercase;letter-spacing:.09em;color:var(--ink-3)}
.nt-d-sec p{margin:0 0 6px;line-height:1.55}
.nt-d-do{padding:8px 12px;border-radius:8px;background:color-mix(in srgb,var(--datum) 10%,transparent)}
.nt-d-facts{margin:0;padding-left:20px;line-height:1.55}
.nt-d-srcs{display:flex;flex-direction:column;gap:6px}
.nt-d-src{border:1px solid var(--line);border-radius:8px;padding:6px 10px}
.nt-d-src summary{display:flex;gap:8px;align-items:center;cursor:pointer;font-size:.86rem}
.nt-d-src[open] summary{margin-bottom:8px}
.nt-d-host{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nt-d-src .ag-src-a{display:block;font-size:.82rem;margin:0 0 4px}
.nt-detail > .nt-d-srcs{margin:14px 0 0}
.nt-vote{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:14px 0 0;padding:10px 0 0;border-top:1px solid var(--line)}

/* The live block on the SOS card and the Brief. */
.ag-live{margin:0 0 20px}
.ag-govs{margin:0 0 14px}
.ag-govs-h{margin:0 0 6px;font-size:.95rem}
.ag-gov{display:flex;gap:10px;align-items:flex-start;padding:9px 10px;margin:0 0 6px;border:1px solid var(--line);border-radius:10px;background:var(--panel);color:inherit;text-decoration:none}
.ag-gov.is-home{border-color:color-mix(in srgb,var(--datum) 55%,var(--line));background:color-mix(in srgb,var(--datum) 7%,var(--panel))}
.ag-gov .lv-dot{margin-top:6px;flex:0 0 auto}
.ag-gov.is-urgent .lv-dot{background:var(--bad)} .ag-gov.is-warn .lv-dot{background:var(--warn)} .ag-gov.is-good .lv-dot{background:var(--ok)}
.ag-gov-t{display:grid;gap:2px;min-width:0}
.ag-gov-s{display:block}
.ag-govs-f{margin:4px 0 0}
.ag-live-h{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;margin-bottom:10px}
.ag-live-h h3{margin:0}
.ag-live-st{display:block;margin:2px 0 0}
.ag-live-st.is-run{color:var(--datum)} .ag-live-st.is-warn{color:var(--warn)} .ag-live-st.is-ok{color:var(--ink-3)}
.ag-live-f{margin-top:4px}
/* Live checks list: SOS + here open on top, the rest folded. */
.ag-watch-bar{display:flex;justify-content:flex-end;margin:0 0 12px}
.ag-watch-h{margin:8px 0 8px}
.ag-watch-row{border-top:1px solid var(--line);padding:0}
.ag-watch-row:last-child{border-bottom:1px solid var(--line)}
.ag-watch-row>summary{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:10px 0;cursor:pointer;list-style:none;min-height:44px}
.ag-watch-row>summary::-webkit-details-marker{display:none}
.ag-watch-t{display:flex;flex-direction:column;min-width:0}
.ag-watch-t b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ag-watch-row.is-warn .ag-watch-t .fine{color:var(--warn)}
.ag-watch-b{padding:4px 0 6px}
.ag-watch-f{margin-top:14px}
.brief-live{margin:0 0 18px}
.sos-live-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--magenta);margin-left:5px;vertical-align:1px}

/* ---------------- Notices (the cards at the top) ---------------- */
/* The top stack (index.html #topstack): notifications off, offline, the pill
   and the notice cards, one under the other in that order. They used to be
   placed one by one, each at its own fixed offset, and so landed on the
   search box and on each other. Off the map it is fixed at the top; on the
   map notify.js moves it into #view-map, where it sits under the search box
   and lines up with it. */
#topstack{position:fixed;left:50%;transform:translateX(-50%);top:calc(env(safe-area-inset-top,0px) + 10px);
  width:min(520px,calc(100% - 20px));z-index:70;display:flex;flex-direction:column;align-items:center;gap:8px;
  pointer-events:none;transition:opacity .15s ease}
#topstack > *{pointer-events:auto}
#view-map > #topstack{position:absolute;top:62px;z-index:8;width:min(520px,calc(100% - 24px))}
/* Phone and tablet: from the search box's left edge to the round buttons on
   the right (#mapquick, 14px in and ~56px wide), which stay tappable. */
@media (max-width:899px){ #view-map > #topstack{left:calc(12px + env(safe-area-inset-left,0px));transform:none;
  width:min(520px,calc(100% - 24px - 70px - env(safe-area-inset-left,0px) - env(safe-area-inset-right,0px)))} }
@media (min-width:900px){ #view-map > #topstack{transform:none;width:min(420px,calc(100% - 510px));
  left:calc((100% - 486px - min(420px,calc(100% - 510px))) / 2)} }
/* Typing a search: the suggestions open under the box, exactly where the
   stack is. Out of the way until the search is done. */
#view-map:has(#searchwrap:focus-within) > #topstack,
#view-map:has(#place-results:not([hidden])) > #topstack{opacity:0;visibility:hidden}
#notices{display:flex;flex-direction:column;gap:8px;width:100%;pointer-events:none}
/* The order is fixed here, not by who was appended first. */
#topstack > .app-bar-warn{order:1} #topstack > .net-bar{order:2} #topstack > .wf-pill{order:3} #topstack > #notices{order:4}
#notices:empty{display:none}
.ntc{pointer-events:auto;display:grid;grid-template-columns:auto 1fr auto;gap:10px;align-items:start;
  background:color-mix(in srgb,var(--panel) 96%,transparent);backdrop-filter:blur(10px);border:1px solid var(--line);border-left:4px solid var(--datum);
  border-radius:12px;padding:10px 8px 10px 12px;box-shadow:0 10px 30px color-mix(in srgb,var(--shadow) 45%,transparent);
  opacity:0;transform:translateY(-14px);transition:opacity .22s ease,transform .22s ease;touch-action:pan-y}
.ntc.is-in{opacity:1;transform:none}
.ntc.is-urgent{border-left-color:var(--magenta)} .ntc.is-warn{border-left-color:var(--warn)} .ntc.is-good{border-left-color:var(--ok)}
.ntc-ico{font-size:1.3rem;line-height:1.2;padding-top:1px}
.ntc-t{background:none;border:0;padding:0;text-align:left;color:var(--ink);cursor:pointer;font:inherit;min-width:0}
.ntc-t strong{display:block;font-size:.95rem;line-height:1.3}
.ntc-t span{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:.84rem;color:var(--ink-2);margin-top:2px}
.ntc-t i{display:block;font-style:normal;font-size:.74rem;color:var(--ink-3);margin-top:3px}
.ntc-x{width:36px;height:36px;border:0;background:none;color:var(--ink-3);font-size:22px;line-height:1;cursor:pointer;border-radius:8px;margin:-4px -2px 0 0}
.ntc-x:active{background:var(--panel-2)}
/* The pill: one line for everything around you, replacing a stack of cards. */
.wf-pill{position:relative;
  display:none;align-items:center;gap:8px;max-width:100%;padding:7px 14px;border-radius:999px;
  border:1px solid var(--line);background:color-mix(in srgb,var(--panel) 94%,transparent);backdrop-filter:blur(10px);
  color:var(--ink);font:inherit;font-size:.84rem;cursor:pointer;box-shadow:0 6px 20px color-mix(in srgb,var(--shadow) 35%,transparent);
  transition:transform .25s ease}
html[data-view="map"] .wf-pill:not([hidden]){display:inline-flex}
.wf-pill-t{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.wf-pill-dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto;background:var(--ink-3)}
.wf-pill.is-heads{border-color:var(--warn)} .wf-pill.is-heads .wf-pill-dot{background:var(--warn)}
.wf-pill.is-alert{border-color:var(--magenta)} .wf-pill.is-alert .wf-pill-dot{background:var(--magenta)}
.wf-pill:not(.is-new) .wf-pill-dot{opacity:.45}
.wf-pill.is-new.is-alert .wf-pill-dot{animation:wf-pulse 1.4s ease-in-out infinite}
.wf-pill.is-bump{transform:scale(1.08)}
@keyframes wf-pulse{50%{box-shadow:0 0 0 6px color-mix(in srgb,var(--magenta) 0%,transparent),0 0 0 0 var(--magenta)}}
/* Banners sit under the pill in the stack, so the summary line is never
   covered and a heads-up visibly folds up into it. */
.nt-tabs{margin:4px 0 12px}
.nt-place{display:flex;flex-direction:column;align-items:flex-start;gap:1px;width:100%;text-align:left;background:none;border:0;
  border-top:1px solid var(--line);padding:8px 2px;color:var(--ink);font:inherit;cursor:pointer}
.nt-settings{margin:16px 0 8px;border-top:1px solid var(--line);padding-top:10px}
.nt-settings summary{cursor:pointer;color:var(--ink-2);font-size:.9rem}
.nt-set{display:flex;flex-direction:column;gap:6px;padding-top:8px}
.nt-set-h{margin-top:6px}
.nt-kinds{display:flex;flex-wrap:wrap;gap:6px}
.ntc-more{pointer-events:auto;align-self:center;border:1px solid var(--line);background:var(--panel);color:var(--ink-2);
  border-radius:999px;padding:4px 12px;font-size:.8rem;cursor:pointer}

/* ---------------- Interpreter ---------------- */
.vc-langs{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:8px;align-items:center;margin-bottom:14px}
.vc-sel,.vc-who,.pl-form select{width:100%;padding:10px 12px;border-radius:8px;border:1px solid var(--line);background:var(--ground);color:var(--ink);font-size:14px}
.vc-swap{width:42px;height:42px;border-radius:50%;border:1px solid var(--line);background:var(--panel);color:var(--datum);font-size:20px;cursor:pointer}
.vc-nosr{margin:0 0 12px;padding:10px 12px;border:1px solid color-mix(in srgb,var(--warn) 35%,transparent);border-radius:8px;color:var(--warn)}
.vc-btns{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:10px}
.vc-btn{display:flex;flex-direction:column;align-items:center;gap:4px;padding:18px 10px;border-radius:16px;border:2px solid var(--line);
  background:var(--panel);color:var(--ink);cursor:pointer;font:inherit;-webkit-tap-highlight-color:transparent;transition:border-color .15s,background .15s}
.vc-btn .vc-mic{font-size:1.9rem}
.vc-btn strong{font-size:1.05rem}
.vc-btn .fine{margin:0;text-align:center}
.vc-btn.is-me{border-color:color-mix(in srgb,var(--datum) 50%,transparent)} .vc-btn.is-them{border-color:color-mix(in srgb,var(--magenta) 50%,transparent)}
.vc-btn.is-on{background:color-mix(in srgb,var(--datum) 16%,transparent);border-color:var(--datum);animation:vc-pulse 1.2s ease-in-out infinite}
.vc-btn.is-them.is-on{background:color-mix(in srgb,var(--magenta) 16%,transparent);border-color:var(--magenta)}
.vc-btn[disabled]{opacity:.45;cursor:default}
@keyframes vc-pulse{0%,100%{box-shadow:0 0 0 0 color-mix(in srgb,var(--datum) 35%,transparent)}50%{box-shadow:0 0 0 10px color-mix(in srgb,var(--datum) 0%,transparent)}}
.vc-live{padding:10px 14px;border-radius:10px;background:var(--panel-2);color:var(--ink);font-size:1.05rem;margin-bottom:10px;min-height:44px}
.vc-opts{display:flex;flex-direction:column;gap:6px;margin:6px 0 12px}
.vc-voices{display:flex;flex-direction:column;gap:8px;padding:8px 0 2px}
.vc-voices:empty{display:none}
.sp-pace{align-self:flex-start}
.vc-check{display:flex;gap:9px;align-items:center;font-size:.88rem;color:var(--ink-2);text-transform:none;letter-spacing:0;margin:0}
.vc-check input{width:17px;height:17px;accent-color:var(--datum);margin:0}
.vc-form{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:8px;align-items:center;margin-bottom:16px}
/* The companion's round button docks bottom-right on a phone, which on a
   667–740px-tall screen is exactly where these rows land: the Interpreter's
   Translate was half under it, so was Scam check's Check and the right-hand
   chips of Plan it with AI (measured 2026-10-05). Each keeps 70px clear on
   the right until the button has been dragged elsewhere. The Interpreter's
   three-up row would have squeezed its text box to a sliver, so there the
   button takes its own line on the left instead. */
@media (max-width:899px){
  html:not(:has(#ai-fab.is-moved)) :is(.vc-form,.sc-acts,.pl-chips){padding-right:70px}
  .vc-form{grid-template-columns:auto minmax(0,1fr)}
  .vc-form .btn{grid-column:1 / -1;justify-self:start;min-width:9em}
}
.vc-form input{width:100%;padding:11px 12px;border-radius:8px;border:1px solid var(--line);background:var(--ground);color:var(--ink);font-size:15px;font-family:inherit;box-sizing:border-box}
.vc-who{width:auto}
.vc-log{display:flex;flex-direction:column;gap:10px}
.vc-hint{text-align:center;padding:16px 0}
.vc-msg{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:12px 14px;border-left:4px solid var(--datum)}
.vc-msg.is-them{border-left-color:var(--magenta)}
.vc-heard{color:var(--ink-3);font-size:.9rem;margin-bottom:6px}
.vc-tag{font-size:.72rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--datum);margin-bottom:2px}
.vc-msg.is-them .vc-tag{color:var(--magenta)}
.vc-msg .vc-tag.vc-into{color:var(--ink-3)}
.vc-pause{display:flex;flex-direction:column;gap:6px;margin-top:4px}
.vc-pause label{margin:0;font-size:.95rem;color:var(--ink-2);text-transform:none;letter-spacing:normal}
.vc-said{font-size:1.45rem;line-height:1.35;color:var(--ink)}
.vc-roman{color:var(--ink-2);font-size:.95rem;margin-top:3px}
.vc-err{color:var(--magenta);font-size:.9rem}
.vc-row{display:flex;gap:8px;margin-top:10px}
.vc-big{position:fixed;inset:0;z-index:90;background:var(--ground);display:flex;flex-direction:column;align-items:center;justify-content:center;
  padding:24px;text-align:center;cursor:pointer}
.vc-big-t{font-size:clamp(2rem,9vw,4.2rem);line-height:1.2;color:var(--ink);word-break:break-word}
.vc-big-r{font-size:clamp(1rem,4vw,1.6rem);color:var(--ink-2);margin-top:14px}

/* ---------------- Trip planner ---------------- */
.pl-form{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:14px 16px 16px;margin-bottom:18px}
.pl-form label:first-child{margin-top:0}
.pl-place{position:relative;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.pl-place input{flex:1 1 200px;min-width:0;padding:11px 12px;border-radius:8px;border:1px solid var(--line);background:var(--ground);color:var(--ink);font-size:15px;font-family:inherit;box-sizing:border-box}
.pl-place .suggest-box{top:calc(100% + 4px)}
.pl-form .fine{margin:6px 0 0}
.pl-row{display:grid;grid-template-columns:minmax(0,1.6fr) minmax(0,1fr);gap:10px}
.pl-row>*{min-width:0}
.pl-row-3{grid-template-columns:repeat(3,minmax(0,1fr))}
@media (max-width:480px){ .pl-row-3{grid-template-columns:1fr} }
.pl-biz input[type=text]{width:100%;padding:10px 12px;border-radius:8px;border:1px solid var(--line);background:var(--ground);color:var(--ink);font-size:14px;font-family:inherit;box-sizing:border-box}
.pl-row-2{grid-template-columns:repeat(2,minmax(0,1fr))}
.pl-form input[type=date],.pl-form input[type=number],.pl-form input[type=time]{width:100%;padding:10px 12px;border-radius:8px;border:1px solid var(--line);background:var(--ground);color:var(--ink);font-size:14px;font-family:inherit;box-sizing:border-box;color-scheme:var(--scheme,dark);display:block;min-width:0;max-width:100%;-webkit-appearance:none;appearance:none;min-height:42px}
.pl-form input[type=number]{-moz-appearance:textfield}
.pl-form input[type=date]::-webkit-date-and-time-value{text-align:left}
.pl-form textarea{width:100%;padding:10px 12px;border-radius:8px;border:1px solid var(--line);background:var(--ground);color:var(--ink);font-size:14px;font-family:inherit;box-sizing:border-box;resize:vertical}
.pl-stay-f{margin:10px 0 2px}
.pl-stay-f>label{display:block;margin-bottom:4px}
.pl-stay-f .fine{margin:4px 0 0}
.pl-stay-row{margin-bottom:8px}
.pl-stay-row .pl-stay-x{flex:none;padding:6px 10px;font-size:16px;line-height:1}
.pl-stay-nights{margin-top:6px}
.pl-stay-nights label{font-size:.78rem;color:var(--ink-3)}
.pl-stay-add{margin-top:2px}
.pl-stay-one{padding:8px 0 2px;border-top:1px solid color-mix(in srgb,var(--datum) 25%,var(--line))}
.pl-stay-one:first-of-type{border-top:0;padding-top:4px}
.pl-day-stay{display:block}
/* Where they stay: the fixed point of the plan, above the figures. */
.pl-stay{margin:0 0 12px;padding:12px 14px;border-radius:14px;border:1px solid color-mix(in srgb,var(--datum) 40%,var(--line));background:color-mix(in srgb,var(--datum) 8%,var(--panel))}
.pl-stay-h{display:flex;flex-direction:column;gap:2px;margin-bottom:6px}
.pl-stay-k{font-size:.72rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-3)}
.pl-stay-h strong{font-size:1.05rem}
.pl-stay-p{margin:0 0 8px;color:var(--ink-2)}
.pl-stay-facts{display:grid;grid-template-columns:auto 1fr;gap:4px 10px;margin:0 0 8px;font-size:.92rem}
.pl-stay-facts dt{color:var(--ink-3)}
.pl-stay-facts dd{margin:0}
.pl-stay-know{margin:0 0 8px;padding-left:18px;font-size:.92rem}
.pl-stay-chips{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 8px}
.pl-stay-chip{padding:3px 10px;border-radius:999px;font-size:.8rem;border:1px solid var(--line);color:var(--ink-2)}
.pl-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:12px}
.pl-chip{padding:7px 12px;border-radius:999px;border:1px solid var(--line);background:var(--ground);color:var(--ink-2);cursor:pointer;font-size:.86rem;font-family:inherit}
.pl-chip.is-on{background:color-mix(in srgb,var(--datum) 16%,transparent);border-color:var(--datum);color:var(--ink)}
.pl-chip.is-own{display:inline-flex;align-items:center;gap:6px;border-style:dashed}
.pl-chip-x{font-size:1rem;line-height:1;color:var(--ink-3)}
/* The form in sections: a small heading, a rule above each after the first. */
.pl-sec-h{display:flex;align-items:baseline;gap:10px;margin:18px 0 8px;padding-top:14px;border-top:1px solid var(--line);
  font-size:.76rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-3)}
.pl-form .pl-sec-h:first-child{margin-top:0;padding-top:0;border-top:0}
.pl-sec-h .pl-count{margin-left:auto;font-weight:400;letter-spacing:0;text-transform:none;color:var(--ink-3)}
.pl-more{margin:-4px 0 12px}
.pl-more>summary{cursor:pointer;color:var(--datum);font-size:.9rem;list-style:none;display:inline-flex;align-items:center;gap:6px;padding:4px 0}
.pl-more>summary::-webkit-details-marker{display:none}
.pl-more>summary::before{content:"▸";font-size:.8em;color:var(--ink-3);transition:transform .15s}
.pl-more[open]>summary::before{transform:rotate(90deg)}
.pl-group{margin:8px 0 0}
.pl-group-h{display:block;font-size:.78rem;color:var(--ink-3);margin:0 0 5px}
.pl-group .pl-chips{margin-bottom:6px}
.pl-own{display:flex;gap:8px;align-items:center;margin:10px 0 4px}
.pl-own input{flex:1 1 160px;min-width:0;padding:9px 12px;border-radius:8px;border:1px solid var(--line);background:var(--ground);color:var(--ink);font-size:14px;font-family:inherit;box-sizing:border-box}
/* "Anything else": grows with the text (plan.js sets the height), no drag
   handle — it does nothing on a phone. Starters above, the count and the
   tools below; the same box fills the full-screen sheet. */
.pl-form textarea,.pl-notes textarea{width:100%;padding:10px 12px;border-radius:8px;border:1px solid var(--line);background:var(--ground);color:var(--ink);font-size:14px;font-family:inherit;box-sizing:border-box;resize:none;line-height:1.45;display:block;min-height:0}
.pl-notes{margin:0 0 4px}
.pl-starters{margin-bottom:8px}
.pl-starters .pl-chip{border-style:dashed;font-size:.82rem;padding:5px 10px;color:var(--ink-3)}
.pl-starters .pl-chip:hover{color:var(--ink)}
.pl-notes-tools{display:flex;align-items:center;justify-content:flex-end;gap:8px;margin:6px 0 0;min-height:30px}
.pl-notes-tools .btn{display:inline-flex;align-items:center;gap:6px}
.pl-notes-count{margin-right:auto;font-size:.78rem;color:var(--ink-3);font-variant-numeric:tabular-nums}
.pl-notes-count.is-near{color:var(--warn);font-weight:600}
.pl-mic.is-on{color:var(--datum);border-color:var(--datum);background:color-mix(in srgb,var(--datum) 14%,transparent)}
.pl-mic.is-on svg{animation:pl-pulse 1.1s ease-in-out infinite}
@keyframes pl-pulse{0%,100%{opacity:1}50%{opacity:.35}}
.pl-notes-pop .pl-notes-big textarea{width:100%;padding:12px 14px;border-radius:10px;border:1px solid var(--line);background:var(--ground);color:var(--ink);font-size:16px;line-height:1.5;font-family:inherit;box-sizing:border-box;resize:none;display:block}
.pl-notes-pop .pl-notes-big{margin:0 0 12px}
.pl-notes-pop .btn.wide{width:100%;margin-top:4px}
/* Changing a plan after it is made: the ask box under the days, what
   changed, and a mark on every stop the change touched. */
.pl-revise{margin:18px 0 6px;padding:14px 14px 12px;border:1px solid var(--line);border-radius:14px;background:var(--panel)}
.pl-revise h3{margin:0 0 6px;font-size:1.02rem}
.pl-revise>.fine{margin:0 0 10px}
.pl-revise .pl-notes{margin:0}
.pl-revise-acts{margin-top:10px}
.pl-revise-done{margin:0 0 10px;padding:8px 10px;border-radius:10px;background:color-mix(in srgb,var(--ok) 12%,transparent);border:1px solid color-mix(in srgb,var(--ok) 40%,transparent)}
.pl-revise-done ul{margin:4px 0 0;padding-left:18px;font-size:.88rem;color:var(--ink-2)}
.pl-revise-note{margin:0;font-size:.92rem}
.pl-revise-big{margin:0 0 12px;padding:8px 10px;border-radius:10px;background:color-mix(in srgb,var(--warn) 12%,transparent);border:1px solid color-mix(in srgb,var(--warn) 40%,transparent)}
.pl-revise-big p{margin:0 0 6px}
.pl-changed{display:inline-block;margin-left:6px;padding:1px 7px;border-radius:999px;font-size:.7rem;font-weight:600;letter-spacing:.03em;text-transform:uppercase;
  color:var(--ok);background:color-mix(in srgb,var(--ok) 14%,transparent);vertical-align:middle}
.pl-item.is-changed{background:color-mix(in srgb,var(--ok) 6%,transparent);border-radius:8px;padding-left:4px;padding-right:4px}
.it-ask .pl-notes{margin:0 0 10px}
.it-ask-status{min-height:1.2em;margin:8px 0 0}
.pl-form .btn.wide{margin-top:16px}
.pl-progress{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:14px 16px;margin-bottom:16px}
.pl-progress h3{margin:0 0 8px}
.pl-trail{max-height:160px;overflow:auto;font-size:.84rem;color:var(--ink-3);border-left:2px solid var(--line);padding-left:10px;margin-bottom:10px}
.pl-trail>div{margin:2px 0}
.pl-think{color:var(--ink-2);font-style:italic}
.pl-prose{white-space:pre-wrap;color:var(--ink-2);font-size:.95rem}
.pl-head h2{margin:0 0 4px;font-size:1.15rem;line-height:1.3}
.pl-sub{margin:0;color:var(--ink-2);font-size:.92rem}
.pl-head .fine{margin:4px 0 0}
.pl-glance{margin:12px 0 10px;grid-template-columns:repeat(auto-fit,minmax(68px,1fr))}
.pl-acts{margin:0 0 12px}
.pl-acts .ui-more{margin-left:0}
/* The introduction: a few lines, then "Read more". */
.pl-intro{color:var(--ink-2);margin:0 0 12px;font-size:.95rem;line-height:1.5}
.pl-intro p{margin:0;white-space:pre-wrap}
.pl-intro.is-clamped p{display:-webkit-box;-webkit-line-clamp:4;line-clamp:4;-webkit-box-orient:vertical;overflow:hidden}
.pl-more-b{margin:4px 0 0;padding:0;border:0;background:none;color:var(--datum);font:inherit;font-size:.88rem;cursor:pointer}
/* Figures the lookups did not back up: a fold with a plain list. */
.pl-check{margin:0 0 14px;padding:10px 12px;border:1px solid color-mix(in srgb,var(--warn) 40%,transparent);border-radius:12px;background:color-mix(in srgb,var(--warn) 7%,transparent)}
.pl-check>summary{cursor:pointer;font-weight:600;color:var(--warn);list-style:none;display:flex;align-items:center;gap:8px}
.pl-check>summary::-webkit-details-marker{display:none}
.pl-check>summary::before{content:"!";flex:none;width:20px;height:20px;border-radius:50%;display:grid;place-items:center;font-size:.8rem;background:var(--warn);color:var(--on-accent)}
.pl-check .fine{margin:8px 0 4px}
.pl-check ul{margin:0;padding-left:20px;color:var(--ink);font-size:.9rem;display:grid;gap:3px}
.pl-check li.fine{list-style:none;margin-left:-20px}
/* Jump to a day. */
.pl-jump{display:flex;gap:6px;overflow-x:auto;scrollbar-width:none;margin:0 0 4px;padding:2px 0}
.pl-jump::-webkit-scrollbar{display:none}
.pl-jump-b{flex:none;display:flex;flex-direction:column;align-items:flex-start;gap:0;padding:6px 12px;border-radius:10px;border:1px solid var(--line);background:var(--panel);color:var(--ink);font:inherit;cursor:pointer;line-height:1.25}
.pl-jump-b strong{font-size:.86rem}
.pl-jump-b span{font-size:.74rem;color:var(--ink-3)}
.pl-day{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:12px 14px;margin:12px 0}
.pl-day-h{display:flex;align-items:flex-start;gap:10px;margin-bottom:6px}
.pl-day-t{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:1px}
.pl-day-h strong{font-size:1.02rem}
.pl-day-h .fine{margin:0}
.pl-day-h .btn{flex:none}
.pl-item{display:grid;grid-template-columns:48px 1fr;gap:10px;padding:10px 0;border-top:1px solid var(--line)}
.pl-item:first-of-type{border-top:0}
.pl-item.is-unverified{opacity:.75}
.pl-item.can-open{cursor:pointer}
.pl-time{font-family:ui-monospace,monospace;font-size:.86rem;color:var(--ink-3);padding-top:3px}
.pl-body{min-width:0}
.pl-name{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.pl-num{flex:none;width:20px;height:20px;border-radius:50%;display:grid;place-items:center;font-size:.72rem;font-weight:700;background:color-mix(in srgb,var(--datum) 16%,transparent);color:var(--datum)}
.pl-item.is-unverified .pl-num{background:var(--panel-2);color:var(--ink-3)}
.pl-name .is-link{color:var(--datum);cursor:pointer}
.pl-facts{display:block;margin:2px 0 0}
/* Why, two lines; the tip and the rest open on a tap. */
.pl-item.can-open:not(.is-open) .pl-why{display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.pl-item.can-open:not(.is-open) .pl-tip{display:none}
.pl-item.can-open .pl-body{position:relative;padding-right:22px}
.pl-item.can-open .pl-body::after{content:"▾";position:absolute;right:2px;top:2px;color:var(--ink-3);font-size:.9rem;transition:transform .15s}
.pl-item.can-open.is-open .pl-body::after{transform:rotate(180deg)}
.pl-tip-k{display:inline-block;margin-right:6px;padding:0 6px;border-radius:4px;font-size:.68rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;background:color-mix(in srgb,var(--datum) 14%,transparent)}
.pl-extras{display:grid;gap:10px;margin:14px 0}
.pl-extra{padding:10px 12px;border:1px solid var(--line);border-radius:12px;background:var(--panel-2)}
.pl-extra h3{margin:0 0 6px;font-size:.92rem}
.pl-extra ul{margin:0;padding-left:18px;font-size:.9rem;color:var(--ink-2);display:grid;gap:3px}
.pl-foot{margin:14px 0 4px}
.pl-book{font-size:.66rem;text-transform:uppercase;letter-spacing:.08em;padding:1px 6px;border-radius:3px;background:color-mix(in srgb,var(--magenta) 14%,transparent);color:var(--magenta);font-weight:600}
.pl-unv{font-size:.66rem;text-transform:uppercase;letter-spacing:.08em;padding:1px 6px;border-radius:3px;background:var(--panel-2);color:var(--ink-3);font-weight:600}
.pl-body .fine{display:block;margin:1px 0 0}
.pl-why{margin:5px 0 0;color:var(--ink-2);font-size:.9rem}
.pl-tip{margin:4px 0 0;color:var(--datum);font-size:.86rem}
.pl-marker{width:28px;height:28px;border-radius:50%;background:var(--datum);color:var(--on-accent);font-weight:700;font-size:13px;display:grid;place-items:center;border:2px solid #fff;box-shadow:0 2px 8px color-mix(in srgb,var(--shadow) 40%,transparent);cursor:pointer}
.pl-saved-h{margin:22px 0 8px}
.pl-saved{display:flex;gap:8px;align-items:center;background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:10px 12px;margin-bottom:8px}
.pl-saved-t{flex:1 1 auto;min-width:0;background:none;border:0;padding:0;text-align:left;color:var(--ink);cursor:pointer;font:inherit}
.pl-saved-t strong{display:block;line-height:1.3}
.pl-saved-t .fine{display:block;margin:1px 0 0}
/* An earlier plan: a card, the actions on their own row under the title. */
.pl-saved.is-card{flex-direction:column;align-items:stretch;gap:10px}
.pl-saved-acts{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.pl-saved-acts .ui-more{margin-left:auto}

/* ---- Web Push panel (Notices, Family) ---- */
.push-panel { display: grid; gap: .5rem; margin: .5rem 0 1rem; }
.push-kinds { display: flex; flex-wrap: wrap; gap: .75rem 1.25rem; align-items: center; padding-left: .25rem; }
.push-kinds .chk { display: inline-flex; gap: .35rem; align-items: center; font-size: .92rem; }
.fam-alerts { margin: 1rem 0 .5rem; border: 1px solid var(--line, #26353F); border-radius: 12px; padding: .6rem .9rem; }
.fam-alerts > summary { cursor: pointer; font-weight: 600; }
.fam-steps { margin: .25rem 0 .5rem 1.1rem; padding: 0; display: grid; gap: .35rem; font-size: .92rem; }
.route-group { margin: 1.1rem 0 .3rem; font-size: .78rem; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3, #8aa); }
.route-row { margin-bottom: .55rem; }
.route-hint-line { margin: .1rem 0 .3rem; }

/* ---- Interpreter: conversation mode ---- */
.vc-lang-l{display:flex;flex-direction:column;gap:4px}
.vc-lang-l .fine{margin:0}
.vc-modes{display:flex;gap:0;margin:0 0 12px;border:1px solid var(--line);border-radius:10px;overflow:hidden}
.vc-modes .seg-b{flex:1;padding:9px 10px;border:0;background:var(--panel);color:var(--ink-2);font:inherit;cursor:pointer}
.vc-modes .seg-b.is-on{background:var(--datum);color:var(--on-accent);font-weight:600}
.vc-conv{display:flex;flex-direction:column;align-items:stretch;gap:10px;margin-bottom:10px}
.vc-ring{display:flex;flex-direction:column;align-items:center;gap:6px;padding:26px 16px;border-radius:22px;border:2px solid var(--line);
  background:var(--panel);color:var(--ink);cursor:pointer;font:inherit;-webkit-tap-highlight-color:transparent;transition:border-color .2s,background .2s}
.vc-ring[disabled]{opacity:.45;cursor:default}
.vc-ring-i{font-size:2.2rem;line-height:1}
.vc-ring-t{font-size:1.2rem}
.vc-ring-s{margin:0;text-align:center;max-width:34ch}
.vc-conv.is-listening .vc-ring{border-color:var(--datum);animation:vc-pulse 1.6s ease-in-out infinite}
.vc-conv.is-hearing .vc-ring{border-color:var(--datum);background:color-mix(in srgb,var(--datum) 18%,transparent)}
.vc-meter{height:6px;border-radius:3px;background:var(--line);overflow:hidden}
.vc-meter i{display:block;height:100%;width:calc(var(--lvl,0) * 100%);background:var(--datum);transition:width .08s linear}
.vc-conv.is-thinking .vc-ring{border-color:var(--warn,#d6b25a)}
.vc-conv.is-speaking .vc-ring{border-color:var(--magenta);background:color-mix(in srgb,var(--magenta) 12%,transparent)}
.vc-turn{display:flex;gap:8px;justify-content:center;flex-wrap:wrap}
.vc-engine{margin:0;text-align:center}
.vc-msg.is-wait{border-left-color:var(--line)}
.vc-facing{transform:rotate(180deg);background:var(--panel-2);border:1px solid var(--line);border-radius:14px;padding:14px;margin-bottom:12px;text-align:center}
.vc-facing-t{font-size:1.6rem;line-height:1.3;color:var(--ink)}
.vc-facing-r{color:var(--ink-2);margin-top:4px}

/* ---- Trip planner: summary and documents ---- */
.seg{display:flex;border:1px solid var(--line);border-radius:10px;overflow:hidden;margin:4px 0 10px}
.seg .seg-b{flex:1;padding:9px 10px;border:0;background:var(--panel);color:var(--ink-2);font:inherit;cursor:pointer}
.seg .seg-b.is-on{background:var(--datum);color:var(--on-accent);font-weight:600}
.pl-doc{margin:14px 0;padding:12px 14px;border:1px solid var(--line);border-radius:14px;background:var(--panel)}
.pl-doc>summary{cursor:pointer;font-weight:600;list-style:none;display:flex;align-items:center;gap:8px}
.pl-doc>summary::-webkit-details-marker{display:none}
.pl-doc>summary::before{content:"▸";font-size:.8em;color:var(--ink-3);transition:transform .15s}
.pl-doc[open]>summary::before{transform:rotate(90deg)}
.pl-doc[open]>summary{margin-bottom:10px}
.pl-themes{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px}
.pl-theme{display:inline-flex;align-items:center;gap:7px;padding:6px 10px;border-radius:999px;border:1px solid var(--line);background:var(--ground);color:var(--ink);font:inherit;font-size:.88rem;cursor:pointer}
.pl-theme.is-on{border-color:var(--datum);box-shadow:0 0 0 2px color-mix(in srgb,var(--datum) 35%,transparent)}
.pl-swatch{width:18px;height:18px;border-radius:50%;display:inline-block}
.pl-sum{margin-top:10px}
.pl-sum-o{font-size:1.02rem;line-height:1.5}
.pl-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(90px,1fr));gap:8px;margin:10px 0}
.pl-tile{background:var(--panel-2);border-radius:10px;padding:8px 10px;display:flex;flex-direction:column}
.pl-tile strong{font-size:1.25rem;color:var(--datum)}
.pl-tile span{font-size:.78rem;color:var(--ink-3)}
.pl-points{margin:0;padding-left:1.3rem;display:grid;gap:6px}
.pl-points details{border-bottom:1px solid var(--line);padding:4px 0 8px}
.pl-points summary{cursor:pointer;font-weight:600;line-height:1.35}
.pl-points details p{margin:6px 0}
.pl-sum-more{margin-top:6px;padding:8px 10px;border-left:3px solid var(--datum);background:var(--panel-2);border-radius:0 8px 8px 0}
.pl-sum-k{display:block;margin-bottom:4px;font-size:.8rem;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-3)}
.pl-hotel{padding:6px 0;border-bottom:1px dashed var(--line)}
.pl-links{display:flex;flex-wrap:wrap;gap:4px 12px;font-size:.85rem;margin-top:2px}
.pl-day.is-flash{outline:2px solid var(--datum);outline-offset:3px;transition:outline-color 1.2s}
.pl-kind{max-width:420px}

/* ---- Background jobs: the dock in the corner (jobs.js) ----
   Follows a trip plan, a trip document, a picture or a clip from every
   screen. A stage and a bar, never the searches behind them. */
.job-dock{position:fixed;right:16px;bottom:calc(20px + var(--safe-b));z-index:55;width:min(340px,calc(100vw - 32px));
  display:flex;flex-direction:column;align-items:flex-end;gap:8px;pointer-events:none}
.job-dock>*{pointer-events:auto}
.job-head{display:inline-flex;align-items:center;gap:9px;max-width:100%;padding:8px 14px 8px 10px;border-radius:999px;
  background:var(--panel-2);border:1px solid var(--line);color:var(--ink);font:inherit;font-size:13px;cursor:pointer;
  box-shadow:0 6px 22px color-mix(in srgb,var(--shadow) 35%,transparent)}
.job-dock.is-busy .job-head{border-color:color-mix(in srgb,var(--datum) 55%,var(--line))}
.job-head-t{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.job-pct{font-family:ui-monospace,monospace;color:var(--datum);font-size:12px}
.job-spin{width:14px;height:14px;border-radius:50%;flex:none;border:2px solid color-mix(in srgb,var(--datum) 25%,transparent);
  border-top-color:var(--datum);animation:job-spin .9s linear infinite}
.job-done{width:18px;height:18px;border-radius:50%;flex:none;display:grid;place-items:center;font-size:11px;
  background:var(--ok);color:var(--on-accent);font-weight:700}
@keyframes job-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.job-spin{animation-duration:3s}}
.job-panel{width:100%;background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:6px;
  box-shadow:0 10px 30px color-mix(in srgb,var(--shadow) 40%,transparent);display:grid;gap:2px}
.job-row{display:grid;grid-template-columns:28px 1fr auto;gap:10px;align-items:center;padding:8px;border-radius:10px}
.job-row+.job-row{border-top:1px solid var(--line)}
.job-ico{width:28px;height:28px;border-radius:8px;display:grid;place-items:center;
  background:color-mix(in srgb,var(--datum) 16%,transparent);color:var(--datum)}
.job-ico svg{width:16px;height:16px;fill:currentColor}
.job-row.is-error .job-ico,.job-row.is-cancelled .job-ico{background:color-mix(in srgb,var(--magenta) 14%,transparent);color:var(--magenta)}
.job-row.is-done .job-ico{background:color-mix(in srgb,var(--ok) 18%,transparent);color:var(--ok)}
.job-body{min-width:0}
.job-t{font-size:13.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.job-s{font-size:12px;color:var(--ink-3);line-height:1.35}
.job-row.is-error .job-s{color:var(--magenta)}
.job-bar{height:5px;border-radius:99px;background:color-mix(in srgb,var(--ink) 10%,transparent);overflow:hidden;margin-top:6px}
.job-bar i{display:block;height:100%;border-radius:inherit;background:var(--datum);transition:width .6s ease}
.job-acts{display:flex;align-items:center;gap:4px}
.job-btn{font:inherit;font-size:12px;padding:5px 10px;border-radius:7px;border:1px solid var(--line);background:var(--panel-2);color:var(--ink);cursor:pointer}
.job-btn.is-go{background:var(--datum);border-color:var(--datum);color:var(--on-accent);font-weight:600}
.job-x{font:inherit;font-size:18px;line-height:1;width:26px;height:26px;border-radius:7px;border:0;background:none;color:var(--ink-3);cursor:pointer}
.job-x:hover{background:var(--panel-2);color:var(--ink)}
.job-lib{font:inherit;font-size:12.5px;margin-top:2px;padding:8px;border:0;border-top:1px solid var(--line);background:none;color:var(--datum);cursor:pointer;border-radius:0 0 10px 10px}
@media (max-width:899px){
  /* Above the tab bar and whatever sheet is up, like the toast. */
  .job-dock{right:10px;bottom:calc(var(--nav) + var(--safe-b) + var(--sheet-h) + 12px);width:min(340px,calc(100vw - 20px))}
  html[data-view="map"] .job-dock:not(.is-open){bottom:calc(var(--nav) + var(--safe-b) + var(--sheet-h) + 58px)}
  /* Same phantom sheet as the companion button: off the map there is none. */
  html:not([data-view="map"]) .job-dock{bottom:calc(var(--nav) + var(--safe-b) + 12px)}
}

/* ---- Trip planner: background progress ---- */
.pl-stage{margin:0 0 4px;color:var(--ink-2);font-size:.92rem}
.pl-progress .job-bar{height:7px;margin:8px 0 12px}
.pl-progress .fine a{color:var(--datum)}
.pl-progress.is-failed{border-color:color-mix(in srgb,var(--magenta) 45%,var(--line))}
.pl-saved-note{font-size:.88rem;color:var(--ink-2);margin:8px 0 14px}
.pl-saved-note a{color:var(--datum)}
.lib-keepbtn.is-on,.pl-keep.is-on{border-color:var(--warn);color:var(--warn)}
.pl-docstatus{display:grid;gap:8px;margin:8px 0}
.pl-docstatus:empty{display:none}
.pl-docrow{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;padding:8px 10px;border-radius:10px;background:var(--panel-2)}
.pl-docrow .job-bar{flex-basis:100%;margin-top:2px}
.pl-docrow.is-done strong{color:var(--ok)}

/* ---- The assistant: one line while it works ---- */
.ai-working{font-family:var(--font);font-size:.82rem;color:var(--ink-3);display:flex;align-items:center;gap:8px}
.ai-working::before{content:"";width:10px;height:10px;border-radius:50%;flex:none;border:2px solid color-mix(in srgb,var(--datum) 25%,transparent);
  border-top-color:var(--datum);animation:job-spin .9s linear infinite}
details.ai-sources>summary{cursor:pointer;list-style:none;display:inline-flex;align-items:center;gap:6px}
details.ai-sources>summary::-webkit-details-marker{display:none}
details.ai-sources>summary::before{content:"▸";font-size:.8em;color:var(--ink-3);transition:transform .15s}
details.ai-sources[open]>summary::before{transform:rotate(90deg)}

/* ---- The Library (library.js) ---- */
.lib{max-width:1040px}
.lib-top{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:0 0 10px}
.lib-top h1{margin:0}
/* The tab row scrolls sideways where the tabs do not fit (a phone with five
   tabs and their counts, 2026-10-08) and sticks under the top while the
   cards scroll; on a wide screen the tabs share the row as before. */
.lib-tabs{display:flex;max-width:640px;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;position:sticky;top:0;z-index:2;
  background:var(--ground);scroll-snap-type:x proximity}
.lib-tabs::-webkit-scrollbar{display:none}
.lib-tabs .seg-b{display:inline-flex;align-items:center;justify-content:center;gap:6px;flex:0 0 auto;white-space:nowrap;padding:9px 14px;min-height:42px;scroll-snap-align:start}
@media (min-width:768px){.lib-tabs .seg-b{flex:1 1 auto}}
.lib-acts .ui-more{margin-left:auto}
.lib-more-row{display:contents}
.lib-n{font-size:11px;font-family:ui-monospace,monospace;padding:0 6px;border-radius:99px;background:color-mix(in srgb,var(--ink) 12%,transparent)}
.seg .seg-b.is-on .lib-n{background:color-mix(in srgb,var(--on-accent) 18%,transparent)}
.lib-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:14px;margin-top:10px}
.lib-grid[aria-busy="true"]{opacity:.55}
.lib-card{display:flex;flex-direction:column;background:var(--panel);border:1px solid var(--line);border-radius:14px;overflow:hidden;min-width:0}
.lib-fig{position:relative;aspect-ratio:16/10;background:var(--panel-2);cursor:pointer;overflow:hidden}
.lib-fig img,.lib-fig video{width:100%;height:100%;object-fit:cover;display:block}
.lib-fig.is-icon{display:grid;place-items:center;
  background:linear-gradient(135deg,color-mix(in srgb,var(--datum) 20%,var(--panel-2)),var(--panel-2))}
.lib-card.is-doc .lib-fig.is-icon{background:linear-gradient(135deg,color-mix(in srgb,var(--magenta) 18%,var(--panel-2)),var(--panel-2))}
.lib-glyph{font:700 1.3rem/1 ui-monospace,monospace;letter-spacing:.12em;color:var(--ink-2);padding:14px 18px;
  border:2px solid color-mix(in srgb,var(--ink) 18%,transparent);border-radius:10px}
.lib-kind{position:absolute;left:8px;top:8px;font-size:11px;padding:2px 8px;border-radius:99px;
  background:color-mix(in srgb,var(--ground) 82%,transparent);color:var(--ink);backdrop-filter:blur(4px)}
.lib-body{padding:10px 12px 4px;flex:1;min-width:0}
.lib-t{font-size:1rem;margin:0 0 3px;line-height:1.3;overflow-wrap:anywhere}
.lib-s{margin:0 0 4px;font-size:.84rem;color:var(--ink-2);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.lib-m{margin:0;font-size:.78rem;color:var(--ink-3);display:flex;flex-wrap:wrap;gap:4px 8px;align-items:center}
.lib-keep{padding:0 7px;border-radius:99px;border:1px solid var(--line)}
.lib-keep.is-kept{border-color:color-mix(in srgb,var(--warn) 60%,transparent);color:var(--warn)}
.lib-acts{display:flex;flex-wrap:wrap;gap:6px;padding:10px 12px 12px}
.lib-acts .lib-del{margin-left:auto;color:var(--ink-3)}
.lib-acts .lib-del:hover{color:var(--magenta);border-color:var(--magenta)}
.lib-empty{padding:26px 20px;border:1px dashed var(--line);border-radius:14px;text-align:center;color:var(--ink-2);grid-column:1/-1}
.lib-empty p{margin:0 0 12px}
.lib-jobs{display:grid;gap:10px;margin:0 0 18px}
.lib-h{font-size:.82rem;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-3);margin:0}
.lib-job{padding:12px 14px;border-radius:12px;background:var(--panel);border:1px solid color-mix(in srgb,var(--datum) 40%,var(--line))}
.lib-job-top{display:flex;justify-content:space-between;gap:10px;align-items:baseline}
.lib-job p{margin:4px 0 0}
.lib-detail{max-width:760px}
.lib-detail h2{margin:12px 0 4px}
.lib-full{width:100%;max-height:70vh;object-fit:contain;border-radius:12px;background:var(--panel-2);margin:10px 0}
.lib-scan-img{max-width:260px;border-radius:12px;margin:10px 0}
.lib-dl{display:grid;grid-template-columns:max-content 1fr;gap:6px 14px;margin:10px 0}
.lib-dl dt{color:var(--ink-3);font-size:.85rem}
.lib-dl dd{margin:0}
@media (max-width:560px){
  .lib-grid{grid-template-columns:1fr 1fr;gap:10px}
  .lib-acts{padding:8px 10px 10px}
  .lib-acts .btn.sm{padding:5px 9px;font-size:12px}
}
@media (max-width:380px){ .lib-grid{grid-template-columns:1fr} }
/* A plan or a document has no picture; on a phone its tile need not be one. */
@media (max-width:560px){ .lib-fig.is-icon{aspect-ratio:auto;height:92px} .lib-glyph{font-size:1.05rem;padding:9px 14px} }

/* ---- sign-up (2026-09-25): names side by side, show password, the
   "check your inbox" step. Tokens only — see theme.css for why. */
.gate-names{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px}
.gate-names>div{min-width:0}
.pw-wrap{position:relative}
.pw-wrap input{padding-right:64px}
.pw-eye{position:absolute;right:6px;top:50%;transform:translateY(-50%);border:0;background:none;
  color:var(--datum);font:inherit;font-size:.8rem;padding:6px 8px;border-radius:6px;cursor:pointer}
.pw-eye:focus-visible{outline:2px solid var(--datum);outline-offset:1px}
.gate-tabs.one{display:none}
.gate-plan{font-size:.8rem;color:var(--ink-2);margin:12px 0 0;text-align:center}
.gate-icon{width:56px;height:56px;border-radius:50%;margin:4px auto 14px;display:grid;place-items:center;
  background:color-mix(in srgb,var(--datum) 14%,transparent);color:var(--datum)}
.gate-icon::before{content:"";width:26px;height:26px;background:currentColor;
  -webkit-mask:var(--gi) center/contain no-repeat;mask:var(--gi) center/contain no-repeat;
  --gi:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 6h18v12H3z' fill='none' stroke='black' stroke-width='2' stroke-linejoin='round'/%3E%3Cpath d='M3 7l9 6 9-6' fill='none' stroke='black' stroke-width='2' stroke-linejoin='round'/%3E%3C/svg%3E")}
.gate-icon[data-kind="ok"]{background:color-mix(in srgb,var(--ok) 16%,transparent);color:var(--ok)}
.gate-icon[data-kind="ok"]::before{--gi:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}
.gate-icon[data-kind="pending"]{background:color-mix(in srgb,var(--warn) 16%,transparent);color:var(--warn)}
.gate-icon[data-kind="pending"]::before{--gi:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='9' fill='none' stroke='black' stroke-width='2'/%3E%3Cpath d='M12 7v5l3 2' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E")}
.gate-icon[data-kind="bad"]{background:color-mix(in srgb,var(--magenta) 14%,transparent);color:var(--magenta)}
.gate-icon[data-kind="bad"]::before{--gi:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 7l10 10M17 7L7 17' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'/%3E%3C/svg%3E")}
#gate-pending{text-align:center}
#gate-pending .btn{margin-top:14px}
#gate-pending #pending-resend+.gate-hint{margin-top:8px}
@media (max-width:360px){.gate-names{grid-template-columns:1fr;gap:0}}

/* The note that says platform settings moved to the console. */
.moved-note{display:grid;gap:6px;justify-items:start;margin:4px 0 14px;
  border-left:3px solid var(--datum)}
.moved-note p{margin:0}

/* ---- Settings → Plan & billing (myplan.js). Tokens only. ---- */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
#myplan{display:grid;gap:14px;min-width:0}
.mp-eyebrow{display:block;font-size:.7rem;text-transform:uppercase;letter-spacing:.1em;color:var(--ink-3)}
.mp-current{display:flex;flex-wrap:wrap;gap:12px;align-items:center;justify-content:space-between;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:14px 16px}
.mp-current>div:first-child{display:grid;gap:2px}
.mp-name{font-size:1.25rem}
.mp-tags{display:flex;flex-wrap:wrap;gap:6px}
.mp-tag{font-size:.75rem;padding:3px 9px;border-radius:999px;background:color-mix(in srgb,var(--datum) 14%,transparent);color:var(--datum)}
.mp-banner{border:1px solid color-mix(in srgb,var(--warn) 40%,transparent);background:color-mix(in srgb,var(--warn) 10%,transparent);
  border-radius:var(--r);padding:10px 14px;font-size:.88rem}
.mp-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px}
.mp-head h4.sub{margin:6px 0 0}
.mp-cycle{display:inline-flex;background:var(--panel);border:1px solid var(--line);border-radius:999px;padding:3px}
.mp-cycle button{border:0;background:none;color:var(--ink-2);font:inherit;font-size:.86rem;padding:7px 14px;border-radius:999px;cursor:pointer;display:flex;align-items:center;gap:6px}
.mp-cycle button.is-on{background:var(--datum);color:var(--on-accent);font-weight:600}
.mp-cycle button:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.mp-save{font-size:.7rem;font-weight:600;padding:2px 7px;border-radius:999px;background:color-mix(in srgb,var(--ok) 20%,transparent);color:var(--ok)}
.mp-cycle button.is-on .mp-save{background:color-mix(in srgb,var(--on-accent) 16%,transparent);color:inherit}
.mp-plans{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}
.mp-plan{position:relative;display:flex;flex-direction:column;align-items:flex-start;gap:6px;text-align:left;
  background:var(--panel);border:1.5px solid var(--line);border-radius:14px;padding:16px;color:var(--ink);
  font:inherit;cursor:pointer;min-width:0;transition:border-color .15s,box-shadow .15s}
.mp-plan:hover{border-color:color-mix(in srgb,var(--datum) 55%,var(--line))}
.mp-plan.is-on{border-color:var(--datum);box-shadow:0 0 0 3px color-mix(in srgb,var(--datum) 20%,transparent)}
.mp-plan:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.mp-ribbon{position:absolute;top:-10px;right:12px;font-size:.68rem;font-weight:700;letter-spacing:.04em;
  background:var(--magenta);color:var(--on-magenta);padding:3px 9px;border-radius:999px}
.mp-pname{font-size:1.02rem}
.mp-price{font-size:1.6rem;font-weight:700;letter-spacing:-.01em;line-height:1.1}
.mp-price small{font-size:.8rem;font-weight:400;color:var(--ink-3)}
.mp-billed{margin-top:-2px}
.mp-feats{list-style:none;margin:6px 0 4px;padding:0;display:grid;gap:4px;font-size:.82rem;color:var(--ink-2)}
.mp-feats li{padding-left:18px;position:relative}
.mp-feats li::before{content:"";position:absolute;left:2px;top:.42em;width:8px;height:4px;
  border:solid var(--ok);border-width:0 0 2px 2px;transform:rotate(-45deg)}
.mp-feats li.more{color:var(--ink-3)}
.mp-feats li.more::before{display:none}
.mp-cta{margin-top:auto;align-self:stretch;text-align:center;padding:8px;border-radius:8px;font-size:.86rem;font-weight:600;
  background:var(--panel-2);color:var(--ink)}
.mp-plan.is-on .mp-cta{background:var(--datum);color:var(--on-accent)}
.mp-addons{display:grid;gap:8px}
.mp-addon{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:12px;align-items:center;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:12px 14px}
.mp-addon.is-on{border-color:var(--datum)}
.mp-addon.is-inc{opacity:.7}
.mp-addon-text{display:grid;gap:2px;min-width:0}
.mp-addon-text .fine{margin:0}
.mp-addon-price{font-size:.86rem;color:var(--ink-2);white-space:nowrap}
.mp-switch{position:relative;display:inline-block;width:42px;height:24px;cursor:pointer}
.mp-switch input{position:absolute;inset:0;opacity:0;margin:0;cursor:pointer}
.mp-switch::before{content:"";position:absolute;inset:0;border-radius:999px;background:var(--panel-2);border:1px solid var(--line);transition:background .15s}
.mp-switch::after{content:"";position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:var(--ink-3);transition:transform .15s,background .15s}
.mp-switch:has(input:checked)::before{background:var(--datum);border-color:var(--datum)}
.mp-switch:has(input:checked)::after{transform:translateX(18px);background:var(--on-accent)}
.mp-switch:has(input:focus-visible)::before{outline:2px solid var(--datum);outline-offset:2px}
.mp-step{display:inline-flex;align-items:center;border:1px solid var(--line);border-radius:8px;overflow:hidden}
.mp-step button{border:0;background:var(--panel-2);color:var(--ink);width:30px;height:30px;font:inherit;font-size:1rem;cursor:pointer}
.mp-step button[disabled]{opacity:.4;cursor:default}
.mp-step span{min-width:28px;text-align:center;font-variant-numeric:tabular-nums}
.mp-foot{position:sticky;bottom:calc(var(--nav, 0px) + 8px);display:flex;flex-wrap:wrap;gap:12px;align-items:center;justify-content:space-between;
  background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:14px 16px;box-shadow:0 8px 24px color-mix(in srgb,var(--shadow) 35%,transparent)}
.mp-total{font-size:1.35rem}
.mp-actions{display:grid;gap:4px;justify-items:end}
@media (max-width:520px){
  .mp-addon{grid-template-columns:minmax(0,1fr) auto;}
  .mp-addon-price{grid-column:1;grid-row:2}
  .mp-actions{justify-items:stretch;width:100%}
}
/* The gate's buttons took the browser's face (Arial) beside the app's. */
.gate-card button{font-family:inherit}
.mp-plus{font-size:.78rem;font-weight:600;color:var(--ink-2);margin-top:4px}
#myplan .btn:disabled{opacity:.45;cursor:not-allowed}

/* Support access: a read-only view by the service's staff, or a note that
   they looked. Above everything, on every screen. Tokens only. */
.support-bar{position:fixed;left:12px;right:12px;top:calc(env(safe-area-inset-top,0px) + 10px);z-index:9999;
  display:flex;gap:12px;align-items:center;justify-content:space-between;padding:10px 14px;
  background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:12px;
  box-shadow:var(--shadow);font-size:14px;line-height:1.4}
.support-bar.warn{border-color:var(--warn)}
.support-bar button{flex:none;border:1px solid var(--line);background:var(--panel-2);color:var(--ink);
  border-radius:8px;padding:6px 12px;font:inherit;cursor:pointer}
/* The metro-map chip's swatch: three line colours, because it is lines. */
.tk-d.tk-d-lines{background:linear-gradient(90deg,var(--datum) 0 33%,var(--warn) 33% 66%,var(--ok) 66%)}
.support-bar.is-second{top:calc(env(safe-area-inset-top,0px) + 74px)}
/* The trial notice's ×: last on the row, a 36px target, no box of its own. */
.support-bar button.support-close{border:0;background:none;color:var(--ink-2);font-size:22px;line-height:1;
  padding:0;width:36px;height:36px;margin:-6px -8px -6px -6px;border-radius:50%}
.support-bar button.support-close:hover,.support-bar button.support-close:focus-visible{color:var(--ink);background:var(--panel-2)}
#myplan .mp-ended{color:var(--warn)}
/* The add-on model: steps, the base, categories, picks, the review. */
.mp-steps{list-style:none;display:flex;gap:6px;margin:0;padding:0;font-size:.78rem;color:var(--ink-3)}
.mp-steps li{display:flex;align-items:center;gap:6px;flex:1 1 0;padding:6px 8px;border-radius:999px;background:var(--panel);border:1px solid var(--line);white-space:nowrap}
.mp-steps li.is-on{color:var(--ink);border-color:var(--datum);font-weight:600}
.mp-step-n{display:inline-grid;place-items:center;width:18px;height:18px;border-radius:50%;background:var(--panel-2);font-size:.7rem}
.mp-steps li.is-on .mp-step-n{background:var(--datum);color:var(--on-accent)}
.mp-base{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:0}
.mp-base summary{display:flex;gap:12px;align-items:center;justify-content:space-between;padding:12px 14px;cursor:pointer;list-style:none}
.mp-base summary::-webkit-details-marker{display:none}
.mp-base summary::after{content:"›";color:var(--ink-3);font-size:1.2rem;transition:transform .15s}
.mp-base[open] summary::after{transform:rotate(90deg)}
.mp-base-t{display:grid;gap:2px;min-width:0;flex:1}
.mp-base-t .fine{margin:0}
.mp-base-p{font-size:.86rem;color:var(--ok);font-weight:600;white-space:nowrap}
.mp-base .mp-feats{padding:0 14px 12px}
.mp-cols{grid-template-columns:repeat(auto-fill,minmax(210px,1fr))}
.mp-gap{margin:6px 0 0}
.mp-picks{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:10px}
.mp-pick{display:flex;flex-direction:column;gap:6px;background:var(--panel);border:1.5px solid var(--line);border-radius:14px;padding:14px;min-width:0}
.mp-pick.is-on{border-color:var(--datum)}
.mp-pick .fine{margin:0}
.mp-pick-foot{margin-top:auto;display:flex;align-items:center;justify-content:space-between;gap:8px;padding-top:4px}
.mp-kind{align-self:flex-start;font-size:.66rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;padding:2px 8px;border-radius:999px;
  background:color-mix(in srgb,var(--magenta) 16%,transparent);color:var(--magenta)}
.mp-cats{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:10px}
.mp-cat{position:relative;display:grid;grid-template-columns:auto minmax(0,1fr);grid-template-rows:auto auto;column-gap:12px;row-gap:2px;align-items:center;
  text-align:left;background:var(--panel);border:1.5px solid var(--line);border-radius:14px;padding:14px 30px 14px 14px;color:var(--ink);font:inherit;cursor:pointer;min-width:0;
  transition:border-color .15s}
.mp-cat:hover{border-color:color-mix(in srgb,var(--datum) 55%,var(--line))}
.mp-cat:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.mp-cat.is-on{border-color:var(--datum)}
.mp-cat .mp-cat-ic{grid-row:1 / span 2}
.mp-cat .fine{margin:0;grid-column:2}
.mp-cat-ic{width:34px;height:34px;padding:7px;border-radius:10px;background:color-mix(in srgb,var(--datum) 14%,transparent);
  fill:none;stroke:var(--datum);stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;flex:none}
.mp-cat-got{grid-column:2;justify-self:start;font-size:.72rem;font-weight:600;color:var(--datum)}
.mp-cat-go{position:absolute;right:12px;top:50%;transform:translateY(-50%);color:var(--ink-3);font-size:1.3rem}
.mp-back{align-self:flex-start;justify-self:start;border:0;background:none;color:var(--datum);font:inherit;font-size:.9rem;padding:4px 0;cursor:pointer}
.mp-cat-head{display:flex;align-items:center;gap:10px}
.mp-cat-head h4.sub{margin:0}
.mp-card{align-items:start}
.mp-card-title{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.mp-card.is-bundle{border-style:dashed;border-color:color-mix(in srgb,var(--magenta) 45%,var(--line))}
.mp-card.is-bundle.is-on{border-style:solid;border-color:var(--datum)}
.mp-card .mp-switch,.mp-card .mp-step{margin-top:2px}
.mp-parts{color:var(--ink-2)}
.mp-needs{color:var(--datum)}
.mp-gives summary{font-size:.8rem;color:var(--ink-2);cursor:pointer;margin-top:2px}
.mp-gives .mp-feats{margin-top:6px}
.mp-next{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.mp-next .fine{margin:0 4px 0 0}
.mp-chip{border:1px solid var(--line);background:var(--panel);color:var(--ink);border-radius:999px;padding:6px 12px;font:inherit;font-size:.82rem;cursor:pointer}
.mp-chip:hover{border-color:var(--datum)}
.mp-review{display:grid;background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:4px 14px}
.mp-line{display:grid;grid-template-columns:minmax(0,1fr) auto 32px;gap:10px;align-items:center;padding:10px 0;border-bottom:1px solid var(--line)}
.mp-line:last-child{border-bottom:0}
.mp-line>span:nth-child(2){font-variant-numeric:tabular-nums;white-space:nowrap}
.mp-x{border:0;background:none;color:var(--ink-3);font-size:1.3rem;line-height:1;width:32px;height:32px;border-radius:50%;cursor:pointer}
.mp-x:hover,.mp-x:focus-visible{background:var(--panel-2);color:var(--ink)}
.mp-offer{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px;padding:12px 14px;border-radius:var(--r);
  border:1px dashed color-mix(in srgb,var(--ok) 55%,var(--line));background:color-mix(in srgb,var(--ok) 8%,transparent)}
.mp-offer .fine{margin:0}
@media (max-width:520px){
  .mp-steps li{padding:5px 6px}
  .mp-cats{grid-template-columns:minmax(0,1fr)}
}

/* ---- the interpreter's tabs; its Photo tab borrows the Scan panel ---- */
.vc-tabs{margin:0 0 14px}

/* ---- live hotel prices (hotels.js): Near me → Stay, and one hotel ---- */
#near-live:empty{display:none}
#near-live{margin:4px 0 14px}
.hl-ctl{display:grid;gap:8px;margin-bottom:10px}
.hl-head{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.hl-row{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) minmax(0,1fr) minmax(0,.9fr);gap:6px}
/* 16px or iOS zooms the page when a field is tapped. */
.hl-row input,.hl-row select{min-width:0;width:100%;min-height:44px;padding:8px;border-radius:8px;border:1px solid var(--line);
  background:var(--panel);color:var(--ink);font:inherit;font-size:16px}
.hl-sort{display:flex}
.hl-sort button{flex:1;min-height:40px;font:inherit;font-size:.9rem}
.hl-list{display:grid;gap:8px}
.hl-card{display:grid;grid-template-columns:64px minmax(0,1fr) auto;gap:10px;align-items:center;text-align:left;width:100%;
  padding:8px;border:1px solid var(--line);border-radius:12px;background:var(--panel);color:var(--ink);font:inherit;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.hl-card:active{background:var(--panel-2)}
.hl-card:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.hl-pic{width:64px;height:64px;border-radius:9px;overflow:hidden;background:var(--panel-2)}
.hl-pic img{width:100%;height:100%;object-fit:cover;display:block}
.hl-body{display:grid;gap:3px;min-width:0}
.hl-name{font-weight:600;line-height:1.25;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.hl-meta{color:var(--warn)}
.hl-tags,.hl-chips{display:flex;flex-wrap:wrap;gap:4px}
.hl-tag{font-size:12px;line-height:1.2;padding:3px 7px;border-radius:999px;background:var(--panel-2);color:var(--ink-2)}
.hl-deal{background:color-mix(in srgb,var(--magenta) 16%,transparent);color:var(--magenta)}
.hl-price{display:grid;justify-items:end;gap:1px;text-align:right}
.hl-price b{font-size:1.08rem}
.hl-src{max-width:9.5em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hl-dialog{width:100%;max-width:min(640px,calc(100vw - 16px));max-height:92dvh;padding:18px 16px calc(18px + env(safe-area-inset-bottom,0px));overflow:auto}
.hl-dialog h2{margin:6px 0 4px;font-size:1.25rem}
.hl-top{position:sticky;top:-18px;z-index:2;display:flex;justify-content:flex-end;margin:-18px -16px 8px;padding:6px 8px;
  background:var(--panel);border-bottom:1px solid var(--line)}
.hl-x{width:44px;height:44px;border:0;border-radius:50%;background:var(--panel-2);color:var(--ink);font-size:24px;line-height:1;cursor:pointer}
.hl-strip{display:flex;gap:6px;overflow-x:auto;scroll-snap-type:x mandatory;margin:0 -16px 10px;padding:0 16px}
.hl-strip img{flex:none;width:72%;max-width:320px;aspect-ratio:4/3;object-fit:cover;border-radius:10px;scroll-snap-align:start}
.hl-addr{margin:2px 0 10px;color:var(--ink-2)}
.hl-sec{margin-top:16px}
.hl-sec h3{font-size:.95rem;margin:0 0 8px}
.hl-offer{display:flex;justify-content:space-between;align-items:center;gap:10px;min-height:52px;padding:8px 10px;margin-bottom:6px;
  border:1px solid var(--line);border-radius:10px;background:var(--panel);color:var(--ink);text-decoration:none}
.hl-offer.is-best{border-color:var(--ok);box-shadow:inset 3px 0 0 var(--ok)}
.hl-o-l{display:flex;align-items:center;gap:8px;min-width:0}
.hl-logo{width:24px;height:24px;border-radius:5px;object-fit:contain;background:var(--panel-2);flex:none}
.hl-o-n{display:grid;min-width:0}
.hl-o-n b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hl-o-r{display:grid;justify-items:end;text-align:right;flex:none}
.hl-notes{margin:0;padding-left:18px;display:grid;gap:5px}
.hl-review{margin:8px 0;padding:8px 10px;border-left:3px solid var(--line);color:var(--ink-2)}
@media (max-width:420px){ .hl-row{grid-template-columns:minmax(0,1fr) minmax(0,1fr)} }

/* ==================================================================
   PHONE FIXES from the 2026-09-28 mobile audit (360–430 px wide, and
   812x375 landscape). Each rule names what was measured going wrong.
   ================================================================== */
/* The map-source panel: the tool strip (z 35) and the assistant button (z 44)
   were drawn over its Save / Clear / Close buttons, which could not be
   tapped at any scroll position. Nothing else is usable while it is open. */
html:has(#basemap-sheet:not([hidden])) #sheet,
html:has(#basemap-sheet:not([hidden])) #ai-fab{display:none}
.sheet-inner select{width:100%;min-height:44px;padding:9px 12px;border-radius:8px;border:1px solid var(--line);
  background:var(--panel-2);color:var(--ink);font:inherit}
#imagery-depth{display:block;margin-top:4px}

@media (max-width:899px){
  /* A tapped place: its "Directions here" landed at the very bottom pixel
     under the strip of switched-on layers. */
  html[data-panel="place"] .sheet-bar{display:none}
  /* The assistant button sits above the nav; the last thing in every view
     (the Itinerary's "Build the plan", the SOS footnote) ended under it.
     Room for the whole button: nav + 18px dock + 60px button + a 12px gap. */
  .view .pad,.view .wide-pad{padding-bottom:calc(var(--nav) + var(--safe-b) + 90px)}
  /* The map key is fixed top-left and covered the zoom buttons whenever a
     tool panel lifted them. An open panel explains its own layer. */
  html[data-panel]:not([data-panel=""]) #legend{display:none}
}

/* Thumb-sized targets. The block above stopped at 38 px for several of
   these; the measured offenders were 14–36 px tall. */
@media (pointer:coarse){
  .btn.sm,#btn-tools,#ai-max{min-height:44px}
  .back-btn{width:44px;height:44px}
  .seg button{min-height:40px}
  .route-mini{min-width:44px;min-height:44px}
  #legend-toggle{min-width:44px;min-height:32px}
  .tk-l{min-height:40px}
  .pl-chip{min-height:40px}
  /* The sheet header's own × already closes a place; this was a 25 px copy. */
  #sheet:not(.is-peek) #pc-close{display:none}
  /* iOS zooms on a focused <select> under 16 px exactly as it does on a text
     field — measured 13–14 px on the SOS country, route mode, weather kind
     and interpreter pickers. */
  select{font-size:16px!important}
}

/* Landscape phones (812x375): 162 px of assistant held a 63 px header and a
   log that refused to shrink below 120 px, so focusing the input scrolled the
   header — and its close button — off the top. The readout in the corner sat
   on the zoom buttons. */
@media (orientation:landscape) and (max-height:500px){
  .ai-head{flex:0 0 auto}
  #ai-log{min-height:40px}
  #hud{display:none}
}

/* ------------------------------------------------------------------
   PHONE FIXES, part two (same audit): landscape tool panels, overlaps,
   the notch.
   ------------------------------------------------------------------ */
/* The notch. With viewport-fit=cover a landscape iPhone draws the page under
   its camera housing on one side; nothing on the map allowed for it. env()
   is 0 everywhere else, so these are no-ops off a notched phone. */
@media (max-width:899px){
  #hud,#legend{left:calc(12px + env(safe-area-inset-left,0px))}
  .maplibregl-ctrl-bottom-left{padding-left:env(safe-area-inset-left,0px)}
  .maplibregl-ctrl-bottom-right{padding-right:env(safe-area-inset-right,0px)}
  #mapquick,#btn-src{right:calc(14px + env(safe-area-inset-right,0px))}
}
@media (max-width:520px){ #searchwrap{left:calc(12px + env(safe-area-inset-left,0px))} }

@media (max-width:899px) and (min-height:501px){
  /* The assistant button sat squarely on MapLibre's ⓘ attribution, which the
     tile licence requires to stay visible and tappable. The credit keeps the
     bottom-right corner (09-29: beside the button it read as a stray "1" in
     the middle of the map) and, on the map only, the button stands 36 px
     higher, over it. A short phone with a half sheet up is handled below —
     there the column leaves no room above, so the button steps left. */
  #ai-fab{right:calc(14px + env(safe-area-inset-right,0px))}
  html[data-view="map"] #ai-fab:not(.is-moved){bottom:calc(var(--ai-bottom) + 44px)}
}
/* A short phone with a half-height sheet up: the button rides above the sheet
   into the right-hand column (measured 12 px into the clean-map button at
   360x740). It steps beside the column, and the credit goes back to the edge. */
@media (max-width:899px) and (min-height:501px) and (max-height:800px){
  html[data-sheet="half"] #ai-fab{right:calc(76px + env(safe-area-inset-right,0px))}
  html[data-sheet="half"] .maplibregl-ctrl-bottom-right{right:0 !important}
}

/* Landscape phones (812x375). The bottom sheet had 312 px between the top of
   the screen and the nav, so a tapped place at `card` height showed its name
   and 25 px of body, and Directions or Near me got about 70 px. Here the sheet
   becomes the desktop's side drawer: full height on the right as soon as
   anything is open, a short launcher strip on the left while nothing is.
   sheet.js turns off the height drag under the same query and publishes a
   --sheet-h of 0 for the drawer, since it no longer covers the bottom edge. */
@media (orientation:landscape) and (max-height:500px) and (max-width:899px){
  :root{--drawer-w:min(400px,52vw)}
  #sheet{border:1px solid var(--line);border-bottom:0;border-radius:14px 14px 0 0}
  #sheet:not(.is-peek){
    left:auto;right:calc(8px + env(safe-area-inset-right,0px));width:var(--drawer-w);
    height:calc(100vh - var(--nav) - var(--safe-b) - 8px);
    height:calc(100dvh - max(calc(var(--nav) + var(--safe-b)), var(--kb)) - 8px)}
  #sheet.is-peek{left:calc(8px + env(safe-area-inset-left,0px));right:auto;width:min(420px,55vw)}
  /* Nothing drags here and the header's chevron has no heights to step
     through: every open state is the full drawer. */
  .sheet-handle,#sheet-size{display:none}
  /* As at full height in portrait: the launcher strip is a second row of
     chrome above the panel. Closing the panel brings it back. */
  #sheet:not(.is-peek) .sheet-bar{display:none}
  /* The right-hand column ran to 278 px and the ⓘ credit starts at 268 on a
     312 px map: a tighter stack clears it. */
  #mapquick{top:60px;gap:6px}
  .sheet-head{cursor:default;touch-action:auto}
  /* The tool strip lives on the left now, so what is on the right edge
     settles to the bottom instead of riding above a sheet that is not there. */
  .maplibregl-ctrl-bottom-right{bottom:calc(env(safe-area-inset-bottom,0px) + 10px)}
  /* The assistant button covered the 3D button, the right-hand column being
     full top to bottom at this height. It docks beside that column instead. */
  #ai-fab{right:calc(76px + env(safe-area-inset-right,0px));
    bottom:calc(max(calc(var(--nav) + var(--safe-b)), var(--kb)) + 10px)}
  /* A panel is open: the right-hand chrome steps left of the drawer, and the
     search box narrows to the map that is left. */
  html[data-sheet]:not([data-sheet="peek"]) #mapquick,
  html[data-sheet]:not([data-sheet="peek"]) #btn-src{right:calc(var(--drawer-w) + 22px + env(safe-area-inset-right,0px))}
  html[data-sheet]:not([data-sheet="peek"]) #ai-fab{right:calc(var(--drawer-w) + 84px + env(safe-area-inset-right,0px))}
  html[data-sheet]:not([data-sheet="peek"]) .maplibregl-ctrl-bottom-right{right:calc(var(--drawer-w) + 8px)}
  html[data-sheet]:not([data-sheet="peek"]) #searchwrap{left:calc(12px + env(safe-area-inset-left,0px));transform:none;
    width:calc(100vw - var(--drawer-w) - 170px - env(safe-area-inset-left,0px) - env(safe-area-inset-right,0px))}
  #nav{padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}
}

/* Scrolling tab strips: a fade at the edge with more tabs beyond it (app.js
   edgeFade writes data-fade). A mask, so it is alpha only and right in every
   look. Desktop turns Settings' strip into a sidebar, so phones only. */
@media (max-width:899px){
  .sos-tabs[data-fade="end"],.set-tabs[data-fade="end"]{
    -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 40px),transparent);
            mask-image:linear-gradient(to right,#000 calc(100% - 40px),transparent)}
  .sos-tabs[data-fade="start"],.set-tabs[data-fade="start"]{
    -webkit-mask-image:linear-gradient(to left,#000 calc(100% - 40px),transparent);
            mask-image:linear-gradient(to left,#000 calc(100% - 40px),transparent)}
  .sos-tabs[data-fade="both"],.set-tabs[data-fade="both"]{
    -webkit-mask-image:linear-gradient(to right,transparent,#000 40px,#000 calc(100% - 40px),transparent);
            mask-image:linear-gradient(to right,transparent,#000 40px,#000 calc(100% - 40px),transparent)}
}

/* The Interpreter's tabs with Photo withdrawn (no vision model routed) were a
   one-button segmented control reading "Speak & type": a choice of one. */
.vc-tabs:has([data-vtab="photo"][hidden]):has([data-vtab="cards"][hidden]){display:none}

/* Clear (×) in every search box — searchclear.js wraps each one in .sx.
   The browser's own cancel button is hidden so there is only ever one, and
   it is the same on every phone. */
input[type=search]::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none;display:none}
.sx{position:relative;display:flex;align-items:center;flex:1 1 auto;min-width:0}
.sx>input{flex:1 1 auto;width:100%;min-width:0;padding-right:38px !important}
.sx-x{position:absolute;right:6px;top:50%;transform:translateY(-50%);width:30px;height:30px;
  display:grid;place-items:center;padding:0;border:0;border-radius:50%;cursor:pointer;
  background:transparent;color:var(--ink-3)}
.sx-x:hover{color:var(--ink);background:var(--panel-2)}
.sx>input:placeholder-shown+.sx-x{display:none}

/* Boxes whose own spacing lived on the input move it to the wrapper. */
.sx:has(>#adv-search){margin-bottom:10px}
.sx>#adv-search{margin-bottom:0}
/* The map search has its Search button at the right edge: × sits left of it. */
#searchbar .sx>#place-search{padding-right:84px !important}
#searchbar .sx-x{right:44px}

/* The Android app's bars (appbridge.js): notifications off, an update, the offer. */
.app-bar{position:fixed;left:8px;right:8px;bottom:calc(72px + var(--safe-b, 0px));z-index:3000;display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;padding:10px 12px;border:1px solid var(--line);border-radius:12px;background:var(--panel);color:var(--ink);box-shadow:var(--shadow);font-size:14px;line-height:1.4}
.app-bar span{flex:1 1 220px;min-width:0}
.app-bar .btn{min-height:40px;display:inline-flex;align-items:center;text-decoration:none}
/* Notifications off: one slim line in the top stack, not a card over the
   search box. × puts it away for a few days (appbridge.js). */
.app-bar-warn{position:relative;left:auto;right:auto;bottom:auto;z-index:auto;flex-wrap:nowrap;gap:6px;max-width:100%;
  padding:3px 4px 3px 12px;border-radius:999px;border-color:var(--warn);font-size:.82rem;line-height:1.3}
.app-bar-warn span{flex:1 1 auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.app-bar-warn .btn{min-height:30px;padding:4px 12px;font-size:.8rem}
.app-bar-x{flex:0 0 auto;width:32px;height:32px;border:0;background:none;color:var(--ink-3);font-size:1.15rem;cursor:pointer;border-radius:50%}
.push-sms{margin-top:12px;padding-top:10px;border-top:1px solid var(--line)}
.push-sms p{margin:0 0 6px}
.push-sms .input{min-height:40px;max-width:190px}

/* ---- Pop (pop.js): a tool's answer, on top of the page -------------------
   Phone: a sheet from the bottom over the dimmed page, as tall as its
   content up to 88% of the screen, or the whole screen for `size:'full'`.
   It rides above the on-screen keyboard (--kb) so a box inside is never
   covered. Wide screens: a centred panel. Tokens only — see theme.css. */
.pop{position:fixed;inset:0;z-index:58;display:flex;flex-direction:column;justify-content:flex-end}
.pop-scrim{position:absolute;inset:0;background:var(--scrim);animation:pop-fade .18s ease both}
.pop-box{position:relative;display:flex;flex-direction:column;min-height:0;
  max-height:calc(88dvh - var(--kb));margin-bottom:var(--kb);
  background:var(--panel);color:var(--ink);border:1px solid var(--line);border-bottom:0;
  border-radius:16px 16px 0 0;box-shadow:0 -8px 30px color-mix(in srgb,var(--shadow) 45%,transparent);
  animation:pop-up .2s ease both;transition:transform .18s ease;outline:none}
.pop-full .pop-box{height:calc(100dvh - var(--kb));max-height:none;border-radius:0;border:0;
  padding-top:env(safe-area-inset-top,0px)}
.pop-grab{width:40px;height:4px;border-radius:2px;background:var(--line);margin:8px auto 0;flex:none;touch-action:none}
.pop-full .pop-grab{display:none}
.pop-head{display:flex;align-items:center;gap:6px;padding:6px 8px 8px 16px;border-bottom:1px solid var(--line);flex:none;touch-action:none}
.pop.is-step .pop-head,.pop-full .pop-head{padding-left:6px}
.pop-full .pop-head{padding-top:10px}
.pop-title{flex:1;min-width:0;margin:0;font-size:1.05rem;line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pop-back,.pop-x{flex:none;width:40px;height:40px;display:grid;place-items:center;padding:0;border:0;border-radius:50%;
  background:transparent;color:var(--ink-2,var(--ink));cursor:pointer}
.pop-back:hover,.pop-x:hover,.pop-back:focus-visible,.pop-x:focus-visible{background:var(--panel-2);color:var(--ink)}
.pop-back[hidden]{display:none}
.pop-body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  padding:12px 16px calc(18px + env(safe-area-inset-bottom,0px))}
.pop-body>:first-child{margin-top:0}
.pop-busy{display:flex;align-items:center;gap:10px;color:var(--ink-3);margin:6px 0}
.pop-spin{width:16px;height:16px;border-radius:50%;flex:none;border:2px solid color-mix(in srgb,var(--datum) 25%,transparent);
  border-top-color:var(--datum);animation:pop-rot .8s linear infinite}
.pop.is-leaving .pop-box{animation:pop-down .18s ease both}
.pop.is-leaving .pop-scrim{animation:pop-fade .18s ease reverse both}
@keyframes pop-up{from{transform:translateY(40px);opacity:.4}to{transform:none;opacity:1}}
@keyframes pop-down{to{transform:translateY(60px);opacity:0}}
@keyframes pop-fade{from{opacity:0}to{opacity:1}}
@keyframes pop-rot{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.pop-box,.pop-scrim,.pop-spin{animation:none!important}}
@media (min-width:900px){
  .pop{justify-content:center;align-items:center;padding:24px}
  .pop-box{width:min(620px,100%);max-height:84vh;margin:0;border:1px solid var(--line);border-radius:14px}
  .pop-full .pop-box{width:min(820px,100%);height:90vh;border:1px solid var(--line);border-radius:14px;padding-top:0}
  .pop-grab{display:none}
  .pop-head{padding-top:10px}
}

/* ---- SOS: summary rows and pops (09-29) ---- */
/* The Here tab is a summary that fits one phone screen: one row for the
   nearest hospital and police, one for your consulate, and the full lists
   in a pop behind "More nearby" and "All embassies". */
.help-k{font-size:.7rem;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3);margin-bottom:2px}
.help-item.is-compact{padding:9px 12px}
.help-item.is-compact .help-t{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.help-item.is-compact .fine{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.help-item.is-compact .row-btns{margin-top:7px}
.sos-more .help-h{margin-top:4px}
.sos-more .row-btns{margin-top:6px;gap:7px}
.sos-all{margin-top:8px}
.pop .help-list{margin-top:0}

/* ---------- what needs the internet (netneed.js) ----------
   The marks exist always and show only while html[data-net="off"]: dimmed
   and dotted for "needs internet", a hollow dot for "available offline". */
.need-tag{display:none;font-size:.74rem;font-weight:600;padding:2px 8px;border-radius:999px;
  border:1px solid var(--line);color:var(--ink-3)}
html[data-net="off"] .need-tag{display:inline-block}
html[data-net="off"] [data-need="off"] .need-tag{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 45%,transparent)}
html[data-net="off"] [data-need="on"]{opacity:.5}
html[data-net="off"] .chip[data-need="on"]::after,
html[data-net="off"] .chip[data-need="part"]::after,
html[data-net="off"] .navbtn[data-need="on"]::after,
html[data-net="off"] .navbtn[data-need="part"]::after{
  content:"";display:inline-block;width:6px;height:6px;margin-left:6px;border-radius:50%;
  vertical-align:middle;background:var(--ink-3)}
html[data-net="off"] .chip[data-need="part"]::after,
html[data-net="off"] .navbtn[data-need="part"]::after{background:transparent;box-shadow:inset 0 0 0 1.5px var(--ink-3)}
html[data-net="off"] .navbtn[data-need]::after{position:absolute;top:8px;right:calc(50% - 18px);margin:0}
.navbtn[data-need]{position:relative}

.net-bar{position:relative;display:flex;align-items:center;max-width:100%;
  background:var(--panel);border:1px solid var(--warn);border-radius:999px;box-shadow:var(--shadow)}
.net-bar[hidden]{display:none}
.net-bar-go{flex:1 1 auto;min-width:0;min-height:36px;padding:6px 4px 6px 14px;border:0;background:none;
  color:var(--ink);font:inherit;font-size:.82rem;text-align:left;cursor:pointer;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.net-bar-x{flex:0 0 auto;width:36px;height:36px;border:0;background:none;color:var(--ink-3);font-size:1.2rem;cursor:pointer}

.need-list .need-h{margin:18px 0 6px;font-size:.95rem}
.need-list .need-h-off{color:var(--ok)}
.need-list .need-h-on{color:var(--warn)}
.need-ul{list-style:none;margin:0;padding:0}
.need-ul li{display:flex;flex-direction:column;gap:2px;padding:9px 0;border-bottom:1px solid var(--line)}
.need-ul li:last-child{border-bottom:0}
.offline-what{display:inline-block;margin-top:8px;padding:0;border:0;background:none;color:var(--datum);
  font:inherit;font-size:.86rem;text-decoration:underline;cursor:pointer}

/* pickCountry (country.js): the search box stays at the top of the Pop while
   the list scrolls under it. A narrower panel than other full Pops on a wide
   screen — it is a list of names. */
.cpick .sx{position:sticky;top:-12px;z-index:1;background:var(--panel);padding:0 0 10px;margin-top:-2px}
.cpick-q{width:100%;padding:11px 14px;border-radius:9px;border:1px solid var(--line);background:var(--ground);color:var(--ink);font-size:16px;box-sizing:border-box}
.cpick-q:focus-visible{outline:2px solid var(--datum);outline-offset:1px}
.cpick-list{border:1px solid var(--line);border-radius:12px;overflow:hidden}
.cpick-list .suggest{min-height:46px;align-items:center}
.cpick-list .suggest.is-on{background:var(--panel-2)}
.cpick-list .suggest.is-on .suggest-l{color:var(--datum)}
.cpick-sep{padding:8px 14px 6px;font-size:.72rem;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3);
  border-bottom:1px solid var(--line);background:var(--panel)}
@media (min-width:900px){ .pop-picker .pop-box{width:min(520px,100%);height:min(680px,86vh)} }

/* ---- Sheet.step (sheet.js): details in place of a map panel's content ----
   The panel's own children are hidden, not removed, so ← returns to them as
   they were. The header sticks while the details scroll. Tokens only. */
.has-step>:not(.pstep){display:none!important}
.pstep-head{position:sticky;top:0;z-index:2;display:flex;align-items:center;gap:4px;
  margin:-4px -4px 8px;padding:4px 4px 6px;background:var(--panel);border-bottom:1px solid var(--line)}
.pstep-title{flex:1;min-width:0;margin:0;font-size:1rem;line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pstep-back{flex:none;width:40px;height:40px;display:grid;place-items:center;padding:0;border:0;border-radius:50%;
  background:transparent;color:var(--ink);cursor:pointer}
.pstep-back:hover,.pstep-back:focus-visible{background:var(--panel-2)}

/* ---- Flights panel (09-29 round 2) ----
   The aircraft card is a Sheet.step now, so the step is the box: no second
   border inside it. Follow sits beside "Centre on it" on the card, pressed
   when on. The search's answer line sits under the box that asked. */
.fr-card>.fine:first-child{margin-top:0}
.fr-card .fr-alert:first-child{margin:0 0 8px}
.fr-card .fr-grid{padding:6px 10px;border:1px solid var(--line);border-radius:9px;background:var(--panel-2)}
.fr-card>.row-btns{margin:8px 0}
.fr-card .row-btns .btn[aria-pressed="true"]{background:color-mix(in srgb,var(--datum) 18%,transparent);
  border-color:var(--datum);color:var(--ink)}
#fr-said{margin:6px 0 0;padding:6px 9px;border-left:3px solid var(--datum);border-radius:0 7px 7px 0;
  background:color-mix(in srgb,var(--datum) 8%,transparent);color:var(--ink-2)}

/* ---- Near me + place card (09-29 round 2) ----
   The answer to a tap has to land where the thumb is, not under the bottom
   edge of the sheet. Near me: the categories stay out as one scrolling row,
   the rarely changed settings fold into one line that says what they are,
   and hotels and tours are a row each that open a Pop. The place card: the
   chip row sticks to the top of the sheet. Tokens only. */
.near-fold{display:flex;align-items:center;gap:8px;margin:2px 0 0}
.near-set{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:7px;min-height:40px;
  margin-left:-6px;padding:6px 8px 6px 6px;border:0;border-radius:8px;background:none;color:var(--ink-2);
  font:inherit;font-size:.84rem;text-align:left;cursor:pointer;-webkit-tap-highlight-color:transparent}
.near-set:focus-visible{background:var(--panel-2);outline:2px solid var(--datum);outline-offset:1px}
.near-set svg{flex:0 0 auto;width:18px;height:18px}
.near-set-i{color:var(--datum)}
.near-set-chev{color:var(--ink-3);transition:transform .18s ease}
.near-set[aria-expanded="true"] .near-set-chev{transform:rotate(180deg)}
.near-set #near-anchor{flex:0 1 auto;min-width:0;margin:0}
#near-panel #near-count{flex:0 0 auto;margin-left:auto;white-space:nowrap}
#near-panel .near-controls{margin:2px 0 8px}
#near-panel #near-list{margin-top:6px}
#near-panel #near-live,#near-panel #near-tours{margin:6px 0 0}
/* The sheet's header already says "Near me"; with the anchor and the count
   moved down to the settings line, the old head line is empty on a phone. */
@media (max-width:899px){ #sheet .near-head{display:none} }

.near-more{display:flex;align-items:center;gap:9px;width:100%;min-height:42px;padding:6px 10px 6px 12px;
  border:1px solid var(--line);border-radius:10px;background:var(--panel-2);color:var(--ink);
  font:inherit;text-align:left;cursor:pointer;-webkit-tap-highlight-color:transparent}
/* Hover only where there is one: on a phone it sticks after the tap. */
@media (hover:hover){
  .near-set:hover{background:var(--panel-2)}
  .near-more:hover{border-color:color-mix(in srgb,var(--datum) 50%,var(--line))}
}
.near-more:active{background:color-mix(in srgb,var(--datum) 10%,var(--panel-2))}
.near-more:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.near-more-i{flex:0 0 auto;font-size:1rem;line-height:1}
/* One line, so the row costs the list as little height as a row can. */
.near-more-t{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;gap:8px}
.near-more-t b{flex:0 0 auto;font-size:.88rem;font-weight:600;white-space:nowrap}
.near-more-t .fine{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.near-more-go{flex:0 0 auto;color:var(--ink-3);font-size:1.3rem;line-height:1}

/* Place card chips (placecard.js `pd-chips`): stuck to the top of the sheet,
   with the sheet's own background so a section scrolls under, not through. */
#sheet-body .pd-chips{position:sticky;top:0;z-index:3;margin:12px -14px 0;padding:8px 14px;
  background:var(--panel);border-bottom:1px solid color-mix(in srgb,var(--line) 60%,transparent)}
#sheet-body .pd-chips + .pd-body{margin-top:10px}
/* The place card's tabs (placecard.js, 10-07): the shared segmented control,
   stuck to the top of the sheet with the sheet's own background. */
.pd-tabs{margin:12px 0 10px}
#sheet-body .pd-tabs{position:sticky;top:0;z-index:3;margin:12px -14px 10px;padding:8px 14px 6px;border-radius:0;
  border-width:0 0 1px;border-color:color-mix(in srgb,var(--line) 60%,transparent);background:var(--panel)}
#sheet-body .pd-tabs .seg-b{border-radius:8px}
#sheet-body .pd-tabs .seg-b:first-child{border-radius:8px}
.pd-tabs .seg-b{min-height:38px;padding:6px 4px;font-size:.88rem}
.pd-glance{margin:4px 0 0;color:var(--ink-2)}
.pd-glance-bad{color:var(--magenta);font-weight:600}
/* Folded rows on Overview and Around: the title, a hint, ⓘ, a chevron. */
.pd-folds{margin-top:12px;border-top:1px solid var(--line)}
.pd-fold{border-bottom:1px solid var(--line)}
.pd-fold>summary{display:flex;align-items:center;gap:8px;padding:11px 2px;cursor:pointer;list-style:none;min-height:44px;box-sizing:border-box}
.pd-fold>summary::-webkit-details-marker{display:none}
.pd-fold>summary::after{content:"";width:8px;height:8px;border-right:1.5px solid var(--ink-3);border-bottom:1.5px solid var(--ink-3);
  transform:rotate(-45deg);margin:0 6px 0 auto;flex:0 0 auto;transition:transform .15s}
.pd-fold-b .pd-country-head{margin-top:8px}
.pd-fold[open]>summary::after{transform:rotate(45deg)}
.pd-fold-t{font-weight:600;font-size:.92rem;color:var(--ink);flex:0 1 auto;min-width:0}
.pd-fold-h{flex:1 1 auto;min-width:0;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pd-fold>summary .ui-info{margin:-6px 0}
.pd-fold-b{padding:0 0 12px}
.pd-fold-b .pd-cond,.pd-fold-b .pd-country{margin-top:2px}
.pd-fold-b .pd-country{border-left-width:1px}
.pd-fold-b>.pd-country{border:0;padding:0;background:none}
.pd-book .pd-fold{border-top:1px solid var(--line);margin-top:12px}
.pd-teaser{margin:8px 0 2px}
.pd-teaser p{font-size:.9rem;line-height:1.55;margin:0;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.pd-teaser .linkish{background:none;border:0;color:var(--datum);cursor:pointer;font:inherit;font-size:.84rem;padding:4px 0 0}
.pd-book-h{display:flex;align-items:center;gap:4px}
.pd-book-h .ui-info{margin:-8px 0}
/* Direct-booking rows: one column, the name left and where it lands right. */
.pd-book .pd-book-links{display:grid;grid-template-columns:minmax(0,1fr);gap:6px}
.pd-book .pd-book-top{justify-content:space-between;flex-wrap:nowrap;gap:10px}
.pd-book .pd-book-note{max-width:none}
/* On a phone one scrolling row: wrapped, ten chips were three rows, and three
   rows stuck to the top of a half-height sheet left little for the answer.
   The fade at the right edge says there are more; it is a sticky overlay,
   not a mask, because a mask would let the section show through the row. */
@media (max-width:899px){
  #sheet-body .pd-chips{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}
  #sheet-body .pd-chips::-webkit-scrollbar{display:none}
  #sheet-body .pd-chips .fd-chip{flex:0 0 auto;white-space:nowrap}
  #sheet-body .pd-chips::after{content:"";position:sticky;right:-14px;flex:0 0 30px;margin:0 -14px 0 -36px;
    pointer-events:none;background:linear-gradient(to right,color-mix(in srgb,var(--panel) 0%,transparent),var(--panel))}
}

/* ---- Directions, Transit, Live (09-29 round 2) ----
   The answer to a tap stays inside the panel's visible height on a phone:
   the travel mode is a row of buttons (one tap), the two route boxes fold
   into one line once a route is showing, the transit options fold into one
   line, and details open as a Sheet.step. Tokens only. */

/* Travel mode: the shared segmented control (.seg/.seg-b), sized for the
   panel, with transit's Options button at the end of the same row. */
.route-moderow{display:flex;gap:6px;align-items:stretch;margin:0 0 6px;min-width:0}
.route-modes{flex:1 1 auto;min-width:0;margin:0;padding:0;background:var(--panel)}
.route-modes .seg-b{padding:8px 4px;font-size:.86rem;white-space:nowrap;min-width:0;border-radius:0}
.route-modes .seg-b + .seg-b{border-left:1px solid var(--line)}
#route-mode[hidden]{display:none}

/* The folded A → B line: one strip, each name its own button back into its box. */
.route-fold{display:flex;align-items:center;gap:0;margin:0 0 6px;min-width:0;
  background:var(--panel-2);border:1px solid var(--line);border-radius:10px;padding:0 2px 0 0}
.route-fold-end{flex:0 1 auto;min-width:0;display:flex;align-items:center;gap:7px;
  background:transparent;border:0;border-radius:9px;padding:7px 8px;
  color:var(--ink);font:inherit;font-size:.88rem;text-align:left;cursor:pointer}
.route-fold-end:hover,.route-fold-end:focus-visible{background:color-mix(in srgb,var(--datum) 12%,transparent)}
.route-fold-n{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.route-fold-to{flex:none;color:var(--ink-3);font-size:.9rem}
.route-fold .route-mini{flex:none}
.route-fold #route-fold-swap{margin-left:auto}
@media (pointer:coarse){ .route-fold-end{min-height:44px} }

/* Folded, the panel is about the answer: "Start here" and "From me" are in
   box A a tap away, Clear is the ✕ on the line, and the row keeps "Start
   navigating" and the turns — or goes, when there is neither. */
#route-panel.is-folded .route-ends{display:none}
#route-panel.is-folded #btn-route-here,
#route-panel.is-folded #btn-route-me,
#route-panel.is-folded #route-clear{display:none}
#route-panel.is-folded .route-btns:not(:has(#nav-start:not([hidden]),#route-turns:not([hidden])))){display:none}
#route-panel.is-folded .route-btns{margin-top:8px}
#route-panel.is-folded #nav-start{flex:1 1 0;min-width:0}
#route-panel:not(.is-folded) #route-turns{display:none}
#route-summary:empty{display:none}

/* Options: a button the height of the mode row, open when outlined. */
.route-optline{flex:none;display:inline-flex;align-items:center;gap:7px;
  background:var(--panel-2);border:1px solid var(--line);border-radius:10px;padding:0 11px;
  color:var(--ink-2);font:inherit;font-size:.84rem;cursor:pointer;white-space:nowrap}
.route-optline::after{content:'';flex:none;width:6px;height:6px;margin:0 1px 3px 0;
  border-right:1.6px solid currentColor;border-bottom:1.6px solid currentColor;transform:rotate(45deg)}
.route-optline[aria-expanded="true"]::after{transform:rotate(-135deg);margin:3px 1px 0 0}
.route-optline[aria-expanded="true"]{border-color:var(--datum);color:var(--ink)}
#transit-opts{padding:10px;border:1px solid var(--line);border-radius:10px;background:var(--panel-2)}
#tp-when{background:var(--ground);color:var(--ink);border:1px solid var(--line);border-radius:8px;padding:5px 8px;font:inherit;font-size:.82rem}

/* "Turn-by-turn (14) ›", beside Start navigating. */
.route-turns{flex:1 1 0;min-width:0;display:inline-flex;align-items:center;gap:6px;
  padding:6px 12px;background:var(--panel-2);border:1px solid var(--line);border-radius:8px;
  color:var(--ink);font:inherit;font-size:13px;text-align:left;cursor:pointer;white-space:nowrap}
.route-turns:hover,.route-turns:focus-visible{border-color:var(--datum)}
.route-turns .fine{margin:0}
.route-turns-go{margin-left:auto;color:var(--ink-3);font-size:1.15rem;line-height:1}
@media (pointer:coarse){ .route-turns{min-height:44px} }
.pstep #route-steps{margin-top:0}
#route-panel .route-head{margin-bottom:2px}

/* The journeys, a little tighter: on a 360x640 phone the half-height panel
   has about 190px under its header, and the first option has to fit in it. */
#route-panel #journey-list{margin-top:6px;gap:6px}
#route-panel .journey-row{padding:7px 10px;gap:4px}

/* A journey, opened as a step: when, then one line per leg with its badge. */
.jstep-sum{display:flex;flex-direction:column;gap:2px;margin:2px 0 10px}
.jstep-sum strong{font-family:ui-monospace,monospace;font-size:1rem}
.jsteps{list-style:none;margin:0;padding:0;display:grid;gap:2px;font-size:.88rem;color:var(--ink-2)}
.jstep-leg{display:grid;grid-template-columns:86px minmax(0,1fr);gap:10px;align-items:start;
  padding:7px 6px;border-radius:8px}
.jstep-leg .leg-badge{justify-self:start;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.jstep-leg.is-tappable{cursor:pointer}
.jstep-leg.is-tappable:hover{background:var(--panel-2)}
.jstep-leg.is-off{color:var(--magenta)}
.jstep-t{line-height:1.35;min-width:0}

/* Transit (and Live): the switches as chips. The checkbox is still inside
   each chip and still the thing Prefs listens to; it is just not drawn. */
.tchips{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;gap:6px;padding:1px 1px 3px}
.tchips::-webkit-scrollbar{display:none}
.tchips .tk-l{flex:none;position:relative;padding:5px 11px;border:1px solid var(--line);border-radius:999px;
  background:var(--panel-2);color:var(--ink-2);white-space:nowrap;text-transform:none;letter-spacing:normal;font-size:.86rem;margin:0}
.tchips .tk-l input{position:absolute;opacity:0;width:1px;height:1px;margin:0;pointer-events:none}
.tchips .tk-l:has(input:checked){border-color:var(--datum);color:var(--ink);
  background:color-mix(in srgb,var(--datum) 16%,transparent)}
.tchips .tk-l:not(:has(input:checked)) .tk-d{opacity:.35}
.tchips .tk-l:has(input:focus-visible){outline:2px solid var(--datum);outline-offset:1px}
/* Live's eleven layers wrap instead: they are all worth seeing at once. */
.tchips.is-wrap{flex-wrap:wrap;overflow:visible}
#transit-panel .transit-sub{margin-top:10px}

/* A stop's departures, as a step of the Transit panel. */
.dep-step #dep-board{margin-top:0;border-top:0;padding-top:0}
.dep-step #dep-stop{display:none}
.dep-acts{margin-top:12px;flex-wrap:wrap}

/* Live: a station still playing after its list is closed. */
.radio-dock{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:8px;
  padding:6px 6px 6px 11px;border:1px solid var(--line);border-radius:10px;background:var(--panel-2)}
.radio-dock-n{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#eye-side > .radio-player{display:none}

/* Companion (companion.js) */
.cmp-main{margin-top:6px}
.cmp-note{margin:6px 0 4px}
.cmp-note .btn{margin-top:6px}
.cmp-actions{display:flex;flex-wrap:wrap;gap:8px;margin:12px 0 4px}
.cmp-sec{margin-top:22px}
details.cmp-sec>summary{cursor:pointer;font-weight:600;padding:6px 0}
.cmp-h{font-size:1rem;margin:0 0 8px}
.cmp-rems{list-style:none;margin:0;padding:0}
.cmp-rem{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--line)}
.cmp-rem-t{flex:1;min-width:0}
.cmp-rem-t strong{display:block;font-weight:600;overflow-wrap:anywhere}
.cmp-form{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.cmp-form input,.cmp-form select,.cmp-lab input,.cmp-lab select{min-height:44px;padding:9px 12px;border-radius:8px;
  border:1px solid var(--line);background:var(--panel);color:var(--ink);font:inherit;font-size:15px;box-sizing:border-box}
.cmp-form input[type=text]{flex:1 1 100%;min-width:0}
.cmp-form select,.cmp-form input[type=datetime-local]{flex:1 1 140px;min-width:0}
.cmp-form input[type=datetime-local]{color-scheme:light dark}
.cmp-card{background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r);padding:10px 12px;margin-bottom:10px}
.cmp-card.is-focus{border-color:var(--datum);box-shadow:0 0 0 2px var(--datum)}
.cmp-card-h{display:flex;align-items:baseline;gap:8px}
.cmp-card-h strong{flex:1;min-width:0;line-height:1.3}
.cmp-ico{flex:0 0 auto}
.cmp-body{white-space:pre-line;margin:6px 0 0;color:var(--ink-2);font-size:.9rem}
.cmp-places{list-style:none;margin:6px 0 0;padding:0}
.cmp-place{display:block;width:100%;text-align:left;background:none;border:0;border-top:1px solid var(--line);padding:7px 0;color:var(--ink);font:inherit;cursor:pointer}
.cmp-place strong{display:block;font-weight:600}
.cmp-card-a{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.cmp-card-a .is-on{border-color:var(--datum);color:var(--datum)}
.cmp-opt{margin:12px 0 0}
.cmp-lab{display:block;margin-top:14px;font-weight:600}
.cmp-lab input,.cmp-lab select{display:block;width:100%;margin-top:6px;font-weight:400}

/* A short phone with a half-height sheet up leaves about 200px of map, and the
   zoom column rising above the sheet ran into the readout: + sat behind it
   (360x640, 09-29). The readout is the thing that can wait — the coordinates
   come back the moment the sheet goes down, and an opened readout stays. */
@media (max-width:899px) and (max-height:760px){
  html[data-view="map"][data-sheet="half"] #hud:not(.open){display:none}
}
.cmp-x{flex:0 0 auto;width:40px;height:40px;border-radius:50%;border:1px solid var(--line);background:none;color:var(--ink-2);font-size:20px;line-height:1;cursor:pointer}
/* Companion food: "right now" chips, the profile, and what nobody checked (09-30). */
.cmp-chips{margin:8px 0}
.cmp-now .cmp-crave{display:block;width:100%;min-height:44px;padding:9px 12px;border-radius:8px;
  border:1px solid var(--line);background:var(--panel);color:var(--ink);font:inherit;margin-top:4px}
.cmp-food .tc-group{border:0;padding:0;margin:14px 0 0}
.cmp-food .tc-group legend{font-weight:600;padding:0;margin-bottom:2px}
/* "Rather not" is a light fill; "strict" the full pressed colour plus a warning ring. */
.cmp-food .tc-chip.is-rather[aria-pressed="true"]{background:color-mix(in srgb,var(--datum) 18%,var(--panel));color:var(--ink);border-color:var(--datum);font-weight:600}
.cmp-food .tc-chip.is-strict[aria-pressed="true"]{box-shadow:0 0 0 2px var(--warn)}
.cmp-caution{display:block;color:var(--warn);margin-top:2px}
.cmp-famous{display:block;color:var(--datum);font-weight:600;margin-top:2px}
.cmp-quote{display:block;font-style:italic;margin-top:2px}
.cmp-credit a{color:inherit}
.cmp-notes{margin-top:6px}
.cmp-notes p{margin:4px 0 0}

/* ---------- Disclaim (disclaim.js): the "check this yourself" small print ---------- */
.disclaim{color:var(--ink-3)}
.disclaim-why{background:none;border:0;padding:0;margin:0;font:inherit;color:var(--datum);
  text-decoration:underline;text-underline-offset:2px;cursor:pointer}
/* ---------- Credits (credits.js): /credits read into a Pop ---------- */
.credit-link{background:none;border:0;padding:0;margin:0;font:inherit;color:var(--ink-3);
  text-decoration:underline;text-underline-offset:2px;cursor:pointer}
.credit-wx{display:block;color:var(--ink-3);font-size:.72rem;text-decoration:none;margin-top:2px}
.dsc-wx .credit-wx{display:inline;margin:0}
/* Platform console → Feature switches → Data credits off (10-12): every
   credit line, the map's ⓘ and the "Data credits" entry points go. Photo
   credits (author, licence, source page) have their own switch. */
html.no-credits :is(.credit-line,.credit-link,.credit-wx,.cam-credit,.fr-credit,
  .pd-guide-credit,.pres-credit,.cmp-credit,.maplibregl-ctrl-attrib){display:none!important}
html.no-photo-credits :is(.photo-credit,.dsc-credit,.fr-photo-credit){display:none!important}
.credits-pop .lead{color:var(--ink-2);margin:0 0 8px}
.credit-pick{display:block;width:100%;text-align:left;background:none;border:0;padding:10px 14px;font:inherit;color:var(--ink);cursor:pointer}
.credits-pop li:has(.credit-pick){padding:0}
.credits-pop h2{font-size:1rem;margin:20px 0 6px;scroll-margin-top:8px}
.credits-pop ul{list-style:none;padding:0;margin:0;border:1px solid var(--line);border-radius:12px;background:var(--panel)}
.credits-pop li{padding:9px 12px;border-top:1px solid var(--line)}
.credits-pop li:first-child{border-top:0}
.credits-pop li b{display:block;font-weight:600}
.credits-pop li span{color:var(--ink-2);font-size:.9rem}
.credits-pop a{color:var(--datum)}
.credits-pop footer{color:var(--ink-3);font-size:.85rem;margin-top:18px}
.about-info .lede{margin:0 0 10px}
.about-sec h3{margin:14px 0 4px;font-size:1rem}
.about-sec p{margin:0 0 8px;color:var(--ink-2);line-height:1.45}
#route-steps .route-step-note{display:block;margin:10px 0 0}
.firstrun{position:fixed;left:50%;transform:translateX(-50%);z-index:57;
  bottom:calc(var(--nav) + var(--safe-b) + var(--sheet-h) + 12px);width:min(520px,calc(100vw - 24px));
  background:var(--panel);color:var(--ink);border:1px solid var(--line);border-left:4px solid var(--warn);
  border-radius:12px;padding:12px 14px;box-shadow:0 10px 30px color-mix(in srgb,var(--shadow) 45%,transparent)}
.firstrun[hidden]{display:none}
/* It sits above the chat window (57 > 45) and would cover its title bar and
   composer; the chat carries its own safety line, and the card comes back,
   still unanswered, once the chat is closed. */
html[data-ai="open"] .firstrun{display:none}
.firstrun p{margin:4px 0 0;font-size:.86rem;color:var(--ink-2);line-height:1.4}
.firstrun .row-btns{margin-top:10px}
/* Above the assistant's round button (60px, docked at most --ai-bottom + 44px
   on a phone, 22px on a wide screen), not over it: covered, the button could
   not be pressed until the card was answered. */
@media (max-width:899px) and (min-height:501px){ .firstrun{bottom:calc(var(--ai-bottom) + 114px)} }
@media (min-width:900px){ .firstrun{bottom:calc(94px + var(--safe-b))} }
.more-about{display:block;margin:12px 2px 0;font-size:.85rem}
.more-about+.more-about{margin-top:6px}
.ai-caution{font-size:.74rem;margin:6px 0 0}

/* ---- locked features (upsell.js): what the account could buy, in place ---- */
.is-locked{position:relative}
.is-locked > *:not(.lock-tag){opacity:.62}
.lock-tag{position:absolute;top:8px;right:8px;display:inline-flex;align-items:center;gap:4px;padding:2px 8px 2px 6px;
  border-radius:999px;font-size:.66rem;font-weight:700;letter-spacing:.03em;line-height:1.5;
  background:color-mix(in srgb,var(--magenta) 16%,var(--panel));color:var(--magenta);pointer-events:none}
.lock-tag svg{width:11px;height:11px;fill:currentColor}
.ai-mi.is-locked .lock-tag{top:50%;transform:translateY(-50%)}
.navbtn.is-locked .lock-tag{top:2px;right:2px;padding:1px 4px;font-size:0}
.navbtn.is-locked .lock-tag svg{width:10px;height:10px}
.upsell{position:relative;max-width:min(420px,calc(100vw - 24px))}
.upsell-badge{display:inline-flex;align-items:center;gap:5px;font-size:.7rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--magenta);margin-bottom:8px}
.upsell-badge svg{width:12px;height:12px;fill:currentColor}
.upsell-x{position:absolute;top:10px;right:10px;border:0;background:none;color:var(--ink-3);font-size:1.5rem;line-height:1;
  width:36px;height:36px;border-radius:50%;cursor:pointer}
.upsell-x:hover,.upsell-x:focus-visible{background:var(--panel-2);color:var(--ink)}
.upsell-price{font-size:1.2rem;font-weight:700;margin:10px 0 0}
.upsell .row-btns{display:flex;flex-wrap:wrap;gap:8px}
.upsell-note{margin:10px 0 0}

/* ---- One line, end to end (busline.js, 10-01) ----
   A departure row opens its whole line: the stops as a vertical line in the
   line's colour (--m), your stop ringed, stops before it folded and faded.
   Tokens only; the line colour is the agency's, set inline as --m. */
.dep-row.is-tappable{cursor:pointer;position:relative;padding-right:16px}
.dep-row.is-tappable::after{content:'›';position:absolute;right:2px;top:50%;transform:translateY(-52%);
  color:var(--ink-3);font-size:1.1rem}
.dep-row.is-tappable:hover .dep-towards,.dep-row.is-tappable:focus-visible .dep-towards{color:var(--datum)}
.dep-row.is-tappable:focus-visible{outline:2px solid var(--datum);outline-offset:2px;border-radius:6px}
.dep-mapped{margin-top:8px}
.dep-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}
.dep-chips .dep-line{border:0;cursor:pointer}
.dep-chips .dep-line:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
/* Finding a stop (busstops.py): a name or the code on the pole, or the
   nearest few. Each row says which road and which way, because the two sides
   of a road share a name and only that tells them apart. */
.stop-find{display:flex;gap:7px;align-items:center;margin:10px 0 6px}
#stop-q{flex:1;min-width:0;background:var(--ground);color:var(--ink);
  border:1px solid var(--line);border-radius:8px;padding:9px 11px;font-size:.86rem;
  font-family:inherit;min-height:38px}
#stop-q:focus{outline:none;border-color:var(--datum)}
#stop-results:empty{display:none}
#stop-results{margin-bottom:8px}
.sf-row{display:flex;gap:10px;align-items:center;width:100%;text-align:left;background:none;
  color:var(--ink);border:0;border-bottom:1px solid var(--line);padding:8px 2px;cursor:pointer;
  font:inherit}
.sf-row:last-child{border-bottom:0}
.sf-row:hover .sf-name,.sf-row:focus-visible .sf-name{color:var(--datum)}
.sf-row:focus-visible{outline:2px solid var(--datum);outline-offset:2px;border-radius:6px}
.sf-code{flex:0 0 auto;min-width:52px;text-align:center;font-family:ui-monospace,monospace;
  font-weight:700;font-size:.8rem;padding:3px 6px;border-radius:6px;
  border:1px solid var(--line);color:var(--ink-2);font-variant-numeric:tabular-nums}
.sf-main{display:flex;flex-direction:column;min-width:0;flex:1}
.sf-name{font-size:.88rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sf-main .fine{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sf-dist{flex:0 0 auto;font-family:ui-monospace,monospace;font-size:.8rem;color:var(--ink-2);
  font-variant-numeric:tabular-nums;text-align:right}
.sf-more{display:flex;justify-content:space-between;gap:8px;align-items:baseline;margin-top:4px}
.sf-more .linkish{background:none;border:0;color:var(--datum);cursor:pointer;font:inherit;
  font-size:.78rem;padding:2px 0}

/* Which pole this board is: the code to check against the sign, the road,
   where the buses go — and the stop across the road, one tap away. */
#dep-where:empty{display:none}
#dep-where{margin:0 0 8px}
.dw-id{display:flex;flex-wrap:wrap;gap:6px;align-items:center;font-size:.8rem;color:var(--ink-2)}
.dw-code{font-family:ui-monospace,monospace;font-weight:700;font-size:.86rem;padding:2px 7px;
  border-radius:6px;border:1px solid var(--datum);color:var(--datum);font-variant-numeric:tabular-nums}
.dw-to{font-size:.82rem;color:var(--ink);margin-top:5px;line-height:1.35}
.dw-to b{font-weight:600}
.dw-other{display:flex;gap:9px;align-items:center;width:100%;text-align:left;margin-top:8px;
  background:var(--panel);color:var(--ink-2);border:1px dashed var(--line);border-radius:8px;
  padding:8px 10px;font:inherit;font-size:.8rem;cursor:pointer}
.dw-other:hover,.dw-other:focus-visible{border-color:var(--datum);color:var(--ink)}
.dw-other .dw-swap{flex:0 0 auto;font-size:1rem;color:var(--datum)}
.dw-other span:last-child{min-width:0}
.dw-other strong{color:var(--ink);font-weight:600}
.bl-head{display:flex;gap:10px;align-items:center;margin-bottom:10px}
.bl-head .dep-line{font-size:1rem;padding:5px 10px}
.bl-htxt{display:flex;flex-direction:column;min-width:0}
.bl-htxt strong{font-size:.95rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bl-rhythm{margin:0 0 12px;padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:var(--panel-2)}
.bl-rhythm:empty{display:none}
.bl-k{margin-bottom:6px}
.bl-next{display:flex;gap:8px;align-items:baseline;flex-wrap:wrap}
.bl-chip{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-weight:700;
  font-size:.9rem;color:var(--ink-3)}
.bl-chip.is-first{font-size:1.25rem;color:var(--ink)}
.bl-chip.is-live{color:var(--ok)}
.bl-chip.is-live.is-first::before{content:'';display:inline-block;width:7px;height:7px;margin:0 6px 2px 0;
  border-radius:50%;background:var(--ok);animation:dep-pulse 2s ease-in-out infinite}
.bl-facts{margin-top:6px}
.bl-dirs{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 10px}
.bl-dirs .btn[aria-pressed="true"]{border-color:var(--datum);color:var(--datum)}
.bl-stops{list-style:none;margin:0;padding:0;position:relative}
.bl-stops>li{position:relative;display:flex;gap:12px;align-items:center;min-height:40px;padding:4px 0 4px 2px}
/* The line itself: one stroke behind the dots, in the line's colour. */
.bl-stops>li::before{content:'';position:absolute;left:9px;top:0;bottom:0;width:4px;background:var(--m,var(--datum))}
.bl-stops>li:first-child::before{top:50%}
.bl-stops>li:last-child::before{bottom:50%}
.bl-dot{flex:none;position:relative;z-index:1;width:18px;height:18px;display:grid;place-items:center}
.bl-dot::after{content:'';width:10px;height:10px;border-radius:50%;background:var(--panel);
  border:2.5px solid var(--m,var(--datum))}
.bl-stop.is-end .bl-dot::after{width:13px;height:13px;background:var(--m,var(--datum))}
.bl-stop.is-here .bl-dot::after{width:16px;height:16px;background:var(--ink);border:4px solid var(--m,var(--datum));
  box-shadow:0 0 0 4px color-mix(in srgb,var(--m,var(--datum)) 30%,transparent)}
.bl-stop.is-here{background:color-mix(in srgb,var(--m,var(--datum)) 10%,transparent);border-radius:8px}
.bl-stop.is-here .bl-name>span:first-child{font-weight:700}
.bl-stop.is-before,.bl-stop.is-past{opacity:.5}
.bl-stop.is-off .bl-name>span:first-child{text-decoration:line-through}
.bl-name{flex:1;min-width:0;display:flex;flex-direction:column;font-size:.88rem;cursor:pointer}
.bl-name>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bl-time{flex:none;display:flex;flex-direction:column;align-items:flex-end;font-family:ui-monospace,monospace;
  font-variant-numeric:tabular-nums;font-size:.85rem;color:var(--ink-2)}
.bl-stop{cursor:pointer}
.bl-stop:focus-visible{outline:2px solid var(--datum);outline-offset:-2px;border-radius:8px}
.bl-bus .bl-name{color:var(--ok);font-weight:700;font-size:.8rem;cursor:default}
.bl-bus .bl-dot::after{content:'🚌';width:auto;height:auto;border:0;background:none;font-size:15px;line-height:1}
.bl-more .bl-dot::after{width:4px;height:4px;border:0;background:var(--m,var(--datum));
  box-shadow:0 -6px 0 var(--m,var(--datum)),0 6px 0 var(--m,var(--datum))}
.bl-morebtn{background:none;border:0;padding:6px 0;color:var(--ink-2);font:inherit;font-size:.82rem;
  text-align:left;cursor:pointer;text-decoration:underline;text-underline-offset:3px}
.bl-morebtn:hover,.bl-morebtn:focus-visible{color:var(--datum)}
.bl-note{margin-top:10px}
.bl-note:empty{display:none}
@media (prefers-reduced-motion:reduce){ .bl-chip.is-live.is-first::before{animation:none} }

/* ---------------- Shared pane pieces (ui.js) ----------------
 * 2026-10-02: panes had become one long column — switch, notes, a form, a
 * feed and the settings, each with a paragraph of fine print. Now: a status
 * line, tabs for the separate jobs, explanations behind ⓘ, and rarely used
 * card actions behind ⋯. Tokens only: a literal colour breaks Holiday. */
.ui-info{display:inline-grid;place-items:center;width:30px;height:30px;margin:-6px -4px -6px 2px;vertical-align:middle;
  border:0;border-radius:50%;background:none;color:var(--ink-3);cursor:pointer;padding:0;-webkit-tap-highlight-color:transparent}
.ui-info svg{width:18px;height:18px;fill:currentColor}
.ui-info:hover,.ui-info:focus-visible{color:var(--datum)}
.ui-prose p{margin:0 0 10px;color:var(--ink-2);line-height:1.55}
.ui-prose p:last-child{margin-bottom:0}
.ui-tabs{position:sticky;top:0;z-index:2;margin:2px 0 14px}
.ui-tabs .seg-b{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:42px;white-space:nowrap;padding:8px 6px}
.ui-n{min-width:18px;height:18px;padding:0 5px;border-radius:9px;font-size:.72rem;font-weight:700;line-height:18px;
  background:color-mix(in srgb,var(--ink) 14%,transparent)}
.seg-b.is-on .ui-n{background:color-mix(in srgb,var(--on-accent) 20%,transparent)}
.ui-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:22px 0 8px}
.ui-head:first-child{margin-top:4px}
.ui-head h2{display:flex;align-items:center;margin:0;font-size:.76rem;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--ink-3)}
.ui-more{flex:0 0 auto;min-width:40px;height:36px;border:1px solid var(--line);border-radius:8px;background:none;
  color:var(--ink-2);font-size:20px;line-height:1;cursor:pointer;margin-left:auto;font-family:inherit}
.ui-menu{display:grid}
.ui-menu-b{display:block;width:100%;text-align:left;background:none;border:0;border-bottom:1px solid var(--line);
  padding:13px 4px;color:var(--ink);font:inherit;cursor:pointer}
.ui-menu-b:last-child{border-bottom:0}
.ui-menu-b strong{display:block;font-weight:600}
.ui-menu-b .fine{display:block;margin:2px 0 0}
.ui-menu-b.is-danger strong{color:var(--magenta)}
.ui-status{display:flex;align-items:center;gap:10px;padding:10px 12px;margin:0 0 12px;
  background:var(--panel);border:1px solid var(--line);border-radius:12px}
.ui-dot{flex:0 0 10px;height:10px;border-radius:50%;background:var(--ink-3)}
.ui-status.is-ok .ui-dot{background:var(--ok)}
.ui-status.is-warn .ui-dot{background:var(--warn)}
.ui-status-t{flex:1;min-width:0;font-size:.9rem;color:var(--ink-2);line-height:1.4}
.ui-status .btn{flex:0 0 auto}
.ui-empty{padding:26px 16px;text-align:center;color:var(--ink-3);border:1px dashed var(--line);border-radius:12px;font-size:.92rem}
.ui-empty p{margin:0}
.ui-empty .btn{margin-top:12px}

/* The Agents hub as a list: icon, name, one or two lines, chevron — ten
   tall cards were two thousand pixels of scrolling on a phone. */
.ag-grid{grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:8px}
.ag-card{display:grid;grid-template-columns:40px minmax(0,1fr) 12px;column-gap:14px;row-gap:1px;align-items:center;
  padding:12px 14px;border-radius:12px}
.ag-card .ag-ico{grid-row:1/3}
.ag-card .ag-t{grid-column:2;align-self:end;font-size:1rem}
.ag-card .ag-d{grid-column:2;align-self:start;font-size:.84rem;color:var(--ink-3);line-height:1.35;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.ag-card::after{content:'';grid-column:3;grid-row:1/3;width:8px;height:8px;margin-left:-4px;
  border-top:2px solid var(--ink-3);border-right:2px solid var(--ink-3);transform:rotate(45deg)}

/* A notice: what, where/when, two lines; the whole card opens Read more. */
.ag-item{display:grid;grid-template-columns:minmax(0,1fr) 12px;column-gap:10px;align-items:center;padding:12px 14px}
.ag-item>*{grid-column:1}
.ag-item::after{content:'';grid-column:2;grid-row:1/3;width:7px;height:7px;margin-left:-4px;
  border-top:2px solid var(--ink-3);border-right:2px solid var(--ink-3);transform:rotate(45deg)}
.ag-item-t .fine{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ag-item-s{margin:6px 0 0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.ag-item:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.ui-gear{display:inline-grid;place-items:center;padding:0;width:38px;min-height:34px}
.ui-gear svg{width:18px;height:18px;fill:currentColor}
.nt-set-h{font-size:.95rem;margin:20px 0 6px}
p.ui-empty{margin:0}
/* A row that opens something: title, one line, chevron. */
.ui-row{display:flex;align-items:center;gap:12px;width:100%;padding:12px 14px;text-align:left;font:inherit;color:var(--ink);
  background:var(--panel);border:1px solid var(--line);border-radius:12px;cursor:pointer}
.ui-row::after{content:'';flex:0 0 8px;height:8px;margin-right:4px;border-top:2px solid var(--ink-3);border-right:2px solid var(--ink-3);transform:rotate(45deg)}
.ui-row-t{flex:1;min-width:0}
.ui-row-t strong{display:block;font-weight:600}
.ui-row-t .fine{display:block;margin:2px 0 0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* A setting: what it does on the left, its switch on the right. */
.ui-sw{display:flex;align-items:center;gap:14px;padding:12px 0;margin:0;border-bottom:1px solid var(--line);cursor:pointer;
  font-size:inherit;text-transform:none;letter-spacing:normal;color:var(--ink);font-weight:400}
.ui-sw>span{flex:1;min-width:0}
.ui-sw strong{display:block;font-weight:600}
.ui-sw .fine{display:block;margin:2px 0 0;line-height:1.4}
.ui-toggle{appearance:none;-webkit-appearance:none;flex:0 0 auto;position:relative;width:46px;height:28px;margin:0;
  border-radius:14px;background:var(--line);cursor:pointer;transition:background .15s}
.ui-toggle::after{content:'';position:absolute;top:3px;left:3px;width:22px;height:22px;border-radius:50%;
  background:var(--ink-2);transition:transform .15s,background .15s}
.ui-toggle:checked{background:var(--datum)}
.ui-toggle:checked::after{transform:translateX(18px);background:var(--on-accent)}
.ui-toggle:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.ui-select{flex:0 0 auto;min-height:40px;padding:6px 10px;border-radius:8px;border:1px solid var(--line);
  background:var(--panel-2);color:var(--ink);font:inherit}
@media (prefers-reduced-motion:reduce){ .ui-toggle,.ui-toggle::after{transition:none} }
.cmp-note:empty{display:none}
.cmp-go{width:100%;min-height:48px;font-weight:600}
.cmp-now .cmp-chips{margin:0}
.cmp-card-a{align-items:center}
/* Hub sections; one whose cards are all switched off for this account goes. */
.ag-group{margin:0 0 18px}
.ag-group-h{margin:0 0 8px;font-size:.76rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-3)}
.ag-group:not(:has(.ag-card:not([hidden]))){display:none}
/* Hub sections; one whose cards are all switched off for this account goes. */
.ag-group{margin:0 0 18px}
.ag-group-h{margin:0 0 8px;font-size:.76rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-3)}
.ag-group:not(:has(.ag-card:not([hidden]))){display:none}
.vc-mode-row{display:flex;gap:8px;align-items:stretch;margin:0 0 12px}
.vc-mode-row .vc-modes{flex:1;margin:0}
.vc-mode-row .vc-gear{width:46px;min-height:auto}
.vc-opts .vc-engine{margin:0 0 6px}
/* Holiday styles every <label> (theme.css); a settings row is not a form label. */
html[data-theme] label.ui-sw{letter-spacing:normal;font-weight:400;color:var(--ink)}

/* ---- Country brief redesign (10-02) ----
   Your countries, changed recently, every country folded by level; compact
   rows (flag, name, one line, level, star, chevron) in panels. */
#view-brief .lede{margin-bottom:14px}
#view-brief .lede .ui-info{margin-left:0}
.adv-bar{margin:0}
.adv-bar .ui-tabs{margin:0 0 6px;background:var(--ground)}
.adv-bar .ui-tabs .seg-b{font-size:.84rem;padding:8px 2px;min-width:0}
.adv-bar .ui-status{margin:0 0 6px}
#adv-list>.ui-head:first-child{margin-top:12px}
.adv-box{background:var(--panel);border:1px solid var(--line);border-radius:12px;overflow:hidden}
#adv-list .pager-list.adv-box{display:block}
/* No content-visibility: lists are 25 rows a page now, and skipped painting
   was a suspect in a screenshot that showed one row twice. */
.adv{display:flex;align-items:center;gap:12px;padding:8px 8px 8px 12px;border-bottom:1px solid var(--line);
  content-visibility:visible}
.adv:hover{background:var(--panel-2)}
.adv.is-sel{background:var(--panel-2)}
.adv:focus-visible{outline:2px solid var(--datum);outline-offset:-2px}
.adv::after{content:'';flex:0 0 7px;height:7px;margin:0 6px 0 -2px;border-top:2px solid var(--ink-3);border-right:2px solid var(--ink-3);transform:rotate(45deg)}
.adv-badge{flex:0 0 34px;height:34px;border-radius:50%;display:grid;place-items:center;font-size:20px;line-height:1;background:var(--panel-2)}
.adv-badge.is-letter{font-size:.86rem;font-weight:700;color:var(--ink-3)}
.adv .adv-body{min-width:0;flex:1}
.adv .adv-country{font-weight:600;font-size:.95rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.adv-meta{font-size:.8rem;color:var(--ink-3);margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.adv .pinbtn{min-width:40px;min-height:40px;margin:0 -8px 0 -6px}
.adv-more{display:block;width:100%;padding:11px;background:none;border:0;color:var(--datum);font:inherit;font-weight:600;cursor:pointer}
.adv-more:hover{background:var(--panel-2)}
.adv-group{background:var(--panel);border:1px solid var(--line);border-radius:12px;margin:0 0 8px;overflow:hidden}
.adv-group>summary{display:flex;align-items:center;gap:12px;padding:12px 14px;cursor:pointer;list-style:none;font-weight:600;color:var(--ink)}
.adv-group>summary::-webkit-details-marker{display:none}
.adv-group>summary::after{content:'';flex:0 0 7px;height:7px;margin:0 4px 3px 0;border-right:2px solid var(--ink-3);border-bottom:2px solid var(--ink-3);
  transform:rotate(45deg);transition:transform .15s}
.adv-group[open]>summary::after{transform:rotate(-135deg);margin-bottom:-3px}
.adv-group>summary:focus-visible{outline:2px solid var(--datum);outline-offset:-2px;border-radius:12px}
.adv-group[open]>summary{border-bottom:1px solid var(--line)}
.adv-group-t{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.adv-group-n{font-size:.82rem;color:var(--ink-3);font-weight:600;font-variant-numeric:tabular-nums}
.adv-group .adv-box{border:0;border-radius:0}
.adv-group .pager{padding:8px 12px;border-top:1px solid var(--line)}
@media (prefers-reduced-motion:reduce){ .adv-group>summary::after{transition:none} }

/* ---- Settings redesign (10-02) ----
   One grouped list instead of a strip of eight tabs that scrolled half of
   them off a phone. A profile row, three groups of rows, Sign out at the
   foot; each row opens its section in a full sheet (settings.js). The
   sections themselves stay in the page, hidden, until a row borrows them. */
#view-settings .set-me{display:flex;align-items:center;gap:14px;width:100%;margin:4px 0 22px;padding:14px;
  text-align:left;font:inherit;color:var(--ink);background:var(--panel);border:1px solid var(--line);
  border-radius:14px;cursor:pointer}
#view-settings .set-me::after,#view-settings .set-row::after{content:'';flex:0 0 8px;height:8px;margin:0 4px 0 2px;
  border-top:2px solid var(--ink-3);border-right:2px solid var(--ink-3);transform:rotate(45deg)}
.set-me-av{flex:0 0 48px;height:48px;border-radius:50%;display:grid;place-items:center;
  background:color-mix(in srgb,var(--datum) 18%,transparent);color:var(--datum);font-weight:700;font-size:1.05rem;letter-spacing:.02em}
.set-me-av:empty{display:none}
.set-me-t{flex:1;min-width:0}
.set-me-t strong{display:block;font-size:1.02rem;font-weight:600;overflow-wrap:anywhere}
.set-me-t .fine{display:block;margin:2px 0 0}
.set-me-t .fine:empty{display:none}
.set-list{max-width:640px}
.set-group{margin:0 0 20px}
.set-group-h{margin:0 0 8px 4px;font-size:.76rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-3)}
.set-card{background:var(--panel);border:1px solid var(--line);border-radius:14px;overflow:hidden}
/* A group whose rows are all hidden for this account goes with them. */
.set-group:not(:has(.set-row:not([hidden]))){display:none}
#view-settings .set-row{display:flex;align-items:center;gap:12px;width:100%;min-height:56px;margin:0;padding:10px 14px;
  text-align:left;font:inherit;color:var(--ink);background:none;border:0;border-radius:0;cursor:pointer}
#view-settings .set-row[hidden]{display:none}
/* The divider starts after the icon, as a list's does. */
#view-settings .set-row:not([hidden])~.set-row:not([hidden]){
  background-image:linear-gradient(var(--line),var(--line));background-repeat:no-repeat;
  background-position:58px 0;background-size:calc(100% - 58px) 1px}
#view-settings .set-row:active,#view-settings .set-me:active{background-color:var(--panel-2)}
#view-settings .set-row:focus-visible,#view-settings .set-me:focus-visible{outline:2px solid var(--datum);outline-offset:-2px}
@media (hover:hover){ #view-settings .set-row:hover,#view-settings .set-me:hover{background-color:var(--panel-2)} }
.set-ico{flex:0 0 32px;height:32px;border-radius:9px;display:grid;place-items:center;
  background:color-mix(in srgb,var(--datum) 14%,transparent);color:var(--datum)}
.set-ico svg{width:18px;height:18px;fill:currentColor}
.set-row-t{flex:1;min-width:0;font-weight:500}
.set-row-t .fine{display:block;margin:1px 0 0;font-weight:400;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.set-row-v{flex:0 0 auto;color:var(--ink-3);font-size:.9rem}
.set-row-v:empty{display:none}
.set-row-v.is-off{color:var(--warn)}
#view-settings .set-out{display:block;width:100%;margin:2px 0 8px;padding:14px;font:inherit;font-weight:600;
  color:var(--magenta);background:none;border:0;border-radius:14px;cursor:pointer}
#view-settings .set-out:active{background:color-mix(in srgb,var(--magenta) 10%,transparent)}
#view-settings .set-out:focus-visible{outline:2px solid var(--magenta);outline-offset:2px}
/* The sections are only ever seen inside a sheet now. */
#view-settings .set-pane,#view-settings .set-pane.is-on{display:none}
#view-settings .moved-note{margin:0 0 20px}
/* Wide screens: the list, not a two-column grid of tabs and pane. */
@media (min-width:900px){
  #view-settings .pad{display:block}
  #view-settings .set-me{max-width:640px}
}
/* In the sheet: the sheet's title already names the section. */
.set-pop .set-pane>h3:first-child{display:none}
.set-pop .set-pane>p.fine:first-of-type{margin-top:0}
/* The plan's total-and-button bar is pinned over the nav on the page; the
   sheet covers the nav, so it rides at the sheet's own foot instead. */
.set-pop #myplan .mp-foot{position:sticky;left:auto;right:auto;bottom:calc(-18px - env(safe-area-inset-bottom,0px));
  margin:16px -16px 0;border-radius:0}
.set-pop #myplan.has-bar{padding-bottom:0}
/* The page's field styles were scoped to #view-settings, which the section
   leaves while it is in the sheet. The sheet is --panel, so fields sit on
   --panel-2 to stay visible. */
.set-pop input[type=text],.set-pop input[type=password]{width:100%;padding:11px 13px;border-radius:8px;
  border:1px solid var(--line);background:var(--panel-2);color:var(--ink);font-size:14px;font-family:ui-monospace,monospace}
.set-pop select{width:100%;padding:10px 12px;border-radius:8px;border:1px solid var(--line);
  background:var(--panel-2);color:var(--ink);font-size:14px}
.set-pop .row-btns>select{flex:1 1 100%}
/* No back arrow on a section's first step, so the title needs its own inset. */
.set-pop:not(.is-step) .pop-head{padding-left:16px}

/* ---- Family redesign (10-02) ----
 * One group at a time: an attention strip only when a phone needs a look,
 * one compact row per phone (initials, name, "place · seen · battery", Map),
 * "Show all on map" with the group's ⋯, and Today's trails. Each phone's
 * detail and actions open in a sheet. Tokens only (Holiday). */
#fam-body .famr{max-width:760px}
#fam-body>.ui-tabs,#fam-body>.famr-switch{max-width:760px}
.famr-switch{width:100%;margin:0 0 14px}
.famr .ui-head:first-child{margin-top:4px}
.famr-attn .ui-status-t{cursor:pointer;color:var(--ink);font-weight:600}
.famr-attn{border-color:color-mix(in srgb,var(--warn) 45%,transparent);
  background:color-mix(in srgb,var(--warn) 9%,var(--panel))}
.famr-more-n{flex:0 0 auto;background:none;border:0;padding:6px 2px;color:var(--ink-2);font:inherit;font-size:.84rem;
  text-decoration:underline;text-underline-offset:3px;cursor:pointer;white-space:nowrap}
.famr-list{display:grid;grid-template-columns:minmax(0,1fr);gap:8px}
.famr-row{display:flex;align-items:center;gap:8px;min-width:0;padding:0 12px 0 0;background:var(--panel);
  border:1px solid var(--line);border-radius:12px}
.famr-open{flex:1;min-width:0;display:flex;align-items:center;gap:12px;padding:11px 0 11px 12px;background:none;border:0;
  text-align:left;color:var(--ink);font:inherit;cursor:pointer;border-radius:12px 0 0 12px}
.famr-open:focus-visible{outline:2px solid var(--datum);outline-offset:-2px}
.famr-av{flex:0 0 40px;height:40px;border-radius:50%;display:grid;place-items:center;font-weight:700;font-size:.95rem;
  color:var(--datum);background:color-mix(in srgb,var(--datum) 16%,transparent)}
.famr-row.is-warn .famr-av{color:var(--warn);background:color-mix(in srgb,var(--warn) 18%,transparent);
  box-shadow:0 0 0 2px color-mix(in srgb,var(--warn) 55%,transparent)}
.famr-row.is-off .famr-av{color:var(--ink-3);background:var(--panel-2)}
.famr-t{flex:1;min-width:0}
.famr-t strong{display:block;font-weight:600}
.famr-t .fine{display:block;margin:2px 0 0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.famr-t .is-warn{color:var(--warn)}
.famr-t .famr-meta{display:flex;min-width:0}
.famr-meta>span{flex:0 0 auto;white-space:nowrap}
.famr-meta>.famr-meta-p{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis}
.famr-sep{margin:0 .35em}
.famr-acts .btn[disabled]{opacity:.5;cursor:default}
.famr-map{flex:0 0 auto}
.famr-acts{display:flex;gap:8px;align-items:stretch;margin:14px 0 0}
.famr-acts .btn.primary{flex:1;min-height:46px}
.famr-acts .ui-more{height:auto;min-width:48px;margin-left:0}
/* The phone's sheet. */
.famr-where{margin:0 0 10px}
.famr-place{display:block;font-size:1.02rem;font-weight:600;color:var(--ink)}
.famr-where .fine{margin:3px 0 0;font-variant-numeric:tabular-nums}
.famr-facts{margin:0 0 12px}
.famr-quick{margin:0 0 6px}
.famr-menu{margin-top:4px}
/* Trails and stops: one line per phone, its two buttons on the right. */
.famr-trail{display:flex;align-items:center;gap:10px;padding:11px 0;border-bottom:1px solid var(--line)}
.famr-trail:last-of-type{border-bottom:0}
.famr-trail-b{flex:0 0 auto;display:flex;gap:6px}
.famr-trails-n{margin:10px 0 0}
.famr-set .push-panel{margin:0}
/* Holiday pads every .btn 18px each side, which pushed the ⚙ off-centre. */
#fam-head-actions .ui-gear{padding:0}

/* ---- SOS / Emergency redesign (10-02) ----
 * The card was a title, a paragraph, the numbers, a paragraph of fine
 * print and eight tabs in a strip that scrolled sideways. Now: the numbers
 * as big danger-tinted tiles, one line under them with the rest behind ⓘ,
 * help near you as rows, and the country guides as tiles that open sheets. */
.sos-head{flex-wrap:nowrap;gap:10px}
.sos-head h1{margin:0;min-width:0}
.sos-pick{min-width:0;max-width:62%;min-height:40px;padding:7px 12px 7px 14px;border-radius:999px;gap:6px;
  font-size:14px;font-weight:600;justify-content:flex-start}
#sos-pick-label{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#sos-sub{display:flex;align-items:center;margin:4px 0 12px;font-size:.92rem}
#sos-top .sos-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:0 0 6px}
/* Three numbers, or 112 alone: the odd one out takes the whole row. */
#sos-top .sos-num:last-child:nth-child(odd){grid-column:1/-1}
.sos-num{display:flex;flex-direction:column;justify-content:center;min-height:78px;padding:10px 14px;border-radius:14px;
  background:color-mix(in srgb,var(--magenta) 13%,var(--panel));border:1px solid color-mix(in srgb,var(--magenta) 40%,transparent);
  -webkit-tap-highlight-color:transparent}
.sos-num:active{background:color-mix(in srgb,var(--magenta) 24%,var(--panel))}
.sos-num:focus-visible{outline:2px solid var(--magenta);outline-offset:2px}
.sos-num .lbl{color:color-mix(in srgb,var(--magenta) 60%,var(--ink));font-weight:700}
.sos-num .num{font-size:2.1rem;line-height:1.05}
.sos-num .num.is-long{font-size:1.2rem;line-height:1.25}
.sos-num .num small{display:block;margin-top:2px;font:500 .74rem/1.3 var(--font);color:var(--ink-2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sos-note{margin:0 0 4px;font-size:.82rem}
.sos-guess{margin:0 0 4px;color:var(--warn)}
/* Help near you */
#sos-body>.ui-head{margin-top:18px}
#sos-body>p.fine{margin:14px 0 0}
.sos-where .ui-status{margin:0 0 8px}
.sos-here .ui-status-t{display:flex;flex-direction:column;gap:1px}
.sos-here .help-k{margin:0}
.sos-here .sos-where-en{font-size:.95rem;font-weight:600;color:var(--ink);line-height:1.3;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.sos-here .fine{margin:0;overflow-wrap:anywhere}
.sos-here .ui-more{height:34px;min-width:36px;margin-left:0}
/* A grid item's minimum width is its content: without minmax(0,…) a long
   hospital name pushed Directions off the screen. */
.sos-help{margin:0 0 8px;grid-template-columns:minmax(0,1fr)}
.sos-help>p.fine{margin:0}
.sos-near{display:flex;align-items:center;gap:8px;padding:10px 12px;background:var(--panel);border:1px solid var(--line);border-radius:12px}
.sos-near-t{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.sos-near-t .fine{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* The name may take two lines: a hospital cut to "Hôpital Européen Geor…" is no help. */
.sos-near-t strong{line-height:1.3;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.sos-near-t .fine{margin:0}
.sos-near .help-k{display:flex;align-items:center;flex-wrap:wrap;gap:2px 6px;margin:0;letter-spacing:.05em;white-space:nowrap}
.sos-near .tag{padding:1px 6px;color:var(--magenta);background:color-mix(in srgb,var(--magenta) 14%,transparent)}
.sos-near .btn{flex:0 0 auto}
.sos-near .ui-more{height:34px;min-width:36px;margin-left:0}
.sos-rows{display:grid;grid-template-columns:minmax(0,1fr);gap:8px}
.sos-emb-sheet .help-h{margin-top:14px}
/* A paged list of places: the same gap between rows as an unpaged one. */
.help-list>.pager-list{display:grid;grid-template-columns:minmax(0,1fr);gap:8px}
/* Know before you need it */
#sos-know{margin-top:8px}
.sos-know-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
.sos-tile{display:flex;flex-direction:column;align-items:flex-start;gap:3px;min-height:70px;padding:12px 14px;text-align:left;
  background:var(--panel);border:1px solid var(--line);border-radius:12px;color:var(--ink);font:inherit;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.sos-tile:last-child:nth-child(odd){grid-column:1/-1}
.sos-tile strong{display:flex;align-items:center;font-weight:600}
.sos-tile .fine{margin:0;font-size:.8rem;line-height:1.35}
.sos-tile:hover{border-color:var(--datum)}
.sos-tile:active{background:var(--panel-2)}
.sos-tile:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.sos-sheet>.sec:first-child,.sos-sheet>.facts:first-child{margin-top:0}

/* ---- SOS away (10-02) ----
 * The card is on another country than the phone: a bar on top with the
 * numbers where the phone is, a line saying whose the big tiles are, and
 * help around a hotel or city in that country. */
.sos-away-bar{display:flex;align-items:center;gap:10px;margin:0 0 10px;padding:10px 12px;border-radius:12px;
  background:color-mix(in srgb,var(--warn) 12%,var(--panel));border:1px solid color-mix(in srgb,var(--warn) 45%,transparent)}
.sos-away-t{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.sos-away-t strong{font-size:.92rem;line-height:1.3}
.sos-away-nums{display:flex;flex-wrap:wrap;gap:6px}
.sos-away-num{display:inline-flex;align-items:baseline;gap:5px;padding:4px 10px;border-radius:999px;text-decoration:none;
  font-size:.82rem;color:var(--ink);background:var(--panel);border:1px solid var(--line)}
.sos-away-num b{font-size:.98rem}
.sos-away-bar .btn{flex:0 0 auto}
.sos-away-h{margin:0 0 6px;font-size:.88rem;font-weight:600;color:var(--ink-2)}
.sos-anchor{margin:0 0 8px}
.sos-anchor .ui-row-t,.sos-save-near .ui-row-t{display:flex;flex-direction:column;gap:1px}
.sos-anchor .help-k{margin:0}
.sos-anchor .fine,.sos-save-near .fine{margin:0}
.ui-menu-b.is-on strong{color:var(--datum)}
.fr-photo-credit{margin:-4px 0 8px}
.fr-status-box{margin:8px 0;padding:8px 10px;border:1px solid var(--line);border-radius:9px}
.fr-status-head{font-weight:600;margin-bottom:2px}

/* Notices by level (10-03): counts on top, Critical/High in full, Low folded. */
.ag-item.is-low{border-left-color:var(--ink-3)}
.nt-chip.is-note{border-color:var(--datum);color:var(--datum);background:color-mix(in srgb,var(--datum) 10%,transparent)}
.lv-sum{display:flex;flex-wrap:wrap;gap:6px;margin:2px 0 12px}
.lv-chip{display:inline-flex;align-items:center;gap:4px;font:inherit;font-size:.82rem;padding:4px 10px;border-radius:999px;
  border:1px solid var(--line);background:var(--panel-2);color:var(--ink-2);cursor:pointer}
.lv-chip b{font-weight:700}
.lv-chip.is-urgent{border-color:var(--magenta);color:var(--magenta);background:color-mix(in srgb,var(--magenta) 12%,transparent)}
.lv-chip.is-warn{border-color:var(--warn);color:var(--warn);background:color-mix(in srgb,var(--warn) 12%,transparent)}
.lv-chip.is-note{border-color:color-mix(in srgb,var(--datum) 60%,transparent);color:var(--datum)}
.lv-chip.is-good{border-color:color-mix(in srgb,var(--ok) 60%,transparent);color:var(--ok)}
.lv-sec{margin:0 0 6px;scroll-margin-top:12px}
.lv-h{display:flex;align-items:baseline;gap:6px;margin:12px 0 8px;font-size:.8rem;font-weight:400;letter-spacing:.02em;color:var(--ink-2)}
.lv-h b{font-size:.78rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--ink)}
.lv-h .fine{margin:0}
.lv-dot{flex:0 0 8px;width:8px;height:8px;border-radius:50%;background:var(--ink-3);align-self:center}
.lv-sec.is-urgent .lv-dot{background:var(--magenta)} .lv-sec.is-warn .lv-dot{background:var(--warn)}
.lv-sec.is-note .lv-dot{background:var(--datum)} .lv-sec.is-good .lv-dot{background:var(--ok)}
details.lv-sec>summary.lv-h{cursor:pointer;list-style:none;padding:8px 0;border-top:1px dashed var(--line)}
details.lv-sec>summary.lv-h::-webkit-details-marker{display:none}
details.lv-sec>summary.lv-h::after{content:'Show';margin-left:auto;font-size:.8rem;color:var(--datum)}
details.lv-sec[open]>summary.lv-h::after{content:'Hide'}

/* Notices: where they are about, changeable in place. */
.nt-loc{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:10px 12px;margin:0 0 12px;
  border:1px solid var(--line);border-radius:12px;background:var(--panel)}
.nt-loc-t{display:flex;flex-direction:column;min-width:0}
.nt-loc-t strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nt-loc-t .fine{margin:1px 0 0}
.nt-where-first{display:flex;flex-direction:column;gap:8px;margin:4px 0 12px}
.nt-where-first .btn{width:100%;justify-content:center}
.nt-where-pick{display:flex;flex-direction:column;gap:6px}
.nt-where-opt{border:1px solid var(--line);border-radius:12px;background:var(--panel);cursor:pointer}
.nt-where-ico{font-size:1.2rem;flex:0 0 auto}

/* Live checks: the most serious rows first, marked. */
.ag-watch-adds{display:flex;gap:6px}
.ag-watch-row.is-urgent>summary{box-shadow:inset 3px 0 0 var(--magenta);padding-left:10px}
.ag-watch-row.is-high>summary{box-shadow:inset 3px 0 0 var(--warn);padding-left:10px}
.ag-watch-row.is-urgent .ag-watch-t .fine{color:var(--magenta)}

/* One city inside a country's Brief or SOS card. */
.ag-city-chips{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 10px}
.ag-city-other{border-style:dashed}
.brief-city,.sos-city{margin-top:8px}

/* ---------------- Companion v2 + Buddy (2026-10-03) ----------------
 * Buddy (buddy.js): the companion's face. The SVG's skin, hair and clothes
 * are artwork colours; everything around it — the disc, the thought cloud,
 * the zzz — is tokens, so it sits right in Night chart and Holiday alike.
 * The mood shows one eye/brow/mouth variant and one prop group. Motion is
 * small loops; prefers-reduced-motion stops all of it (still pose). */
.bd{--bd-size:96px;width:var(--bd-size);height:calc(var(--bd-size) * 124 / 120);flex:0 0 auto;position:relative;line-height:0}
.bd-svg{display:block;width:100%;height:100%;overflow:visible}
.bd-bg{fill:var(--panel-2);stroke:var(--line);stroke-width:1.2}
.bd.no-bg .bd-bg{display:none}
.bd .bd-v{display:none}
.bd .bd-e-open,.bd .bd-b-norm,.bd .bd-m-smile{display:inline}
.bd .bd-cheeks{opacity:.42;transition:opacity .4s}
.bd .bd-z{fill:var(--ink-2)}
.bd .bd-cloud{fill:var(--panel);stroke:var(--ink-3);stroke-width:1.2}
.bd .bd-dot{fill:var(--ink-2)}
.bd[data-mood="happy"] .bd-e-open,.bd[data-mood="happy"] .bd-m-smile{display:none}
.bd[data-mood="happy"] .bd-e-happy,.bd[data-mood="happy"] .bd-m-open,.bd[data-mood="happy"] .bd-p-happy{display:inline}
.bd[data-mood="happy"] .bd-cheeks{opacity:.6}
.bd[data-mood="tired"] .bd-e-open,.bd[data-mood="tired"] .bd-m-smile{display:none}
.bd[data-mood="tired"] .bd-e-tired,.bd[data-mood="tired"] .bd-m-flat,.bd[data-mood="tired"] .bd-p-tired{display:inline}
.bd[data-mood="hot"] .bd-m-smile{display:none}
.bd[data-mood="hot"] .bd-m-wavy,.bd[data-mood="hot"] .bd-p-hot{display:inline}
.bd[data-mood="hot"] .bd-cheeks{opacity:.95}
.bd[data-mood="cold"] .bd-b-norm,.bd[data-mood="cold"] .bd-m-smile{display:none}
.bd[data-mood="cold"] .bd-b-worry,.bd[data-mood="cold"] .bd-m-wavy,.bd[data-mood="cold"] .bd-p-cold{display:inline}
.bd[data-mood="unwell"] .bd-e-open,.bd[data-mood="unwell"] .bd-b-norm,.bd[data-mood="unwell"] .bd-m-smile{display:none}
.bd[data-mood="unwell"] .bd-e-tired,.bd[data-mood="unwell"] .bd-b-worry,.bd[data-mood="unwell"] .bd-m-flat,.bd[data-mood="unwell"] .bd-p-unwell{display:inline}
.bd[data-mood="unwell"] .bd-cheeks{opacity:.2}
.bd[data-mood="worried"] .bd-b-norm,.bd[data-mood="worried"] .bd-m-smile{display:none}
.bd[data-mood="worried"] .bd-b-worry,.bd[data-mood="worried"] .bd-m-flat{display:inline}
.bd[data-mood="thinking"] .bd-m-smile{display:none}
.bd[data-mood="thinking"] .bd-m-o,.bd[data-mood="thinking"] .bd-p-thinking{display:inline}
.bd[data-mood="thinking"] .bd-e-open{transform:translate(1.4px,-1.6px)}
.bd[data-mood="rain"] .bd-p-rain{display:inline}

.bd-all{animation:bd-bob 3.6s ease-in-out infinite;animation-delay:var(--bd-delay,0s)}
.bd-body{transform-box:fill-box;transform-origin:50% 100%;animation:bd-breath 3.6s ease-in-out infinite;animation-delay:var(--bd-delay,0s)}
.bd-blink{transform-box:fill-box;transform-origin:50% 50%;animation:bd-blink 4.8s infinite;animation-delay:var(--bd-delay,0s)}
.bd.is-greet .bd-arm{animation:bd-wave 1.6s ease-in-out 2}
.bd-momo.is-greet .bd-arm{animation-name:bd-wave-s}
.bd[data-mood="rain"] .bd-arm{animation:none}
.bd-sweat{animation:bd-drip 2.4s ease-in infinite}
.bd-fan{animation:bd-fan .9s ease-in-out infinite}
.bd-z{animation:bd-z 3s ease-out infinite}
.bd-z.z2{animation-delay:.6s}.bd-z.z3{animation-delay:1.2s}
.bd[data-mood="cold"] .bd-shake{animation:bd-shiver 2.6s linear infinite}
.bd-puff{animation:bd-puff 2.6s ease-out infinite}
.bd-spark{animation:bd-twinkle 1.8s ease-in-out infinite}
.bd-spark.s2{animation-delay:.6s}.bd-spark.s3{animation-delay:1.2s}
.bd-dot{animation:bd-dot 1.4s ease-in-out infinite}
.bd-dot.d2{animation-delay:.2s}.bd-dot.d3{animation-delay:.4s}
.bd-drops path{animation:bd-rain 1.1s linear infinite}
.bd-drops .r2{animation-delay:.3s}.bd-drops .r3{animation-delay:.55s}.bd-drops .r4{animation-delay:.8s}
@keyframes bd-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-1.8px)}}
@keyframes bd-breath{0%,100%{transform:scale(1,1)}50%{transform:scale(1.012,1.028)}}
@keyframes bd-blink{0%,91%,97%,100%{transform:scaleY(1)}94%{transform:scaleY(.08)}}
@keyframes bd-wave{0%,100%{transform:rotate(0)}22%{transform:rotate(-122deg)}38%{transform:rotate(-100deg)}54%{transform:rotate(-128deg)}70%{transform:rotate(-102deg)}84%{transform:rotate(-120deg)}}
@keyframes bd-wave-s{0%,100%{transform:rotate(0)}22%{transform:rotate(-95deg)}38%{transform:rotate(-70deg)}54%{transform:rotate(-100deg)}70%{transform:rotate(-72deg)}84%{transform:rotate(-92deg)}}
@keyframes bd-drip{0%{transform:translateY(-2px);opacity:0}15%,70%{opacity:1}100%{transform:translateY(9px);opacity:0}}
@keyframes bd-fan{0%,100%{transform:rotate(-16deg)}50%{transform:rotate(12deg)}}
@keyframes bd-z{0%{opacity:0;transform:translate(0,4px)}25%{opacity:1}100%{opacity:0;transform:translate(5px,-7px)}}
@keyframes bd-shiver{0%,28%,100%{transform:translateX(0)}3%,9%,15%,21%{transform:translateX(-.9px)}6%,12%,18%,24%{transform:translateX(.9px)}}
@keyframes bd-puff{0%{opacity:0;transform:translate(0,0)}20%{opacity:.9}100%{opacity:0;transform:translate(-6px,-4px)}}
@keyframes bd-twinkle{0%,100%{transform:scale(.55);opacity:.5}50%{transform:scale(1.1);opacity:1}}
@keyframes bd-dot{0%,100%{opacity:.25}40%{opacity:1}}
@keyframes bd-rain{0%{transform:translate(0,-6px);opacity:0}20%{opacity:1}100%{transform:translate(-3px,16px);opacity:0}}
@media (prefers-reduced-motion:reduce){.bd,.bd *{animation:none !important;transition:none !important}}

/* The "Choose your companion" sheet. */
.bd-choose-lede{margin:0 0 12px;color:var(--ink-2)}
.bd-choose-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.bd-opt{display:flex;flex-direction:column;align-items:center;gap:6px;padding:12px 4px 10px;border:2px solid var(--line);
  border-radius:18px;background:var(--panel);color:var(--ink);font:inherit;cursor:pointer;-webkit-tap-highlight-color:transparent}
.bd-opt.is-on{border-color:var(--datum);background:color-mix(in srgb,var(--datum) 10%,var(--panel))}
.bd-opt:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.bd-opt-n{font-weight:700;font-size:.95rem;line-height:1.2}
.bd-name-l{display:block;margin:16px 0 14px}
.bd-name-l .fine{display:block;margin:0 0 4px}
input.bd-name,.cmp-tell input,.cmp-chat input,.cmp-mem-add input{display:block;width:100%;min-height:44px;padding:9px 12px;border-radius:10px;
  border:1px solid var(--line);background:var(--panel-2);color:var(--ink);font:inherit;box-sizing:border-box}
.bd-go{width:100%;min-height:46px}

/* Companion v2 screen (companion.js). Tokens only. */
.cmp-gear{display:grid;place-items:center;width:40px;height:40px;border:1px solid var(--line);border-radius:10px;
  background:var(--panel);color:var(--ink-2);cursor:pointer;padding:0}
.cmp-gear svg{width:20px;height:20px;fill:currentColor}
.cmp-gear:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.cmp-hero{display:flex;align-items:flex-end;gap:8px;margin:2px 0 12px}
.cmp-hero .bd{cursor:pointer}
.cmp-bubble{position:relative;flex:1;min-width:0;margin:0 0 22px 6px;padding:10px 13px;background:var(--panel);
  border:1px solid var(--line);border-radius:16px;color:var(--ink);font-size:.96rem;line-height:1.38}
.cmp-bubble::before{content:'';position:absolute;left:-7px;bottom:14px;width:12px;height:12px;background:var(--panel);
  border-left:1px solid var(--line);border-bottom:1px solid var(--line);transform:rotate(45deg)}
.cmp-bubble b{display:block;font-size:.74rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3);margin-bottom:2px}
.cmp-feel{margin:0 0 10px;padding:10px 12px 12px;background:var(--panel);border:1px solid var(--line);border-radius:var(--r)}
.cmp-feel-h{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:0 0 8px}
.cmp-feel-h strong{font-size:.98rem}
.cmp-feel-h .fine{margin:0}
.cmp-feel .tc-chips{gap:6px}
.cmp-feel .tc-chip{min-height:38px;padding:5px 12px;font-size:.9rem}
.cmp-tell{display:flex;gap:6px;margin-top:8px}
.cmp-tell input{flex:1;min-width:0}
.cmp-wx{display:flex;align-items:center;gap:12px;margin:0 0 10px;padding:10px 14px;background:var(--panel);
  border:1px solid var(--line);border-radius:var(--r)}
.cmp-wx-t{flex:1;min-width:0}
.cmp-wx-t strong{display:block;line-height:1.3}
.cmp-wx-t .fine{display:block;margin:2px 0 0}
.cmp-wx-n{font-size:1.9rem;font-weight:700;line-height:1;color:var(--ink);font-variant-numeric:tabular-nums}
.cmp-wx.is-hot{box-shadow:inset 3px 0 0 var(--warn)}
.cmp-wx.is-cold{box-shadow:inset 3px 0 0 var(--datum)}
.cmp-wx.is-rain{box-shadow:inset 3px 0 0 var(--datum)}
.cmp-feed-h{margin:16px 0 8px}
.cmp-earlier{margin:14px 0 6px;font-size:.8rem;font-weight:600;color:var(--ink-2);text-transform:uppercase;letter-spacing:.04em}
.cmp-card.is-old{opacity:.72}
.cmp-card.k-meal,.cmp-card.k-explore,.cmp-card.k-tip{box-shadow:inset 3px 0 0 var(--ok)}
.cmp-card.k-heat,.cmp-card.k-uv,.cmp-card.k-air,.cmp-card.k-rain,.cmp-card.k-cold{box-shadow:inset 3px 0 0 var(--warn)}
.cmp-card.k-care,.cmp-card.k-checkin{box-shadow:inset 3px 0 0 var(--magenta)}
.cmp-card.is-sos{border-color:var(--magenta)}
.cmp-card.is-focus{box-shadow:0 0 0 2px var(--datum)}
.cmp-card .cmp-body{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.cmp-card .cmp-body.is-open{display:block;-webkit-line-clamp:unset}
.cmp-card-a{align-items:center}
.cmp-card-a .ui-more{height:36px}
.cmp-card-a .btn.is-on{border-color:var(--datum);color:var(--datum)}
.cmp-thumb{min-width:44px}
.cmp-why{display:flex;flex-wrap:wrap;gap:8px}
.cmp-why .tc-chip{font-size:.95rem}
.cmp-chat{position:sticky;bottom:10px;z-index:3;display:flex;align-items:center;gap:6px;margin:16px 0 4px;padding:5px 5px 5px 6px;
  background:var(--panel);border:1px solid var(--line);border-radius:999px;box-shadow:0 8px 22px -10px color-mix(in srgb,var(--shadow) 70%,transparent)}
.cmp-chat input{flex:1;min-width:0;border:0;background:none;border-radius:999px;min-height:42px}
.cmp-chat input:focus{outline:none}
.cmp-chat:focus-within{border-color:var(--datum)}
.cmp-send{flex:0 0 auto;display:grid;place-items:center;width:42px;height:42px;border:0;border-radius:50%;
  background:var(--datum);color:var(--on-accent);cursor:pointer;padding:0}
.cmp-send svg{width:20px;height:20px;fill:currentColor}
.cmp-mem-add{display:flex;gap:6px;margin:0 0 6px}
.cmp-mem-add input{flex:1;min-width:0}
.cmp-mem .cmp-rem-t .fine{display:block}
.cmp-confirm{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:12px 0 0;padding:10px 12px;
  border:1px solid color-mix(in srgb,var(--magenta) 45%,transparent);border-radius:12px;background:color-mix(in srgb,var(--magenta) 8%,var(--panel))}
.cmp-confirm span{flex:1 1 100%;color:var(--ink)}
.cmp-mem-foot{display:flex;justify-content:flex-end;margin-top:10px}
.cmp-row-b{display:flex;align-items:center;gap:12px}
.cmp-row-b .bd{--bd-size:48px}
.cmp-card-a{gap:6px}
.cmp-card-a .btn.sm{padding:6px 11px}
.cmp-card-a .cmp-thumb{min-width:40px;padding:6px 8px}
.cmp-feel-h strong{white-space:nowrap}
.cmp-feel-h .fine{text-align:right}

/* ---------------- Companion = the assistant (10-03) ----------------
 * ai.js draws the traveller's character (buddy.js) in the map's round
 * button and in the chat's title bar; the character's own artwork colours
 * live in buddy.js and the "Buddy" section above. Here: the frame around it,
 * the safety line under the box, the PII note and the hand-off card.
 * Tokens only. */
#ai-fab{width:60px;height:60px;padding:0;overflow:hidden;background:var(--panel-2);
  border:2px solid var(--magenta)}
#ai-fab .bd{--bd-size:58px;pointer-events:none;margin-top:3px}
#ai-fab .bd .bd-bg{display:none}
#ai-fab .bd-svg{width:100%;height:100%;fill:initial}
#ai-fab:focus-visible{outline:2px solid var(--datum);outline-offset:3px}
@media (hover:hover){#ai-fab:hover .bd{transform:translateY(-1px)}}
/* The title bar: the character's face and the companion's name. */
.ai-face{position:relative;width:32px;height:32px;border-radius:50%;overflow:hidden;
  background:var(--panel-2);border:1px solid var(--line);fill:initial;margin:-4px 0}
/* Drawn larger than the disc and shifted so the head, not the body, fills it. */
.ai-face .bd{--bd-size:50px;position:absolute;left:-10px;top:-6px}
.ai-face .bd-momo{top:-9px}
.ai-face .bd .bd-bg{display:none}
/* "For your safety…": one quiet line under the box until it is closed. */
.ai-safety{display:flex;align-items:center;gap:8px;margin:-4px 12px 8px;padding:6px 6px 6px 10px;
  border-radius:10px;background:var(--panel-2);color:var(--ink-2);font-size:.78rem;line-height:1.35}
.ai-safety>svg{flex:0 0 auto;width:16px;height:16px;fill:var(--ink-3)}
.ai-safety span{flex:1;min-width:0}
.ai-safety button{flex:0 0 auto;width:32px;height:32px;display:grid;place-items:center;border:0;border-radius:8px;
  background:none;color:var(--ink-3);cursor:pointer;padding:0}
.ai-safety button svg{width:15px;height:15px;fill:currentColor}
.ai-safety button:focus-visible{outline:2px solid var(--datum);outline-offset:1px}
#ai-panel.is-folded .ai-safety{display:none}
/* Something sensitive was hidden before the model read it. */
.ai-pii{margin:5px 2px 0;font-size:.76rem;line-height:1.35;color:var(--ink-2);text-align:right}
.ai-pii::before{content:'';display:inline-block;width:7px;height:7px;margin-right:6px;border-radius:50%;
  background:var(--warn);vertical-align:1px}
/* Hand-off: the feature that does this, filled in, one button away. */
.ai-handoff{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:8px 10px;margin-top:9px;
  padding:11px 12px;border:1px solid color-mix(in srgb,var(--datum) 45%,var(--line));border-radius:14px;
  background:color-mix(in srgb,var(--datum) 7%,var(--panel))}
.ai-ho-i{width:22px;height:22px;fill:var(--datum);margin-top:1px}
/* What the chat put on the map, and the way back to it (ai.js runMap). */
.ai-maprow{display:flex;flex-wrap:wrap;gap:6px;margin-top:9px}
.ai-body a{color:var(--datum);text-decoration:underline;overflow-wrap:anywhere}
.ai-pin{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;cursor:pointer;
  font:600 .8rem/1 var(--mono,ui-monospace,monospace);color:var(--on-accent);background:var(--datum);
  border:2px solid var(--panel);box-shadow:0 1px 4px var(--shadow)}
.ai-ho-t{display:flex;flex-direction:column;gap:2px;min-width:0}
.ai-ho-t strong{font-size:.95rem;color:var(--ink)}
.ai-ho-s{font-size:.84rem;color:var(--ink-2);overflow-wrap:anywhere}
.ai-ho-r{margin:2px 0 0}
.ai-ho-go{grid-column:1 / -1;min-height:40px;width:100%}
.ai-ho-go:disabled{opacity:.55;cursor:not-allowed}
@media (prefers-reduced-motion:reduce){#ai-fab .bd{transform:none!important}}

/* The companion's opening line in the chat: one-tap questions under it. */
.ai-chips{display:flex;flex-wrap:wrap;gap:6px;margin:-2px 0 10px}
.ai-chip{white-space:normal;text-align:left;font-size:.84rem}
/* Zoomed out past the globe into the solar system: map pins stay behind. */
.wf-in-space .maplibregl-marker,
.wf-in-space .maplibregl-popup{visibility:hidden;pointer-events:none}
/* The page's own mark: in the header of a tool, view or agent, always shown,
   so travellers learn while online what needs a connection (netneed.js). */
.need-page{display:inline-block;vertical-align:middle;margin:0 0 0 8px;padding:2px 9px;border-radius:999px;
  font-size:.72rem;font-weight:600;line-height:1.5;letter-spacing:.01em;white-space:nowrap;cursor:pointer;
  border:1px solid var(--line);background:var(--panel-2);color:var(--ink-3)}
.need-page.is-off{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 45%,transparent)}
.need-page.is-on{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 45%,transparent)}
.need-page.is-offline.is-on{background:color-mix(in srgb,var(--warn) 14%,transparent)}
.need-page.is-offline.is-part{background:color-mix(in srgb,var(--ink-3) 12%,transparent)}
.sheet-head .need-page{flex:0 0 auto;margin-left:0;margin-right:6px}
h1 > .need-page{margin:0 0 0 10px;font-family:var(--font);vertical-align:middle;position:relative;top:-2px}
/* Settings → Your data (yourdata.js) */
.yd-meter{margin:4px 0 14px}
.yd-bar{height:8px;border-radius:999px;background:var(--panel-2);overflow:hidden}
.yd-fill{height:100%;background:var(--ok);border-radius:999px;transition:width .3s}
.yd-fill.is-full{background:var(--warn)}
.yd-h{margin:16px 0 6px;font-size:.95rem}
.yd-list{list-style:none;margin:0;padding:0}
.yd-row{border-bottom:1px solid var(--line)}
.yd-row:last-child{border-bottom:0}
.yd-open{display:flex;flex-direction:column;align-items:flex-start;gap:3px;width:100%;padding:10px 0;border:0;background:none;color:var(--ink);font:inherit;text-align:left;cursor:pointer}
.yd-where{font-size:.72rem;font-weight:600;padding:1px 8px;border-radius:999px;border:1px solid var(--line);color:var(--ink-3)}
.yd-where.is-phone{color:var(--ok);border-color:color-mix(in srgb,var(--ok) 45%,transparent)}
.yd-where.is-phone-cloud{color:var(--datum);border-color:color-mix(in srgb,var(--datum) 45%,transparent)}
.yd-sync{margin:14px 0;padding:12px 14px;border:1px solid var(--line);border-radius:var(--r)}
.yd-sync-h{display:flex;align-items:center;justify-content:space-between;font-weight:700;cursor:pointer}
.yd-sens{border-left:3px solid var(--warn);padding:6px 10px;background:var(--panel-2);border-radius:6px}
.yd-lock{margin-top:12px;padding-top:10px;border-top:1px solid var(--line);display:grid;gap:8px}
/* lock.js: the traveller's key for Sync to cloud */
.lk-form{display:grid;gap:12px}
.lk-lab{display:grid;gap:4px;margin:0;min-width:0}
.lk-lab>span{font-size:13px;font-weight:600;color:var(--ink-2)}
.lk-input{min-width:0;width:100%;box-sizing:border-box;padding:10px 12px;min-height:44px;border-radius:8px;border:1px solid var(--line);background:var(--panel);color:var(--ink);font:inherit;font-size:16px}
.lk-code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:18px;letter-spacing:.05em;text-align:center;padding:14px 10px;margin:0;border:1px dashed var(--line);border-radius:8px;background:var(--panel-2);user-select:all;overflow-wrap:anywhere;color:var(--ink)}
.lk-warn{border-left:3px solid var(--warn);padding:6px 10px;background:var(--panel-2);border-radius:6px;margin:0}
.lk-status{min-height:1.2em;margin:0}
.lk-or{text-align:center;margin:0}
.lk-link{background:none;border:0;padding:4px 0;color:var(--datum);font:inherit;text-decoration:underline;cursor:pointer;justify-self:start}
.lk-ways{list-style:none;margin:0;padding:0;display:grid;gap:2px;font-size:14px;color:var(--ink-3)}
.lk-ways .is-on{color:var(--ink)}
.lk-ask{padding:8px 10px;border-radius:8px;background:var(--panel-2)}
.lk-ask p{margin:0 0 6px}
.lk-pk{display:flex;justify-content:space-between;align-items:center;gap:8px}
/* sensitive.js: a gentle word under a field holding a card or passport number */
.sens-warn{margin:4px 0 0;padding:4px 8px;border-left:3px solid var(--warn);background:var(--panel-2);border-radius:6px}
.yd-stat{margin:6px 0 8px}
.yd-cache{display:flex;align-items:center;gap:8px;padding:9px 0}
.yd-cache .btn{margin-left:auto}
.storage-bar{}

/* ---- Book tab (placecard.js, 10-07) -------------------------------------
   Trip bar, Agoda's live price, the links, then the cross-site comparison. */
.pd-trip{border:1px solid var(--line);border-radius:12px;background:var(--panel-2);margin:2px 0 12px;overflow:hidden}
.pd-trip-sum{display:flex;align-items:center;flex-wrap:wrap;gap:2px 10px;width:100%;padding:10px 12px;background:none;border:0;
  color:var(--ink);font:inherit;text-align:left;cursor:pointer;min-height:48px}
.pd-trip-d{font-weight:650;font-size:.95rem}
.pd-trip-sum .fine{flex:1 1 auto}
.pd-trip-edit-l{color:var(--datum);font-size:.86rem;font-weight:600;margin-left:auto}
.pd-trip-sum.is-open .pd-trip-edit-l{visibility:hidden}
.pd-trip-ed{padding:4px 12px 12px;border-top:1px solid var(--line)}
.pd-trip-quick{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0}
.pd-pick{border:1px solid var(--line);background:var(--panel);color:var(--ink-2);border-radius:999px;padding:6px 12px;font:inherit;
  font-size:.84rem;cursor:pointer;min-height:34px}
.pd-pick:hover{border-color:var(--datum);color:var(--ink)}
.pd-pick.is-on{border-color:var(--datum);color:var(--ink);background:color-mix(in srgb,var(--datum) 14%,transparent)}
.pd-trip-ed .pd-book-dates{margin:4px 0 10px}
.pd-trip-ed .pd-book-field{flex:1 1 130px}
.pd-trip-ed .pd-book-field input{width:100%;box-sizing:border-box}
.pd-steps{display:grid;gap:6px;margin-bottom:12px}
.pd-step{display:flex;align-items:center;gap:10px}
.pd-step-l{flex:1;font-size:.92rem}
.pd-step-b{width:36px;height:36px;border-radius:50%;border:1px solid var(--line);background:var(--panel);color:var(--ink);
  font-size:1.1rem;line-height:1;cursor:pointer}
.pd-step-b:disabled{opacity:.35;cursor:default}
.pd-step-v{min-width:22px;text-align:center;font-weight:650;font-variant-numeric:tabular-nums}
.pd-trip-done{width:100%;min-height:40px}
.pd-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:5px}
.pd-tag{font-size:.72rem;line-height:1.3;padding:2px 7px;border-radius:999px;border:1px solid var(--line);color:var(--ink-2);
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pd-tag.is-good{border-color:color-mix(in srgb,var(--ok) 55%,transparent);color:var(--ok)}
.pd-tag.is-deal{border-color:var(--magenta);color:var(--magenta);font-weight:650}
.pd-live{margin:0 0 14px}
.pd-live-main{border:1px solid var(--datum);border-radius:12px;padding:12px;background:color-mix(in srgb,var(--datum) 8%,transparent)}
.pd-live-src{font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3)}
.pd-live-top{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 10px;margin:2px 0}
.pd-live-price strong{font-size:1.45rem;font-variant-numeric:tabular-nums}
.pd-live-was{color:var(--ink-3);text-decoration:line-through;font-size:.9rem}
.pd-live-go{display:flex;justify-content:center;margin-top:10px;min-height:42px;align-items:center;text-decoration:none}
.pd-live-none{margin:0 0 8px}
.pd-alts{display:grid;gap:6px;margin-bottom:6px}
.pd-alt{display:flex;align-items:stretch;border:1px solid var(--line);border-radius:10px;overflow:hidden}
.pd-alt-who{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px;padding:8px 10px;background:none;border:0;color:var(--ink);
  font:inherit;text-align:left;cursor:pointer}
.pd-alt-who:hover{background:var(--panel-2)}
.pd-alt-n{font-weight:600;font-size:.9rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pd-alt-p{display:flex;flex-direction:column;align-items:flex-end;justify-content:center;padding:6px 12px;border-left:1px solid var(--line);
  text-decoration:none;color:var(--datum);white-space:nowrap}
.pd-alt-p strong{font-variant-numeric:tabular-nums}
.pd-live-foot{display:flex;align-items:center;gap:2px;margin-top:6px}
.pd-live-foot .ui-info{margin:-8px 0}

/* ---- the AI allowance (allowance.js, 2026-10-08) ---- */
.alw-card{display:grid;grid-template-columns:auto 1fr;gap:12px 14px;align-items:center;padding:12px 14px;margin:10px 0;
  background:var(--panel);border:1px solid var(--line);border-radius:14px}
.alw-card.is-compact{padding:10px 12px;margin:8px 0 0}
.alw-card.is-out{border-color:color-mix(in srgb,var(--warn) 60%,var(--line))}
.alw-text{display:flex;flex-direction:column;gap:4px;min-width:0}
.alw-text .btn{align-self:flex-start;margin-top:4px}
.alw-ring{display:block;transform:rotate(-90deg)}
.alw-ring circle{fill:none;stroke-width:3.4}
.alw-track{stroke:color-mix(in srgb,var(--ink) 12%,transparent)}
.alw-fill{stroke:var(--datum);stroke-linecap:round;transition:stroke-dasharray .6s ease}
.alw-ring.is-warn .alw-fill,.alw-ring.is-near .alw-fill{stroke:var(--warn)}
.alw-ring.is-out .alw-fill{stroke:var(--magenta)}
.alw-pct{fill:var(--ink);font:700 9px/1 system-ui,sans-serif;text-anchor:middle;dominant-baseline:central;transform:rotate(90deg);transform-origin:21px 21px}
.alw-spark{grid-column:1/-1;display:flex;align-items:flex-end;gap:2px;height:28px}
.alw-spark i{flex:1 1 0;min-width:2px;border-radius:2px 2px 0 0;background:color-mix(in srgb,var(--datum) 55%,transparent)}
.alw-what{color:var(--ink-2)}
.ai-quota{height:3px;margin:0 12px;border-radius:2px;background:color-mix(in srgb,var(--ink) 12%,transparent);overflow:hidden}
.ai-quota i{display:block;height:100%;border-radius:2px;background:var(--warn);transition:width .5s ease}
.ai-quota.is-out i{background:var(--magenta)}
.ai-allow-note{margin:6px 0 0;color:var(--ink-2)}
.mp-allow{margin:4px 0 12px}
.mp-allow-line{color:var(--ink-2)}
.alw-prices{border-collapse:collapse;width:100%;margin:6px 0 10px}
.alw-prices td{padding:5px 0;border-top:1px solid var(--line);vertical-align:top}
.alw-prices td .fine{display:block}
.alw-prices .alw-pn{text-align:right;white-space:nowrap;font-weight:600}
.alw-text strong .ui-info{margin-left:6px;vertical-align:middle}
/* Coupon codes on the plan page (myplan.js, 2026-10-08). */
.mp-coupon{margin:10px 0 4px}
.mp-coupon-row{display:flex;gap:8px;align-items:center}
.mp-coupon-in{flex:1 1 auto;min-width:0;padding:9px 12px;border:1px solid var(--line);border-radius:8px;background:var(--panel);color:var(--ink);font:inherit;letter-spacing:.08em;text-transform:uppercase}
.mp-coupon-said{display:block;margin-top:4px;color:var(--warn)}
.mp-coupon-said.is-ok{color:var(--ok)}
.mp-coupon-on{display:block;margin-top:4px;color:var(--ok)}
.mp-redeem{margin-top:8px}

/* Delete your account: not inside the Android app (2026-10-08 decision; put
   back by deleting this rule if Google Play rejects on it). The iPhone app
   keeps it (App Store Review Guideline 5.1.1(v)), and so does a browser. */
html.in-app:not(.in-app-ios) #del-account{display:none}

/* Plan page, 2026-10-08: add-ons the account already has are active, not
   for sale — no price, no switch — and the billing period has its own row. */
.mp-addon.is-owned{border-color:color-mix(in srgb,var(--datum) 45%,var(--line))}
.mp-owned{font-size:.86rem;font-weight:600;color:var(--datum);white-space:nowrap}
.mp-kind.is-owned{background:color-mix(in srgb,var(--datum) 16%,transparent);color:var(--datum)}
.mp-stop{justify-self:start;align-self:flex-start;background:none;border:0;padding:4px 0;margin-top:2px;font:inherit;font-size:.8rem;color:var(--ink-3);text-decoration:underline;cursor:pointer}
.mp-stop:hover{color:var(--magenta)}
.mp-line.is-owned{opacity:.85}
.mp-cycle-row{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;width:100%;padding-top:8px;border-top:1px solid var(--line)}
.mp-cycle-row .btn{margin-left:auto}

/* Coming up (comingup.js): events months ahead, deadline counting down. */
.cu-strip{margin:0 0 14px}
.cu-strip[hidden]{display:none}
.cu-head{display:flex;align-items:center;gap:8px;margin:0 0 8px}
.cu-h{margin:0;font-size:1rem;display:flex;align-items:center;gap:6px}
.cu-n{font-size:.75rem;font-weight:600;padding:1px 7px;border-radius:999px;background:var(--panel-2);color:var(--ink-2)}
.cu-list{display:grid;gap:8px}
.cu-card{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:4px 10px;align-items:start;
  background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--datum);border-radius:12px;
  padding:10px 12px;cursor:pointer}
.cu-card.is-soon{border-left-color:var(--warn)}
.cu-card.is-hot{border-left-color:var(--magenta)}
.cu-card.is-now{border-left-color:var(--ok)}
.cu-card.is-muted{opacity:.6}
.cu-card:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.cu-card-t{min-width:0}
.cu-card-t strong{display:block;font-size:.97rem;line-height:1.3}
.cu-card-s{grid-column:1/-1;margin:2px 0 0;color:var(--ink-2);font-size:.9rem;line-height:1.45;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.cu-due{font-size:.75rem;font-weight:600;padding:3px 8px;border-radius:999px;white-space:nowrap;
  background:var(--panel-2);color:var(--ink-2);border:1px solid var(--line);max-width:46vw;overflow:hidden;text-overflow:ellipsis}
.cu-due.is-soon,.cu-chip.is-soon{border-color:var(--warn);color:var(--warn);background:color-mix(in srgb,var(--warn) 12%,transparent)}
.cu-due.is-hot,.cu-chip.is-hot{border-color:var(--magenta);color:var(--magenta);background:color-mix(in srgb,var(--magenta) 12%,transparent)}
.cu-due.is-now,.cu-chip.is-now{border-color:var(--ok);color:var(--ok);background:color-mix(in srgb,var(--ok) 12%,transparent)}
.cu-marks{grid-column:1/-1;display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:6px}
.cu-marks .chip{font-size:.8rem}
.cu-marks .ui-more{margin-left:auto}
.cu-all{margin-top:8px}
.cu-g{margin:16px 0 8px;font-size:.95rem}
.cu-g:first-child{margin-top:4px}
.cu-pop .cu-card{margin-bottom:8px}
.cu-fold{margin-top:14px}
.cu-fold summary{cursor:pointer;color:var(--ink-2);font-size:.9rem;margin-bottom:8px}
.cu-reg p{margin:0 0 6px}
.cu-d-acts{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0 8px}
.cu-detail .cu-marks{margin:4px 0 10px}
.cu-trip{margin:4px 0 12px}
.cu-bar{position:relative;display:flex;align-items:center;max-width:100%;
  background:var(--panel);border:1px solid var(--magenta);border-radius:999px;box-shadow:var(--shadow)}
.cu-bar[hidden]{display:none}
.cu-bar-go{flex:1 1 auto;min-width:0;min-height:36px;padding:6px 4px 6px 14px;border:0;background:none;
  color:var(--ink);font:inherit;font-size:.82rem;text-align:left;cursor:pointer;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cu-bar-x{flex:0 0 auto;width:36px;height:36px;border:0;background:none;color:var(--ink-3);font-size:1.2rem;cursor:pointer}
#topstack > .cu-bar{order:3}
/* The deadline banner is the map's: on other screens the strip says it. */
body > #topstack > .cu-bar{display:none}

/* ---- How-to guides (guide.js) ------------------------------------------
   Drawings are lines in the look's own colours, so every look and dark mode
   draw them right; Show me dims the page and lights one real element. */
.gd{display:flex;flex-direction:column;gap:10px;padding-bottom:4px}
.gd-art{display:flex;align-items:center;justify-content:center;height:164px;padding:8px 0;overflow:hidden;
  border-radius:14px;background:var(--panel-2);touch-action:pan-y;user-select:none}
.gd-draw{width:min(260px,80%);max-height:148px}
.gd-draw svg{max-height:148px}
.gd-draw svg{display:block;width:100%;height:auto;overflow:visible}
.gd-draw .ln{fill:none;stroke:var(--ink-2);stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
.gd-draw .ac{fill:none;stroke:var(--datum);stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round}
.gd-draw .fl{fill:var(--panel)}
.gd-draw .ac.fl{fill:color-mix(in srgb,var(--datum) 14%,var(--panel))}
.gd-draw .af{fill:var(--datum)}
.gd-draw .kn{fill:var(--panel)}
.gd-draw .kn-s{fill:none;stroke:var(--on-accent);stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round}
.gd-draw .no{fill:color-mix(in srgb,var(--magenta) 16%,var(--panel));stroke:var(--magenta);stroke-width:2}
.gd-draw .no-s{fill:none;stroke:var(--magenta);stroke-width:2.6;stroke-linecap:round}
.gd-draw .dt{fill:var(--ink-2)}
.gd-draw .dash{stroke-dasharray:3 5}
.gd-draw .tx{fill:var(--ink-3);font-size:11px;text-anchor:middle;font-family:inherit}
.gd-draw .tx.on{fill:var(--datum);font-weight:600}
.gd-draw .tx.kt{fill:var(--on-accent);font-weight:600}
.gd-draw .tb{fill:var(--ink);font-size:17px;font-weight:700;text-anchor:middle;font-family:inherit}
.gd-row{display:flex;align-items:center;justify-content:center;gap:14px}
.gd-pick{display:flex;flex-direction:column;align-items:center;gap:4px;font-size:.85rem;color:var(--ink-2)}
.gd-tag{display:flex;flex-direction:column;gap:4px}
.gd-field{display:flex;align-items:center;min-width:110px;padding:8px 12px;border:2px solid var(--datum);border-radius:10px;
  background:var(--panel);color:var(--ink);font-weight:600}
.gd-caret{display:inline-block;width:2px;height:1.1em;margin-left:2px;background:var(--datum);animation:gd-blink 1s steps(1) infinite}
@keyframes gd-blink{50%{opacity:0}}
.gd-chat{align-items:flex-end}
.gd-lines{display:flex;flex-direction:column;gap:6px;max-width:190px}
.gd-say{padding:7px 11px;border-radius:14px 14px 14px 4px;background:var(--panel);border:1px solid var(--line);font-size:.82rem;color:var(--ink);line-height:1.3}
.gd-say.me{align-self:flex-end;border-radius:14px 14px 4px 14px;background:var(--datum);border-color:var(--datum);color:var(--on-accent)}
.gd-dots{display:flex;justify-content:center;gap:6px}
.gd-dots i{width:7px;height:7px;border-radius:50%;background:var(--line)}
.gd-dots i.is-past{background:color-mix(in srgb,var(--datum) 45%,var(--line))}
.gd-dots i.is-on{width:20px;border-radius:4px;background:var(--datum)}
.gd .gd-t{margin:4px 0 0;font-size:1.05rem}
.gd .gd-p{margin:0;color:var(--ink-2);line-height:1.45;min-height:calc(1.45em * 4)}
.gd-btns{display:flex;gap:8px;justify-content:flex-end;flex-wrap:wrap;margin-top:6px}
.gd-btns .btn[hidden]{display:none}
.gd .gd-btns .btn:first-child{margin-right:auto}
.gd-list{display:flex;flex-direction:column;gap:8px}
.gd-meta{flex:none;white-space:nowrap}

.gd-spot{position:fixed;inset:0;z-index:9500}
.gd-hole{position:fixed;border-radius:12px;cursor:pointer;
  box-shadow:0 0 0 3px var(--datum),0 0 0 200vmax rgba(0,0,0,.62);transition:left .2s,top .2s,width .2s,height .2s;
  animation:gd-ring 1.6s ease-in-out infinite}
@keyframes gd-ring{50%{box-shadow:0 0 0 6px color-mix(in srgb,var(--datum) 55%,transparent),0 0 0 200vmax rgba(0,0,0,.62)}}
.gd-bub{position:fixed;padding:12px 14px;border-radius:14px;background:var(--panel);color:var(--ink);border:1px solid var(--line);
  box-shadow:0 10px 30px rgba(0,0,0,.3)}
.gd-bub-top{display:flex;align-items:center;justify-content:space-between;margin:-4px -6px 2px 0}
.gd-x{width:36px;height:36px;border:0;background:none;color:var(--ink-2);font-size:22px;line-height:1;cursor:pointer;border-radius:8px}
.gd-bub .gd-t{display:block;font-size:1rem}
.gd-bub .gd-p{margin:4px 0 0;font-size:.9rem;color:var(--ink-2);line-height:1.4}
.gd-bub .gd-hint{margin:6px 0 0}

.gd-nudge{position:fixed;left:50%;transform:translateX(-50%);z-index:57;
  bottom:calc(var(--nav) + var(--safe-b) + 12px);width:min(520px,calc(100vw - 24px));
  background:var(--panel);color:var(--ink);border:1px solid var(--line);border-left:4px solid var(--datum);
  border-radius:12px;padding:12px 14px;box-shadow:0 10px 30px color-mix(in srgb,var(--shadow) 45%,transparent)}
.gd-nudge p{margin:4px 0 0;font-size:.86rem;color:var(--ink-2);line-height:1.4}
.gd-nudge .row-btns{margin-top:10px}
html[data-ai="open"] .gd-nudge{display:none}
@media (min-width:900px){ .gd-nudge{bottom:calc(24px + var(--safe-b))} }

/* Who's travelling (aboutme.js) and the "For you" line on notices and events. */
.ab-sheet{display:grid;gap:12px;padding-bottom:12px}
.ab-lead{margin:0}
.ab-group{border:0;padding:0;margin:0}
.ab-group legend{padding:0 0 4px;font-weight:600}
.ab-hint{margin:0 0 6px}
.ab-chips{display:flex;flex-wrap:wrap;gap:8px}
.ab-chip.is-skip{text-decoration:line-through;color:var(--ink-3)}
.ab-age{min-height:44px;max-width:180px}
.ab-now{margin:8px 0 0}
.ab-access{border:1px solid var(--line);border-radius:12px;padding:10px 12px}
.ab-access summary{cursor:pointer;font-weight:600;min-height:28px}
.ab-access .ab-chips{margin-top:6px}
.ab-foot{display:grid;gap:8px;justify-items:start;border-top:1px solid var(--line);padding-top:12px}
.ab-foot .fine{margin:0}
.fy-tag,.fy-lo{display:inline-block;justify-self:start;grid-column:1/-1;margin:6px 0 0;padding:2px 9px;border-radius:999px;
  font-size:.8rem;line-height:1.5;font-weight:600}
.fy-tag{background:color-mix(in srgb,var(--ok) 16%,transparent);color:var(--ink)}
.fy-lo{background:color-mix(in srgb,var(--ink-3) 14%,transparent);color:var(--ink-2);font-weight:500}
.fy-nudge{display:block;width:100%;text-align:left;margin:0 0 10px;padding:10px 12px;min-height:44px;border-radius:12px;
  border:1px dashed var(--line);background:transparent;color:var(--ink);font:inherit;cursor:pointer}
.fy-nudge:focus-visible{outline:2px solid var(--datum);outline-offset:2px}
.nt-d-map{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;margin:10px 0}
.ag-item .fy-lo,.ag-item .fy-tag{margin-right:6px}
/* What your companion knows (known.js): the one picture, and memory offers. */
.kn-box{display:grid;gap:8px;margin:0 0 14px;padding:12px;border:1px solid var(--line);border-radius:12px;min-width:0}
.kn-box[hidden]{display:none}
.kn-box .fine{margin:0}
.kn-h{margin:0;font-weight:600;font-size:.9rem;color:var(--ink)}
.kn-offer{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;min-width:0}
.kn-t{display:grid;gap:2px;min-width:0;flex:1 1 180px}
.kn-t .fine{overflow-wrap:anywhere}
.kn-offer .btn{min-height:40px;flex:0 0 auto}
.kn-lines summary{cursor:pointer;font-weight:600;min-height:32px;display:flex;align-items:center}
.kn-ul{margin:6px 0 8px;padding-left:18px;display:grid;gap:4px}
.kn-ul li{overflow-wrap:anywhere}
.kn-mem{color:var(--ink-2);font-size:.85em}
.kn-counts{color:var(--ink-2)}

/* Travellers' photos on the place card (userphotos.js). */
.tp-box{margin:8px 0 0}
.tp-row{display:flex;gap:8px;align-items:center;justify-content:space-between;margin:4px 0 0}
.tp-pending{opacity:.55;outline:2px dashed var(--line);outline-offset:-2px}

/* Install + alerts line (install.js): in #topstack once signed in, under the
   sign-in card before. The steps sheet draws Share → Add to Home Screen. */
#topstack > .inst-bar{order:1}
.gate-card > .inst-bar{margin-top:14px;min-width:0}
.gate-card > .inst-bar span{white-space:normal}
.inst-bar .btn{white-space:nowrap;flex:0 0 auto}
.inst-scrim{position:fixed;inset:0;z-index:4000;background:var(--scrim);display:flex;align-items:flex-end;justify-content:center;
  padding:16px 16px calc(16px + env(safe-area-inset-bottom,0px))}
.inst-card{width:100%;max-width:420px;background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:16px;
  padding:18px 18px 16px;box-shadow:var(--shadow)}
.inst-card h2{margin:0 0 12px;font-size:1.05rem}
.inst-steps{list-style:none;margin:0 0 10px;padding:0;display:grid;gap:10px;counter-reset:inst}
.inst-steps li{display:flex;gap:12px;align-items:center;line-height:1.4;counter-increment:inst}
.inst-ic{flex:0 0 36px;height:36px;border-radius:10px;background:var(--panel-2);color:var(--datum);display:grid;place-items:center}
.inst-card .btn{width:100%;margin-top:8px;min-height:44px}
/* Android chooser: two options, one marked best for this phone. */
.inst-opt{border:1px solid var(--line);border-radius:12px;padding:12px 14px;margin:0 0 10px}
.inst-opt h3{margin:0 0 4px;font-size:.95rem;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.inst-opt p{margin:0 0 4px;line-height:1.4}
.inst-opt .btn{display:flex;align-items:center;justify-content:center;width:100%;margin-top:8px;min-height:44px;text-decoration:none}
.inst-best{font-size:.72rem;font-weight:600;padding:2px 8px;border-radius:999px;background:var(--panel-2);color:var(--datum)}
.inst-opt-set{margin-top:16px}
