/* ============================================================================
   Atlantic Mirror — editorial-atlas design system.
   Warm paper + ink; a literary serif (Newsreader) against a grotesque (Archivo).
   Two framed map-cards. Country labels orient each; the selected city goes
   vermilion, its three counterparts go teal in the other card with an arc to each.
   ============================================================================ */

:root {
  --paper:        #f0ecdf;   /* page */
  --surface:      #f7f3ea;   /* map-card interior ("water") */
  --paper-card:   #f8f5ee;   /* info card */

  --ink:          #211d18;
  --ink-soft:     #6a6252;
  --ink-faint:    #726955;   /* darkened from #9a9080 (2026-07-04): as TEXT it was 2.1–2.8:1 —
                                this passes 4.5:1 (WCAG AA) on paper, surface, and card alike */

  /* Land/stroke contrast tuned 2026-07-04 after low-vision feedback ("beige blob"): country
     borders now ≥3:1 against land (WCAG graphics floor; they were 1.74:1), coast 2.7:1 vs water. */
  --land:         #e1d6bd;
  --coast:        #a2946f;   /* coastline — makes the landmass shape legible against the water */
  --substate:     #bfb28c;   /* US state lines — deliberately quieter than country borders */
  --border:       #7d6f54;   /* country borders — ink-family, not beige-family */
  --frame:        #d8cfb7;   /* map-card frame */

  --dot:          #7a5f48;   /* sepia-brown, 4.1:1 vs land (2026-07-04): dots are the CONTENT — they
                                must out-rank the border/coast context lines, and the hue shift keeps
                                them from reading as terrain texture */
  --sel:          #cf3b23;    /* vermilion — selected city */
  --sel-deep:     #b3311b;
  --match:        #1a7b73;    /* deep teal — its counterparts */
  --match-deep:   #135f59;

  --hair:         rgba(33, 29, 24, 0.12);
  --shadow:       0 1px 2px rgba(33,29,24,.06), 0 12px 30px -14px rgba(33,29,24,.34);

  --serif: "Newsreader", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --sans:  "Archivo", ui-sans-serif, "Helvetica Neue", Helvetica, Arial, sans-serif;
  --edge: clamp(14px, 3.2vw, 34px);
  --peek-h: 190px;    /* mobile: reserved bottom strip for the collapsed peek sheet */
  --search-h: 56px;   /* mobile: reserved top strip for the persistent search bar */
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0; background: var(--paper); color: var(--ink); font-family: var(--sans);
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; overflow: hidden;
}
body::before {   /* printed-paper tooth */
  content: ""; position: fixed; inset: 0; z-index: 9; pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  opacity: 0.33; mix-blend-mode: soft-light;
}
#app { position: relative; z-index: 1; height: 100%; display: flex; flex-direction: column; }

/* ---------- Masthead ---------------------------------------------------- */
.masthead {
  flex: 0 0 auto; padding: clamp(10px, 2vh, 20px) var(--edge) 8px;
  display: grid; grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  gap: 4px clamp(16px, 3vw, 40px); align-items: baseline;
}
.masthead__title { display: flex; align-items: baseline; gap: 18px; min-width: 0; }
.masthead h1 {
  margin: 0; font-family: var(--serif); font-weight: 500; font-optical-sizing: auto;
  font-size: clamp(26px, 4.6vw, 50px); letter-spacing: -0.018em; line-height: 0.98; white-space: nowrap;
}
.masthead__rule {
  flex: 1 1 auto; height: 1px; min-width: 24px;
  background: linear-gradient(90deg, var(--ink) 0%, var(--hair) 100%); transform: translateY(-0.28em);
}
.dek {
  margin: 0; max-width: 68ch; justify-self: end; text-align: right; text-wrap: balance;
  font-size: clamp(12.5px, 1.35vw, 15px); line-height: 1.42; color: var(--ink-soft); font-weight: 400;
}
.dek em { font-family: var(--serif); font-style: italic; color: var(--ink); font-size: 1.06em; }

