:root {
  --blue: #005293;
  --tint: #005293; /* §7 accent — one filled primary per view */
  --yellow: #ffcd00;
  --free: #1a9d5a;
  --retail: #0c8f8f;
  --customer: #12b5b0;
  --paid: #5b6b7b;
  --private: #b2544c;
  --unknown: #9aa0a6;

  /* v42 traffic-light: ONE colour language app-wide. GREEN=free now ·
     ORANGE=paid now · RED=don't · GREY=unknown. Tuned for AA contrast against a
     white "P"/marker in both themes. */
  --tl-green: #1a9d5a;
  --tl-orange: #d9730a;
  --tl-red: #e4231a;
  --tl-grey: #9aa0a6;

  --bg: #f5f6f8;
  --surface: #ffffff;
  --text: #1c2530;
  --muted: #5f6b78;
  --border: #e2e6ea;
  --shadow: 0 2px 10px rgba(20, 30, 45, 0.08);
  --radius: 14px;
  --topbar-h: 60px;
  /* Native-app (Capacitor) prep: iOS notch / home-indicator insets */
  --sat: env(safe-area-inset-top, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
  --sal: env(safe-area-inset-left, 0px);
  --sar: env(safe-area-inset-right, 0px);

  font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial,
    sans-serif;
}

* {
  box-sizing: border-box;
}

/* SPEC9 §3: our own pressed states replace the WebView's gray tap flash. */
html {
  -webkit-tap-highlight-color: transparent;
}

button,
a,
select,
.card,
/* v40 §2: the map markers are the PRIMARY tap target (marker → card). Leaflet
   tags every marker element .leaflet-marker-icon; without touch-action here iOS
   WKWebView holds the tap ~300ms to rule out a double-tap-zoom before it will
   dispatch the click — the exact "delay between action and reaction" reported.
   manipulation opts out of that wait so a marker tap dispatches on the frame. */
.leaflet-marker-icon,
.leaflet-interactive {
  touch-action: manipulation;
}

html,
body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  /* Fixed-viewport map shell: the page itself must never scroll. Without this,
     the results sheet (translated below the fold when closed) expands the
     scrollable area, and any overscroll — or a focus/programmatic scroll onto an
     off-screen sheet control — drags the whole layout, detaching the absolutely
     positioned map card from the map so markers show "through" it. `clip` (with
     a `hidden` fallback for old engines) removes the scroll container entirely
     so even programmatic scrollTop can't move it. Scrolling lives inside the
     sheet's own .result-list. */
  overflow: hidden;
  overflow: clip;
  overscroll-behavior: none;
}

/* ---------- Topbar ---------- */

.topbar {
  height: calc(var(--topbar-h) + var(--sat));
  display: flex;
  align-items: center;
  gap: 12px;
  padding: var(--sat) 14px 0;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: relative;
  z-index: 1000;
}

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
}

.brand-mark {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: var(--blue);
  color: var(--yellow);
  font-weight: 800;
}

.brand-name {
  color: var(--blue);
}

.search-wrap {
  position: relative;
  flex: 1;
  max-width: 560px;
}

#search {
  width: 100%;
  padding: 10px 14px;
  font-size: 15px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg);
  color: var(--text);
}

#search:focus {
  outline: 2px solid var(--tint);
  outline-offset: 1px;
}

/* §7: replace the browser default (orange/yellow) select/segment focus ring. */
.settings-select:focus,
.seg:focus-visible,
.seg-inline:focus-visible {
  outline: 2px solid var(--tint);
  outline-offset: 1px;
}

.suggestions {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow);
  z-index: 1200;
  max-height: 320px;
  overflow-y: auto;
}

.suggestion {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2px 8px;
  padding: 10px 12px;
  min-height: 48px; /* SPEC9 §4: comfortable touch rows */
  align-content: center;
  border-radius: 8px;
  cursor: pointer;
}

.suggestion:active {
  background: rgba(0, 82, 147, 0.14);
}

/* Dropdown loading shimmer rows (Photon in flight) */
.sug-skel {
  display: flex;
  align-items: center;
  min-height: 40px;
  padding: 10px 12px;
}

.sug-skel .skel-line {
  height: 12px;
  flex: none;
}

.sug-skel .skel-line.w60 { width: 60%; }
.sug-skel .skel-line.w40 { width: 40%; }

.suggestion.active {
  background: rgba(0, 82, 147, 0.1);
}

.s-name {
  font-weight: 600;
}

.s-meta {
  grid-column: 1;
  color: var(--muted);
  font-size: 13px;
}

.s-type {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--blue);
  background: rgba(0, 82, 147, 0.08);
  padding: 2px 6px;
  border-radius: 6px;
}

.btn-ghost {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 10px;
  cursor: pointer;
  font-size: 14px;
}

.btn-ghost:hover {
  border-color: var(--blue);
  color: var(--blue);
}

.lang-toggle {
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 9px 10px;
  flex: none;
}

.icon-only {
  padding: 9px 11px;
  flex: none;
  font-size: 16px;
  line-height: 1;
}

/* Narrow screens: compact buttons + logo-only brand so the search input keeps width */
@media (max-width: 480px) {
  .topbar {
    gap: 8px;
    padding: 0 10px;
  }

  .brand-name {
    display: none;
  }

  .loc-text {
    display: none;
  }

  .btn-ghost {
    width: 38px;
    height: 38px;
    padding: 0;
    justify-content: center;
    border-radius: 50%;
    flex: none;
  }

  .loc-icon {
    font-size: 18px;
  }
}

/* ---------- Layout ---------- */

.layout {
  position: relative;
  height: calc(100% - var(--topbar-h) - var(--sat));
  /* Clip the results sheet's off-screen (translated-down) travel at the source
     so it never becomes a scroll container — otherwise a focus/programmatic
     scroll drags the whole layout and detaches the absolutely-positioned map
     card from the map. `clip` (hidden fallback) blocks programmatic scrollTop
     too. The sheet scrolls internally via its own .result-list. */
  overflow: hidden;
  overflow: clip;
}

#map {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.panel {
  position: absolute;
  z-index: 500;
  background: var(--surface);
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow);
}

/* Mobile: bottom sheet */
.panel {
  left: 0;
  right: 0;
  bottom: 0;
  max-height: 52%;
  border-top-left-radius: 18px;
  border-top-right-radius: 18px;
}

/* ---------- Tier filter chips ---------- */

.tier-chips {
  display: flex;
  gap: 7px;
  padding: 9px 14px;
  overflow-x: auto;
  scrollbar-width: none;
  border-bottom: 1px solid var(--border);
  /* SPEC9 §2: subtle right-edge fade hints at horizontal scroll */
  -webkit-mask-image: linear-gradient(90deg, #000 94%, transparent);
  mask-image: linear-gradient(90deg, #000 94%, transparent);
}

.tier-chips::-webkit-scrollbar {
  display: none;
}

.tier-chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 11px;
  border-radius: 999px;
  border: 1px solid var(--tc, var(--border));
  background: transparent;
  color: var(--text);
  font-size: 12px; /* SPEC9 §2: quieter tier row */
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  opacity: 0.55;
  transition: background 0.15s ease-out, opacity 0.15s ease-out, transform 0.06s;
}

.tier-chip:active,
.feature-chip:active {
  transform: scale(0.95);
}

.tier-chip.on {
  opacity: 1;
  background: var(--tc-fill, rgba(0, 82, 147, 0.12));
  border-color: var(--tc, var(--blue));
}

.chip-count {
  font-size: 11px;
  font-weight: 700;
  color: var(--muted); /* SPEC9 §2: counts whisper, they don't shout */
}

.chip-free { --tc: var(--free); --tc-fill: rgba(26, 157, 90, 0.16); }
.chip-retail { --tc: var(--retail); --tc-fill: rgba(12, 143, 143, 0.18); }
.chip-customer { --tc: var(--customer); --tc-fill: rgba(18, 181, 176, 0.16); }
.chip-unknown { --tc: var(--unknown); --tc-fill: rgba(154, 160, 166, 0.2); }
.chip-paid { --tc: var(--paid); --tc-fill: rgba(91, 107, 123, 0.18); }
.chip-private { --tc: var(--private); --tc-fill: rgba(178, 84, 76, 0.16); }

/* ---------- Panel controls: tier chips + single Filter button ---------- */
/* One quiet row replaces the old radius row + tier row + features row. It
   stays hidden until a place is searched, so first load is clean. */

.panel-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 10px 9px 14px;
  border-bottom: 1px solid var(--border);
}

.panel-controls[hidden] {
  display: none;
}

/* The tier chips flex/scroll inside the controls row; the row owns the border. */
.panel-controls .tier-chips {
  flex: 1;
  min-width: 0;
  padding: 0;
  border-bottom: none;
}

.filter-btn {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 7px 15px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  transition: transform 0.06s, border-color 0.15s ease-out;
}

.filter-btn:active {
  transform: scale(0.96);
}

.filter-btn:hover {
  border-color: var(--blue);
}

.filter-btn.active {
  border-color: var(--blue);
  color: var(--blue);
}

/* Active narrowing indicator — a quiet dot, not a loud count. */
.filter-btn.active::after {
  content: "";
  position: absolute;
  top: 5px;
  right: 7px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--blue);
}

/* ---------- First-run empty state ---------- */

.empty-state {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 28px 24px;
  text-align: center;
}

.empty-state[hidden] {
  display: none;
}

.empty-lead {
  margin: 0;
  font-size: 19px;
  font-weight: 800;
  line-height: 1.3;
  color: var(--text);
}

.empty-sub {
  margin: 0;
  max-width: 30ch;
  font-size: 15px;
  line-height: 1.45;
  color: var(--muted);
}

.empty-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 48px;
  margin-top: 6px;
  padding: 12px 22px;
  border-radius: 12px;
  font-size: 16px;
  font-weight: 700;
  transition: transform 0.06s, filter 0.15s ease-out;
}

.empty-cta:active {
  transform: scale(0.97);
}

.empty-cta .loc-icon {
  font-size: 18px;
}

/* ---------- Filter dialog: radius + feature toggles ---------- */

.filter-dialog .filter-section {
  margin: 16px 0;
}

.filter-dialog .filter-section > label {
  display: block;
  margin-bottom: 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--muted);
}

/* Feature chips wrap and breathe inside the dialog (no scroll/fade here). */
.filter-dialog .feature-chips {
  flex-wrap: wrap;
  gap: 8px;
  padding: 0;
  overflow: visible;
  border-bottom: none;
  -webkit-mask-image: none;
  mask-image: none;
}

.filter-dialog .feature-label {
  width: 100%;
  margin: 0 0 2px;
}

.filter-dialog .feature-chip {
  min-height: 40px;
  padding: 8px 14px;
  font-size: 13px;
}

/* ---------- Feature filter chips (SPEC8 §4) ---------- */

