/* Nomadic Traveller Map — tokens (Atlas, locked 2026-09-13, plan.md §0/spec §6.2)
   + layout + motion. Borders are dark warm "chart ink," not white — clearer
   against both water and land than any translucent-white value tested
   (4.0:1 / 8.8:1 vs 3–3.7 / 6–8 for the alternatives). */
:root{
  --water:#7C99B4; --land:#E9DCC3; --land-hi:#D6CAB3; --visited:#9C3826; --visited-hi:#8C3222;
  --dot:#C8BDA8; --border-line:#3F3529;
  --ink:#2B3640; --muted:#55636E; --hair:#E3E8EC; --surface:rgba(255,255,255,.92); --error:#A94F3A;
  --shadow:0 1px 2px rgba(30,45,60,.06),0 10px 30px rgba(30,45,60,.12);
  --ease:cubic-bezier(.2,.8,.2,1); --spring:cubic-bezier(.34,1.56,.64,1);
  font-family:system-ui,-apple-system,"Segoe UI Variable Text","Segoe UI",Roboto,sans-serif;
  color:var(--ink); -webkit-font-smoothing:antialiased;
}
*{box-sizing:border-box}
html,body{margin:0;height:100%;overflow:hidden;background:var(--water)}
button,input{font:inherit;color:inherit}
button{cursor:pointer}
:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.num{font-variant-numeric:tabular-nums}
.muted{color:var(--muted)}

/* ── map ── */
#map{position:fixed;inset:0;width:100%;height:100%;display:block;touch-action:none;cursor:grab;opacity:0;transition:opacity .6s ease}
#map.ready{opacity:1}
#map.panning{cursor:grabbing}
#map path{stroke:var(--border-line);stroke-width:.6px;vector-effect:non-scaling-stroke;stroke-linejoin:round}
.t{fill:var(--land)}
.c{fill:var(--land);cursor:pointer;transform-box:fill-box;transform-origin:center;
   transition:fill .5s ease,transform .28s var(--spring)}
.c:hover{fill:var(--land-hi);transition-duration:.12s,.28s}
.dot{fill:var(--dot);stroke:var(--border-line);stroke-width:1px;vector-effect:non-scaling-stroke}
/* Country/territory name labels. Never intercept a click/hover/tap meant for
   the shape underneath (pointer-events:none) or a drag-select (user-select:
   none); font-size and opacity are both set per-frame in JS (sizeToScreen())
   — the constant-on-screen-size trick already used for dots/status glyphs,
   plus a reveal threshold tied to the place's own on-screen size so a world
   view isn't 240 names stacked on each other. border-line reads fine on land
   at FULL strength (8.8:1) and nearly vanishes on the dark red visited fill
   at full strength too (1.7:1) — measured, not assumed — so .is-visited swaps
   to a light fill instead. **The actual rendered contrast is against the
   opacity-BLENDED colour**, set in JS — an earlier 0.7/0.92 blended down to
   4.08:1 on land, under the 4.5 minimum, which is why a real user reported
   not being able to see labels that were technically present. Now 0.9/0.95,
   blending to 6.8:1 / 6.0:1 — legible at a glance, not just in a screenshot
   examined closely. */
/* Small caps, names and codes alike (added 2026-09-14). font-variant:small-caps
   only affects LOWERCASE letters — an uppercase letter keeps its normal full
   height regardless — so the source text has to actually BE lowercase
   ("france", not "France") for every letter to come out the same small-caps
   height; app.js writes both the name and the fallback ISO code in lowercase
   for exactly this reason. Letter-spacing is a touch wider than default,
   which small-caps glyphs this small otherwise read as slightly cramped. */
.lbl{fill:var(--border-line);font-weight:600;font-variant:small-caps;letter-spacing:.02em;
  text-anchor:middle;dominant-baseline:middle;pointer-events:none;user-select:none}