/* ---------- Stage / map cards ------------------------------------------- */
#stage { position: relative; flex: 1 1 auto; min-height: 0; }
#map { display: block; width: 100%; height: 100%; cursor: crosshair; touch-action: none; }
#map.can-pick { cursor: pointer; }   /* a click would land on a city — the only hover signal while pinned */

.panel-bg    { fill: var(--surface); filter: drop-shadow(0 8px 20px rgba(33,29,24,0.10)); }
.panel-frame { fill: none; stroke: var(--frame); stroke-width: 1px; }
.panel-title {
  font-family: var(--sans); font-weight: 600; font-size: 10.5px; letter-spacing: 0.22em;
  fill: var(--ink-faint); pointer-events: none;   /* full opacity — a .75 multiplier sank it to 2.1:1 */
}

.land     { fill: var(--land); stroke: var(--coast); stroke-width: 0.9px; stroke-linejoin: round;
            vector-effect: non-scaling-stroke; }   /* like every other stroke — without this the
                                                      coast became ~13px bands at deep zoom */
.substate { fill: none; stroke: var(--substate); stroke-width: 0.5px; vector-effect: non-scaling-stroke; }
.borders  { fill: none; stroke: var(--border); stroke-width: 1px; vector-effect: non-scaling-stroke; }

/* Dots — fill & opacity here (transitioned); radius (by prominence) driven in JS. */
.dot { fill: var(--dot); stroke: var(--surface); stroke-width: 0.8px; opacity: 0.85;
       transition: fill .18s ease, opacity .2s ease; }   /* paper casing lifts dots off the land */
/* Unselected dots keep their normal weight while selecting — the vermilion/teal dots
   and the arcs carry the emphasis; fading everything else just made the map harder to read. */
.is-selecting .dot--match { opacity: 1; fill: var(--match); stroke: var(--paper-card); stroke-width: 0.9px; }
.is-selecting .dot--sel   { opacity: 1; fill: var(--sel);   stroke: var(--paper-card); stroke-width: 1px; }

/* Overlays are decorative — never intercept the pointer. An arc origin sits on the
   selected dot's centre, so a hittable arc creates a dead spot for hover right there. */
.arcs, .labels { pointer-events: none; }
.arc { fill: none; stroke: var(--match); stroke-width: 1.5px; stroke-linecap: round; opacity: 0.55; }

/* On-map labels: only the selected city and its counterparts. */
.city-label {
  font-family: var(--serif); font-weight: 500;
  paint-order: stroke fill; stroke: var(--surface); stroke-width: 3.4px; stroke-linejoin: round;
  pointer-events: none;
}
.city-label--sel   { fill: var(--sel-deep); font-weight: 600; }
.city-label--match { fill: var(--match-deep); font-weight: 600; }

/* ---------- Hint -------------------------------------------------------- */
.hint {
  position: absolute; left: 50%; bottom: clamp(14px, 3vh, 26px); transform: translateX(-50%);
  margin: 0; padding: 7px 15px; display: flex; align-items: center; gap: 9px;
  background: color-mix(in srgb, var(--paper-card) 80%, transparent);
  border: 1px solid var(--hair); border-radius: 999px;
  font-size: 12.5px; color: var(--ink-soft); backdrop-filter: blur(3px);
  transition: opacity .35s ease, transform .35s ease;
}
.hint__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--sel); animation: pulse 2.4s ease-out infinite; }
@keyframes pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--sel) 55%, transparent); }
  70% { box-shadow: 0 0 0 9px transparent; } 100% { box-shadow: 0 0 0 0 transparent; }
}
#app.has-selection .hint { opacity: 0; transform: translateX(-50%) translateY(6px); pointer-events: none; }