.feature-chips {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  overflow-x: auto;
  scrollbar-width: none;
  border-bottom: 1px solid var(--border);
  -webkit-mask-image: linear-gradient(90deg, #000 94%, transparent);
  mask-image: linear-gradient(90deg, #000 94%, transparent);
}

.feature-chips::-webkit-scrollbar {
  display: none;
}

.feature-label {
  flex: none;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin-right: 2px;
}

.feature-chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}

.feature-chip.on {
  color: var(--text);
  border-color: var(--blue);
  background: rgba(0, 82, 147, 0.12);
}

/* Prominent Park & Ride card chip — these lots are usually free. */
.chip-pr {
  background: rgba(26, 157, 90, 0.15);
  border-color: var(--free);
  color: var(--free);
  font-weight: 700;
}

/* EV / motorcycle overlay markers (POIs, not parking results) */
.ev-mark,
.mc-mark {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 13px;
  font-weight: 800;
  box-shadow: 0 1px 4px rgba(10, 20, 35, 0.35);
  border: 2px solid #fff;
}

/* v6 §2: EV mark is dark by default, green when charging/parking is free. */
.ev-mark {
  background: #46505b;
  color: #fff;
}

.ev-mark.ev-free {
  background: #1a9d5a;
}

.mc-mark {
  background: #5b6b7b;
  color: #fff;
  font-size: 13px;
}

.municipal-card.municipal-accessible {
  border-left-color: #3b6fd4;
}

.list-group-header {
  margin: 12px 14px 4px;
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.01em;
  color: var(--text);
}

.list-group-header.muted {
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}

.near-anchor {
  margin: 2px 0;
  font-size: 12px;
  color: var(--muted);
  display: flex;
  align-items: center;
  gap: 5px;
}

.anchor-mark {
  width: 20px;
  height: 20px;
  border-radius: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  background: var(--yellow);
  color: #3a3000;
  border: 1.5px solid #d9ad00;
  box-shadow: 0 1px 4px rgba(10, 20, 35, 0.3);
  cursor: pointer;
}

.anchor-mark.labelled {
  width: auto;
  height: 22px;
  padding: 0 8px 0 6px;
  border-radius: 11px;
  white-space: nowrap;
}

.anchor-name {
  font-size: 11px;
  font-weight: 700;
  color: #3a3000;
}

.know-block {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

.know-block h3 {
  margin: 0 0 4px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.know-block p {
  margin: 2px 0;
  font-size: 12px;
  color: var(--muted);
}

.know-block .unknown-help {
  color: var(--text);
}

.know-source {
  margin: 4px 0 0;
  font-size: 11px;
  color: var(--muted);
}

.list-status {
  margin: 0;
  padding: 10px 14px;
  font-size: 15px;
  color: var(--muted);
}

.list-status[hidden] {
  display: none;
}

.list-status.loading::after {
  content: "";
  display: inline-block;
  width: 12px;
  height: 12px;
  margin-left: 8px;
  border: 2px solid var(--border);
  border-top-color: var(--blue);
  border-radius: 50%;
  vertical-align: middle;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.result-list {
  flex: 1;
  overflow-y: auto;
  padding: 4px 14px 14px;
  display: flex;
  flex-direction: column;
  gap: 12px; /* SPEC9 §2: more breathing room between cards */
  font-size: 15px;
  line-height: 1.4;
}

/* Cards are flex items in a scrollable column; without this, the explicit
   min-height on .card replaces the content-based minimum size and lets the
   flexbox compress cards below their content height when the list overflows —
   long tier subtitles then collide with the meta line. Never shrink. */
.result-list > * {
  flex: none;
}

.card {
  border: 1px solid var(--border);
  border-left: 5px solid var(--unknown);
  border-radius: var(--radius);
  padding: 13px 15px;
  min-height: 44px; /* comfortable tap target */
  cursor: pointer;
  background: var(--surface);
  transition: box-shadow 0.15s, border-color 0.15s, transform 0.06s;
}

.card:hover {
  box-shadow: var(--shadow);
}

.card:active {
  transform: scale(0.985);
  filter: brightness(0.97);
}

.card.active {
  border-color: var(--blue);
  box-shadow: 0 0 0 2px rgba(0, 82, 147, 0.25);
}

.card.tier-free {
  border-left-color: var(--free);
}
.card.tier-retail {
  border-left-color: var(--retail);
}
.card.tier-customer {
  border-left-color: var(--customer);
}
.card.tier-paid {
  border-left-color: var(--paid);
}
.card.tier-private {
  border-left-color: var(--private);
}
.card.tier-unknown {
  border-left-color: var(--unknown);
  opacity: 0.85;
}

.card-top {
  display: flex;
  align-items: center;
  gap: 8px;
}

.card-top h3 {
  margin: 0;
  font-size: 17px; /* SPEC9 §2: bigger titles */
  font-weight: 700;
  min-width: 0; /* allow wrapping inside the flex row instead of overflowing */
  overflow-wrap: anywhere;
  line-height: 1.35;
}

.dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex: none;
}

/* Verdict headline in the detail sheet (the plain-language "what is this?"
   line). Sheet-only now — cards carry their tier word in the meta line. */
.tier-label {
  margin: 8px 0 2px;
  font-size: 16px;
  font-weight: 700;
  line-height: 1.35; /* long retail subtitles wrap cleanly at any length */
}

/* v48: the sheet's verdict headline reads the SAME evaluated traffic-light
   status (js signTrafficStatus → st-*) as the map card, the plate, and the dot,
   so a fee-active free lot shows ORANGE "Avgift nu" text — never a green lie. */
.tier-label.st-free,
.tier-label.st-freenow {
  color: var(--tl-green);
}
.tier-label.st-paid {
  color: var(--tl-orange);
}
.tier-label.st-private {
  color: var(--tl-red);
}
.tier-label.st-unknown {
  color: var(--tl-grey);
  font-weight: 500;
}

.dist {
  margin: 4px 0 0;
  font-size: 14px; /* SPEC9 §2: the ONE muted meta line */
  line-height: 1.35;
  color: var(--muted);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.chip {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--muted);
}

.data-source {
  margin: 0;
  padding: 6px 14px 0;
  font-size: 12px;
  color: var(--muted);
  overflow-wrap: anywhere;
  word-break: break-word;
}

.data-source:empty {
  display: none;
}

.chain-note {
  margin: 2px 0;
  font-size: 12px;
  color: var(--customer);
}

.badge {
  display: inline-block;
  margin: 6px 0 0;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
}

.badge-free {
  background: rgba(26, 157, 90, 0.15);
  color: var(--free);
}

.badge-notfree {
  background: rgba(140, 145, 150, 0.2);
  color: var(--muted);
}

.card.conf-notfree {
  opacity: 0.55;
}

.card-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}

.act {
  font-size: 11px;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--muted);
  cursor: pointer;
}

.act {
  transition: transform 0.06s, border-color 0.15s ease-out;
}

.act:active,
.fab:active,
.btn:active,
.btn-ghost:active,
.s-remove:active {
  transform: scale(0.94); /* SPEC9 §3: <100ms pressed feedback everywhere */
}

.act.on,
.act:hover {
  border-color: var(--free);
  color: var(--free);
}

.act-notfree.on,
.act-notfree:hover {
  border-color: var(--private);
  color: var(--text);
}

.osm-link {
  font-size: 11px;
  color: var(--blue);
}

.municipal-section {
  padding: 0 14px 14px;
}

.municipal-section h3 {
  margin: 6px 0 8px;
  font-size: 13px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.municipal-card {
  border-left-color: #0c8f8f;
  margin-bottom: 10px;
  cursor: default;
}

.municipal-card.municipal-paid {
  border-left-color: var(--paid);
  opacity: 0.85;
}

.municipal-section > div {
  margin-bottom: 6px;
}

.settings-row {
  margin: 14px 0;
  font-size: 14px;
}

.settings-row label {
  display: block;
  margin-bottom: 6px;
  font-size: 13px;
  color: var(--muted);
}

.settings-inline {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.settings-select {
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
}

.settings-inline input[type='text'] {
  flex: 1;
  min-width: 160px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
}

.settings-disabled {
  color: var(--muted);
  opacity: 0.7;
}

.settings-row h3 {
  margin: 0 0 8px;
  font-size: 14px;
}

.disclaimer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 14px calc(8px + var(--sab));
  border-top: 1px solid var(--border);
  font-size: 11px;
  color: var(--muted);
}

.nav-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
}

/* display:flex above would defeat the hidden attribute (author styles beat
   the UA [hidden] rule) — keep the chooser genuinely collapsed until tapped. */
.nav-row[hidden] {
  display: none;
}

/* SPEC9 §3: nav providers are buttons, not text links — big targets with
   instant pressed feedback. */
.nav-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 10px 16px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg);
  font-size: 14px;
  font-weight: 700;
  color: var(--blue);
  transition: transform 0.06s, background 0.15s ease-out;
}

.nav-link:active {
  transform: scale(0.96);
  background: rgba(0, 82, 147, 0.14);
}

.ad-banner {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3000;
  padding: 10px 0 calc(10px + var(--sab));
  text-align: center;
  font-size: 12px;
  color: var(--muted);
  background: var(--surface);
  border-top: 1px solid var(--border);
}

.ad-banner[hidden] {
  display: none; /* reserves zero space while ads are off */
}

.link-btn {
  background: none;
  border: none;
  color: var(--blue);
  cursor: pointer;
  font-size: 11px;
  text-decoration: underline;
  white-space: nowrap;
}

/* ---------- Road-sign P markers & clusters ---------- */

.pmark-wrap {
  background: none;
  border: none;
}

/* SPEC9 §1: compact marker variant for low zooms */
.pmark.pm-sm {
  width: 22px;
  height: 22px;
  border-radius: 6px;
  border-width: 2px;
}

.pmark.pm-sm .pm-p {
  font-size: 11px;
}

.pmark.pm-sm .pm-dot {
  width: 8px;
  height: 8px;
  top: -3px;
  right: -3px;
}

.pmark {
  position: relative;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: #0d5eaf;
  display: grid;
  place-items: center;
  box-shadow: 0 2px 6px rgba(10, 20, 35, 0.35);
  border: 2.5px solid var(--unknown);
  transition: transform 0.12s;
}

.pmark .pm-p {
  color: #fff;
  font-weight: 800;
  font-size: 15px;
  line-height: 1;
  font-family: inherit;
}

.pm-dot {
  position: absolute;
  top: -4px;
  right: -4px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 1.5px solid #fff;
  background: var(--unknown);
}

.pm-free { border-color: var(--free); }
.pm-free .pm-dot { background: var(--free); }
.pm-retail { border-color: var(--retail); }
.pm-retail .pm-dot { background: var(--retail); }
.pm-customer { border-color: var(--customer); }
.pm-customer .pm-dot { background: var(--customer); }
.pm-paid { border-color: #3a4a5c; }
.pm-paid .pm-dot { background: #3a4a5c; }
.pm-private { border-color: var(--private); }
.pm-private .pm-dot { background: var(--private); }
.pm-unknown { opacity: 0.85; }

.pm-active {
  transform: scale(1.25);
  z-index: 1000;
  animation: pm-pop 0.28s ease-out;
}

@keyframes pm-pop {
  0% { transform: scale(0.9); }
  55% { transform: scale(1.38); }
  100% { transform: scale(1.25); }
}

.pm-conf-free {
  box-shadow: 0 0 0 3px rgba(26, 157, 90, 0.55), 0 2px 6px rgba(10, 20, 35, 0.35);
}

.pm-conf-notfree {
  opacity: 0.45;
}

.pm-badge {
  position: absolute;
  bottom: -9px;
  left: 50%;
  transform: translateX(-50%);
  background: #fff;
  color: #1c2530;
  font-size: 9px;
  font-weight: 700;
  padding: 0 4px;
  border-radius: 5px;
  border: 1px solid #c9cfd6;
  white-space: nowrap;
}

.cluster-bubble {
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--yellow);
  color: #1c2530; /* dark text on yellow: AA contrast */
  font-weight: 800;
  font-size: 13px;
  border: 2.5px solid #fff;
  box-shadow: 0 2px 6px rgba(10, 20, 35, 0.35);
  cursor: pointer;
}

/* ---------- Floating map buttons & count chip ---------- */

.map-fabs {
  position: absolute;
  right: 12px;
  bottom: calc(54% + 12px);
  z-index: 600;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* v42 §2: one-tap Park-now — bottom-centre, above the FAB row, 56pt. */
.park-now-btn {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(24px + var(--sab, 0px));
  z-index: 620;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: none;
  background: var(--tint);
  color: #fff;
  font-size: 26px;
  font-weight: 800;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.28);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: transform 0.12s ease;
}
.park-now-btn:active { transform: translateX(-50%) scale(0.93); }
.park-now-btn[hidden] { display: none; }

/* Park-now carousel nav inside the docked card. */
.mc-parknow-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin: 2px 0 6px;
}
.mc-parknow-nav .pn-arrow {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}
.mc-parknow-nav .pn-arrow:disabled { opacity: 0.35; cursor: default; }
.mc-parknow-nav .pn-count { font-size: 13px; color: var(--muted); min-width: 54px; text-align: center; }

.fab {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  display: grid;
  place-items: center;
  box-shadow: var(--shadow);
  cursor: pointer;
  font-size: 12px;
  font-weight: 700;
}

.fab.on {
  background: var(--blue);
  color: #fff;
  border-color: var(--blue);
}

.map-count {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 600;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 5px 12px;
  font-size: 12px;
  font-weight: 600;
  box-shadow: var(--shadow);
}

/* ---------- Detail sheet ---------- */

.detail-sheet {
  position: absolute;
  z-index: 900;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--surface);
  border-top-left-radius: 18px;
  border-top-right-radius: 18px;
  box-shadow: 0 -6px 24px rgba(10, 20, 35, 0.25);
  padding: 8px 16px calc(16px + var(--sab));
  max-height: 70%;
  overflow-y: auto;
  /* P2-logic: slide up from fully below with an OPAQUE surface from frame 1.
     No opacity fade — fading the whole sheet made the map show through it
     mid-animation. The surface background is always solid; only position moves. */
  transform: translateY(100%);
  transition: transform 0.2s ease-out;
}

.detail-sheet.open {
  transform: translateY(0);
}

.sheet-handle {
  width: 48px; /* SPEC9 §3: clearer swipe-down affordance */
  height: 5px;
  border-radius: 3px;
  background: var(--muted);
  opacity: 0.5;
  margin: 4px auto 10px;
}