.lbl.is-visited{fill:#FBF6EC}
.c.is-visited{fill:var(--visited)}
.c.is-visited:hover{fill:var(--visited-hi)}
.c.is-selected{transform:scale(1.06);filter:url(#lift)}
.c.is-selected:not(.is-visited){fill:var(--land-hi)}
.dot.is-selected{transform:scale(1.7)}
.ripple{fill:none;stroke:var(--visited);stroke-width:2.5px;vector-effect:non-scaling-stroke;pointer-events:none;
  transform-box:fill-box;transform-origin:center;animation:ripple .7s var(--ease) forwards}
@keyframes ripple{from{transform:scale(.15);opacity:.75}to{transform:scale(1);opacity:0}}

/* ── floating chrome ── */
.glass{background:var(--surface);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);box-shadow:var(--shadow);border-radius:16px}
.top{position:fixed;inset:16px 16px auto 16px;display:flex;justify-content:space-between;align-items:flex-start;pointer-events:none}
.top>*{pointer-events:auto}
.brandWrap{position:relative}
.brand{display:flex;gap:10px;align-items:center;height:40px;padding:0 16px 0 12px;border-radius:999px;border:0;text-align:left}
.brandText{display:block}
.brand b{display:block;font-size:15px;letter-spacing:.2px}
.brand small{display:block;font-size:12px;color:var(--muted)}
/* The wordmark's own description. Shown on hover (mouse) and on a .show class
   the script toggles (touch, which has no hover state to rely on). A real
   element rather than a `title` attribute — native tooltips are slow, unstyled,
   and simply never appear on a phone. */
.brandTip{position:absolute;left:0;top:calc(100% + 8px);margin:0;width:max-content;max-width:min(320px,calc(100vw - 32px));
  padding:9px 13px;border-radius:12px;font-size:12.5px;line-height:1.45;color:var(--ink);
  opacity:0;transform:translateY(-4px);pointer-events:none;transition:opacity .16s ease,transform .16s var(--ease);z-index:7}
.brand:hover+.brandTip,.brand:focus-visible+.brandTip,.brandTip.show{opacity:1;transform:none}
/* Escape must dismiss a tooltip (WAI-ARIA practices), and simply dropping the
   .show class doesn't: the button still holds keyboard focus, so :focus-visible
   immediately puts it back. `hush` outranks every reveal rule until the pointer
   leaves or focus moves on — which is the only way to dismiss it without
   blurring the button and dumping focus onto <body>, the exact defect V1 fixed. */
.brandWrap.hush .brandTip{opacity:0;transform:translateY(-4px)}
.mark{width:12px;height:12px;border-radius:50%;background:var(--visited);box-shadow:0 0 0 4px color-mix(in srgb,var(--visited) 22%,transparent)}
.pill{display:flex;align-items:center;gap:10px;height:40px;padding:0 14px 0 16px;border:0;border-radius:999px;font-size:14px;transition:transform .2s var(--spring)}
.pill:hover{transform:translateY(-1px)}
.pill b{font-weight:650}
.pill svg{width:16px;height:16px;stroke:var(--ink);stroke-width:1.8;stroke-linecap:round}
#count{display:inline-block}
#count.bump{animation:bump .32s var(--spring)}
@keyframes bump{50%{transform:scale(1.25);color:var(--visited-hi)}}

/* entry bar */
/* --barW is a variable, not a literal, because #clearMap and #emailMap are fixed
   elements that have to land exactly against this bar's edges. Deriving their
   position from the same expression is what keeps them attached to it at every
   width; two hand-tuned numbers would drift apart the first time either changed.
   The `100vw - 440px` term reserves the space the flanking buttons and the
   corner chrome need, so the bar yields as the window narrows instead of
   pushing the Save button underneath the zoom controls. */
/* 760, up from 640, since the bar gained a third field (the status picker, F25).
   Squeezing it out of the old width would have left the Year(s) field too narrow
   to show its own placeholder. */
:root{--barW:min(760px,calc(100vw - 440px))}
.bar{position:fixed;left:50%;bottom:20px;transform:translateX(-50%);width:var(--barW);
  display:flex;align-items:stretch;gap:6px;padding:6px}
.bar.shake{animation:shake .32s ease}
@keyframes shake{25%{transform:translateX(calc(-50% - 6px))}75%{transform:translateX(calc(-50% + 6px))}}
.field{position:relative;flex:1;display:flex;flex-direction:column;justify-content:center;padding:7px 14px;border-radius:11px;transition:background .15s}
.field+.field::before{content:"";position:absolute;left:-3px;top:12px;bottom:12px;width:1px;background:var(--hair)}
.field:focus-within{background:#fff;box-shadow:0 0 0 1px var(--hair)}
.field.combo{flex:1.35}
/* Fixed width, unlike the two text fields: a segmented control has three fixed
   labels and nothing to gain from stretching, and letting it flex would steal
   room from the inputs that do. */
.statusField{flex:0 0 auto;padding:6px 10px}
.statusField label{margin-bottom:3px}
.statusField .statusRow{margin:0;width:176px}
.statusField .statusRow button{padding:4px 0;font-size:11.5px}
.field label{font-size:11px;font-weight:600;letter-spacing:.3px;color:var(--muted)}
.field input{border:0;outline:0;background:transparent;padding:2px 0 0;font-size:15px;width:100%}
.field input::placeholder{color:#7D8A95}
.btn{border:0;border-radius:11px;background:var(--ink);color:#fff;font-weight:600;font-size:14px;padding:0 22px;min-height:44px;transition:background .15s,transform .15s}
.btn:hover{background:#3A4854}
.btn:active{transform:scale(.97)}
.err{position:absolute;left:14px;bottom:calc(100% + 8px);margin:0;font-size:12.5px;color:var(--error);background:#fff;padding:6px 10px;border-radius:8px;box-shadow:var(--shadow);
  opacity:0;transform:translateY(4px);transition:opacity .15s,transform .15s;pointer-events:none}
.err.show{opacity:1;transform:none}

/* dropdown (opens upward from the Country field) — position:fixed, a body-
   level element (see index.html), positioned in JS every time it opens
   (renderList() in app.js), not via a CSS-relative ancestor. z-index matches
   the tier used by the other transient floating surfaces (.tip is 6). */
.list{position:fixed;margin:0;padding:6px;list-style:none;z-index:6;
  background:#fff;border-radius:14px;box-shadow:var(--shadow);max-height:340px;overflow:auto;
  opacity:0;transform:translateY(6px);transition:opacity .12s,transform .12s;pointer-events:none}
.list.open{opacity:1;transform:none;pointer-events:auto}
.list li{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:9px 10px;border-radius:9px;cursor:pointer;font-size:14.5px}
.list li small{font-size:12px;color:var(--muted);white-space:nowrap}
.list li small i{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--visited);margin-right:5px;vertical-align:1px}
.list li[aria-selected=true]{background:color-mix(in srgb,var(--visited) 14%,#fff)}
.list li mark{background:none;color:inherit;font-weight:650}
.list .none{color:var(--muted);cursor:default;font-size:13px}

/* popover */
.pop{position:fixed;width:272px;padding:16px;z-index:5;opacity:0;transform:translateY(6px) scale(.98);pointer-events:none;
  transition:opacity .18s ease,transform .18s var(--ease)}
.pop.open{opacity:1;transform:none;pointer-events:auto}
.pop h2{margin:0;font-size:17px;font-weight:650}
.pop p{margin:2px 0 12px;font-size:12.5px}
.pop label{font-size:11px;font-weight:600;letter-spacing:.3px;color:var(--muted)}
.pop input{display:block;width:100%;margin-top:4px;padding:10px 12px;border:1px solid var(--hair);border-radius:10px;font-size:15px;background:#fff;outline:0;transition:border-color .15s,box-shadow .15s}
.pop input:focus{border-color:#B9C4CC;box-shadow:0 0 0 3px color-mix(in srgb,var(--visited) 18%,transparent)}
.pop .perr{min-height:18px;margin:6px 0 4px;font-size:12.5px;color:var(--error)}
.statusRow{display:grid;grid-template-columns:repeat(3,1fr);gap:4px;margin:0 0 12px;padding:3px;background:#F1F4F6;border-radius:10px}
.statusRow button{border:0;background:transparent;border-radius:7px;padding:6px 0;font-size:12.5px;color:var(--muted);transition:background .15s,color .15s}
.statusRow button:hover{color:var(--ink)}
.statusRow button[aria-pressed=true]{background:#fff;color:var(--ink);font-weight:650;box-shadow:0 1px 2px rgba(30,45,60,.10)}
.pop .row{display:flex;justify-content:space-between;align-items:center;gap:14px}
.pop .btn{min-height:40px}
.x{position:absolute;top:10px;right:10px;width:28px;height:28px;border:0;border-radius:50%;background:transparent;color:var(--muted);font-size:18px;line-height:1}
.x:hover{background:#F1F4F6;color:var(--ink)}
.link{border:0;background:none;padding:6px 2px;color:var(--muted);font-size:13px;text-decoration:underline;text-underline-offset:3px}
.link:hover{color:var(--error)}
.link[hidden]{display:none}

/* tooltip */
.tip{position:fixed;left:0;top:0;padding:6px 10px;border-radius:8px;background:var(--ink);color:#fff;font-size:12.5px;white-space:nowrap;pointer-events:none;
  opacity:0;transition:opacity .1s;z-index:6}
.tip.show{opacity:1}
.tip span{opacity:.7;margin-left:6px}

/* side panel */
.scrim{position:fixed;inset:0;background:rgba(30,45,60,.12);opacity:0;pointer-events:none;transition:opacity .3s}
.scrim.open{opacity:1;pointer-events:auto}
.panel{position:fixed;top:0;right:0;bottom:0;width:min(480px,100vw);background:#fff;box-shadow:-10px 0 40px rgba(30,45,60,.12);
  display:flex;flex-direction:column;transform:translateX(104%);transition:transform .32s var(--ease);z-index:8}
.panel.open{transform:none}
.panel>header{position:relative;padding:22px 24px 14px}
.panel h2{margin:0;font-size:20px;font-weight:650}
.panel header p{margin:3px 0 0;font-size:13px}
/* min-height is load-bearing, not defensive tidiness. The panel is a flex column
   and a flex item shrinks below its content by default, so anything that grows
   the footer steals height from the table first — and the table is what the
   panel is FOR. Expanding "About this map" on a 390x700 phone with 20 countries
   collapsed this to exactly 0px and pushed the footer 30px past the panel's
   bottom edge. A floor here plus a scroll cap on the About body (below) means
   neither can starve the other. */
.tablewrap{flex:1;min-height:120px;overflow:auto;padding:0 12px}
table{width:100%;border-collapse:collapse;font-size:13.5px}
th{position:sticky;top:0;background:#fff;text-align:left;padding:0;border-bottom:1px solid var(--hair);z-index:1}
th button{border:0;background:none;padding:10px 12px;font-size:11px;font-weight:600;letter-spacing:.3px;color:var(--muted);text-transform:uppercase;white-space:nowrap}
th button:hover{color:var(--ink)}
th[aria-sort] button{color:var(--ink)}
th[aria-sort=ascending] button::after{content:" ↑"}
th[aria-sort=descending] button::after{content:" ↓"}
td{padding:11px 12px;border-bottom:1px solid #F0F3F5;vertical-align:top}
tbody tr{cursor:pointer;transition:background .12s}
tbody tr:hover{background:color-mix(in srgb,var(--visited) 9%,#fff)}
tbody.enter tr{animation:rowin .3s var(--ease) both;animation-delay:calc(min(var(--i),20) * 15ms)}
@keyframes rowin{from{opacity:0;transform:translateY(6px)}}
td.name{font-weight:560;position:relative;padding-left:30px}
td.cont{white-space:nowrap}
td.name i{position:absolute;left:13px;top:17px;width:8px;height:8px;border-radius:50%;background:var(--visited)}
.tbadge{display:inline-block;margin-left:8px;padding:1px 7px 2px;border:1px solid var(--hair);border-radius:999px;
  font-size:10px;font-weight:600;letter-spacing:.3px;color:var(--muted);text-transform:uppercase;vertical-align:2px}
.tbadge.on{border-color:var(--ink);color:var(--ink)}
td.name i.lived{box-shadow:0 0 0 2px var(--ink) inset;background:transparent}
td.name i.home{box-shadow:0 0 0 2px var(--ink);background:var(--visited)}

/* Lived/Home are marked with a small ink glyph at the place's centre, not a
   third and fourth fill colour — the palette stays water + land + visited. */
.mk{pointer-events:none;stroke:var(--ink);stroke-width:1.6px;vector-effect:non-scaling-stroke}
.mk-lived{fill:none}
.mk-home{fill:var(--ink);stroke:#fff;stroke-width:1.4px}
.r{text-align:right}
th.r button{width:100%;text-align:right}
tfoot td{position:sticky;bottom:0;background:#fff;border-top:1px solid var(--hair);border-bottom:0;padding:14px 12px;font-size:13.5px}
tfoot b{font-size:16px}
.empty{padding:40px 24px;text-align:center;font-size:14px}
.panel footer{padding:14px 24px 18px;border-top:1px solid var(--hair);font-size:13px}
.footRow{display:flex;gap:8px}
.footRow .btn{flex:1;min-height:40px;font-size:13.5px;padding:0 12px}
.btn.ghost{background:transparent;color:var(--muted);box-shadow:inset 0 0 0 1px var(--hair)}
.btn.ghost:hover{background:#FCF3F1;color:var(--error);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--error) 35%,transparent)}
/* "About this map" in the panel. Collapsed by default — the panel's job is the
   table, and this is read once. */
.aboutApp{margin:0 0 12px;border-bottom:1px solid var(--hair);padding-bottom:12px}
.aboutApp summary{cursor:pointer;font-size:13px;font-weight:650;color:var(--ink);padding:4px 0;list-style:none;display:flex;align-items:center;gap:7px}
.aboutApp summary::-webkit-details-marker{display:none}
.aboutApp summary::before{content:"";width:0;height:0;border:4.5px solid transparent;border-left-color:var(--muted);transition:transform .18s var(--ease);transform-origin:2px 50%}
.aboutApp[open] summary::before{transform:rotate(90deg)}
.aboutApp summary:hover{color:var(--visited)}
/* Capped and scrollable so a long read can never push the footer past the bottom
   of the panel — the other half of the .tablewrap min-height fix above. 38vh
   leaves the table the majority of a short screen while still showing several
   paragraphs at once. */
.aboutAppBody{padding-top:4px;max-height:38vh;overflow-y:auto}
.aboutAppBody p{margin:0 0 10px;font-size:12.5px;line-height:1.55;color:var(--muted)}
.aboutAppBody p:last-child{margin-bottom:0}
.aboutAppBody b{color:var(--ink);font-weight:650}
.aboutAppBody a{color:var(--muted);text-underline-offset:3px}
.aboutAppBody a:hover{color:var(--visited)}
.footNote{margin:10px 0 6px;font-size:12px;line-height:1.45}
.footNote.stale{color:var(--error)}
.panel footer p{margin:0}

/* zoom buttons — always visible, because zooming shouldn't depend on a pinch
   landing cleanly. Desktop: bottom right, with the reset button above them and
   the counts pill alongside, so the corner reads as one control column. */
.zoom{position:fixed;right:16px;bottom:20px;z-index:4;display:flex;flex-direction:column;overflow:hidden;padding:0}
.zoom button{width:44px;height:44px;border:0;background:transparent;font-size:19px;line-height:1;color:var(--ink);
  transition:background .15s}
.zoom button:first-child{border-bottom:1px solid var(--hair)}
.zoom button:hover:not(:disabled){background:#F1F4F6}
.zoom button:active:not(:disabled){background:#E7ECF0}
.zoom button:disabled{color:#AEB8C0;cursor:default}

/* toast + reset */
.toast{position:fixed;left:50%;top:18px;transform:translate(-50%,-10px);display:flex;gap:14px;align-items:center;padding:10px 12px 10px 16px;border-radius:12px;
  background:var(--ink);color:#fff;font-size:13.5px;opacity:0;pointer-events:none;transition:opacity .2s,transform .25s var(--ease);z-index:7}
.toast.show{opacity:1;transform:translate(-50%,0);pointer-events:auto}
.toast button{border:0;background:rgba(255,255,255,.14);color:#fff;border-radius:8px;padding:5px 10px;font-size:13px;font-weight:600}
.reset{position:fixed;right:16px;bottom:116px;width:44px;height:44px;border:0;border-radius:50%;font-size:17px;
  opacity:0;transform:scale(.8);pointer-events:none;transition:opacity .2s,transform .2s var(--spring)}
.reset.show{opacity:1;transform:none;pointer-events:auto}

/* "official count" caveat — still the bottom-right corner, but now BESIDE the
   zoom/reset column rather than stacked above it, which would push it a third of
   the way up the screen */
/* Moved from right:72px to the bottom-LEFT on 2026-09-15, to make room for the
   Save button beside the entry bar — and it fixed a pre-existing bug on the way.
   Measured across desktop widths: at 1024px and below this pill was already
   overlapping the entry bar (74px of overlap at 1024, 236px at 700), because
   both sat at bottom:20 and the bar's centred 640px left too little beside it.
   V2 verified 360/390/430 and 1440 and never looked at the 641–1150 band, so
   nothing caught it. The left corner was empty at every width. */
.about{position:fixed;left:16px;bottom:20px;z-index:4}
.aboutBtn{height:32px;padding:0 12px;font-size:12px;color:var(--muted);border-radius:999px}
.aboutBtn b{color:var(--ink);font-weight:650}
.aboutCard{position:absolute;left:0;bottom:calc(100% + 8px);width:280px;padding:16px;
  opacity:0;transform:translateY(6px) scale(.98);pointer-events:none;transition:opacity .16s,transform .16s var(--ease)}
.aboutCard.open{opacity:1;transform:none;pointer-events:auto}
.aboutCard p{margin:0 0 10px;font-size:12.5px;line-height:1.5}
.aboutCard p:last-child{margin-bottom:0}
.aboutCard b{color:var(--ink)}

/* ── the "add a country" pill (phone only; hidden on desktop, where the bar is
      always open because there is room for it) ── */
/* z-index 4 keeps it under the popover (5) and the panel (8): it is the resting
   state's control, and anything that takes over the lower screen outranks it. */
.addBtn{position:fixed;left:50%;bottom:calc(16px + env(safe-area-inset-bottom));z-index:4;
  display:none;align-items:center;gap:8px;height:48px;padding:0 22px;border:0;border-radius:999px;
  font-size:15px;font-weight:600;transform:translateX(-50%);
  transition:opacity .2s,transform .24s var(--spring)}
.addBtn span{font-size:19px;font-weight:400;line-height:0;color:var(--visited)}
.addBtn.off{opacity:0;transform:translateX(-50%) scale(.9) translateY(8px);pointer-events:none}
/* ── the two map-level actions, flanking the entry bar ───────────────────────
   Clear sits just left of the bar, Save just right of Submit. Both are anchored
   off --barW rather than a fixed offset, so they stay welded to the bar's edges
   at every width. Deliberately quieter than Submit: Submit is the thing you
   press constantly, these two are occasional, and Clear is destructive (it has
   Undo, but it should still never be the loudest thing on screen). */
.dockBtn{position:fixed;bottom:20px;z-index:4;height:36px;padding:0 14px;border:0;border-radius:999px;
  font-size:12.5px;font-weight:600;color:var(--ink);white-space:nowrap;
  transition:background .15s,transform .15s,opacity .18s}
.dockBtn:hover{background:#F1F4F6}
.dockBtn:active{transform:scale(.97)}
.dockBtn.ghost{color:var(--muted)}
.dockBtn.ghost:hover{color:var(--visited);background:#F6EFEF}
#clearMap{right:calc(50% + var(--barW) / 2 + 10px)}
#emailMap{left:calc(50% + var(--barW) / 2 + 10px)}
/* Unsaved work should say so where the button is, not only in the panel. */
#emailMap.stale{box-shadow:0 0 0 1px var(--visited),var(--shadow);color:var(--visited)}
.barX,.barTitle{display:none}

/* A short viewport — a phone in landscape, or a squat desktop window — puts the
   entry bar and the "195 countries" pill in the same strip; lift the pill clear. */
/* The counts pill carries its own explanation, which is the point of it — but
   below 1280px there isn't room for all of "195 countries · 45 territories"
   AND the Clear button beside the bar. The numbers are the part that has to
   survive; the card behind the pill still spells the rest out in full. */
/* 1439, raised from 1279 when the bar widened to 760px for the status picker:
   a wider bar starts further left, and at 1280 the full-text pill ran into the
   Clear button beside it (measured: 52px of overlap). Below 1440 the numbers
   alone carry it; the card behind the pill still spells it out. */
@media (max-width:1439px){ .aboutWord{display:none} }

/* 641–900px: a narrow desktop window. Flanking the bar here would squeeze it to
   about 260px — two fields and a Submit button in less space than one field
   needs — so the two actions move to a row ABOVE the bar instead, left-aligned
   after the counts pill. The bar also gives up the width the zoom column needs
   (it was overlapping it here before this change, the same pre-existing bug the
   counts pill had). Flanking resumes at 901px, where there is room for it. */
@media (min-width:641px) and (max-width:900px){
  :root{--barW:min(760px,calc(100vw - 160px))}
  /* 108px, raised from 84px once the bar gained the status field: the bar is now
     71–78px tall, so its top edge sits 91–98px from the bottom and the old row
     was landing inside it. Measured, not nudged. */
  .about{bottom:108px}
  .dockBtn{bottom:108px}
  #clearMap{right:auto;left:224px}
  #emailMap{left:322px}
}

@media (max-height:540px){ .about{bottom:calc(94px + env(safe-area-inset-bottom))} }

/* ── mobile: a phone composition, not the desktop layout stacked (plan L14) ── */
@media (max-width:640px){
  .addBtn{display:flex}
  .barX{display:block;top:6px;right:8px}
  .barTitle{display:block;position:absolute;top:15px;left:16px;font-size:13px;font-weight:650;color:var(--muted);letter-spacing:.2px}

  /* The entry sheet slides out of the way instead of sitting open. Transform
     only — no height/overflow animation, which would clip the combobox list. */
  /* bottom stays 0 while CLOSED, deliberately not var(--kb,0px): the closed
     state hides the sheet with a fixed translateY sized to its own height, and
     that math assumes it starts at the true viewport bottom. Tracking the
     keyboard unconditionally (§V2b) raises a CLOSED sheet's resting position
     too, and the fixed translateY then no longer clears the visible area —
     a keyboard open for the POPOVER was pulling the dismissed entry sheet back
     into view underneath it. Keyboard-tracking only applies once .up cancels
     the transform and bottom starts actually meaning something on screen. */
  .bar{left:0;right:0;bottom:0;width:100vw;flex-wrap:wrap;gap:8px;
    border-radius:20px 20px 0 0;padding:38px 12px calc(14px + env(safe-area-inset-bottom));
    transform:translateY(calc(100% + 28px));transition:transform .34s var(--ease),bottom .2s ease;
    max-height:calc(100vh - var(--kb,0px) - 16px);overflow-y:auto}
  .bar.up{transform:none;bottom:var(--kb,0px)}
  .field{flex:1 1 100%;background:#fff;box-shadow:0 0 0 1px var(--hair);padding:9px 14px}
  /* On a phone the sheet is a stack of full-width rows, so the status picker
     becomes one too — the same shape it has in the popover, which is the other
     place a phone user meets this control. */
  .statusField{flex:1 1 100%;padding:9px 14px}
  .statusField .statusRow{width:100%}
  .statusField .statusRow button{padding:8px 0;font-size:12.5px}
  .field+.field::before{display:none}
  .field input{font-size:16px} /* 16px keeps iOS from zooming the page on focus */
  .btn{flex:1 1 100%;min-height:48px}
  /* the desktop shake translates X off a -50% centre; this bar isn't centred */
  .bar.shake{animation-name:shakeM}
  @keyframes shakeM{25%{transform:translateX(-6px)}75%{transform:translateX(6px)}}

  .toast{top:auto;bottom:calc(76px + env(safe-area-inset-bottom));max-width:calc(100vw - 24px);transform:translate(-50%,10px)}
  .toast.show{transform:translate(-50%,0)}

  /* Corner chrome sits in the corners, at last: these were bottom:236px and
     bottom:288px — magic numbers measured off the parked entry sheet, which is
     what left the "195 countries" pill stranded mid-ocean. */
  /* Bottom row on a phone: zoom on the left, "add a country" centred, reset on
     the right — both thumbs get a control and nothing sits under the add pill. */
  .zoom{left:12px;right:auto;bottom:calc(16px + env(safe-area-inset-bottom))}
  .reset{right:12px;bottom:calc(16px + env(safe-area-inset-bottom));width:44px;height:44px}
  .about{left:auto;right:12px;bottom:calc(74px + env(safe-area-inset-bottom))}
  /* Clear and Save share the counts pill's row, on the left where it is empty.
     The bottom row below is already full — zoom, the add pill, reset — and
     nothing may sit under the add pill. Second words are dropped (.dockWord) and
     the pills shrink: this row is only ~150px wide beside the counts pill at
     360px, which two full labels could not fit. They keep a 44px hit area via
     ::after rather than growing, the same trick the other compact controls use. */
  .dockWord{display:none}
  /* 112px, not 74px: the zoom control is a COLUMN of two 44px buttons, so it is
     88px tall and reaches up to 104px from the bottom — the left half of the
     74px row is its, not free space. Measured, after a first attempt at 74px
     put Clear squarely on top of it (a 44×30px overlap). They flank at the same
     height instead, mirroring the desktop arrangement, clear of the thumb row
     below (zoom · add · reset) and of the counts pill at 74px on the right. */
  .dockBtn{bottom:calc(112px + env(safe-area-inset-bottom));height:30px;padding:0 11px;font-size:11.5px}
  .dockBtn::after{content:"";position:absolute;left:0;right:0;top:50%;height:44px;transform:translateY(-50%)}
  #clearMap{right:auto;left:12px}
  #emailMap{left:auto;right:12px}
  /* a bottom sheet owns the lower screen: these stand down with the rest */
  body.entry-open .dockBtn,body.pop-open .dockBtn{opacity:0;pointer-events:none;transition:opacity .18s}
  .aboutCard{left:auto;right:0}
  .aboutCard{width:min(300px,calc(100vw - 24px))}
  /* while a bottom sheet — the entry form or a country's popover — owns the
     lower screen, the resting controls get out of its way rather than floating
     over its buttons */
  body.entry-open .reset,body.entry-open .about,body.entry-open .zoom,
  body.pop-open .reset,body.pop-open .about,body.pop-open .zoom,body.pop-open .addBtn{opacity:0;pointer-events:none;transition:opacity .18s}

  /* bottom (not transform) carries the keyboard offset, so it composes cleanly
     with the open/close transform above instead of fighting it */
  .pop{left:0!important;top:auto!important;bottom:var(--kb,0px);width:100vw;border-radius:20px 20px 0 0;
    padding:20px 18px calc(18px + env(safe-area-inset-bottom));transition:opacity .18s ease,transform .18s var(--ease),bottom .16s ease;
    /* a short phone in landscape with the keyboard up can leave very little
       room above it — scroll the sheet's own content rather than clip it or
       push it off the top of the screen */
    max-height:calc(100vh - var(--kb,0px) - 16px);overflow-y:auto}
  .pop input{font-size:16px}
  .brand{height:38px;padding:0 14px 0 11px}
  .brand small{display:none}

  /* Touch targets. Rather than inflating small controls until the layout turns
     chunky, the compact ones keep their size and grow an invisible 44px hit
     area — the finger gets the target the eye doesn't need. */
  .pill{height:44px}
  .aboutBtn{height:34px;position:relative}
  .link{position:relative}
  /* NOT .x — it is already position:absolute, and relative would drop both
     close buttons out of their corners and into the flex flow */
  .aboutBtn::after,.x::after,.link::after{content:"";position:absolute;inset:-9px}

  /* ── the table becomes phone rows, not four squeezed desktop columns ──
     Name + badges lead; years and continent share a quiet meta line. "# Times"
     is dropped here and only here: for a visit it is just the number of years
     already listed beside it, so on a phone it cost a column to say nothing.
     Its sort control stays in the header chips. */
  .panel{width:100vw}
  .tablewrap{padding:0 6px}
  table,tbody,tfoot,tfoot tr,tfoot td{display:block}
  thead{display:block;position:sticky;top:0;z-index:2;background:#fff;border-bottom:1px solid var(--hair)}
  thead tr{display:flex;gap:6px;padding:8px 4px;overflow-x:auto;scrollbar-width:none}
  thead tr::-webkit-scrollbar{display:none}
  th{display:block;position:static;flex:0 0 auto;border:0}
  th button{min-height:44px;padding:0 15px;border-radius:999px;background:#F1F4F6;color:var(--muted);
    text-transform:none;letter-spacing:0;font-size:12.5px;white-space:nowrap}
  th[aria-sort] button{background:var(--ink);color:#fff}
  th.r button{width:auto;text-align:center}

  tbody tr{display:grid;grid-template-columns:1fr auto;align-items:baseline;gap:3px 12px;
    position:relative;padding:13px 6px 13px 26px;border-bottom:1px solid #F0F3F5}
  td{display:block;padding:0;border:0;vertical-align:baseline}
  td.name{position:static;grid-column:1/-1;padding-left:0;font-size:15.5px;font-weight:600}
  td.name i{left:6px;top:17px}
  tbody td:nth-child(2){grid-column:1;font-size:13px;color:var(--muted)}
  tbody td:nth-child(3){display:none}
  td.cont{grid-column:2;justify-self:end;text-align:right;font-size:13px;white-space:nowrap}
  .tbadge{margin-left:6px}
  tfoot td{padding:14px 8px}
  .panel>header{padding:18px 18px 12px}
  .panel footer{padding:12px 18px calc(16px + env(safe-area-inset-bottom))}
}
@media (prefers-reduced-motion:reduce){*,*::before,*::after{transition-duration:0s!important;animation-duration:0s!important;animation-delay:0s!important}}