/* ---------- Search ------------------------------------------------------- */
.search {
  position: absolute; top: clamp(12px, 3vh, 22px); left: 50%; transform: translateX(-50%);
  z-index: 6; display: flex; align-items: center; gap: 7px;
  padding: 6px 13px; border: 1px solid var(--hair); border-radius: 999px;
  background: color-mix(in srgb, var(--paper-card) 86%, transparent); backdrop-filter: blur(3px);
}
.search__toggle {
  flex: none; display: grid; place-items: center; width: 18px; height: 18px;
  padding: 0; border: none; background: none; color: var(--ink-faint); cursor: text;
}
.search__toggle svg { display: block; }
.search__input {
  width: 200px; border: none; background: none; outline: none; padding: 1px 0;
  font-family: var(--sans); font-size: 13px; color: var(--ink);
}
.search__input::placeholder { color: var(--ink-faint); }
.search__clear {
  flex: none; display: none; place-items: center; width: 18px; height: 18px; padding: 0;
  border: none; background: none; color: var(--ink-faint); font-size: 18px; line-height: 1; cursor: pointer;
}
.search__clear:hover { color: var(--ink); }
.search--has-query .search__clear { display: grid; }   /* shown only when there's text to clear */
.search__results {
  position: absolute; top: calc(100% + 7px); left: 0; right: 0; margin: 0; padding: 5px;
  list-style: none; background: var(--paper-card); border: 1px solid var(--hair);
  border-radius: 12px; box-shadow: var(--shadow); max-height: min(46vh, 340px); overflow-y: auto;
}
.search__results[hidden] { display: none; }
.search__opt {
  display: flex; align-items: baseline; gap: 8px; padding: 7px 9px; border-radius: 8px; cursor: pointer;
}
.search__opt[aria-selected="true"] { background: color-mix(in srgb, var(--match) 12%, var(--paper-card)); }
.search__opt-city { font-family: var(--serif); font-weight: 500; font-size: 14px; color: var(--ink); }
.search__opt-country { font-size: 11px; color: var(--ink-soft); }
.search__opt-tag {
  margin-left: auto; align-self: center; font-size: 8.5px; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--ink-faint); border: 1px solid var(--hair); border-radius: 5px; padding: 2px 5px; white-space: nowrap;
}
.search__empty { padding: 8px 9px; font-size: 12px; font-style: italic; color: var(--ink-faint); }

/* ---------- Launcher (mobile: chips in the otherwise-empty bottom strip) ---- */
#launcher {
  display: none;   /* desktop: never; mobile idle: shown (see media query) */
  position: absolute; left: var(--edge); right: var(--edge); bottom: 0; height: var(--peek-h);
  flex-direction: column; align-items: center; justify-content: center; gap: 11px; text-align: center;
}
.launcher__label { font-size: 10.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-faint); }
.launcher__chips { display: flex; flex-wrap: wrap; gap: 9px; justify-content: center; }
.chip {
  font-family: var(--serif); font-size: 15px; padding: 7px 16px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--hair); background: color-mix(in srgb, var(--paper-card) 82%, transparent);
  color: var(--ink); transition: border-color .15s ease, background .15s ease;
}
.chip:hover { border-color: var(--ink-faint); background: var(--paper-card); }
.chip:active { transform: translateY(1px); }

/* ---------- Zoom controls ----------------------------------------------- */
#controls {
  position: absolute; right: clamp(12px, 2.4vw, 22px); top: clamp(12px, 3vh, 22px);
  display: flex; flex-direction: column; gap: 6px;
}
#controls button {
  width: 34px; height: 34px; display: grid; place-items: center;
  background: color-mix(in srgb, var(--paper-card) 86%, transparent);
  border: 1px solid var(--hair); border-radius: 9px; color: var(--ink-soft);
  font-family: var(--sans); font-size: 17px; line-height: 1; cursor: pointer;
  backdrop-filter: blur(3px); transition: background .15s ease, color .15s ease, border-color .15s ease;
}
#controls button:hover { color: var(--ink); border-color: var(--ink-faint); }
#controls button:active { transform: translateY(1px); }
#controls button:focus-visible { outline: 2px solid var(--sel); outline-offset: 2px; }
#controls button:disabled { opacity: 0.35; cursor: default; }        /* reset is dead until you move a card */
#controls button:disabled:hover { color: var(--ink-soft); border-color: var(--hair); }