.sheet-close {
  position: absolute;
  top: 10px;
  right: 12px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: none;
  background: var(--bg);
  color: var(--muted);
  font-size: 17px;
  cursor: pointer;
}

.sheet-body h2 {
  margin: 0;
  font-size: 20px; /* SPEC9 §3: larger sheet title */
  line-height: 1.3;
}

.sheet-rows {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 12px 0;
  font-size: 13px;
}

.sheet-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.sheet-row .icn {
  color: var(--muted);
  flex: none;
  margin-top: 1px;
}

/* v11: the detail sheet's Navigera split button — bigger + margin above. */
.sheet-body .nav-split {
  margin-top: 12px;
}
.sheet-body .nav-go,
.sheet-body .nav-caret {
  min-height: 48px;
  font-size: 16px;
  font-weight: 800;
}

.icn {
  display: inline-flex;
  vertical-align: -2px;
}

.conf-mini {
  color: var(--free);
  margin-left: auto;
}

.time-status {
  margin: 2px 0;
  font-size: 12px;
  font-weight: 600;
}

.time-status.ok { color: var(--free); }
.time-status.no { color: #b2544c; }

/* ---------- Recents dropdown ---------- */

.recents-header {
  padding: 6px 10px 2px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.suggestion.recent {
  display: flex;
  align-items: center;
  gap: 8px;
}

.suggestion.recent .icn {
  color: var(--muted);
  flex: none;
}

.suggestion.recent .s-meta {
  margin-left: auto;
}

.s-remove {
  border: none;
  background: none;
  color: var(--muted);
  font-size: 15px;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: 6px;
}

.s-remove:hover {
  background: var(--bg);
  color: var(--text);
}

/* ---------- Skeleton loading ---------- */

.skel-card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.skel-line {
  height: 11px;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--border) 25%, var(--bg) 50%, var(--border) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.2s infinite;
}

.skel-line.w40 { width: 40%; }
.skel-line.w60 { width: 60%; }
.skel-line.w80 { width: 80%; }

@keyframes shimmer {
  to { background-position: -200% 0; }
}

/* SPEC9 §4: brief highlight pulse on the search pin. Filter/opacity only —
   Leaflet owns the marker element's transform for positioning. */
.pin-pulse {
  animation: pin-pulse 0.9s ease-out 2;
}

@keyframes pin-pulse {
  0%, 100% { filter: none; }
  40% { filter: drop-shadow(0 0 8px rgba(0, 82, 147, 0.95)) brightness(1.2); }
}

@media (prefers-reduced-motion: reduce) {
  .skel-line { animation: none; }
  .detail-sheet { transition: none; }
  .pmark { transition: none; }
  .pin-pulse { animation: none; }
  .card,
  .tier-chip,
  .feature-chip,
  .act,
  .nav-link,
  .map-card { transition: none; animation: none; }
  .card:active,
  .tier-chip:active,
  .feature-chip:active,
  .act:active,
  .fab:active,
  .btn:active,
  .btn-ghost:active,
  .s-remove:active,
  .nav-link:active,
  .nav-caret:active,
  .mc-more:active { transform: none; }
}

.btn-secondary {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
}

/* ---------- Toast ---------- */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(52% + 16px + var(--sab));
  transform: translateX(-50%);
  z-index: 2000;
  background: #26313f;
  color: #fff;
  padding: 10px 16px;
  border-radius: 10px;
  font-size: 13px;
  box-shadow: var(--shadow);
  max-width: 88vw;
  text-align: center;
}

/* ---------- Info dialog ---------- */

.info-dialog {
  border: none;
  border-radius: var(--radius);
  padding: 22px;
  max-width: 460px;
  width: calc(100% - 32px);
  color: var(--text);
  background: var(--surface);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
}

.info-dialog::backdrop {
  background: rgba(10, 15, 22, 0.5);
}

.info-dialog h2 {
  margin-top: 0;
  color: var(--blue);
}

.info-dialog ul {
  padding-left: 18px;
  font-size: 14px;
  line-height: 1.5;
}

.info-dialog code {
  background: var(--bg);
  padding: 1px 4px;
  border-radius: 4px;
  font-size: 12px;
}

.btn {
  padding: 8px 16px;
  border: none;
  border-radius: 8px;
  background: var(--blue);
  color: #fff;
  cursor: pointer;
  font-size: 14px;
}

/* ---------- Desktop: left panel ---------- */

@media (min-width: 900px) {
  .panel {
    top: 0;
    bottom: 0;
    left: 0;
    right: auto;
    width: 380px;
    max-height: none;
    border-radius: 0;
    border-right: 1px solid var(--border);
  }

  #map {
    left: 380px;
  }

  .toast {
    left: calc(380px + (100% - 380px) / 2);
    bottom: calc(24px + var(--sab));
  }

  .map-fabs {
    right: 16px;
    bottom: calc(24px + var(--sab));
  }

  /* Desktop: detail sheet docks over the left panel as a side section */
  .detail-sheet {
    left: 0;
    right: auto;
    width: 380px;
    max-height: 65%;
    border-radius: 0 18px 0 0;
    border-right: 1px solid var(--border);
  }

  .map-count {
    left: calc(380px + (100% - 380px) / 2);
  }
}

/* ---------- Dark mode ---------- */

/* Dark theme comes from the OS by default, but a forced Ljus (data-theme=light)
   opts out and a forced Mörk (data-theme=dark, block below) opts in regardless
   of the OS — v6 §3. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #12171d;
    --surface: #1b222b;
    --text: #e7ecf1;
    --muted: #9aa6b2;
    --border: #2b333d;
    --shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
    --tint: #4da3ff; /* §7 accent — accessible blue on dark */
    /* v42 traffic-light, brightened for contrast on the dark map/surface. */
    --tl-green: #2ebd74;
    --tl-orange: #f0912f;
    --tl-red: #ff5a4d;
    --tl-grey: #aab2bd;
  }

  :root:not([data-theme="light"]) .brand-name { color: var(--yellow); }
  :root:not([data-theme="light"]) #search::placeholder { color: var(--muted); }
  :root:not([data-theme="light"]) .s-type {
    color: var(--yellow);
    background: rgba(255, 205, 0, 0.12);
  }
  :root:not([data-theme="light"]) .btn-ghost:hover {
    color: var(--yellow);
    border-color: var(--yellow);
  }
  :root:not([data-theme="light"]) .link-btn { color: var(--yellow); }
}

/* v6 §3: forced dark theme — same declarations, overriding a light OS. */
:root[data-theme="dark"] {
  --bg: #12171d;
  --surface: #1b222b;
  --text: #e7ecf1;
  --muted: #9aa6b2;
  --border: #2b333d;
  --shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
  --tint: #4da3ff;
}

:root[data-theme="dark"] .brand-name { color: var(--yellow); }
:root[data-theme="dark"] #search::placeholder { color: var(--muted); }
:root[data-theme="dark"] .s-type {
  color: var(--yellow);
  background: rgba(255, 205, 0, 0.12);
}
:root[data-theme="dark"] .btn-ghost:hover {
  color: var(--yellow);
  border-color: var(--yellow);
}
:root[data-theme="dark"] .link-btn { color: var(--yellow); }

/* ---------- Sign scanner ---------- */

.scan-dialog {
  max-width: 520px;
  max-height: calc(100% - 32px);
  overflow-y: auto;
}

.scan-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.scan-head h2 {
  margin: 0 0 4px;
  color: var(--blue);
  font-size: 20px;
}

.scan-intro {
  margin: 0 0 14px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--muted);
}

.scan-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

/* A class `display` would otherwise beat the [hidden] UA rule — on the web the
   photo buttons are hidden (type-in only), so honour the attribute. */
.scan-actions[hidden] {
  display: none;
}

.scan-actions .btn {
  flex: 1 1 auto;
  min-width: 130px;
}

.scan-preview {
  display: block;
  width: 100%;
  max-height: 200px;
  object-fit: contain;
  margin: 14px 0 4px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--bg);
}

.scan-status {
  margin: 12px 0 4px;
  font-size: 13px;
  color: var(--blue);
  font-weight: 600;
}

.scan-label {
  display: block;
  margin: 14px 0 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}

.scan-text {
  width: 100%;
  resize: vertical;
  padding: 10px 12px;
  font-size: 15px;
  font-family: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
}

.scan-red {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px 0;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

.scan-red input {
  width: 18px;
  height: 18px;
  accent-color: var(--private);
}

.scan-interpret {
  width: 100%;
  padding: 11px;
  font-size: 15px;
  font-weight: 600;
}

.scan-tier {
  display: inline-block;
  margin: 14px 0 4px;
  padding: 4px 12px;
  border-radius: 999px;
  color: #fff;
  font-size: 13px;
  font-weight: 700;
}
.scan-tier.tier-free { background: var(--free); }
.scan-tier.tier-paid { background: var(--paid); }
.scan-tier.tier-private { background: var(--private); }
.scan-tier.tier-customer { background: var(--customer); }
.scan-tier.tier-retail { background: var(--retail); }
.scan-tier.tier-unknown { background: var(--unknown); }

.scan-parts {
  margin: 8px 0;
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}

.scan-part {
  display: grid;
  grid-template-columns: 84px 1fr;
  gap: 10px;
  padding: 10px 12px;
  align-items: start;
}

.scan-part + .scan-part {
  border-top: 1px solid var(--border);
}

.scan-part-label {
  font-weight: 700;
  color: var(--blue);
  font-size: 14px;
  word-break: break-word;
}

.scan-part-meaning {
  font-size: 14px;
  line-height: 1.45;
  color: var(--text);
}

.scan-caveats {
  margin: 12px 0 4px;
  padding: 12px 14px 12px 30px;
  list-style: disc;
  background: rgba(255, 205, 0, 0.14);
  border-radius: 12px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--text);
}

.scan-caveats li + li {
  margin-top: 6px;
}

.scan-honesty {
  margin: 16px 0 10px;
  padding: 10px 12px;
  border-left: 4px solid var(--blue);
  background: var(--bg);
  border-radius: 0 8px 8px 0;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.45;
  color: var(--text);
}

.scan-footer {
  margin: 0;
  text-align: right;
}

/* --- reconstructed "sign I read" diagram (AI mode) --- */
.scan-recon {
  margin: 10px 0 4px;
}

.scan-recon-label {
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}

.scan-recon-svg {
  display: block;
  width: 100%;
  max-width: 260px;
  height: auto;
  margin: 0 auto 6px;
}

/* v46 §3: confirm-by-reconstruction — the reconstructed sign next to the user's
   own photo, and the Ja/Nej confirmation. */
.scan-typein {
  display: block;
  margin: 8px 0 2px;
  font-size: 13px;
  text-decoration: underline;
}
.scan-confirm {
  margin: 8px 0 4px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg);
}
.scan-confirm-q {
  margin: 0 0 10px;
  font-size: 15.5px;
  font-weight: 800;
  color: var(--text);
  text-align: center;
}
.scan-confirm-body {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
}
.scan-confirm-body .scan-recon { margin: 0; flex: 1 1 200px; min-width: 160px; }
.scan-confirm-photo {
  flex: 0 1 120px;
  max-width: 130px;
  max-height: 150px;
  object-fit: contain;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface);
}
.scan-confirm-actions {
  display: flex;
  gap: 10px;
  margin-top: 12px;
}
.scan-confirm-actions .btn { flex: 1; }

/* --- plain-language verdict headline --- */
.scan-verdict {
  margin: 14px 0 6px;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-left: 5px solid var(--blue);
  font-size: 16px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--text);
}

.scan-verdict.verdict-free { border-left-color: var(--free); }
.scan-verdict.verdict-paid { border-left-color: var(--paid); }
.scan-verdict.verdict-private { border-left-color: var(--private); }
.scan-verdict.verdict-unknown { border-left-color: var(--unknown); }

.scan-verdict-src {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--blue);
}

/* --- AI mode --- */
.scan-ai {
  width: 100%;
  margin: 4px 0 8px;
  padding: 11px;
  font-size: 15px;
  font-weight: 700;
}

.scan-ai[disabled] {
  opacity: 0.6;
}

.scan-ai-bullets {
  margin: 8px 0 4px;
  padding: 0 0 0 20px;
  list-style: disc;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text);
}

.scan-ai-bullets li + li {
  margin-top: 5px;
}

.settings-note {
  margin: 6px 0 0;
  font-size: 12px;
  line-height: 1.4;
  color: var(--muted, #6b7280);
}

/* ==========================================================================
   iOS-only native feel (Capacitor). EVERY rule below is scoped under
   `body.platform-ios`, which app.js adds ONLY when Capacitor.getPlatform()
   === 'ios'. Android and the plain web app never get this class, so their
   appearance is unchanged. Do not add un-gated rules here.
   ========================================================================== */

/* (1) SF-first font stack on iOS. */
body.platform-ios {
  font-family: -apple-system, system-ui, "SF Pro Text", "SF Pro Display",
    "Helvetica Neue", Helvetica, Arial, sans-serif;
  /* (5) No stray text selection / callouts on app chrome. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* Re-enable selection where the user genuinely edits/reads text. */
body.platform-ios input,
body.platform-ios textarea,
body.platform-ios [contenteditable],
body.platform-ios .scan-text,
body.platform-ios .sheet-body {
  -webkit-user-select: text;
  user-select: text;
}

/* (2) Full safe-area insets, incl. side insets for notch/landscape. */
body.platform-ios .topbar {
  padding-left: calc(14px + var(--sal));
  padding-right: calc(14px + var(--sar));
}

body.platform-ios .panel {
  padding-left: var(--sal);
  padding-right: var(--sar);
}

body.platform-ios .map-fabs {
  right: calc(12px + var(--sar));
}

/* (7) Momentum (rubber-band) scrolling on the scroll containers. */
body.platform-ios .panel,
body.platform-ios .result-list,
body.platform-ios .detail-sheet,
body.platform-ios .info-dialog,
body.platform-ios .tier-chips {
  -webkit-overflow-scrolling: touch;
}

/* (8, light) A touch more presence on the app title — not a full large-title
   bar (the simplified v19 UX stays uncluttered). */
body.platform-ios .brand-name {
  font-size: 18px;
  letter-spacing: -0.01em;
}

/* (5) iOS controls: filled, more-rounded primary buttons with a spring press.
   Brand blue #005293 stays the tint. Hover is neutralised (touch, not pointer);
   :active gives an opacity+scale press instead. */
body.platform-ios .btn {
  border-radius: 12px;
  padding: 11px 18px;
  font-weight: 600;
  font-size: 15px;
  transition: transform 0.08s ease-out, opacity 0.08s ease-out;
}

body.platform-ios .btn-ghost {
  border-radius: 11px;
}

body.platform-ios .btn:active,
body.platform-ios .btn-ghost:active,
body.platform-ios .fab:active {
  opacity: 0.55;
  transform: scale(0.96);
}

/* Kill the desktop hover tint on iOS (sticky-hover after a tap looks wrong). */
body.platform-ios .btn-ghost:hover {
  border-color: var(--border);
  color: var(--text);
}

/* (5) iOS-style switch for the "any numbers in RED?" scan toggle. */
body.platform-ios .scan-red input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  width: 44px;
  height: 27px;
  border-radius: 999px;
  background: #d0d3d8;
  transition: background 0.2s ease-out;
  cursor: pointer;
  vertical-align: middle;
  flex: none;
}

body.platform-ios .scan-red input[type="checkbox"]::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 23px;
  height: 23px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  transition: transform 0.2s ease-out;
}

body.platform-ios .scan-red input[type="checkbox"]:checked {
  background: var(--blue);
}

body.platform-ios .scan-red input[type="checkbox"]:checked::after {
  transform: translateX(17px);
}

/* (4) iOS bottom-sheet feel for the spot detail sheet: ~14px top corners, a
   centred grabber pill, and a spring scale/slide-in. */
body.platform-ios .detail-sheet {
  border-top-left-radius: 14px;
  border-top-right-radius: 14px;
  /* P2-logic: transform-only spring (opaque from frame 1 — no opacity fade). */
  transition: transform 0.32s cubic-bezier(0.32, 0.72, 0, 1);
}

body.platform-ios .sheet-handle {
  width: 36px;
  height: 5px;
  opacity: 0.28;
}

/* The mobile results panel is itself a bottom sheet — round it to match. */
body.platform-ios .panel {
  border-top-left-radius: 14px;
  border-top-right-radius: 14px;
}

/* (4) Turn the centred modal dialogs (scan / filter / settings / about) into
   iOS-style bottom sheets: docked to the bottom, full width, rounded top,
   grabber pill, dim backdrop and a spring rise. */
body.platform-ios .info-dialog {
  margin: auto auto 0;
  width: 100%;
  max-width: 100%;
  border-radius: 14px 14px 0 0;
  padding-top: 26px;
  padding-bottom: calc(22px + var(--sab));
  animation: ios-sheet-rise 0.32s cubic-bezier(0.32, 0.72, 0, 1);
}

/* Centred grabber pill on each sheet. */
body.platform-ios .info-dialog::before {
  content: "";
  position: absolute;
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  width: 36px;
  height: 5px;
  border-radius: 3px;
  background: var(--muted);
  opacity: 0.28;
}

body.platform-ios .info-dialog::backdrop {
  background: rgba(10, 15, 22, 0.45);
}

@keyframes ios-sheet-rise {
  from { transform: translateY(16px) scale(0.985); opacity: 0; }
  to   { transform: translateY(0) scale(1); opacity: 1; }
}

/* The scan dialog keeps its own close button; nudge its head below the pill. */
body.platform-ios .scan-dialog .scan-head {
  margin-top: 2px;
}

@media (prefers-reduced-motion: reduce) {
  body.platform-ios .info-dialog { animation: none; }
  body.platform-ios .detail-sheet { transition: none; }
}

/* ==========================================================================
   UX v5 — topbar redesign, price pills, callout, draggable sheet, settings,
   nav action sheet. Shared (web + Android + iOS) unless scoped to platform-ios.
   ========================================================================== */

/* ---------- (§5) Topbar: [P] [search flex-1, camera embedded] ---------- */

.search-wrap {
  position: relative;
  flex: 1;
  min-width: 0;
  max-width: 640px;
  display: flex;
  align-items: center;
}

#search {
  padding: 10px 42px 10px 14px; /* right pad so the camera never overlaps text */
}

#search.has-pill {
  padding-left: 116px; /* room for the "📍 Min plats" pill */
}

.search-cam {
  position: absolute;
  right: 5px;
  top: 50%;
  transform: translateY(-50%);
  width: 34px;
  height: 34px;
  border: none;
  background: none;
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  display: grid;
  place-items: center;
  border-radius: 9px;
  cursor: pointer;
}

.search-cam:active {
  transform: translateY(-50%) scale(0.92);
}

.search-pill {
  position: absolute;
  left: 6px;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 9px;
  border-radius: 999px;
  background: rgba(0, 82, 147, 0.12);
  color: var(--tint);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  pointer-events: none;
}

.search-pill[hidden] {
  display: none;
}

/* ---------- (§2) Airbnb-style price / brand pill markers ---------- */

.pill-marker {
  width: 0;
  height: 0;
}

.pill {
  position: relative;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.15;
  border: 1px solid rgba(10, 20, 35, 0.16);
  box-shadow: 0 1px 4px rgba(10, 20, 35, 0.32);
  cursor: pointer;
  transition: transform 0.12s ease-out;
}

.pill-free {
  background: var(--free);
  color: #fff;
}

.pill-paid {
  background: #29323d;
  color: #fff;
  border-color: rgba(255, 255, 255, 0.18);
}

.pill-unknown {
  background: #eef0f3;
  color: #5f6b78;
}

.pill-store {
  background: #fff;
  color: #1c2530; /* brand colour applied inline (trademark-safe: text only) */
  font-weight: 700;
}

.pill-cluster {
  background: #29323d;
  color: #fff;
  font-weight: 800;
  border-color: rgba(255, 255, 255, 0.2);
}

.pill-selected {
  transform: translate(-50%, -50%) scale(1.16);
  box-shadow: 0 0 0 3px rgba(0, 82, 147, 0.4), 0 2px 8px rgba(10, 20, 35, 0.4);
  z-index: 1000;
}

.pill-conf-free {
  box-shadow: 0 0 0 3px rgba(26, 157, 90, 0.55), 0 1px 4px rgba(10, 20, 35, 0.32);
}

.pill-conf-notfree {
  opacity: 0.5;
}

/* ---------- v11: docked bottom map card (Google-Maps pattern) ---------- */

.map-card {
  position: absolute;
  z-index: 650;
  left: 10px;
  right: 10px;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  max-width: 460px;
  margin: 0 auto;
  padding: 6px 15px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 18px;
  box-shadow: 0 10px 30px rgba(10, 20, 35, 0.3);
  animation: mc-in 0.16s ease-out;
  touch-action: pan-y;
}

.map-card[hidden] { display: none; }

/* v11 fix: while the docked card is open it owns the screen — hide the FAB
   stack, the top tier strip and the floating chips so the card sits on a
   clean map with no competing chrome behind/around it. Restored on dismiss. */
body.card-open .map-fabs,
body.card-open .map-tier-strip,
body.card-open .map-float-chips,
body.card-open .map-hint {
  display: none;
}

/* P1-2: an open results sheet (half/full) docks the same chrome away on mobile,
   so the float chips + FAB stack never overlay the sheet (320×568 catastrophe).
   Desktop keeps its always-on sidebar + map-side FABs, so this is mobile-only.
   v13 §2: the locate FAB is deliberately NOT in these lists — it stays visible
   with the card or sheet open (the driver's return-to-me button must never
   disappear). It just rises above whichever panel is open. */
@media (max-width: 899px) {
  body.sheet-open .map-fabs,
  body.sheet-open .map-tier-strip,
  body.sheet-open .map-float-chips,
  body.sheet-open .map-hint {
    display: none;
  }
}

/* ---------- v13 §2: return-to-my-location FAB (Google-Maps convention) ------ */
.locate-fab {
  position: absolute;
  right: 12px;
  bottom: calc(150px + env(safe-area-inset-bottom, 0px));
  z-index: 665; /* above the docked card (650) — always reachable */
  width: 56px;  /* the LARGEST control on the map */
  height: 56px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  display: grid;
  place-items: center;
  box-shadow: 0 4px 14px rgba(10, 20, 35, 0.32);
  cursor: pointer;
  transition: transform 0.08s ease-out, background 0.15s ease-out,
    color 0.15s ease-out, border-color 0.15s ease-out;
}
.locate-fab:active { transform: scale(0.94); }
.locate-fab svg { width: 24px; height: 24px; }

/* (a) following — filled blue, map is centred on the live fix */
.locate-fab.locate-following {
  background: var(--blue);
  border-color: var(--blue);
  color: #fff;
}
/* (b) available — GPS on but the user panned away: outline/tint, tap to return */
.locate-fab.locate-available {
  background: var(--surface);
  border-color: var(--blue);
  color: var(--blue);
}
/* (c) off / denied / undetermined — neutral */
.locate-fab.locate-off {
  background: var(--surface);
  border-color: var(--border);
  color: var(--text);
}

/* Rise above whichever panel is open so it is never covered. The docked card is
   ~150px tall (default offset already clears it); an open results sheet owns the
   lower half, so lift to just above its top edge. */
@media (max-width: 899px) {
  body.sheet-open .locate-fab { bottom: calc(50% + 16px); }
}

@keyframes mc-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* v30: in-context location pre-prompt card. Same visual family as .map-card,
   but it must NOT block the map — no backdrop, map interactive behind it. */
.geo-prompt {
  position: absolute;
  z-index: 660;
  left: 10px;
  right: 10px;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  max-width: 460px;
  margin: 0 auto;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 18px;
  box-shadow: 0 10px 30px rgba(10, 20, 35, 0.3);
  animation: mc-in 0.16s ease-out;
}
.geo-prompt[hidden] { display: none; }
.geo-prompt-body { display: flex; gap: 12px; align-items: flex-start; }
.geo-prompt-icon { font-size: 26px; line-height: 1.15; }
.geo-prompt-title { margin: 0 0 3px; font-weight: 700; font-size: 16px; color: var(--text); }
.geo-prompt-desc { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.4; }
.geo-prompt-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 14px;
}
.geo-prompt-actions button {
  font: inherit;
  font-weight: 600;
  font-size: 15px;
  padding: 9px 16px;
  border-radius: 12px;
  cursor: pointer;
  border: 1px solid var(--border);
}
.geo-prompt-allow {
  background: var(--blue);
  color: #fff;
  border-color: var(--blue);
}
.geo-prompt-deny {
  background: transparent;
  color: var(--text);
}
.geo-prompt-allow:focus-visible,
.geo-prompt-deny:focus-visible {
  outline: 2px solid var(--tint);
  outline-offset: 2px;
}

/* grab affordance — swipe up opens detail, swipe down dismisses */
.mc-grab {
  width: 36px;
  height: 4px;
  margin: 2px auto 8px;
  border-radius: 999px;
  background: var(--border);
}