/* ---------- Info card ---------------------------------------------------- */
.panel {
  position: absolute; left: clamp(10px, 2vw, 20px); bottom: clamp(10px, 2.4vh, 20px);
  width: min(290px, 32vw); max-height: min(60%, 480px); overflow-y: auto;
  padding: 15px 17px 16px; background: var(--paper-card); border: 1px solid var(--hair);
  border-radius: 13px; box-shadow: var(--shadow);
  opacity: 0; transform: translateY(10px) scale(0.99); pointer-events: none;
  transition: opacity .26s ease, transform .26s cubic-bezier(.2,.8,.2,1);
  will-change: transform, opacity;
}
.panel.is-open { opacity: 1; transform: none; }
.panel--pinned { pointer-events: auto; }     /* only a pinned card intercepts the pointer (no hover flicker) */

.panel__close {
  position: absolute; top: 8px; right: 10px; width: 26px; height: 26px;
  border: none; background: none; color: var(--ink-faint); font-size: 20px; line-height: 1;
  cursor: pointer; border-radius: 6px; display: none;
}
.panel__close:hover { color: var(--ink); }
.panel--pinned .panel__close { display: grid; place-items: center; }

.panel__bar {
  display: none;    /* desktop: full captions always show; the bar is the mobile expander */
  width: 100%; margin-top: 10px; padding: 10px; border: none; border-radius: 8px;
  background: color-mix(in srgb, var(--match) 13%, var(--paper-card));
  color: var(--match-deep); font-family: var(--sans); font-weight: 600; font-size: 12px;
  letter-spacing: 0.01em; cursor: pointer;
}
.panel__bar:hover { background: color-mix(in srgb, var(--match) 20%, var(--paper-card)); }

.p-city {
  font-family: var(--serif); font-weight: 500; font-optical-sizing: auto;
  font-size: 22px; line-height: 1.06; letter-spacing: -0.01em; margin: 0; color: var(--sel-deep);
}
.p-city__country {
  font-family: var(--sans); font-weight: 500; font-size: 10.5px; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--ink-soft); margin-left: 7px; white-space: nowrap;
}
.p-lead {
  font-size: 9.5px; font-weight: 600; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--match-deep); margin: 11px 0 8px; padding-top: 10px; border-top: 1px solid var(--hair);
}
.p-note {
  font-family: var(--serif); font-style: italic; font-size: 11.5px; line-height: 1.34;
  color: var(--ink-soft); margin: 0 0 13px;
}
.p-note em { font-style: normal; font-weight: 600; color: var(--ink); }
/* Two kinds of link on the card, each with its OWN signifier (feedback 2026-07-04):
   .p-link  = external (Wikipedia) — marked by ↗ alone (title only); NO resting underline, so the
              underline signifier stays reserved for in-app actions (hover/focus restores it);
   .p-goto  = in-app action — teal like its map dot, underlined at rest; clicking it SELECTS that
              counterpart (its Wikipedia link is then one hop away via its own title). */