.mc-head {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.mc-title {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  line-height: 1.25;
}

.mc-star {
  flex: none;
  border: none;
  background: none;
  cursor: pointer;
  font-size: 20px;
  line-height: 1;
  color: var(--muted);
  padding: 0 2px;
}
.mc-star.on { color: var(--yellow); }

.mc-status {
  margin: 4px 0 0;
  font-size: 16px; /* v13 §4: glance polish — the status line is the headline */
  font-weight: 600;
  line-height: 1.3;
  color: var(--muted);
}
/* v48: the status-line TEXT colour reads the SAME evaluated traffic-light status
   as the P-sign plate and the list/card dots (js signTrafficStatus → st-*), so
   the words and the colour can never disagree: GREEN free/free-now, ORANGE a fee
   is active now, RED private/förbud, GREY unknown. signTrafficStatus only emits
   free/freenow/paid/private/unknown (store tiers are collapsed upstream). */
.mc-status.st-free,
.mc-status.st-freenow { color: var(--tl-green); }
.mc-status.st-paid { color: var(--tl-orange); }
.mc-status.st-private { color: var(--tl-red); }
.mc-status.st-unknown { color: var(--tl-grey); }

.mc-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 6px;
  margin: 6px 0 0;
  font-size: 12.5px;
  color: var(--muted);
}
.mc-cost { font-weight: 700; color: var(--blue); }
:root[data-theme="dark"] .mc-cost { color: var(--tint); }

.mc-badges {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 5px;
}
.mc-badge {
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--bg);
  border: 1px solid var(--border);
  font-size: 11px;
  font-weight: 600;
  color: var(--text);
}

/* v45: venue's-own-terms block + honest chain hint. Supplementary, muted — it
   never competes with the coloured status headline. Shared by card + sheet. */
.venue-own {
  margin: 8px 0 0;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--bg);
  border: 1px solid var(--border);
}
.venue-label {
  margin: 0 0 2px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--muted);
}
.venue-terms {
  margin: 0;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text);
}
.venue-src {
  margin: 4px 0 0;
  font-size: 11.5px;
  color: var(--muted);
}
.chain-hint {
  margin: 8px 0 0;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--muted);
}
/* In the detail sheet the block sits flush with the sheet rows' rhythm. */
.sheet-rows + .venue-own,
.sheet-rows + .chain-hint { margin-top: 10px; }

/* v46 §4: the anchor-matched venue popup (MoS "Platsens egna villkor"). Leaflet
   popups are otherwise an unstyled white bubble — theme the wrapper so the text
   reads in both light and dark. */
.leaflet-popup.venue-anchor-popup .leaflet-popup-content-wrapper,
.leaflet-popup.venue-anchor-popup .leaflet-popup-tip {
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
}
.leaflet-popup.venue-anchor-popup .leaflet-popup-content { margin: 10px 12px; }
.venue-anchor-pop { margin: 0; border: 0; padding: 0; background: transparent; }
.venue-anchor-name {
  margin: 0 0 4px;
  font-size: 13.5px;
  font-weight: 800;
  color: var(--text);
}
.venue-anchor-pop .venue-terms { color: var(--text); }
/* A subtle ring on the store pin when it carries published venue terms. */
.anchor-mark.has-terms { box-shadow: 0 0 0 2px var(--tint); }

.mc-actions {
  display: flex;
  gap: 8px;
  margin-top: 12px;
}
/* v13 §4: card action controls are >=48pt tall for confident in-car taps. */
.mc-actions .nav-split { flex: 1; min-height: 48px; }
.mc-actions .nav-go { min-height: 48px; font-size: 15px; }
.mc-more {
  flex: none;
  width: 48px;
  min-height: 48px;
  border: 1px solid var(--border);
  background: var(--bg);
  border-radius: 12px;
  font-size: 20px;
  font-weight: 700;
  line-height: 1;
  color: var(--text);
  cursor: pointer;
}
.mc-more:active { transform: scale(0.96); }

/* v11: shared Navigera split button (card + detail sheet) */
.nav-split {
  display: flex;
  align-items: stretch;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 1px 4px rgba(10, 20, 35, 0.18);
}
.nav-split .nav-go {
  flex: 1;
  margin: 0;
  border-radius: 0;
  box-shadow: none;
}
.nav-caret {
  flex: none;
  width: 44px;
  border: none;
  border-left: 1px solid rgba(255, 255, 255, 0.28);
  background: var(--blue);
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
}
.nav-caret:active { transform: scale(0.97); }

/* v11: paid-only "Betala i <app> ▾" row on the card */
.mc-pay {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.mc-pay-go {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: 1px solid var(--blue);
  background: var(--bg);
  color: var(--blue);
  border-radius: 12px;
  padding: 10px 12px;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
}
:root[data-theme="dark"] .mc-pay-go { border-color: var(--tint); color: var(--tint); }
.mc-pay-go:active { transform: scale(0.98); }
.mc-pay-caret {
  flex: none;
  width: 44px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  border-radius: 12px;
  padding: 10px 0;
  font-size: 14px;
  cursor: pointer;
}
.mc-pay-more {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.nav-link.current { font-weight: 800; }
.nav-link.current::after { content: " ✓"; color: var(--free); }

/* ---------- (§4) Draggable results sheet + grabber + summary ---------- */

.sheet-grabber {
  display: block;
  width: 100%;
  border: none;
  background: none;
  padding: 8px 0 4px;
  cursor: grab;
  touch-action: none;
}

.grabber-bar {
  display: block;
  width: 40px;
  height: 5px;
  border-radius: 3px;
  background: var(--muted);
  opacity: 0.4;
  margin: 0 auto;
}

.sheet-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 2px 14px 8px;
}

.summary-text {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.summary-text:empty {
  display: none;
}

.summary-actions {
  display: flex;
  gap: 6px;
  flex: none;
  margin-left: auto;
}

.sum-btn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: transform 0.06s;
}

.sum-btn.lang-toggle {
  font-size: 13px;
  letter-spacing: 0.02em;
}

.sum-btn:active {
  transform: scale(0.94);
}

.tier-chips[hidden] {
  display: none;
}

/* Mobile: the results panel is a draggable, full-height sheet with detents. */
@media (max-width: 899px) {
  .panel.sheet {
    top: auto;
    height: 90%;
    max-height: none;
    transition: transform 0.34s cubic-bezier(0.32, 0.72, 0, 1);
    will-change: transform;
  }
}

/* ---------- (§4) Map FABs: text FABs (radius/filter) ---------- */

.fab {
  position: relative;
}

.fab.fab-text {
  width: auto;
  min-width: 44px;
  height: 40px;
  padding: 0 13px;
  border-radius: 20px;
  font-size: 12px;
}

.fab.active {
  border-color: var(--tint);
  color: var(--tint);
}

.fab.active::after {
  content: "";
  position: absolute;
  top: 4px;
  right: 6px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--tint);
}

/* ---------- (§7) Detail sheet: segmented confirm, contribute, provenance -- */

.segmented {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--border);
  border-radius: 9px;
}

.seg {
  border: none;
  background: none;
  padding: 6px 14px;
  border-radius: 7px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
  transition: transform 0.06s;
}

.seg.on {
  background: var(--surface);
  box-shadow: 0 1px 3px rgba(10, 20, 35, 0.16);
  color: var(--tint);
}

.seg:active {
  transform: scale(0.96);
}

.confirm-seg {
  display: flex;
  width: 100%;
  margin: 12px 0;
}

.confirm-seg .seg {
  flex: 1;
}

.confirm-seg .seg-free.on {
  background: rgba(26, 157, 90, 0.18);
  color: var(--free);
}

.confirm-seg .seg-notfree.on {
  background: rgba(178, 84, 76, 0.18);
  color: var(--private);
}

.prov-block {
  margin: 10px 0;
}

.prov-block summary {
  list-style: none;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  color: var(--tint);
}

.prov-block summary::-webkit-details-marker {
  display: none;
}

.prov-block summary::after {
  content: " ›";
}

.prov-block[open] summary::after {
  content: " ⌄";
}

.prov-block p {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--muted);
}

/* Raw OSM tag list inside "About the data" — contributor-facing, monospace
   key=value rows so the exact underlying data is legible and obviously "raw". */
.osm-tags-label {
  margin: 10px 0 4px !important;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 11px !important;
}
.osm-tags {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 168px;
  overflow-y: auto;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
}
.osm-tag {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--text);
  overflow-wrap: anywhere;
  word-break: break-word;
}
.osm-k { color: var(--tint); font-weight: 600; }
.osm-eq { color: var(--muted); margin: 0 2px; }
.osm-v { color: var(--text); }

/* ---------- v33: map legend sheet ("?" chip) ---------- */
.legend-dialog { max-width: 380px; }
.legend-body { margin: 4px 0 10px; }
.legend-head {
  margin: 14px 0 6px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.legend-head:first-child { margin-top: 4px; }
.legend-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 0;
  font-size: 14px;
  color: var(--text);
}
.legend-text { min-width: 0; }
/* mini P-sign swatch — same rounded sign + white P as the map markers */
.legend-psign {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: var(--ps-bg, var(--unknown));
  display: grid;
  place-items: center;
  box-shadow: 0 1px 2px rgba(10, 20, 35, 0.35);
}
.legend-psign > span {
  color: #fff;
  font-weight: 800;
  font-size: 13px;
  line-height: 1;
}
.legend-clock { margin-left: -6px; font-size: 13px; }
.legend-tag {
  flex: none;
  min-width: 22px;
  text-align: center;
  padding: 1px 6px;
  border-radius: 6px;
  background: #fff;
  color: #1c2530;
  font-size: 11px;
  font-weight: 800;
  border: 1px solid rgba(10, 20, 35, 0.16);
}
.legend-badge {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #fff;
  border: 1px solid rgba(10, 20, 35, 0.22);
  display: grid;
  place-items: center;
  font-size: 12px;
}
.legend-nopark {
  flex: none;
  width: 22px;
  height: 0;
  border-top: 2.5px dashed #d6332a;
}
/* v36: STFS street-rule legend swatches (mirror the canvas stroke styles). */
.legend-rule {
  flex: none;
  width: 22px;
  height: 0;
}
/* v46 §2: only two line styles survive — solid (may park) and one dashed
   (förbud). The sample shows both side by side; colour carries the live status. */
.legend-ruleset {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  width: 44px;
}
.legend-rule-solid { border-top: 2.6px solid var(--tl-green); }
.legend-rule-dash { border-top: 2.6px dashed var(--tl-red); }
.legend-pilot {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--muted, #6b7480);
  line-height: 1.4;
}
.legend-storepin {
  flex: none;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  color: var(--tint);
}
.legend-storepin svg { width: 18px; height: 18px; }

.contribute-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 12px 0;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

.contribute-label {
  width: 100%;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.btn-quiet {
  border: none;
  background: rgba(0, 82, 147, 0.12);
  color: var(--tint);
  border-radius: 10px;
  padding: 8px 13px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.06s;
}

.btn-quiet:active {
  transform: scale(0.96);
}

/* ---------- (§7) Navigate action sheet ---------- */

.action-sheet {
  position: fixed;
  inset: 0;
  z-index: 2500;
  display: flex;
  align-items: flex-end;
}

.action-sheet[hidden] {
  display: none;
}

.action-sheet-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(10, 15, 22, 0.45);
}

.action-sheet-menu {
  position: relative;
  width: 100%;
  padding: 8px 8px calc(8px + var(--sab));
  display: flex;
  flex-direction: column;
  gap: 8px;
  transform: translateY(14px);
  transition: transform 0.26s cubic-bezier(0.32, 0.72, 0, 1);
}

.action-sheet.open .action-sheet-menu {
  transform: none;
}

.action-item {
  width: 100%;
  padding: 15px;
  border: none;
  border-radius: 14px;
  background: var(--surface);
  color: var(--tint);
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: transform 0.06s, opacity 0.1s;
}

.action-item:active {
  transform: scale(0.98);
  opacity: 0.8;
}

.action-cancel {
  color: var(--text);
  font-weight: 700;
  margin-top: 4px;
}

/* ---------- (§8) Settings: iOS grouped-list feel + segmented + dev ---------- */

.settings-group {
  margin: 18px 0;
}

.settings-group-title {
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.settings-list {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}

.settings-item {
  padding: 12px 14px;
}

.settings-item + .settings-item {
  border-top: 1px solid var(--border);
}

.settings-item-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.settings-item > label,
.settings-item-head {
  display: block;
  margin: 0 0 8px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}

.settings-item-row > span {
  font-size: 14px;
}

.seg-inline {
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 8px;
  padding: 7px 14px;
  font-size: 14px;
  font-weight: 600;
  color: var(--tint);
  cursor: pointer;
}

.settings-source {
  margin: 0;
  font-size: 12px;
  color: var(--muted);
  cursor: default;
  user-select: none;
  overflow-wrap: anywhere;
  word-break: break-word;
  line-height: 1.4;
}

.settings-source:empty::before {
  content: "ParkGratis";
  color: var(--muted);
}

.dev-section[hidden] {
  display: none;
}

/* ---------- v6: plan-ahead, parking types, appearance, scale bar ---------- */

/* Section labels shared by the type grid + plan-ahead blocks. */
.filter-section-label {
  display: block;
  margin-bottom: 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--muted);
}

/* v6 §2: 4-card parking-type grid. */
.type-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}

.type-card {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 48px;
  padding: 10px 8px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: transparent;
  color: var(--muted);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

.type-card.on {
  color: var(--text);
  border-color: var(--blue);
  background: rgba(0, 82, 147, 0.12);
}

/* v6 §1: plan-ahead rows + quick chips. */
.plan-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}

.plan-row > label {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}

.plan-start {
  flex: 0 1 auto;
  max-width: 62%;
}

/* datetime-local: make the empty format placeholder + spinners theme-correct.
   color-scheme flips the native widget (picker, arrows) to match the app theme;
   the edit text uses --text, and an unset field's format hint reads as muted. */
.plan-start { color-scheme: light; }
:root[data-theme="dark"] .plan-start { color-scheme: dark; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .plan-start { color-scheme: dark; }
}
.plan-start::-webkit-datetime-edit { color: var(--text); }
.plan-start:not(:focus)::-webkit-datetime-edit-year-field[aria-valuenow=""],
.plan-start:not(:focus)::-webkit-datetime-edit-month-field[aria-valuenow=""],
.plan-start:not(:focus)::-webkit-datetime-edit-day-field[aria-valuenow=""],
.plan-start:not(:focus)::-webkit-datetime-edit-hour-field[aria-valuenow=""],
.plan-start:not(:focus)::-webkit-datetime-edit-minute-field[aria-valuenow=""] {
  color: var(--muted);
}
.plan-start::-webkit-calendar-picker-indicator {
  opacity: 0.7;
  cursor: pointer;
}

.plan-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 10px;
}

.plan-chip {
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.plan-chip.on {
  color: var(--text);
  border-color: var(--blue);
  background: rgba(0, 82, 147, 0.12);
}

/* v6 §1: active-planning chip in the sheet chip row. */
.planning-chip-row {
  padding: 8px 14px 0;
}

.planning-chip-row[hidden] {
  display: none;
}

.planning-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--blue);
  background: rgba(0, 82, 147, 0.12);
  color: var(--text);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

.planning-chip-x {
  font-size: 12px;
  color: var(--muted);
}

/* v6 §1: spots failing the minimum duration dim (not hidden). */
.pill-dim {
  opacity: 0.4;
}

.card-dim {
  opacity: 0.4;
}

/* v6 §2: ♿ badge on accessible pills; grows when Accessible is selected. */
.pill-badge {
  margin-left: 3px;
  font-size: 0.85em;
}

.pill-badge.big {
  font-size: 1.15em;
  margin-left: 4px;
}

/* v6 §3: iOS-style toggle switch (Show stores). */
.toggle-switch {
  position: relative;
  flex: none;
  width: 46px;
  height: 28px;
  border: none;
  border-radius: 999px;
  background: var(--border);
  cursor: pointer;
  transition: background 0.15s;
}

.toggle-switch::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(10, 20, 35, 0.3);
  transition: transform 0.15s;
}

.toggle-switch[aria-checked="true"] {
  background: var(--blue);
}

.toggle-switch[aria-checked="true"]::after {
  transform: translateX(18px);
}

/* v6 §3: Om section navigation rows. */
.settings-nav-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 12px 14px;
  border: none;
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.settings-nav-row + .settings-nav-row,
.settings-version {
  border-top: 1px solid var(--border);
}

.settings-nav-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 14px;
  font-weight: 600;
}

.settings-nav-sub {
  font-size: 12px;
  font-weight: 400;
  color: var(--muted);
}

.settings-nav-chevron {
  color: var(--muted);
  font-size: 20px;
  line-height: 1;
}

.settings-version {
  margin: 0;
  padding: 12px 14px 4px;
  font-size: 12px;
  color: var(--muted);
}

/* v6 §4: metric scale bar — theme-aware via vars, subtle in both modes.
   v33: bottom-LEFT (see initMap), clear of the right-side FAB stack and the
   Leaflet attribution it used to overlap. */
.leaflet-control-scale {
  margin-left: 10px;
  margin-bottom: 4px;
}

/* v9 §2: NVDB provenance line inside the "About the data" disclosure. */
.prov-nvdb {
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 12px;
}

/* v9 §3: no-parking street overlay lines render above base tiles. */
.nopark-line {
  pointer-events: stroke;
}

/* v36: STFS street-rule segments + tap mini-card (Uppsala pilot). */
.streetrule-line {
  pointer-events: stroke;
}
.rule-card {
  position: fixed;
  left: 50%;
  bottom: calc(52% + 16px + var(--sab));
  transform: translateX(-50%);
  z-index: 2100;
  width: min(92vw, 340px);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px 14px;
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.28);
}
.rule-card[hidden] { display: none; }
.rule-card-close {
  position: absolute;
  top: 6px;
  right: 8px;
  border: none;
  background: none;
  color: var(--muted);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 6px;
}
.rule-card-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-right: 22px;
}
.rule-card-dot {
  flex: none;
  width: 12px;
  height: 12px;
  border-radius: 50%;
}
.rule-card-type {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
}
.rule-card-text {
  margin: 8px 0 0;
  font-size: 13px;
  line-height: 1.45;
}
.rule-card-caveat {
  margin: 8px 0 0;
  font-size: 12px;
  font-style: italic;
  color: #b26a00;
}
.rule-card-source {
  margin: 10px 0 0;
  padding: 0;
  border: none;
  background: none;
  color: var(--tint);
  font-size: 12px;
  text-align: left;
  text-decoration: underline;
  cursor: pointer;
}
.rule-card-source:disabled {
  color: var(--muted);
  text-decoration: none;
  cursor: default;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .rule-card-caveat { color: #f0b429; }
}
:root[data-theme="dark"] .rule-card-caveat { color: #f0b429; }

.leaflet-control-scale-line {
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: none;
  color: var(--text);
  font-size: 11px;
  line-height: 1.6;
  padding: 0 6px;
  box-shadow: 0 1px 3px rgba(10, 20, 35, 0.18);
}

/* ---------- iOS polish (§9), scoped to platform-ios ---------- */

/* (9) Hide the Leaflet +/- zoom control on iOS (pinch exists); web keeps it. */
body.platform-ios .leaflet-control-zoom {
  display: none;
}

/* Kill ALL underlines — links become tinted, no underline. */
body.platform-ios a,
body.platform-ios .link-btn {
  text-decoration: none;
}

body.platform-ios .link-btn {
  color: var(--tint);
}

/* (§5) iOS searchbar look: 17px, subdued fill, rounded 10px, no border. */
body.platform-ios #search {
  font-size: 17px;
  background: rgba(120, 120, 128, 0.14);
  border: 1px solid transparent;
  border-radius: 10px;
}

/* :active press states on every tappable; no tap highlight. */
body.platform-ios .fab:active,
body.platform-ios .sum-btn:active,
body.platform-ios .seg:active,
body.platform-ios .btn-quiet:active,
body.platform-ios .nav-go:active,
body.platform-ios .action-item:active,
body.platform-ios .pill {
  -webkit-tap-highlight-color: transparent;
}

/* Type ramp: heading tracking. */
body.platform-ios .sheet-body h2,
body.platform-ios .settings-dialog h2 {
  letter-spacing: -0.01em;
}

/* ==================== v7: one-stop parking ==================== */

/* §1 sort control */
.sort-row {
  margin: 6px 14px 0;
}
.sort-control {
  width: 100%;
}
.sort-control .seg {
  flex: 1;
}

/* §1 cost estimate chip / inline */
.chip-cost {
  --tc: var(--blue);
  border-color: var(--blue);
  color: var(--blue);
  font-weight: 700;
}
:root[data-theme="dark"] .chip-cost { color: var(--tint); border-color: var(--tint); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .chip-cost { color: var(--tint); border-color: var(--tint); }
}
.cost-inline {
  color: var(--blue);
  font-weight: 700;
}
:root[data-theme="dark"] .cost-inline { color: var(--tint); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .cost-inline { color: var(--tint); }
}

/* P1-4: "too short for the chosen time" — a neutral, non-price treatment so it
   never reads as a cost. Muted amber to signal a soft exclusion, not an error. */
.chip-tooshort {
  border-color: var(--muted);
  color: var(--muted);
  font-weight: 600;
}
.cost-tooshort {
  color: var(--muted);
  font-weight: 600;
}

/* §4 sheet header star + §4/§5 overflow */
.sheet-star,
.sheet-more {
  border: none;
  background: none;
  cursor: pointer;
  color: var(--muted);
  font-size: 22px;
  line-height: 1;
  padding: 2px 6px;
  border-radius: 8px;
}
.sheet-star.on {
  color: var(--yellow);
}
.sheet-more {
  font-size: 20px;
  font-weight: 700;
}
.sheet-star:active,
.sheet-more:active {
  background: rgba(120, 130, 140, 0.14);
}

/* §1 Betala payment hand-off */
.betala {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.betala-label {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
}
.pay-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}
.pay-btn {
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  border-radius: 10px;
  padding: 9px 14px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.pay-btn.preferred {
  border-color: var(--blue);
  color: var(--blue);
}
:root[data-theme="dark"] .pay-btn.preferred { border-color: var(--tint); color: var(--tint); }
.pay-btn:active {
  transform: scale(0.97);
}
.pay-more {
  border: none;
  background: none;
  color: var(--blue);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  padding: 9px 4px;
}
:root[data-theme="dark"] .pay-more { color: var(--tint); }

/* §3 reminders */
.remind {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.remind-label {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
}
.remind-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}
.remind-chip {
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  border-radius: 999px;
  padding: 7px 13px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.remind-chip:active {
  transform: scale(0.97);
}
/* Pressed/locked state after a reminder is scheduled — a filled blue pill with
   a check, so the tap reads as registered even before the async schedule lands. */
.remind-chip.pressed {
  background: var(--blue);
  border-color: var(--blue);
  color: #fff;
  cursor: default;
}
.remind-chip.pressed::before {
  content: "✓ ";
}

/* §2/§5 sheet secondary actions row */
.sheet-actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}
.sheet-actions .btn {
  flex: 1;
  margin: 0;
}

/* §2 car walk-back row */
.car-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 8px 14px 0;
}
.car-to {
  flex: 1;
  text-align: left;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 10px;
  padding: 8px 12px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.car-clear {
  border: none;
  background: none;
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  padding: 8px 6px;
}
.car-mark {
  font-size: 22px;
  line-height: 1;
  filter: drop-shadow(0 1px 2px rgba(10, 20, 35, 0.5));
}

/* §1 zone / phone code (Göteborg) */
.zone-code {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  margin-top: 8px;
  border: 1px dashed var(--paid);
  background: rgba(91, 107, 123, 0.08);
  border-radius: 10px;
  padding: 8px 12px;
  cursor: pointer;
  width: 100%;
  text-align: left;
}
.zone-num {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 26px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--text);
}
.zone-hint {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
}

/* §4 Hem/Jobb quick slots */
.quick-slots {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 12px;
}
.quick-slot {
  width: 100%;
}

/* §2 tappable toast action */
.toast-action {
  border: none;
  background: rgba(255, 255, 255, 0.18);
  color: #fff;
  border-radius: 8px;
  padding: 4px 12px;
  margin-left: 6px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

/* §4 favorite gold ring on the pill + star in the search dropdown */
.pill-fav {
  box-shadow: 0 0 0 3px rgba(255, 205, 0, 0.85), 0 1px 4px rgba(10, 20, 35, 0.32);
}
.s-fav-star {
  color: var(--yellow);
  margin-right: 2px;
}

/* §4 favorites dropdown row: star + name on ONE line, left-aligned. The base
   .suggestion is a 2-col grid (name | type chip) which pushed the star to col1
   and the name to col2 (far right). A flat flex row fixes the layout. */
.suggestion.fav {
  display: flex;
  align-items: center;
  gap: 8px;
}
.suggestion.fav .s-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ============================================================================
   v8: P-sign markers + map-only interface (owner feedback)
   ========================================================================= */

/* ---------- v8 §1: P-sign icon markers (rounded sign + white P + tag) ------ */
.psign-marker { width: 0; height: 0; }

.psign-wrap {
  position: relative;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  transform: translate(-50%, -50%);
  transition: transform 0.12s ease-out;
  /* v13 §1: isolate each marker's layout/paint so re-styling one P-sign can't
     force a reflow of the whole marker pane during a pan. */
  contain: layout style;
}

/* v13 §1: while the map is actively panning/zooming, kill the P-sign transform
   transition — otherwise the tween re-fires on every Leaflet reposition frame,
   a measurable per-frame cost in dense areas. Restored on moveend/zoomend. */
.map-moving .psign-wrap { transition: none; }

.psign {
  position: relative;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  background: var(--ps-bg, var(--unknown));
  border: 1.5px solid rgba(255, 255, 255, 0.92);
  box-shadow: 0 1px 4px rgba(10, 20, 35, 0.42);
  cursor: pointer;
  /* v40 §2: sub-frame press feedback. The scale is on .psign (not the
     positioned .psign-wrap), so it never touches Leaflet's marker transform. A
     ~1-frame transition keeps the press instant IN and eases the release. */
  transition: transform 0.07s ease-out;
}

/* v40 §2: instant pressed state on the map's tap targets — a marker/cluster/POI
   pin now acknowledges the touch within one frame, before showCard/zoom runs,
   so even a fast handler no longer FEELS delayed. .ev-mark/.mc-mark have no
   positioning transform of their own, so a bare scale is safe. */
.psign:active,
.ev-mark:active,
.mc-mark:active { transform: scale(0.9); }
.ev-mark,
.mc-mark { transition: transform 0.07s ease-out; }

/* v11 FIND: a transparent >=44x44pt hit zone around the 30px sign so taps
   land reliably, without changing the visual size. */
.psign::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}

/* small pointer notch under the sign — sign-on-post feel; matches sign colour */
.psign::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -5px;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid var(--ps-bg, var(--unknown));
}