.p-link {
  color: inherit; text-decoration: none;
  border-bottom: 1px solid transparent;   /* reserved space — no layout shift on hover */
  transition: border-color .15s ease;
}
.p-link:hover, .p-link:focus-visible {
  border-bottom-color: color-mix(in srgb, currentColor 55%, transparent); outline: none;
}
.p-ext { font-family: var(--sans); font-size: 0.72em; margin-left: 2px; }
.p-goto {
  padding: 0; border: none; background: none; cursor: pointer; text-align: left;
  font: inherit; color: var(--match-deep);
  border-bottom: 1px solid color-mix(in srgb, var(--match-deep) 35%, transparent);
  transition: border-color .15s ease;
}
.p-goto:hover, .p-goto:focus-visible { border-bottom-color: currentColor; outline: none; }
.p-match { display: grid; grid-template-columns: auto 1fr; gap: 2px 9px; margin: 0 0 11px; }
.p-match:last-child { margin-bottom: 2px; }
.p-match__rank {
  font-family: var(--serif); font-style: italic; font-size: 13px; color: var(--match);
  grid-row: 1 / span 2; align-self: start; font-variant-numeric: tabular-nums;
}
.p-match__name { font-family: var(--serif); font-weight: 500; font-size: 15px; color: var(--ink); line-height: 1.12; }
.p-match__country { font-family: var(--sans); font-weight: 400; font-size: 10.5px; color: var(--ink-soft); letter-spacing: 0.02em; }
.p-match__cap { font-family: var(--serif); font-style: italic; font-size: 12.5px; line-height: 1.32; color: var(--ink-soft); }
.p-pin-hint {   /* desktop hover cards only — a hover card can't be moused onto, so say how to get one that can */
  margin: 10px 0 0; padding-top: 8px; border-top: 1px solid var(--hair);
  font-family: var(--serif); font-style: italic; font-size: 11.5px; color: var(--ink-soft);
}

/* ---------- Colophon + load --------------------------------------------- */
.colophon {
  flex: 0 0 auto; padding: 7px var(--edge) max(7px, env(safe-area-inset-bottom));
  display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center;
  border-top: 1px solid var(--hair); font-size: 10.5px; letter-spacing: 0.03em; color: var(--ink-faint);
}
.colophon__sep { opacity: 0.5; }
.colophon__gh { margin-left: auto; }   /* text left, link right — the ↗/no-resting-underline external grammar */
.masthead, .colophon { animation: rise .7s both cubic-bezier(.2,.8,.2,1); }
.colophon { animation-delay: .12s; }
@keyframes rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.panel-card { animation: develop 1s both ease-out; }
@keyframes develop { from { opacity: 0; } to { opacity: 1; } }

/* ============================================================================
   Mobile: stacked cards; info becomes a PEEK sheet (map stays tappable).
   ============================================================================ */
@media (max-width: 820px) {
  .masthead { grid-template-columns: 1fr; gap: 4px; }
  .masthead__rule { display: none; }
  .dek { justify-self: start; text-align: left; }

  /* Footer: drop the method clause on phones — scale + GitHub are the essentials there. */
  .colophon__method { display: none; }

  /* Persistent full-width search bar in the reserved top strip (no collapse → no collapse-jank). */
  .search { left: var(--edge); right: var(--edge); top: 8px; transform: none; padding: 8px 13px; }
  .search__input { flex: 1 1 auto; width: auto; }

  /* Push the maps between a reserved top strip (search bar) and bottom strip (peek sheet / launcher). */
  #map { position: relative; top: var(--search-h); height: calc(100% - var(--peek-h) - var(--search-h)); }
  #controls { top: calc(var(--search-h) + 12px); }     /* drop the reset below the search bar, onto the map */
  .hint { display: none; }                             /* replaced by the chip launcher on mobile */
  #app:not(.has-selection) #launcher { display: flex; }

  .panel {
    left: 0; right: 0; top: auto; bottom: 0; width: auto; height: auto;
    border-radius: 18px 18px 0 0; border-bottom: none;
    padding: 12px 16px max(10px, env(safe-area-inset-bottom));
    transform: translateY(102%);
  }
  .panel.is-open { transform: none; }
  .panel__bar { display: block; }

  /* collapsed peek = header + note + the #1 counterpart (teaser) + the expand bar */
  .p-lead { display: none; }
  .p-note { margin: 4px 0 8px; }
  .p-match { margin-bottom: 4px; }
  .p-match ~ .p-match { display: none; }
  .p-match__cap { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

  .panel--expanded { max-height: 68%; overflow-y: auto; }
  .panel--expanded .p-lead { display: block; }
  .panel--expanded .p-note { margin: 8px 0 12px; }
  .panel--expanded .p-match ~ .p-match { display: grid; }
  .panel--expanded .p-match { margin-bottom: 11px; }
  .panel--expanded .p-match__cap { -webkit-line-clamp: initial; overflow: visible; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}