.psign-p {
  color: #fff;
  font-weight: 800;
  font-size: 17px;
  line-height: 1;
}

/* v42 traffic-light SIGN colours: GREEN=free now · ORANGE=paid now · RED=don't ·
   GREY=unknown. Store/customer signs are coloured by evaluated status (green/
   orange) — teal survives only as the tag colour, not the sign. */
.ps-free,
.ps-freenow { --ps-bg: var(--tl-green); }
.ps-retail,
.ps-customer { --ps-bg: var(--tl-green); }
.ps-paid { --ps-bg: var(--tl-orange); }
.ps-unknown { --ps-bg: var(--tl-grey); }
.ps-private { --ps-bg: var(--tl-red); }

/* v42 §3: Gatuparkering streetspot — an OUTLINE P-sign (inner white ring) to
   read apart from a solid lot marker while keeping the traffic-light colour. */
.ps-street { box-shadow: inset 0 0 0 2.5px rgba(255, 255, 255, 0.92); }

/* forbidden/private/resident: strike through the P */
.ps-private .psign-p {
  text-decoration: line-through;
  text-decoration-thickness: 2px;
}

/* price / brand tag hanging under the sign */
.psign-tag {
  margin-top: 6px;
  max-width: 96px;
  padding: 1px 6px;
  border-radius: 6px;
  background: #fff;
  color: #1c2530;
  font-size: 11px;
  font-weight: 700;
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border: 1px solid rgba(10, 20, 35, 0.16);
  box-shadow: 0 1px 3px rgba(10, 20, 35, 0.32);
}

.psign-tag-store { font-weight: 800; }
/* galleria / mall tag + v44 generic store-name tag: read by name, neutral slate
   tint (not a brand colour). The white pill (.psign-tag) is white in both themes
   so the slate text stays legible in light and dark. */
.psign-tag-mall,
.psign-tag-name { font-weight: 800; color: #3a4653; }

/* corner mini-badges (accessible / park & ride) + free-now clock */
.ps-badge,
.ps-clock {
  position: absolute;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: #fff;
  border: 1px solid rgba(10, 20, 35, 0.22);
  display: grid;
  place-items: center;
  font-size: 9px;
  line-height: 1;
}

.ps-acc { bottom: -5px; right: -6px; }
.ps-pr { bottom: -5px; left: -6px; }
.ps-clock { top: -6px; left: -6px; }
.ps-acc.big { width: 18px; height: 18px; font-size: 11px; }
/* garage/covered roof mark, top-right; a bold dark ⌂ reads on the white chip in
   both themes */
.ps-garage {
  top: -6px;
  right: -6px;
  color: #1c2530;
  font-size: 12px;
  font-weight: 800;
}

/* selected sign: scale up + tint ring (kept from the pill design) */
.psign-sel .psign {
  transform: scale(1.22);
  box-shadow: 0 0 0 3px rgba(0, 82, 147, 0.42), 0 2px 8px rgba(10, 20, 35, 0.45);
  z-index: 1000;
}

.ps-conf-free {
  box-shadow: 0 0 0 3px rgba(26, 157, 90, 0.6), 0 1px 4px rgba(10, 20, 35, 0.4);
}
.ps-conf-notfree { opacity: 0.5; }
.ps-dim { opacity: 0.4; }
/* A dimmed sign must dim its hanging price/brand tag too (it's a sibling of the
   .psign box inside .psign-wrap, so the parent's opacity doesn't reach it). */
.psign.ps-dim ~ .psign-tag { opacity: 0.4; }
.psign.ps-conf-notfree ~ .psign-tag { opacity: 0.5; }
.ps-fav {
  box-shadow: 0 0 0 3px rgba(255, 205, 0, 0.9), 0 1px 4px rgba(10, 20, 35, 0.4);
}

/* clusters: dark rounded square with a count (matches the sign look) */
.psign-cluster {
  display: grid;
  place-items: center;
  transform: translate(-50%, -50%);
  min-width: 30px;
  height: 30px;
  padding: 0 7px;
  border-radius: 8px;
  background: #29323d;
  color: #fff;
  font-weight: 800;
  font-size: 13px;
  border: 1.5px solid rgba(255, 255, 255, 0.85);
  box-shadow: 0 2px 6px rgba(10, 20, 35, 0.42);
  cursor: pointer;
  /* v40 §2: the cluster owns its positioning transform, so the press must
     COMPOSE the scale onto the translate — a bare scale would fling it. */
  transition: transform 0.07s ease-out;
}
.psign-cluster:active { transform: translate(-50%, -50%) scale(0.92); }

@media (prefers-reduced-motion: reduce) {
  .psign-wrap { transition: none; }
  /* v40 §2: keep the tap instant but drop the scale animation for reduced-motion
     users (the touch-action delay fix still applies — that is not motion). */
  .psign:active,
  .ev-mark:active,
  .mc-mark:active { transform: none; }
  .psign-cluster:active { transform: translate(-50%, -50%); }
}

/* ---------- v8 §2: top-of-map tier strip (count + chips + gear) ------------ */
.map-tier-strip {
  position: absolute;
  top: calc(10px + var(--sat));
  left: 8px;
  right: 8px;
  z-index: 600;
  display: flex;
  align-items: center;
  gap: 8px;
}

.map-tier-strip[hidden] { display: none; }

/* keep Leaflet's zoom control (web/Android) clear of the taller v13 §3 strip */
.leaflet-top.leaflet-left { top: calc(62px + var(--sat)); }

/* v13 §3: the count sits between the Gratis toggle and the ?/gear. It takes the
   middle space and ellipsises rather than pushing anything off a 320px strip —
   NO horizontal scrolling anywhere on the strip. */
.map-count-chip {
  flex: 1 1 auto;
  min-width: 0;
  text-align: center;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0 12px;
  height: 44px;
  line-height: 44px;
  font-size: 15px;
  font-weight: 700;
  box-shadow: var(--shadow);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.map-count-chip:empty { display: none; }

/* v13 §3: the ONE big glanceable Gratis (free-only) toggle. 44pt tall, high
   contrast, reads at a glance while driving. ON = filled green (free = green
   throughout the app). */
.strip-gratis {
  flex: none;
  height: 44px;
  padding: 0 18px;
  border-radius: 999px;
  border: 1.5px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 16px;
  font-weight: 800;
  letter-spacing: 0.01em;
  box-shadow: var(--shadow);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s ease-out, color 0.15s ease-out,
    border-color 0.15s ease-out, transform 0.06s;
}
.strip-gratis:active { transform: scale(0.96); }
.strip-gratis.on {
  background: var(--free);
  border-color: var(--free);
  color: #fff;
}

.strip-gear {
  flex: none;
  width: 44px; /* v13 §3: 44pt tap target */
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 17px;
  box-shadow: var(--shadow);
  cursor: pointer;
  display: grid;
  place-items: center;
}
.strip-gear:active { transform: scale(0.94); }

/* ---------- v8 §2: slim first-run hint bar (replaces the big empty card) --- */
.map-hint {
  position: absolute;
  left: 12px;
  right: auto;
  max-width: calc(100% - 88px);
  bottom: calc(16px + var(--sab));
  z-index: 550;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-start;
  padding: 10px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow);
}
.map-hint[hidden] { display: none; }

.map-hint-text {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text);
}

.map-hint .quick-slots {
  flex-direction: row;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 0;
}

.quick-chip {
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  border-radius: 999px;
  padding: 5px 12px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.quick-chip:active { transform: scale(0.96); }

/* ---------- v8 §2: floating Min bil + planning chips above the FAB stack --- */
.map-float-chips {
  position: absolute;
  left: 12px;
  bottom: calc(112px + var(--sab));
  z-index: 560;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-start;
  max-width: calc(100% - 80px);
}

.map-float-chips .planning-chip-row,
.map-float-chips .car-row {
  padding: 0;
  margin: 0;
}

.map-float-chips .planning-chip {
  background: var(--surface);
  border-color: var(--blue);
  box-shadow: var(--shadow);
}

.map-float-chips .car-row {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px 8px 4px 10px;
  box-shadow: var(--shadow);
  gap: 4px;
  /* P1-2: keep the car chip a single line ("🚗 4,3 km ↗ · Rensa"). */
  flex-wrap: nowrap;
  white-space: nowrap;
  max-width: calc(100vw - 88px);
}
.map-float-chips .car-to {
  overflow: hidden;
  text-overflow: ellipsis;
}
.map-float-chips .car-to {
  border: none;
  background: none;
  box-shadow: none;
  padding: 2px 4px;
  font-size: 13px;
}
.map-float-chips .car-clear { padding: 2px 6px; }
/* v31: walking-mode nav hand-off button in the walk-back chip. */
.map-float-chips .car-nav {
  border: none;
  background: var(--accent, #005293);
  color: #fff;
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 12px;
  font-weight: 600;
}

/* P1-2: on desktop the results live in the 380px left sidebar; the floating
   chips must sit over the MAP (right of the sidebar), never on top of the list.
   This block must FOLLOW the base .map-float-chips rule to win the cascade. */
@media (min-width: 900px) {
  .map-float-chips {
    left: calc(380px + 12px);
    max-width: calc(100vw - 380px - 24px);
  }
}

/* v31: far-zoom "clusters only" dot for isolated spots. */
.psign-dot {
  display: block;
  width: 10px;
  height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 50%;
  background: var(--tier-free, #1a9d5a);
  border: 2px solid #fff;
  box-shadow: 0 1px 3px rgba(10, 20, 35, 0.4);
}

/* v31: list note when the viewport holds more than the shown nearest-N. */
.list-more-note {
  margin: 8px 4px 4px;
  font-size: 12px;
  color: var(--muted, #6b7280);
  text-align: center;
}

/* ---------- v8 §2: FAB stack sits at the bottom (sheet starts closed) ------ */
.map-fabs {
  bottom: calc(16px + var(--sab));
}

/* the results sheet starts fully off-screen on mobile until JS positions it */
@media (max-width: 899px) {
  .panel.sheet { transform: translateY(100%); }
}

/* desktop keeps the always-on left sidebar: the mobile-only strip + List FAB
   would just duplicate it */
@media (min-width: 900px) {
  .map-tier-strip,
  #fab-list { display: none; }
}

/* iOS: keep the top strip clear of the notch and the FAB stack off the inset */
body.platform-ios .map-hint,
body.platform-ios .map-float-chips {
  left: calc(12px + var(--sal));
}
body.platform-ios .map-tier-strip {
  left: calc(8px + var(--sal));
  right: calc(8px + var(--sar));
}

/* ======================= v39: self-explaining map + scanner rethink ======= */

/* PART A §1 — one-time inline card footers (colour key, garage note). */
.sheet-onetime-note {
  margin: 12px 0 0;
  padding: 8px 12px;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--muted);
  background: var(--bg);
  border: 1px dashed var(--border);
  border-radius: 10px;
}

/* v43 — first-launch animated walkthrough ("video" explainer). A full-screen
   modal overlay that auto-advances through ~5 scenes built from the app's own
   traffic-light components. Pure CSS/SVG animation, no assets. */
.ob-overlay {
  position: fixed;
  inset: 0;
  z-index: 5000;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: calc(18px + var(--sat)) 18px calc(24px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(160deg, #0a2740 0%, #063a63 55%, #0a2740 100%);
  color: #fff;
  overscroll-behavior: contain;
  animation: ob-fade-in 0.28s ease both;
}
@keyframes ob-fade-in { from { opacity: 0; } to { opacity: 1; } }

/* Progress bar — one segment per scene, fill animates across scene duration. */
.ob-progress {
  display: flex;
  gap: 6px;
  width: min(460px, 100%);
  margin-bottom: 8px;
}
.ob-seg {
  flex: 1;
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.28);
  overflow: hidden;
}
.ob-seg > i {
  display: block;
  height: 100%;
  width: 0;
  background: var(--yellow);
  border-radius: 2px;
}

.ob-skip {
  align-self: flex-end;
  margin-top: 2px;
  padding: 8px 14px;
  min-height: 40px;
  border: 0;
  border-radius: 20px;
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  z-index: 2;
}
.ob-skip:active { background: rgba(255, 255, 255, 0.28); }

/* The scene stage — mini map canvas the visuals live inside. */
.ob-stage {
  flex: 1;
  width: min(460px, 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
  pointer-events: none;
}
.ob-scene { width: 100%; }
.ob-map {
  position: relative;
  width: 100%;
  aspect-ratio: 5 / 3;
  border-radius: 18px;
  background:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 34px),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 34px),
    #0e3757;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
  overflow: hidden;
}

/* P-sign marker (mirrors the legend P-sign). */
.ob-psign {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50% 50% 50% 4px;
  background: var(--ob-ps, #1a9d5a);
  color: #fff;
  font-weight: 800;
  font-size: 16px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
}
.ob-mark {
  position: absolute;
  transform: translate(-50%, -50%);
  opacity: 0;
  animation: ob-pop 0.5s ease forwards;
}
@keyframes ob-pop {
  from { opacity: 0; transform: translate(-50%, -30%) scale(0.4); }
  to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
.ob-d0 { animation-delay: 0.15s; }
.ob-d1 { animation-delay: 0.5s; }
.ob-d2 { animation-delay: 0.85s; }
.ob-d3 { animation-delay: 1.2s; }
.ob-d4 { animation-delay: 1.55s; }

/* Scene 2 — legend rows + docked card. */
.ob-legend {
  position: absolute;
  left: 14px;
  top: 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ob-legend-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 600;
  opacity: 0;
  transform: translateX(-8px);
  animation: ob-slide-in 0.45s ease forwards;
}
.ob-legend-row .ob-psign { width: 24px; height: 24px; font-size: 13px; }
@keyframes ob-slide-in { to { opacity: 1; transform: translateX(0); } }

.ob-card {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 12px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 14px;
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
}
.ob-dot { width: 12px; height: 12px; border-radius: 50%; flex: none; }
.ob-card-txt { display: flex; flex-direction: column; line-height: 1.25; }
.ob-card-txt strong { font-size: 14px; }
.ob-card-txt span { font-size: 12px; color: var(--muted); }
.ob-navbtn {
  margin-left: auto;
  padding: 6px 12px;
  border-radius: 16px;
  background: var(--blue);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  opacity: 0;
  animation: ob-fade-in 0.4s ease 0.3s forwards;
}
.ob-slideup {
  opacity: 0;
  transform: translateY(16px);
  animation: ob-slide-up 0.5s ease forwards;
}
@keyframes ob-slide-up { to { opacity: 1; transform: translateY(0); } }

/* Scene 3 — street-rule lines draw + rule bubble. */
.ob-streets { position: absolute; inset: 0; width: 100%; height: 100%; }
.ob-line {
  fill: none;
  stroke-width: 5;
  stroke-linecap: round;
  stroke-dasharray: 320;
  stroke-dashoffset: 320;
  animation: ob-draw 1s ease forwards;
}
.ob-line2 { animation-delay: 0.3s; }
.ob-line3 { animation-delay: 0.6s; }
@keyframes ob-draw { to { stroke-dashoffset: 0; } }
.ob-rulecard {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 12px;
  padding: 10px 12px;
  border-radius: 12px;
  background: var(--surface);
  color: var(--text);
  font-size: 13px;
  font-weight: 600;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
}

/* Scene 4 — the Park-now button pulsing. */
.ob-parknow {
  position: absolute;
  left: 50%;
  top: 42%;
  transform: translate(-50%, -50%);
  width: 58px;
  height: 58px;
  border: 0;
  border-radius: 50%;
  background: var(--blue);
  color: #fff;
  font-size: 24px;
  font-weight: 800;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);
}
.ob-pulse { animation: ob-pulse 1.4s ease-in-out infinite; }
@keyframes ob-pulse {
  0%, 100% { box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45), 0 0 0 0 rgba(255, 205, 0, 0.5); }
  50% { box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45), 0 0 0 14px rgba(255, 205, 0, 0); }
}

/* Scene 5 — scanner verdict + Min bil pin. */
.ob-verdict {
  position: absolute;
  left: 14px;
  top: 16px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-radius: 14px;
  background: var(--surface);
  color: var(--text);
  font-size: 14px;
  font-weight: 700;
  border-left: 5px solid var(--ob-ps, #1a9d5a);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
  opacity: 0;
  animation: ob-fade-in 0.5s ease 0.1s forwards;
}
.ob-verdict-icon { font-size: 18px; }
.ob-carpin {
  position: absolute;
  right: 16px;
  bottom: 16px;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border-radius: 16px;
  background: var(--blue);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
}
.ob-carpin-icon { font-size: 16px; }

.ob-caption {
  width: min(460px, 100%);
  margin: 14px 0 0;
  min-height: 2.6em;
  text-align: center;
  font-size: 19px;
  font-weight: 700;
  line-height: 1.35;
  z-index: 2;
}

.ob-cta { width: min(460px, 100%); z-index: 2; }
.ob-cta .btn { width: 100%; min-height: 50px; font-size: 16px; }

/* End card. */
.ob-end { text-align: center; }
.ob-end-mark { display: flex; justify-content: center; margin-bottom: 14px; }
.ob-end-mark .ob-psign { width: 52px; height: 52px; font-size: 26px; }
.ob-end-title { margin: 0 0 8px; font-size: 26px; }
.ob-end-body { margin: 0; font-size: 15px; opacity: 0.85; }

/* Invisible tap zones for Back/Next (left / right thirds). Below the chrome. */
.ob-zone {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 33%;
  border: 0;
  background: transparent;
  cursor: pointer;
  z-index: 1;
}
.ob-zone-prev { left: 0; }
.ob-zone-next { right: 0; }

/* Reduced motion — crossfade only, no slide/draw/pulse motion. */
@media (prefers-reduced-motion: reduce) {
  .ob-overlay,
  .ob-mark,
  .ob-legend-row,
  .ob-navbtn,
  .ob-slideup,
  .ob-verdict { animation: ob-fade-in 0.2s ease both; }
  .ob-line { animation: none; stroke-dashoffset: 0; }
  .ob-pulse { animation: none; }
  .ob-seg > i { transition: none !important; }
}
.ob-overlay.ob-reduced .ob-mark,
.ob-overlay.ob-reduced .ob-legend-row,
.ob-overlay.ob-reduced .ob-slideup,
.ob-overlay.ob-reduced .ob-navbtn,
.ob-overlay.ob-reduced .ob-verdict { animation: ob-fade-in 0.2s ease both; }
.ob-overlay.ob-reduced .ob-line { animation: none; stroke-dashoffset: 0; }
.ob-overlay.ob-reduced .ob-pulse { animation: none; }

/* PART B §1 — "Registret säger" location-first panel. */
.scan-register {
  margin: 4px 0 14px;
  padding: 12px 14px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-left: 5px solid var(--blue);
  border-radius: 12px;
}
.scan-register[hidden] { display: none; }
.scan-register-head {
  margin: 0 0 2px;
  font-size: 15px;
  font-weight: 800;
  color: var(--blue);
}
.scan-register-sub {
  margin: 0 0 8px;
  font-size: 12px;
  color: var(--muted);
}
.scan-register-text {
  margin: 0 0 8px;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--text);
}
.scan-register-conf {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  background: rgba(255, 205, 0, 0.2);
  color: var(--text);
}
.scan-register-conf.conf-high {
  background: rgba(26, 157, 90, 0.16);
  color: var(--free);
}
.scan-register-source {
  display: block;
  margin-top: 10px;
  padding: 0;
  border: 0;
  background: none;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--blue);
  text-align: left;
  cursor: pointer;
}
.scan-register-source[disabled] { color: var(--muted); cursor: default; }

.scan-verify-head {
  margin: 6px 0 10px;
  font-size: 15px;
  font-weight: 800;
  color: var(--text);
}
.scan-verify-head[hidden] { display: none; }

.scan-build {
  width: 100%;
  margin: 10px 0 2px;
}

/* PART B §3 — redesigned big-binary verdict card. */
.scan-verdict-card {
  margin: 14px 0 6px;
  padding: 16px;
  border-radius: 14px;
  border: 1px solid var(--border);
  border-top: 6px solid var(--unknown);
  background: var(--surface);
}
.scan-verdict-card.verdict-yes { border-top-color: var(--free); }
.scan-verdict-card.verdict-no { border-top-color: var(--private); }
.scan-verdict-card.verdict-maybe { border-top-color: #d99a00; }

.scan-verdict-headline {
  font-size: 22px;
  font-weight: 800;
  line-height: 1.2;
  color: var(--text);
}
.verdict-yes .scan-verdict-headline { color: var(--free); }
.verdict-no .scan-verdict-headline { color: var(--private); }
.verdict-maybe .scan-verdict-headline { color: #b57d00; }

.scan-verdict-headline .scan-verdict-src {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 7px;
  border-radius: 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  vertical-align: middle;
  color: #fff;
  background: var(--blue);
}
.scan-verdict-qualifier {
  margin: 8px 0 0;
  font-size: 14.5px;
  line-height: 1.45;
  color: var(--text);
}
.scan-verdict-chip {
  display: inline-block;
  margin: 12px 8px 0 0;
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 700;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
}
.scan-verdict-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 12px;
}
.scan-verdict-actions .btn { flex: 1 1 auto; min-width: 120px; }

/* PART B §2 — reconciliation banner / agree mark. */
.scan-reconcile {
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 13.5px;
}
.scan-reconcile.reconcile-agrees {
  background: rgba(26, 157, 90, 0.14);
  color: var(--free);
}
.scan-reconcile.reconcile-conflicts {
  background: rgba(178, 84, 76, 0.14);
  color: var(--private);
}
.scan-reconcile.reconcile-partial {
  background: rgba(255, 205, 0, 0.18);
  color: var(--text);
}
.scan-reconcile-head { margin: 0; font-weight: 700; line-height: 1.4; }
.scan-reconcile-diffs { margin-top: 8px; display: grid; gap: 6px; }
.scan-reconcile-row {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 6px;
  font-size: 12.5px;
  color: var(--text);
}
.scan-reconcile-field { font-weight: 700; }

/* disclosure holding the per-token breakdown. */
.scan-interp {
  margin-top: 12px;
  border-top: 1px solid var(--border);
  padding-top: 8px;
}
.scan-interp > summary {
  cursor: pointer;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--blue);
  list-style: none;
}
.scan-interp > summary::after { content: " ›"; }
.scan-interp[open] > summary::after { content: " ⌄"; }

/* PART B §5 — no-camera composer. */
.scan-composer[hidden] { display: none; }
.composer-back {
  display: inline-block;
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 700;
  color: var(--blue);
}
.composer-intro {
  margin: 0 0 12px;
  font-size: 13px;
  color: var(--muted);
}
.composer-section { margin: 0 0 14px; }
.composer-label {
  margin: 0 0 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}
.composer-tiles {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.composer-tile {
  flex: 1 1 auto;
  min-width: 84px;
  min-height: 48px;
  padding: 10px 12px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: 12px;
  cursor: pointer;
}
.composer-tile.on {
  border-color: var(--blue);
  background: rgba(0, 82, 147, 0.1);
  color: var(--blue);
}
.composer-timerow {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
}
.composer-time {
  min-height: 44px;
  padding: 8px 10px;
  font-size: 15px;
  color: var(--text);
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: 10px;
}

/* v39 scope-add — Navigera inside EV/MC POI popups. */
.poi-nav { margin-top: 8px; }
.poi-nav .nav-split { display: flex; gap: 6px; }
.poi-nav .nav-go { flex: 1 1 auto; }
