/*
 * RTL-first. Layout uses logical properties throughout (margin-inline-start,
 * not margin-left) so the whole sheet works unchanged if dir flips to ltr.
 */

/* Default theme: one scheme, site-wide, matching
   https://trees.goinfo.co.il/statics/reports/open_for_objection.html
   exactly (forest-green chrome, mint page background, white raised cards,
   sun/sky/berry as the secondary palette) - by explicit request, every page
   now shares this single scheme instead of its own accent mood. The only
   other look is still the explicit opt-in [data-theme="fashion"] near the
   end of this file. */
:root {
  --bg: #f2f7ee;
  --fg: #24331f;
  --muted: #5b6f56;
  --border: #dfe9d8;
  --accent: #2e7d46;
  --surface: #eaf3e6;
  --danger: #e05353;
  --card: #ffffff;
  --radius: 10px;
  --maxw: 1100px;

  /* The reference page's full named palette, not just the tokens above -
     used for the header gradient and the finance/welfare two-series charts
     (--fin-ok/--fin-bad/--fin-compare below), so those keep distinguishable
     hues instead of collapsing onto one green --accent. */
  --forest-dark: #1b5e34;
  --forest: #2e7d46;
  --leaf: #4caf50;
  --leaf-light: #a5d6a7;
  --sun: #f5a623;
  --sky: #2ba8e0;
  --berry: #e05353;
  --bark: #a1725c;
  --terracotta: #e08130;
  --shadow: rgba(27, 94, 52, 0.16);
  --shadow-soft: rgba(27, 94, 52, 0.10);

  --fin-ok: var(--leaf);
  --fin-bad: var(--danger);
  --fin-compare: var(--sky);

  /* canopy-map.html's "no data for this area" fill - derived from --muted/
     --bg rather than a fixed gray, so it automatically follows whichever
     theme is active (including fashion/zebra below) without repeating this
     per theme block. */
  --map-nodata: color-mix(in srgb, var(--muted) 35%, var(--bg) 65%);
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Same forest scheme, deepened rather than swapped for an unrelated dark
       theme - the reference page has no dark mode of its own, so this is an
       extension of it, not a copy of one. */
    --bg: #0f1c13;
    --fg: #e6f0e1;
    --muted: #9db393;
    --border: #24382a;
    --accent: #5fce8f;
    --surface: #17251b;
    --danger: #f2766b;
    --card: #142018;

    --forest-dark: #123a24;
    --forest: #1d5c34;
    --leaf: #3f9a5c;
    --leaf-light: #4f7a5a;
    --sun: #e0a83f;
    --sky: #4fb8e8;
    --berry: #e0736b;
    --bark: #b88a6e;
    --terracotta: #e0985a;
  }
}

/* Explicit "יום" pick: pins the same light values as the default :root block
   above, unconditionally (not inside a prefers-color-scheme query), so a
   visitor who explicitly chose day mode gets it even when their OS/browser
   prefers dark - otherwise the @media block above silently wins and e.g.
   canopy-map.html's choropleth colors mismatch the desktop/light look. */
[data-theme="clouds"] {
  --bg: #f2f7ee;
  --fg: #24331f;
  --muted: #5b6f56;
  --border: #dfe9d8;
  --accent: #2e7d46;
  --surface: #eaf3e6;
  --danger: #e05353;
  --card: #ffffff;

  --forest-dark: #1b5e34;
  --forest: #2e7d46;
  --leaf: #4caf50;
  --leaf-light: #a5d6a7;
  --sun: #f5a623;
  --sky: #2ba8e0;
  --berry: #e05353;
  --bark: #a1725c;
  --terracotta: #e08130;
  --shadow: rgba(27, 94, 52, 0.16);
  --shadow-soft: rgba(27, 94, 52, 0.10);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 16px/1.55 system-ui, "Segoe UI", Arial, sans-serif;
}

.wrap { max-width: var(--maxw); margin-inline: auto; padding: 1.5rem 1rem 4rem; }

header.site {
  border-block-end: none;
  border-radius: 18px;
  margin-block-end: 1.25rem;
  /* The reference page's own header: a diagonal forest-to-leaf gradient,
     not a flat fill or a quiet tint - this is the single most visually
     distinctive piece of "the reference's color scheme" and every page now
     shares it. */
  background: linear-gradient(135deg, var(--forest-dark), var(--forest) 60%, var(--leaf));
  box-shadow: 0 8px 20px var(--shadow);
  color: #fff;
}
/* wrap, not nowrap: three items (title, byline, meta) plus a long Hebrew
   h1 in uppercase tracking on a narrow phone would otherwise overflow the
   header sideways instead of dropping to a second line. */
header.site .wrap { padding-block: 1.1rem; display: flex; align-items: baseline; flex-wrap: wrap; gap: .4rem 1rem; }
header.site h1 { font-size: 1.15rem; margin: 0; color: #fff; }
header.site a { color: #eafbe7; text-decoration: none; font-size: .9rem; }
header.site a:hover { color: #fff; }
/* An attribution line, not a headline - kept quiet on purpose. */
header.site .site-by { display: flex; flex-direction: column; font-size: .78rem; color: #d7ecd2; }
/* Quieter still than the byline it sits under - a caveat, not a warning. */
header.site .site-disclaimer { font-size: .7rem; opacity: .85; }

/* Light pills on the dark green header, not the plain button treatment
   (which would render as a same-hue-on-same-hue green pill and lose the
   pressed/unpressed contrast). */
header.site .theme-pick button {
  background: rgba(255, 255, 255, .15);
  color: #eafbe7;
  border-color: rgba(255, 255, 255, .35);
}
header.site .theme-pick button[aria-pressed="true"] {
  background: #fff;
  color: var(--forest-dark);
  border-color: #fff;
}
header.site .meta { color: #d7ecd2; }

/* Pushes itself (and the probed-timestamp span after it) to the far end of
   the header row, away from the title cluster. */
.theme-pick { display: flex; gap: .3rem; margin-inline-start: auto; }
.theme-pick button {
  font-size: .72rem;
  padding: .3rem .65rem;
  border-radius: 999px;
}
.theme-pick button[aria-pressed="true"] {
  background: var(--accent);
  color: var(--bg);
  border-color: var(--accent);
}

/* Icon + word on desktop, icon-only on mobile - same convention as
   yeela-license-tracker's own theme toggle (☀️/🌙/🦓), which frees up
   header room on a phone without losing the word for anyone with room to
   spare for it. */
@media (max-width: 640px) {
  .theme-pick .theme-btn-label { display: none; }
}

/* Mixed Hebrew/Latin content reorders incorrectly without per-element dir.
   Anything holding API-sourced text gets dir="auto" in the markup. */
[dir="auto"] { unicode-bidi: plaintext; }

input[type="search"], input[type="text"], input[type="email"], select, textarea {
  font: inherit;
  padding: .55rem .7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--fg);
  inline-size: 100%;
}
textarea { resize: vertical; }

.searchbar { display: flex; gap: .5rem; margin-block-end: 1.25rem; }
.searchbar input { flex: 1; }

button {
  font: inherit;
  padding: .55rem .9rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--fg);
  cursor: pointer;
}
button:hover:not(:disabled) { border-color: var(--accent); }
button:disabled { opacity: .5; cursor: default; }

.card {
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: .9rem 1rem;
  margin-block-end: .75rem;
  /* White, raised off the mint page background - the reference's own card
     look, not a bordered box the same colour as the page around it. */
  background: var(--card);
  box-shadow: 0 6px 16px var(--shadow-soft);
}
.card h3 { margin: 0 0 .3rem; font-size: 1rem; }
.card h3 a { color: var(--accent); text-decoration: none; }
/* Notes text is free-form and sometimes carries a long unbroken run (a raw
   URL, a resource id) with no natural break point - without this, one such
   run stretches the whole card (and everything above it) past the viewport
   at narrow widths instead of just wrapping. */
.card p { margin: .25rem 0; color: var(--muted); font-size: .9rem; overflow-wrap: anywhere; }

.meta { display: flex; flex-wrap: wrap; gap: .5rem; font-size: .8rem; color: var(--muted); }
.tag {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: .1rem .55rem;
}

.notice { padding: .8rem 1rem; border-radius: var(--radius); margin-block-end: 1rem; }
.notice.error { background: color-mix(in srgb, var(--danger) 12%, transparent); border: 1px solid var(--danger); }
.notice.info  { background: var(--surface); border: 1px solid var(--border); color: var(--muted); }
/* Links inside result text (area-cleanup's "who to call" links, etc.) -
   left unstyled these fall back to the browser's default blue, which reads
   fine on the light themes but goes muddy/illegible on fashion's black
   surface. var(--accent) is already the site's own "this is clickable"
   colour everywhere else (card titles, doc links), and stays readable on
   every theme including zebra's intentional monochrome. */
.notice a, .acc-hint a { color: var(--accent); font-weight: 600; }
.notice a:visited, .acc-hint a:visited { color: var(--accent); }
.notice a:hover, .acc-hint a:hover { text-decoration: none; }

.skeleton { color: var(--muted); padding: 2rem 0; }

/* plan-timeline.html/plan-compare.html's own loading status - a live-updating
   count while ~20-27k rows page in over several seconds needs to be seen,
   not read as one more muted hint line easy to miss. Shrinks back down to a
   plain .acc-hint (class swapped in JS) the moment loading finishes, so the
   final "נטענו X תכניות" line doesn't keep demanding attention afterward. */
.plan-loading {
  display: flex; align-items: center; gap: .6rem;
  font-size: 1.05rem; font-weight: 600; color: var(--fg);
  padding: .9rem 1.1rem; margin-block-end: 1rem;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.plan-loading::before {
  content: ''; flex: 0 0 auto; inline-size: 1.1rem; block-size: 1.1rem;
  border: 3px solid color-mix(in srgb, var(--accent) 30%, transparent);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: plan-loading-spin .8s linear infinite;
}
@keyframes plan-loading-spin { to { transform: rotate(360deg); } }

/* ---------- API map ---------- */

.lead { color: var(--muted); max-inline-size: 62ch; margin-block-end: 1.5rem; }

.controls { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; margin-block-end: .75rem; }
.controls input[type="search"] { flex: 1; min-inline-size: 15rem; }
.check { display: flex; align-items: center; gap: .4rem; font-size: .9rem; color: var(--muted); white-space: nowrap; }
.check input { inline-size: auto; }

#summary { margin-block-end: 1rem; }

.api-head { display: flex; align-items: baseline; gap: .75rem; justify-content: space-between; }

/* Status colour is carried by a text label too, not colour alone. */
.badge {
  font-size: .75rem;
  padding: .15rem .6rem;
  border-radius: 999px;
  white-space: nowrap;
  border: 1px solid;
}
.badge.ok      { color: #1a7f45; border-color: #1a7f45; background: color-mix(in srgb, #1a7f45 10%, transparent); }
.badge.warn    { color: #9a6700; border-color: #9a6700; background: color-mix(in srgb, #9a6700 10%, transparent); }
.badge.bad     { color: var(--danger); border-color: var(--danger); background: color-mix(in srgb, var(--danger) 10%, transparent); }
.badge.limited { color: #6d4aa8; border-color: #6d4aa8; background: color-mix(in srgb, #6d4aa8 10%, transparent); }
.badge.unknown { color: var(--muted); border-color: var(--border); }

@media (prefers-color-scheme: dark) {
  .badge.ok      { color: #5fce8f; border-color: #2f7d4f; }
  .badge.warn    { color: #e0b341; border-color: #7d652f; }
  .badge.limited { color: #b79ae8; border-color: #5c4487; }
}

/* Left border repeats the verdict for scanning down the list. */
.card.api { border-inline-start-width: 3px; }
.card.api.ok   { border-inline-start-color: #1a7f45; }
.card.api.warn { border-inline-start-color: #9a6700; }
.card.api.bad  { border-inline-start-color: var(--danger); }
.card.api.limited { border-inline-start-color: #6d4aa8; }

/* ---------- top view ---------- */

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: .6rem;
  margin-block-end: 1rem;
}

.stat {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  text-align: start;
  padding: .7rem .85rem;
  border: 1px solid var(--border);
  border-inline-start-width: 3px;
  border-radius: 16px;
  background: var(--card);
  box-shadow: 0 6px 16px var(--shadow-soft);
}
button.stat { cursor: pointer; }
.stat-n { font-size: 1.6rem; font-weight: 600; line-height: 1.1; font-variant-numeric: tabular-nums; }
.stat-l { font-size: .8rem; color: var(--muted); }

.stat.ok      { border-inline-start-color: #1a7f45; }
.stat.warn    { border-inline-start-color: #9a6700; }
.stat.limited { border-inline-start-color: #6d4aa8; }
.stat.bad     { border-inline-start-color: var(--danger); }
.stat.unknown { border-inline-start-color: var(--muted); }
.stat.active  { background: var(--surface); box-shadow: inset 0 0 0 1px var(--accent); }

/* ---------- committees.html: filter row + expanded document list ---------- */

/* Several label+control pairs (each already an .acc-year-pick) wrapping
   together as one row, rather than one control per line. */
.cm-filters { display: flex; flex-wrap: wrap; gap: 0 1.5rem; align-items: flex-end; }
/* .acc-year-pick's own flex-wrap is for a single lone group; several of them
   sharing one row need each group's label+control to stay paired, so only the
   row as a whole (.cm-filters) wraps, never a label away from its control. */
.cm-filters .acc-year-pick { margin-block-end: .75rem; flex-wrap: nowrap; }
#cmSearch, #cmSite { min-inline-size: 18rem; }

.cm-doclist { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .3rem; }
.cm-doclist a { color: var(--accent); }

/* The meeting-number cell itself doubles as the decisions-protocol download
   trigger (committees.js downloadDecisionsProtocol) - styled like a plain
   inline link (accent color, underline only on hover) rather than a boxed
   button, so it still reads as "the meeting's identifier", just clickable. */
.cm-decisions-dl {
  background: none; border: none; padding: 0; font: inherit; font-weight: inherit;
  color: var(--accent); cursor: pointer;
}
.cm-decisions-dl:hover:not(:disabled) { text-decoration: underline; }
.cm-decisions-dl:disabled { color: inherit; cursor: default; }

.cm-search-results { list-style: none; padding: 0; margin: .5rem 0; display: flex; flex-direction: column; gap: .6rem; }
.cm-search-result { border: 1px solid var(--border); border-radius: var(--radius); padding: .5rem .75rem; background: var(--surface); }
.cm-search-result .cm-sr-title { font-weight: 600; }
.cm-search-result .cm-sr-title a { color: var(--accent); }
.cm-search-result .cm-sr-meta { color: var(--muted); font-size: .85rem; }
.cm-search-result .cm-sr-snippet { margin-block-start: .3rem; font-size: .9rem; }
.cm-search-result mark { background: var(--accent); color: var(--bg); border-radius: .2em; padding: 0 .1em; }

/* local-pdf-search.html's grep-style match list - one snippet per hit, same
   mark styling as committees.html's own search results above. */
.lps-match { border: 1px solid var(--border); border-radius: var(--radius); padding: .5rem .75rem; background: var(--surface); margin-block-end: .5rem; font-size: .9rem; line-height: 1.6; }
.lps-match mark { background: var(--accent); color: var(--bg); border-radius: .2em; padding: 0 .1em; }

/* local-pdf-search.html's picked-files chip list and per-file result
   groups, for its multi-PDF mode. */
.lps-file-list { list-style: none; padding: 0; margin: .5rem 0 0; display: flex; flex-wrap: wrap; gap: .4rem; }
.lps-file-list li { display: flex; align-items: center; gap: .4rem; border: 1px solid var(--border); border-radius: var(--radius); padding: .25rem .3rem .25rem .6rem; background: var(--surface); font-size: .85rem; }
.lps-file-list li.lps-file-error { border-color: var(--danger); color: var(--danger); }
.lps-file-remove { border: none; background: transparent; color: inherit; cursor: pointer; font-size: 1rem; line-height: 1; padding: .15rem .35rem; border-radius: var(--radius); }
.lps-file-remove:hover { background: var(--border); }
.lps-file-group + .lps-file-group { margin-block-start: 1.2rem; }
.lps-file-group h3 { margin-block: 0 .4rem; font-size: 1rem; }

/* Floating search bar (committees.html) - fixed to the viewport bottom so
   it's reachable while scrolling the checklist/results elsewhere on the
   page. .committees-page gets extra .wrap bottom padding so the bar never
   sits over the last section's own content/buttons. */
.committees-page .wrap { padding-block-end: 6rem; }
.cm-floating-search {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .6rem;
  padding: .6rem 1rem;
  background: var(--card);
  border-block-start: 1px solid var(--border);
  box-shadow: 0 -4px 14px rgba(0, 0, 0, .15);
}
.cm-floating-search-file { display: flex; align-items: center; gap: .3rem; font-size: 1.1rem; cursor: pointer; }
.cm-floating-search-file input[type="file"] { max-inline-size: 9rem; font-size: .75rem; }
.cm-floating-search input[type="text"] { flex: 1 1 12rem; min-inline-size: 0; }
.cm-floating-search-status { font-size: .78rem; color: var(--muted); white-space: nowrap; }

/* Document checklist - a grid of small colorful cards (one per document,
   real link to the real file - click straight through, no intermediate
   step) rather than a list of full titles, same "happy" palette tokens
   (--leaf/--sun/--sky/--berry/--bark/--terracotta) already used site-wide -
   see the reference open_for_objection.html's own .card/.cards. Three per
   row by explicit request, dropping to two only on very narrow phones so
   the boxes stay tappable rather than shrinking to nothing. */
.cm-checklist { list-style: none; padding: 0; margin: .5rem 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: .7rem; }
@media (max-width: 480px) {
  .cm-checklist { grid-template-columns: repeat(2, 1fr); }
}
.cm-checklist-row { position: relative; max-inline-size: 130px; margin-inline: auto; inline-size: 100%; }
.cm-checklist-row a {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .2rem;
  aspect-ratio: 1; max-inline-size: 130px; margin-inline: auto;
  border-radius: 14px; border-top: 5px solid var(--cm-card-accent, var(--leaf));
  background: var(--card); box-shadow: 0 4px 12px var(--shadow-soft);
  text-decoration: none; color: var(--fg); transition: transform .12s ease, box-shadow .12s ease;
}
.cm-checklist-row a:hover, .cm-checklist-row a:focus-visible { transform: translateY(-3px); box-shadow: 0 8px 18px var(--shadow); }
.cm-checklist-num { font-size: 1.3rem; font-weight: 700; color: var(--cm-card-accent, var(--leaf)); }
.cm-checklist-date { font-size: .68rem; color: var(--muted); }
.cm-checklist-row input[type="checkbox"] { position: absolute; inset-block-start: .3rem; inset-inline-end: .3rem; }
.cm-checklist-row:has(input:checked) a { opacity: .45; }

.cm-script-wrap { display: flex; flex-direction: column; gap: .5rem; align-items: flex-start; }
.cm-script {
  inline-size: 100%;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: .8rem;
  line-height: 1.5;
  padding: .75rem;
  color: var(--fg);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  resize: vertical;
  white-space: pre;
  overflow-x: auto;
}

/* local-finance.html: persistent page-wide status line for the sessionStorage-
   backed fetch cache (see cachedCall() in local-finance.js) - shown while any
   data.gov.il request is in flight, then a brief cache/network summary once
   everything settles, auto-hiding itself after a few seconds. A dot instead
   of a spinner graphic (no extra asset, no animation library) - just pulses
   via the loading modifier below. */
.fin-data-status {
  display: flex; align-items: center; gap: .5rem;
  font-size: .82rem; color: var(--muted);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: .4rem .75rem; margin-block-end: 1rem;
}
.fin-data-status::before {
  content: ''; flex: 0 0 auto; inline-size: .5rem; block-size: .5rem; border-radius: 50%;
  background: var(--muted);
}
.fin-data-status.fin-status-loading { color: var(--fg); }
.fin-data-status.fin-status-loading::before {
  background: var(--accent);
  animation: fin-status-pulse 1s ease-in-out infinite;
}
@keyframes fin-status-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: .4; transform: scale(.7); }
}

/* local-finance.html: one <details> per sheet (גיליון) in a statement, so a
   34-sheet report opens collapsed rather than as one very long scroll. */
.fin-sheet { border: 1px solid var(--border); border-radius: var(--radius); margin-block-end: .6rem; padding: .5rem .75rem; }
.fin-sheet summary { cursor: pointer; font-weight: 600; }
.fin-sheet summary:hover { color: var(--accent); }
.fin-sheet .matrix-wrap { margin-block-start: .6rem; }
.fin-export-row { display: flex; flex-wrap: wrap; gap: .5rem; margin-block-end: .5rem; }

/* local-finance.html: the whole national block (KPIs + national charts) in
   one <details>, styled as a section heading rather than a boxed sheet.
   Starts collapsed on every screen size. */
.fin-national > summary { cursor: pointer; font-size: 1.05rem; font-weight: 600; color: var(--muted); margin-block-end: 1rem; }
.fin-national > summary:hover { color: var(--accent); }
.fin-national[open] > summary { margin-block-end: 1.5rem; }

/* local-finance.html: the small/medium/large/very-large liabilities-ratio
   charts - always shown directly, not behind a click, since with 8 of them
   (4 size tiers x high/low) someone comparing a few tiers would otherwise
   be opening and closing accordions constantly. A bordered card still
   separates each one visually within its shared .fin-tier-row pair. */
.fin-tier {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-block-end: .75rem;
  padding-inline: 1rem;
}
.fin-tier-label { font-size: 1rem; font-weight: 600; color: var(--fg); margin: .85rem 0 0; }
.fin-tier .acc-chart { padding-block-end: 1rem; }

/* One size tier's "highest ratio" and "lowest ratio" accordions, grouped
   under a shared label instead of two same-looking rows with no visual
   link between them. flex-basis:20rem + wrap (the same responsive pattern
   .acc-charts already uses) puts the pair side by side wherever there's
   room for both and stacks them - no media query needed - once there isn't. */
.fin-tier-group { margin-block-end: 1.5rem; }
.fin-tier-group-label { font-size: .95rem; font-weight: 600; color: var(--muted); margin: 0 0 .5rem; }
.fin-tier-row { display: flex; flex-wrap: wrap; gap: 1rem; }
.fin-tier-row .fin-tier { flex: 1 1 20rem; min-inline-size: 0; margin-block-end: 0; }

/* גדולות (a real list, dozens of authorities) next to גדולות מאוד (a short
   list, a handful of 200,000+ cities) - unlike the wrap-and-stack pairs
   above, this pair never stacks even on a phone: the short list would
   otherwise claim a full mobile-width row of its own for maybe 6-8 bars.
   nowrap keeps them side by side always; the main list gets most of the
   width (flex:2) and the short one stays a narrower side column (flex:1),
   both shrinkable below their content's natural size (min-inline-size:0)
   since neither has anywhere to overflow to. */
.fin-tier-row-side { flex-wrap: nowrap; }
.fin-tier-row-side .fin-tier.fin-tier-main { flex: 2 1 0; }
.fin-tier-row-side .fin-tier.fin-tier-side { flex: 1 1 0; }

/* ---------- page sections (ערים / כלל הארץ) ---------- */

.acc-section { margin-block-end: 2.5rem; }
.acc-section > h2 {
  font-size: 1.15rem;
  font-weight: 600;
  margin: 0 0 1rem;
  padding-block-end: .4rem;
  border-block-end: 1px solid var(--border);
}
/* The per-city year breakdown: a plain data table, kept to a readable width
   rather than stretched across the whole page like the live records table. */
#cityTable { max-inline-size: 32rem; }
#cityTable .matrix { font-variant-numeric: tabular-nums; }
#cityTable .matrix tbody th { font-weight: 600; }
/* Narrower columns overall (less padding than the site-wide .matrix
   default) - "פצועים קשה"/"פצועים קל" (3rd/4th column) each wrap onto their
   own 2 lines instead of forcing a wide column to fit the site-wide
   nowrap default, which is what was actually stretching this table out. */
#cityTable .matrix th, #cityTable .matrix td { padding: .4rem .5rem; }
#cityTable .matrix th:nth-child(3), #cityTable .matrix th:nth-child(4) {
  white-space: normal; max-inline-size: 4.5rem; line-height: 1.25;
}

/* ---------- fatalities-by-year chart ---------- */

/* The two year charts sit side by side and wrap to a stack when the row gets
   too narrow for both to keep readable bar widths. */
.acc-charts {
  display: flex;
  flex-wrap: wrap;
  gap: 2rem 3rem;
  margin-block-end: 1.25rem;
}
/* min-inline-size:0 overrides a flex item's default min-width:auto - without
   it, a wide-content descendant (local-finance's grouped chart, scrollable
   via its own overflow-x:auto) refuses to let THIS figure shrink below that
   content's natural width, and the overflow escapes to the page instead of
   staying contained in the descendant's own scrollbar. */
.acc-charts .acc-chart { flex: 1 1 20rem; margin: 0; min-inline-size: 0; }

/* local-finance's revenue/expense + per-capita grouped charts need real
   width once a compare authority doubles every year's bar group (measured:
   ~512px of content squeezed into a ~410-426px half-share of a two-column
   row triggers the group's own overflow-x:auto, so the far side scrolls out
   of view with no visible scrollbar hint - reads as "cut off", not
   "scrollable"). Full-width stacking gives each chart the whole row instead
   of half, the same fix as widening the page, without touching the shared
   two-small-charts layout accidents.html/committees.html still rely on. */
.fin-charts-stack .acc-chart { flex-basis: 100%; }

.acc-chart { margin: 0 0 1.25rem; }
/* The "all accidents" chart is the neutral-magnitude twin of the red "killed"
   one, so its bars take the accent hue instead of danger. */
.acc-chart.total .acc-bar-fill { background: var(--accent); }
/* A positive-value chart (e.g. a national surplus, not a deficit) - same
   green as the revenue side of the combo bar above, kept as one semantic name
   rather than repeating the hex value at every call site. */
.acc-chart.ok-chart .acc-bar-fill { background: #1a7f45; }
@media (prefers-color-scheme: dark) {
  .acc-chart.ok-chart .acc-bar-fill { background: #5fce8f; }
}
.acc-chart figcaption {
  font-size: .85rem;
  font-weight: 600;
  color: var(--muted);
  margin-block-end: .75rem;
}
.acc-bars {
  display: flex;
  /* flex-start, not flex-end: every .acc-bar-track is a fixed 150px box at
     the top of its column, so aligning columns by their tops keeps all bars'
     zero-baselines level regardless of category-label length below them.
     flex-end would align by the *label's* bottom instead - fine when every
     label is a same-height year (accidents.html), but companies.html's
     status/type labels wrap to a different number of lines each, which then
     pushed each track up or down by however tall its own label happened to
     be, throwing the bars' baseline out of line with each other. */
  align-items: flex-start;
  gap: .5rem;
  max-inline-size: 32rem;
  /* A handful of bars (accidents/committees' 5-7-category charts) always fit
     and never trigger this; a chart with more categories and long labels
     (e.g. finance's top-10-authorities, real multi-word city names) can
     still be wider than the viewport even under the cap above - scrolling
     the chart internally is exactly .matrix-wrap's fix for the same problem
     on wide tables, so the body itself never has to. */
  overflow-x: auto;
  padding-block-end: .25rem;
}
.acc-bar {
  flex: 1 0 2.75rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .35rem;
}
/* Fixed-height track; the fill grows from the shared zero baseline, so the
   value label - the first flex child - rides right on top of each bar. */
.acc-bar-track {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  block-size: 150px;
  inline-size: 100%;
}
.acc-bar-v {
  font-size: .8rem;
  font-weight: 600;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
  margin-block-end: .2rem;
}
.acc-bar-fill {
  inline-size: 100%;
  max-inline-size: 3rem;
  border-radius: 4px 4px 0 0;
  background: var(--danger);
}
.acc-bar-y { font-size: .78rem; color: var(--muted); font-variant-numeric: tabular-nums; }
/* When a single year is picked, its bar stays lit and the others recede,
   so the chart echoes the dropdown selection. */
.acc-bars:has(.acc-bar.active) .acc-bar { opacity: .4; }
.acc-bars:has(.acc-bar.active) .acc-bar.active { opacity: 1; }

/* Horizontal bar list (local-finance's top-N authorities ranking): a leaderboard
   of 20 reads far better top-to-bottom, one row per entry, than as 20 vertical
   bars squeezed into a fixed-height row - this is a different mark, not a
   rotated .acc-bars, so it gets its own component rather than reusing that one
   awkwardly. inline-size (a logical property, not width) is what makes the
   fill grow from the reading-start edge automatically in this RTL page. */
.acc-chart-wide { max-inline-size: none; }
/* .acc-bars (renderBarChart's vertical-bar markup) has its own independent
   32rem cap below - acc-chart-wide alone only lifts the figure's cap, so a
   renderBarChart-based chart (e.g. plan-compare.html's year-breakdown) needs
   this too or it stays squeezed regardless of the class on its figure. */
.acc-chart-wide .acc-bars { max-inline-size: none; }
.acc-hbars { display: flex; flex-direction: column; gap: .4rem; }
.acc-hbar-group-header {
  font-size: .8rem; font-weight: 700; color: var(--muted);
  margin-block-start: .5rem; padding-block-end: .15rem; border-block-end: 1px solid var(--border);
}
.acc-hbar-group-header:first-child { margin-block-start: 0; }
/* police-compare.js's category-breakdown rows under a groupHeader carry
   just a city name, not the full "group — city" text the shared 8rem
   column was sized for - narrowed so the bar itself starts right after the
   header's own text (a group name like "עבירות נגד גוף") instead of a wide
   near-empty gap between the header and where the graph actually begins.
   Same page-specific-narrowing pattern as .tree-canopy-page's own
   .acc-hbar-y override below (that one widens instead of narrows, for
   longer labels - same idea, opposite direction). */
#pcCategoryBreakdown .acc-hbar-y { flex-basis: 4.5rem; }
.acc-hbar { display: flex; align-items: center; gap: .6rem; }
.acc-hbar-y {
  flex: 0 0 8rem;
  font-size: .82rem;
  color: var(--muted);
  text-align: end;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* plan-compare.html: the main "השוואה" chart's city labels link out to
   plan-timeline.html?city=... (see linkifyChartCities in plan-compare.js) -
   explicitly green via --forest rather than --accent, since --accent itself
   turns gold under the "fashion" theme and black under "zebra" - this link
   should read as green on every theme, not follow the chart's own colors. */
.pc-chart-city-link { color: var(--forest); text-decoration: underline; }
.pc-chart-city-link:hover { opacity: .8; }
/* renderHBarChart's own optional `href` per entry (see charts.js) - an
   `<a class="acc-hbar-y">` instead of the usual `<span>`, so it inherits
   .acc-hbar-y's layout (width/ellipsis/alignment) as-is and only needs its
   color/hover called out here; same green-link language as
   .pc-chart-city-link above, for the same reason (theme-stable, not
   dependent on --accent). Scoped to the `a` tag specifically so every
   plain `<span class="acc-hbar-y">` chart elsewhere on the site (the vast
   majority) is untouched. */
a.acc-hbar-y { color: var(--forest); text-decoration: underline; }
a.acc-hbar-y:hover { opacity: .8; }
.acc-hbar-track { flex: 1; block-size: 1.1rem; background: var(--surface); border-radius: 4px; overflow: hidden; }
.acc-hbar-fill { block-size: 100%; border-radius: 4px; background: var(--accent); }
/* canopy-map.html's own three detail charts (cmDetailCanopy/cmDetailStreet/
   cmDetailHeat, see renderDetail() in canopy-map.js) only - NOT a global
   change to .acc-hbar-track, which renderHBarChart's other callers
   (tree-canopy.html, canopy-heat-compare.html, local-finance.html, etc.)
   also use and didn't ask for a shorter bar. 1.1rem -> .77rem, 30% less
   (user request). */
#cmDetailCanopy .acc-hbar-track, #cmDetailStreet .acc-hbar-track, #cmDetailHeat .acc-hbar-track { block-size: .77rem; }
.acc-hbar-v { flex: 0 0 auto; font-size: .82rem; font-weight: 600; font-variant-numeric: tabular-nums; min-inline-size: 4.5rem; }
/* A compare authority's own row in the same leaderboard (see
   renderHBarChart's `compare` entry flag) - the same pale tint used for a
   compare authority's bars everywhere else on this page. */
.acc-hbar-compare .acc-hbar-fill { background: color-mix(in srgb, var(--accent) 55%, var(--bg) 45%); }
.acc-hbar-compare .acc-hbar-y { color: color-mix(in srgb, var(--muted) 80%, transparent); font-size: .78rem; }

/* Two-segment "combined" bar (canopy-heat-compare.js's own
   renderStackedBarChart - public+private tree % shown as one bar instead
   of two separate ones when both are active). display:flex row of two
   fills instead of one - each segment stays square (no radius; the parent
   track's own border-radius + overflow:hidden already rounds the OUTER
   ends of the combined bar, exactly like a single fill normally gets). */
.acc-hbar-track-stacked { display: flex; }
.acc-hbar-track-stacked .acc-hbar-fill { border-radius: 0; }

/* Grouped bar chart with a gridlined y-axis (local-finance's revenue/
   expense, per-resident and liabilities charts) - see renderGroupedChart().
   Side-by-side bars on a shared axis, not layered/overlapping ones: a value
   can be read straight off the chart instead of needing the table
   underneath. Color encodes which CITY a bar belongs to (--accent vs.
   --fin-compare), identical across all three charts; which SERIES it is
   (front/back, e.g. income/expense) is carried by position within its
   city's pair plus a lighter tint, not a second hue - see the legend this
   renders. */
/* Every column (the axis, and each year/gap group) stacks in NORMAL FLOW:
   an optional pct-label row, then a zone fixed at exactly FIN_PLOT_PX tall
   (never a percentage or flex-stretch height - this site sets
   box-sizing:border-box globally, so a percentage height combined with any
   ancestor padding silently shrinks below what JS computed bar heights
   against, throwing gridlines and bars out of alignment), then a year-
   label row. As long as every column's pct-label row is the same height
   (all share the .fin-chart-pct class, real text or not), the FIN_PLOT_PX
   zones line up across every column with no shared-ancestor height tricks
   needed - align-items:flex-end on .fin-chart-body would otherwise still
   be fighting the same box-sizing issue this avoids entirely. */
.fin-chart-body { display: flex; align-items: flex-start; gap: .6rem; }
.fin-chart-axis { flex: 0 0 auto; display: flex; flex-direction: column; text-align: end; }
.fin-chart-axis-scale {
  display: flex; flex-direction: column; justify-content: space-between;
  font-size: .72rem; color: var(--muted); font-variant-numeric: tabular-nums;
}
.fin-chart-plot { flex: 1; min-inline-size: 0; overflow-x: auto; display: flex; align-items: flex-start; gap: 1.3rem; }
.fin-chart-group { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; }
.fin-chart-pct {
  display: block; block-size: 1.1rem; text-align: center; font-size: .68rem; color: var(--muted);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.fin-chart-bars-wrap {
  display: flex; align-items: flex-end; gap: .5rem; /* between the main/compare sub-groups within one year - see .fin-chart-plot for the larger between-YEAR gap */
  background-image: linear-gradient(to top, var(--border) 0 1px, transparent 1px 100%);
  background-repeat: repeat-y; background-position: bottom;
}
.fin-chart-bars { display: flex; align-items: flex-end; gap: 3px; }
.fin-chart-bar { inline-size: 14px; border-radius: 3px 3px 0 0; background: var(--accent); }
.fin-chart-bar-light { background: color-mix(in srgb, var(--accent) 45%, var(--bg) 55%); }
.fin-chart-bar-compare { background: var(--fin-compare); }
.fin-chart-bar-compare.fin-chart-bar-light { background: color-mix(in srgb, var(--fin-compare) 45%, var(--bg) 55%); }
.fin-chart-y { margin-block-start: .4rem; font-size: .74rem; color: var(--muted); white-space: nowrap; }
/* A run of missing years (e.g. 2020-2021) between two real ones - a dashed
   box instead of just skipping straight from 2019 to 2022, so a reader
   scanning the x-axis doesn't read the two surviving years as adjacent. */
.fin-chart-gap-box { border-inline: 1px dashed var(--border); }
.fin-chart-gap-label { text-align: center; line-height: 1.3; white-space: normal; max-inline-size: 5rem; }

/* Legend for the two-series chart above - color meaning is never carried by
   hue alone elsewhere on the site either (see .badge), so this pairs a swatch
   with a text label rather than just a colored dot. */
.acc-legend { display: flex; gap: 1rem; font-size: .8rem; color: var(--muted); margin-block-end: .5rem; }
.acc-legend-item { display: flex; align-items: center; gap: .35rem; }

/* local-finance.html: the liabilities chart is called out as the most
   important one on the page - a bigger, high-contrast headline and bolder
   figures than every other chart here, plus a tinted card so it reads as a
   destination rather than one more figure in the scroll. Scoped by this
   chart's own #id rather than a class, since renderGroupedChart (charts.js)
   is shared by every grouped chart on every page and must stay neutral -
   this is a look for one specific chart, not a variant of the component. */
#finChartAuthLiabRatio {
  padding: 1rem;
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 7%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
}
#finChartAuthLiabRatio figcaption {
  font-size: 1.6rem;
  font-weight: 800;
  color: var(--fg);
  text-align: center;
}
#finChartAuthLiabRatio .acc-legend,
#finChartAuthRevenue .acc-legend,
#finChartAuthPerCapita .acc-legend {
  justify-content: center;
}
/* Centers the axis (Y-axis number scale) and the bar groups TOGETHER as one
   unit, not just the bars within their own already-full-width box - the
   first attempt only did the latter, so the axis numbers (a fixed-width
   column that never grows) stayed pinned to their own edge regardless of
   the bars moving. .fin-chart-plot's flex:1 (the global default - it fills
   whatever space the axis doesn't use) is overridden to flex:0 1 auto here
   so the plot stops claiming all the leftover width; with both children
   sized to their own content, centering the shared .fin-chart-body row
   moves axis+bars as a single block instead of leaving the axis stranded.
   Applies to all three of this page's authority charts (revenue, per-
   capita, liabilities) - only the liabilities chart also gets the bigger/
   bolder "most important graph" treatment above/below this block. */
#finChartAuthLiabRatio .fin-chart-body,
#finChartAuthRevenue .fin-chart-body,
#finChartAuthPerCapita .fin-chart-body {
  justify-content: center;
}
#finChartAuthLiabRatio .fin-chart-plot,
#finChartAuthRevenue .fin-chart-plot,
#finChartAuthPerCapita .fin-chart-plot {
  flex: 0 1 auto;
  justify-content: center;
}
#finChartAuthLiabRatio .acc-legend-item,
#finChartAuthLiabRatio .fin-chart-y,
#finChartAuthLiabRatio .fin-chart-axis-scale span,
#finChartAuthLiabRatio .fin-chart-pct {
  font-weight: 700;
}
#finChartAuthLiabRatio .fin-chart-axis-scale span { color: var(--fg); }
/* Same table-below-the-chart pattern as everywhere else on this page, just
   bolder/larger to match the chart above it being called out. */
#finLiabTable .matrix { font-size: 1rem; }
#finLiabTable .matrix td { font-weight: 700; }
#finLiabTable .matrix thead th { font-weight: 800; color: var(--fg); }
.acc-legend-swatch { inline-size: .8rem; block-size: .8rem; border-radius: 3px; display: inline-block; }

/* The table is the widest thing on the page; it scrolls, the body never does. */
.matrix-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); }

.matrix { border-collapse: collapse; inline-size: 100%; font-size: .85rem; }
.matrix th, .matrix td { padding: .45rem .7rem; text-align: start; white-space: nowrap; }
/* help-*.html tables hold prose (field/button explanations, a sentence or
   more per cell), not compact data rows - the site-wide nowrap above is
   right for numbers/short labels but forces a whole paragraph onto one
   horizontally-scrolling line on mobile. .prose opts a table back into
   normal wrapping instead, and gives the first (label) column a sane
   minimum so it doesn't collapse to one letter per line. */
.matrix.prose th, .matrix.prose td { white-space: normal; }
.matrix.prose th:first-child, .matrix.prose td:first-child { min-inline-size: 6rem; }
@media (max-width: 640px) {
  .matrix.prose { font-size: .8rem; }
  .matrix.prose th, .matrix.prose td { padding: .4rem .5rem; }
}
.matrix thead th {
  font-size: .75rem;
  font-weight: 600;
  color: var(--muted);
  background: var(--surface);
  border-block-end: 1px solid var(--border);
  position: sticky;
  inset-block-start: 0;
}
/* A 50-row preview must not push the rest of the page down: it gets its own
   viewport and scrolls inside it. The sticky thead above keeps the headers -
   and therefore the sort controls - reachable while scrolled. */
.matrix-wrap.scroll { max-block-size: 26rem; overflow-y: auto; }

/* Only columns the server can sort by are interactive - see headCell(). */
.matrix th.sortable { cursor: pointer; user-select: none; }
.matrix th.sortable:hover { color: var(--fg); }
.matrix th.sortable:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); }
.matrix th.sorted { color: var(--accent); }
.s-mark { font-size: .7em; margin-inline-start: .3rem; opacity: .45; }
.matrix th.sorted .s-mark { opacity: 1; }

.matrix tr.grp th {
  font-size: .8rem;
  background: var(--surface);
  border-block: 1px solid var(--border);
}
.grp-sub { font-weight: 400; color: var(--muted); font-size: .75rem; }

/* A compare authority's row, directly beneath the main authority's row for
   the same year (see renderAuthorityTable et al.) - a clearly visible tint
   plus muted text, closed off by a bottom border so each year's two-row
   group reads as one unit rather than bleeding into the next year's. */
.matrix tr.fin-row-compare {
  background: color-mix(in srgb, var(--muted) 16%, transparent);
  color: var(--muted);
  border-block-end: 1px solid var(--border);
}

.matrix tr.row { cursor: pointer; border-block-end: 1px solid var(--border); }
.matrix tr.row:hover, .matrix tr.row:focus-visible { background: var(--surface); outline: none; }
.matrix tr.row:focus-visible { box-shadow: inset 0 0 0 2px var(--accent); }
.matrix tr.row td:first-child { border-inline-start: 3px solid transparent; font-weight: 500; }
.matrix tr.row.ok      td:first-child { border-inline-start-color: #1a7f45; }
.matrix tr.row.warn    td:first-child { border-inline-start-color: #9a6700; }
.matrix tr.row.limited td:first-child { border-inline-start-color: #6d4aa8; }
.matrix tr.row.bad     td:first-child { border-inline-start-color: var(--danger); }
.matrix tr.row.unknown td:first-child { border-inline-start-color: var(--border); }

/* Jump target needs to announce itself - the card is mid-page and looks like its neighbours. */
.card.api.flash { background: color-mix(in srgb, var(--accent) 10%, transparent); transition: background .4s; }

/* ---------- portal grid ---------- */

.section { font-size: 1rem; margin-block: 2rem .75rem; color: var(--muted); font-weight: 600; }
.section:first-of-type { margin-block-start: 0; }

.portal-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: .75rem;
}

.portal {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  text-align: start;
  padding: .85rem;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--card);
  box-shadow: 0 6px 16px var(--shadow-soft);
  cursor: pointer;
}
.portal:hover { border-color: var(--accent); }
.portal.active { border-color: var(--accent); background: var(--surface); box-shadow: inset 0 0 0 1px var(--accent); }

.p-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.p-name { font-weight: 600; }
.p-sub  { font-size: .78rem; color: var(--muted); }
.p-about { font-size: .85rem; color: var(--muted); line-height: 1.45; }

/* ---------- apps: big, welcoming, nothing that reads as a URL ----------
   No title/subtitle/description text, no arrow-hint line - an icon and a
   name, styled as a destination to tap rather than a link to read. Fixed
   light colours rather than the page's own theme variables: the point is
   to stand out as an inviting button regardless of which of the two site
   themes (or accidents.html's own warning mood) happens to be active. */
/* One heading + grid per category (src/apps.js renderAppsByCategory) - its
   own rule rather than reusing .section, whose :first-of-type margin reset
   would otherwise fire on EVERY category heading (each is the first h3
   within its own separate <section>, not just the page's first one). */
.apps-category + .apps-category { margin-block-start: 1.5rem; }
/* The pinned app (renderAppsByCategory's PINNED_APP_ID) has no heading of
   its own, so it can't rely on the sibling-selector rule above for spacing
   before the first real category section. */
.apps-pinned { margin-block-end: 1.5rem; }
.apps-category-h { font-size: 1rem; margin-block: 0 .6rem; color: var(--muted); font-weight: 600; }

.apps-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: .85rem;
}
.app-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  text-align: center;
  text-decoration: none;
  padding: 1.5rem 1rem;
  border-radius: 1.1rem;
  border: 1px solid #f0d9bc;
  background: linear-gradient(160deg, #fffaf3, #ffe6c2);
  color: #3a2c17;
  box-shadow: 0 3px 10px -6px rgba(0, 0, 0, .35);
  transition: transform .15s ease, box-shadow .15s ease;
}
.app-tile:hover, .app-tile:focus-visible {
  transform: translateY(-3px);
  box-shadow: 0 10px 22px -10px rgba(0, 0, 0, .4);
}
.app-icon { font-size: 2.3rem; line-height: 1; }
.app-name { font-weight: 600; font-size: .95rem; }

/* tree-canopy's own icon (src/apps.js APP_ICON) - a small house badge
   tucked in the corner of the tree, not beside it, so the icon never grows
   wider than a plain single-glyph one. Sized in em, relative to whichever
   container places it (.app-icon in the apps grid, .app-sibling in the
   per-page context strip - both happen to already share the same 2.3rem
   icon font-size, so this scales identically in either without its own
   per-container override). */
.tc-icon { position: relative; display: inline-block; }
.tc-icon-badge {
  position: absolute; inset-block-end: -.15em; inset-inline-end: -.15em;
  font-size: .55em; line-height: 1;
  background: var(--card); border-radius: 999px; box-shadow: 0 0 0 2px var(--card);
}

/* trees' own icon - the ambulance rides along smaller, inline beside the
   tree rather than badged in a corner (unlike tc-icon-badge above) - a
   supporting detail, not a second subject the same size as the tree. Also
   em-relative for the same reason tc-icon-badge is. */
.icon-small { font-size: .6em; vertical-align: middle; }

/* ---------- per-page "app context" strip (src/apps.js renderAppContext) ---
   Sits under an app's own header: a 🏠 back to apps.html, then small icon-
   links to its category siblings (this app's own icon shown too, inert, as
   "you are here") - all derived from apis.json rather than hand-written per
   page. Small and understated on purpose - this is a footnote to the page,
   not a second hero section competing with the one above it. */
.app-context { margin-block-end: 1.2rem; }
.app-siblings { display: flex; flex-wrap: wrap; gap: .5rem; }
/* Icon + a visible caption underneath, not just a hover title - relying on
   hover alone means the icon is the only identifier at a glance, and in
   zebra mode (grayscale, see [data-theme="zebra"] .app-sibling-icon below)
   color stops being a differentiator too, so a permanent label matters
   more here than most places on the site. */
.app-sibling {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .2rem;
  inline-size: 4.6rem; padding: .5rem .2rem;
  border-radius: 12px; border: 1px solid var(--border); background: var(--card);
  text-decoration: none; transition: border-color .15s ease, transform .15s ease;
}
.app-sibling-icon { font-size: 2.3rem; line-height: 1; }
.app-sibling-label { font-size: .62rem; line-height: 1.15; text-align: center; color: var(--muted); }
.app-sibling:hover, .app-sibling:focus-visible { border-color: var(--accent); transform: translateY(-1px); }
.app-sibling-current { border-color: var(--accent); background: var(--surface); box-shadow: inset 0 0 0 1px var(--accent); cursor: default; }

/* Mobile keeps the same icon size as desktop (a touch target still earns
   at least as much room as a pointer one) - kept as its own rule rather
   than folded into the base so a future desktop-only change here doesn't
   need to be re-checked against mobile too. */
@media (max-width: 640px) {
  .app-sibling { inline-size: 4.6rem; }
  .app-sibling-icon { font-size: 2.3rem; }
}

/* Colorblind/low-vision high-contrast theme: emoji glyphs are pre-rendered
   full-color pixels, not CSS colors, so the --accent/--card variable
   overrides above have no effect on them at all - grayscale(1) is the only
   way to actually desaturate them, same principle as the theme's own name
   (zebra: no hue anywhere, not even in the icons). */
[data-theme="zebra"] .app-icon,
[data-theme="zebra"] .app-sibling-icon,
[data-theme="zebra"] .theme-pick button {
  filter: grayscale(1);
}
/* The document-checklist cards (committees.html) cycle through the site's
   "happy" palette per card via --cm-card-accent - zebra never redefines
   those tokens (they're colour, not theme-aware vars), so grayscale(1) is
   the only way to desaturate them too, same reasoning as above. */
[data-theme="zebra"] .cm-checklist-row a {
  filter: grayscale(1);
}

/* ---------- "continue" disclosure past the portals ----------
   Native <details>/<summary>: no JS toggle to write or keep accessible,
   the browser already handles open/closed and keyboard use. The `open`
   attribute ships in the markup so desktop (and no-JS/no-CSS clients)
   just see the full page; only the mobile media query below closes it
   by default and gives the summary a tap target worth pressing. */
.more summary.more-toggle {
  list-style: none;
  cursor: pointer;
  color: var(--accent);
  font-weight: 600;
  font-size: .9rem;
  margin-block: .5rem 1.25rem;
}
.more summary.more-toggle::-webkit-details-marker { display: none; }
.more[open] summary.more-toggle { display: none; }

/* ---------- live explorer ---------- */

.toggle-ex { font-size: .85rem; padding: .35rem .7rem; margin-block-start: .5rem; }

.explorer {
  margin-block-start: .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: .7rem;
  background: var(--surface);
}
.ex-bar { display: flex; gap: .4rem; align-items: stretch; flex-wrap: wrap; }
.ex-method {
  font-size: .78rem; font-weight: 600;
  padding: .5rem .6rem;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg); color: var(--accent);
  text-decoration: none; white-space: nowrap;
  display: inline-flex; align-items: center;
}
.ex-method:hover { border-color: var(--accent); }
.ex-method.disabled { pointer-events: none; opacity: .5; color: var(--muted); }
.ex-method.static { color: var(--muted); cursor: default; }
.ex-url { flex: 1; min-inline-size: 12rem; font-family: ui-monospace, Menlo, monospace; font-size: .8rem; }
.ex-status { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap; margin-block: .6rem .4rem; }

.ex-out pre {
  margin: 0;
  max-block-size: 22rem;
  overflow: auto;              /* long responses scroll inside the panel */
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: .6rem;
  font-size: .78rem;
  line-height: 1.45;
  white-space: pre;
}
.j-key  { color: var(--accent); }
.j-str  { color: #1a7f45; }
.j-num  { color: #9a6700; }
.j-bool { color: var(--danger); }
@media (prefers-color-scheme: dark) {
  .j-str { color: #5fce8f; }
  .j-num { color: #e0b341; }
}

/* Endpoints are LTR inside an RTL page; they must scroll, not widen it. */
.endpoint { overflow-x: auto; }
.endpoint code {
  font-size: .82rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: .15rem .4rem;
  white-space: nowrap;
}

/* ---------- data.gov.il explorer ---------- */

.ckan { border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem; }
.ckan .lead { margin-block-start: 0; font-size: .92rem; }

.ck-crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem; margin-block-end: .8rem; font-size: .85rem; }
.ck-crumb {
  font: inherit; font-size: .85rem; padding: .15rem .4rem; cursor: pointer;
  color: var(--accent); background: none; border: none; border-radius: 4px; text-decoration: underline;
}
.ck-crumb:hover { background: var(--surface); }
.ck-here { color: var(--muted); }
.ck-sep { color: var(--muted); }

.ck-controls { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin-block-end: .6rem; }
.ck-controls input[type="search"] { flex: 1 1 14rem; font-size: .9rem; padding: .45rem .65rem; }
.ck-controls input[type="search"]:disabled { opacity: .5; cursor: not-allowed; }
.ck-controls select {
  font: inherit; font-size: .82rem; padding: .35rem .5rem; max-inline-size: 100%;
  color: var(--fg); background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
}
.ck-count { font-size: .85rem; color: var(--muted); margin-block-end: .6rem; }

/* The moag explorer's "only directly-queryable datasets" toggle - inline with
   the rest of .ck-controls rather than a styled checkbox of its own. */
.mg-only { display: flex; align-items: center; gap: .35rem; font-size: .82rem; color: var(--muted); cursor: pointer; white-space: nowrap; }

/* min(17rem, 100%) rather than a bare 17rem: below a 17rem viewport the track
   would otherwise stay 17rem wide and push the page sideways. */
.ck-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(17rem, 100%), 1fr)); gap: .6rem; }
.ck-card {
  display: flex; flex-direction: column; gap: .3rem; text-align: start; cursor: pointer;
  padding: .7rem .8rem; font: inherit;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  /* A `1fr` track floors at min-content, so one long unbroken string in a title
     or description widens the track past the viewport and scrolls the whole
     page - measured at 85px over on a 380px screen. These two lines are what
     stop dataset text from dictating the layout. */
  min-inline-size: 0;
  overflow-wrap: anywhere;
}
.ck-card:hover { background: var(--surface); border-color: var(--accent); }
.ck-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.ck-title { font-weight: 600; font-size: .92rem; }
.ck-org { font-size: .78rem; color: var(--muted); }
.ck-notes { font-size: .8rem; color: var(--muted); line-height: 1.4; }
.ck-meta { display: flex; flex-wrap: wrap; gap: .3rem; align-items: center; margin-block-start: .2rem; }
.ck-n { font-size: .72rem; color: var(--muted); }

.ck-detail h3 { margin-block: 0 .6rem; font-size: 1.05rem; }
.ck-detail h4 { margin-block: 1.2rem .5rem; font-size: .9rem; color: var(--muted); }
.ck-facts { display: grid; grid-template-columns: auto 1fr; gap: .25rem .8rem; margin: 0 0 .8rem; font-size: .85rem; }
.ck-facts dt { color: var(--muted); }
.ck-facts dd { margin: 0; }
.ck-desc { font-size: .88rem; line-height: 1.6; white-space: pre-wrap; }
.ck-tags { display: flex; flex-wrap: wrap; gap: .3rem; }
.ck-open {
  font: inherit; font-size: .76rem; padding: .2rem .55rem; cursor: pointer;
  color: var(--bg); background: var(--accent); border: 1px solid var(--accent); border-radius: 999px;
}
.ck-open:hover { filter: brightness(1.1); }
.ck-nodata { font-size: .72rem; color: var(--muted); }
/* Built in the browser from the DataStore, so it actually produces a file -
   unlike the resource's own URL, which the WAF answers with a challenge page. */
.ck-dl {
  font: inherit; font-size: .76rem; padding: .2rem .55rem; cursor: pointer; white-space: nowrap;
  color: var(--accent); background: var(--bg); border: 1px solid var(--accent); border-radius: 999px;
}
.ck-dl:hover:not(:disabled) { background: var(--surface); }
.ck-dl:disabled { opacity: .6; cursor: progress; }

/* The record table: one column per field, so it is wide by nature. */
.ck-rec th { vertical-align: top; }
.ck-type { display: block; font-size: .65rem; font-weight: 400; color: var(--muted); }
.ck-fil th { padding: .25rem .35rem; background: var(--surface); position: sticky; inset-block-start: 3.1rem; }
.ck-fil input {
  inline-size: 100%; min-inline-size: 6rem; font: inherit; font-size: .75rem; padding: .2rem .35rem;
  color: var(--fg); background: var(--bg); border: 1px solid var(--border); border-radius: 4px;
}
.ck-rec tbody td { border-block-end: 1px solid var(--border); max-inline-size: 22rem; overflow: hidden; text-overflow: ellipsis; }

/* ---------- portal drill-in ---------- */

.p-open { font-size: .8rem; color: var(--accent); margin-block-start: .2rem; }

.drill {
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  padding: .9rem 1rem;
  margin-block: 1rem 0;
  background: var(--surface);
}
.drill-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.drill-head h2 { font-size: 1.05rem; margin: 0; }
.drill-title { display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; }
.drill-home { font-size: .78rem; color: var(--accent); text-decoration: none; white-space: nowrap; }
.drill-home:hover { text-decoration: underline; }
.drill-close { font-size: .8rem; padding: .25rem .6rem; }
.drill-sub { font-size: .85rem; color: var(--muted); margin-block: .2rem .6rem; }

/* The request is shown so the result can be reproduced outside the page. */
/* The preview stops at the catalogue; this points at the page that does not. */
/* No color rule here used to mean "whatever the browser's default link
   color is" - fine on a white desktop background, but the mobile theme's
   near-black bg turned that default (a dark visited-link purple) almost
   unreadable. Same accent as every other link on the page. */
.drill-more { margin-inline-start: .5rem; font-size: .8rem; white-space: nowrap; color: var(--accent); }

.drill-url { margin-block: .6rem 0; overflow-x: auto; }
.drill-url code { font-size: .74rem; color: var(--muted); white-space: nowrap; }

/* Preview tables hold prose, unlike the API matrix - let long values wrap
   inside a bounded cell instead of stretching the table off-screen. */
.matrix.preview td { white-space: normal; max-inline-size: 22rem; }
.matrix.preview td.ident { font-weight: 500; }
.matrix.preview .col-dt { white-space: nowrap; min-inline-size: 6.5rem; }
.matrix.preview tbody tr:nth-child(even) { background: color-mix(in srgb, var(--fg) 3%, transparent); }

/* police-compare.js's own compare table (#pcTable) only borrows "preview"
   for its striped rows, not its prose-wrapping - its own cells are short
   (a city name, a handful of numbers), so the 22rem wrap-friendly rule
   above just breaks a city name across 2-3 lines instead of keeping it on
   one, especially cramped on a narrow phone screen (user request: widen &
   fix the city name column). Restores the site's normal single-line .matrix
   behavior for this table specifically. */
#pcTable .matrix.preview td, #pcTable .matrix.preview th { white-space: nowrap; max-inline-size: none; }
/* The per-city color swatch there ties a row back to the chart above it -
   useful on desktop, but not worth the width it costs the city-name column
   on a narrow phone screen where every column is already tight (user
   request, mobile only). */
@media (max-width: 640px) {
  #pcTable .fin-city-cell .acc-legend-swatch { display: none; }
}

/* Filter box inside a portal drill-in. */
.drill-filter { display: flex; gap: .5rem; align-items: center; margin-block-end: .7rem; }
/* Same treatment as .ck-dl in the data.gov.il explorer: built here from
   DataStore records, so it downloads exactly what's filtered on screen. */
.drill-dl {
  font: inherit; font-size: .76rem; padding: .2rem .55rem; cursor: pointer; white-space: nowrap;
  color: var(--accent); background: var(--bg); border: 1px solid var(--accent); border-radius: 999px;
}
.drill-dl:hover:not(:disabled) { background: var(--surface); }
.drill-dl:disabled { opacity: .6; cursor: progress; }
/* Offset paging. Server-side `start`, so these move through the whole result
   set rather than through what was already fetched. */
.pager { display: flex; flex-wrap: wrap; gap: .3rem; align-items: center; margin-block-start: .7rem; }
.pager .pg {
  font: inherit;
  font-size: .82rem;
  padding: .25rem .6rem;
  min-inline-size: 2.2rem;
  color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
}
.pager .pg:hover:not(:disabled) { background: var(--surface); }
.pager .pg:disabled { color: var(--muted); cursor: default; opacity: .55; }
.pager .pg.cur {
  color: var(--bg);
  background: var(--accent);
  border-color: var(--accent);
  font-weight: 600;
}
.pg-gap { color: var(--muted); padding-inline: .1rem; }

/* Column filters. Each is one fq clause, so they compose with the search box. */
.drill-cols { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin-block-end: .7rem; }
.drill-cols select {
  font: inherit;
  font-size: .82rem;
  padding: .3rem .5rem;
  max-inline-size: 100%;
  color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.drill-filter input[type="search"] { flex: 1; font-size: .9rem; padding: .45rem .65rem; }
/* Server-side vs local is not cosmetic: it says whether you are searching the
   whole collection or only the rows already fetched. */
.drill-scope {
  font-size: .72rem;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: .15rem .55rem;
  white-space: nowrap;
}

/* Expandable rows: a dataset opens into its downloadable files
   (portal.js/committees.js); companies.html reuses the same mechanic to open
   a row into ica_companies fields the columns above have no room for. */
.matrix.preview.expandable tr.has-files,
.matrix.preview.expandable tr.has-detail { cursor: pointer; }
.matrix.preview.expandable tr.has-files:hover,
.matrix.preview.expandable tr.has-files:focus-visible,
.matrix.preview.expandable tr.has-detail:hover,
.matrix.preview.expandable tr.has-detail:focus-visible { background: var(--surface); outline: none; }
.matrix.preview.expandable tr.has-files:focus-visible,
.matrix.preview.expandable tr.has-detail:focus-visible { box-shadow: inset 0 0 0 2px var(--accent); }
.matrix.preview .c-x { inline-size: 1.6rem; text-align: center; }
.x-mark { color: var(--muted); font-size: .8rem; }
.matrix.preview tr.files-row td,
.matrix.preview tr.detail-row td { background: var(--surface); padding: .5rem .7rem; }

/* companies.html's per-row detail panel: a plain label/value grid. */
.co-detail { margin: 0; display: grid; gap: .35rem .1rem; }
.co-detail div { display: flex; gap: .5rem; }
.co-detail dt { flex: 0 0 11rem; color: var(--muted); }
.co-detail dd { margin: 0; }

/* housing-lottery.html's per-row detail panel - same grid idiom as .co-detail. */
.hl-detail { margin: 0; display: grid; gap: .35rem .1rem; }
.hl-detail div { display: flex; gap: .5rem; }
.hl-detail dt { flex: 0 0 11rem; color: var(--muted); }
.hl-detail dd { margin: 0; }

/* whois.html's result card - same label/value grid idiom as .co-detail
   above, plus a status-badge row and a registrar/contact list neither of
   companies.html's own rows need. */
.whois-card { border: 1px solid var(--border); border-radius: var(--radius); padding: .8rem 1rem; background: var(--surface); }
.whois-card h3 { margin-block: 0 .4rem; }
.whois-card h4 { margin-block: 1rem 0 .4rem; font-size: .9rem; color: var(--muted); }
.whois-statuses { display: flex; gap: .3rem; flex-wrap: wrap; margin-block-end: .6rem; }
.whois-dl { margin: 0; display: grid; gap: .35rem .1rem; }
.whois-dl div { display: flex; gap: .5rem; }
.whois-dl dt { flex: 0 0 11rem; color: var(--muted); }
.whois-dl dd { margin: 0; }
.whois-entities { margin: 0; padding-inline-start: 1.2rem; }
.whois-entities li { margin-block-end: .2rem; }

/* Israeli license-plate visual (vehicle-lookup.js's renderCard) - real
   yellow/black plate colors are fixed regardless of site theme (that's the
   whole point), not tied to --fg/--bg. print-color-adjust keeps the yellow
   and blue from being stripped to white by the browser's print engine,
   needed since #vlPdfBtn's "download PDF" is just window.print(). */
.plate-il {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  background: #ffcf00;
  border: 2px solid #111;
  border-radius: .35rem;
  padding: .35rem .6rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
  print-color-adjust: exact;
  -webkit-print-color-adjust: exact;
}
.plate-il-num {
  font-family: 'Arial Narrow', Arial, sans-serif;
  font-weight: 800;
  font-size: 1.4rem;
  letter-spacing: .04em;
  color: #111;
}
.plate-il-euroband {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  background: #1155cc;
  color: #fff;
  border-radius: .2rem;
  padding: .15rem .35rem;
  line-height: 1;
}
.plate-il-flag { display: block; border-radius: 1px; }
.plate-il-il { font-weight: 700; font-size: .65rem; letter-spacing: .02em; }

.files { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .3rem; }
.files a {
  display: flex; align-items: center; gap: .6rem;
  padding: .4rem .6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  text-decoration: none;
  color: var(--fg);
  font-size: .85rem;
}
.files a:hover { border-color: var(--accent); }
/* Format first and size up front: one of these is a 9 MB CSV. */
.f-fmt {
  font-size: .7rem; font-weight: 600; color: var(--accent);
  border: 1px solid var(--accent); border-radius: 4px;
  padding: .05rem .35rem; min-inline-size: 3rem; text-align: center;
}
.f-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.f-size { color: var(--muted); font-size: .78rem; white-space: nowrap; }
.f-tag {
  font-size: .68rem; color: var(--muted);
  border: 1px solid var(--border); border-radius: 999px; padding: .05rem .45rem;
  white-space: nowrap;
}
.f-go { color: var(--accent); }
.files-note { font-size: .76rem; color: var(--muted); margin-block: .45rem 0; }
.slow-note { display: block; font-size: .78rem; color: var(--muted); margin-block-start: .25rem; }

/* ---------- legible by default, mobile and desktop alike ----------
   One design language everywhere, not a phone-only look and a separate
   desktop one: bigger type, higher-contrast muted text, roomier click
   targets, a stronger focus ring. This used to be desktop-only, paired
   with an unrelated dark/gold theme forced onto small screens; that split
   is gone; a phone and a laptop should feel like the same site. */
body { font-size: 1.1rem; line-height: 1.65; }

h1 { font-size: 1.3rem; }
.section { font-size: 1.05rem; }

button, input[type="search"], input[type="text"], select {
  font-size: 1rem;
  padding: .7rem .95rem;
}

.card, .portal, .stat { padding: 1rem 1.2rem; }
.portal-grid, .stat-row { gap: .85rem; }
.stat-n { font-size: 1.75rem; }
.stat-l { font-size: .88rem; }

.tag, .badge { font-size: .8rem; padding: .2rem .65rem; }

.matrix th, .matrix td { padding: .6rem .85rem; font-size: .92rem; }

a:focus-visible, button:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

/* Small screens still need less padding and a shorter first screen - that's
   real estate, not a different design language, so it stays viewport-based
   while reading colour from whichever theme is active. */
@media (max-width: 640px) {
  .card, .portal, .stat { padding: .85rem 1rem; }
  .wrap { padding-block: 1.5rem 4.5rem; }

  /* Grouped charts (local-finance.html's revenue/per-capita/liabilities,
     welfare.html's payments/recipients) need up to ~520px of bar-group width
     with a compare authority set - fine on desktop, wider than most phone
     screens. Bar height already shrinks in charts.js itself (inline styles,
     not reachable from CSS); this half is the width side of the same fix -
     narrower bars and tighter gaps so a full compare-mode chart has a real
     chance of fitting without .fin-chart-plot's own overflow-x:auto kicking
     in and silently scrolling part of it out of view. */
  .fin-chart-bar { inline-size: 6px; }
  .fin-chart-bars { gap: 2px; }
  .fin-chart-bars-wrap { gap: .3rem; }

  /* local-finance.html's compare slots #2/#3 (finCompare2/finCompare3) -
     desktop only. Even with the narrower bars just above, a 4-way grouped
     chart (main + 3 compares, 8 bars per year) has no real room on a phone
     screen, so mobile keeps exactly the single #1 compare field it always
     had - see renderAuthorityCharts()'s own matchMedia check in
     local-finance.js, which drops anything past that first slot for the
     same reason even if it's still sitting in the URL from a desktop visit. */
  .fin-compare-extra { display: none; }
  .fin-chart-plot { gap: .8rem; }

  /* The per-year "64% מ-רעננה" header doesn't fit above a narrowed bar
     group, so the compare-name half drops to its own line. The pct row is
     what keeps every column's plot zone aligned (see .fin-chart-pct's
     desktop comment), so ALL pct rows - including the empty ones and the
     axis placeholder - get the two-line height, not just columns that
     actually have a compare label. */
  .fin-chart-pct { block-size: 2.2rem; }
  .fin-chart-pct-name { display: block; }

  /* local-finance's per-authority data tables: the identity columns (שנה,
     plus רשות in compare mode - both carry .fin-city-cell / the row th) stay
     pinned while the value columns scroll under them, and the type drops
     below the site-wide mobile .92rem so more columns fit before scrolling
     starts at all. Pinned cells need OPAQUE backgrounds - the tint
     tr.fin-row-compare uses is over `transparent`, and scrolled columns
     would ghost straight through it. */
  #finAuthTable .matrix th, #finAuthTable .matrix td,
  #finLiabTable .matrix th, #finLiabTable .matrix td,
  #finAreasTable .matrix th, #finAreasTable .matrix td {
    font-size: .8rem;
    padding: .5rem .55rem;
  }
  #finAuthTable .matrix tbody th, #finAuthTable .matrix thead th:first-child,
  #finLiabTable .matrix tbody th, #finLiabTable .matrix thead th:first-child,
  #finAreasTable .matrix tbody th, #finAreasTable .matrix thead th:first-child {
    position: sticky; inset-inline-start: 0; z-index: 2;
    /* fixed width so the city column's own sticky offset below lines up */
    inline-size: 3.2rem; min-inline-size: 3.2rem;
    background: var(--bg);
  }
  #finAuthTable .matrix .fin-city-cell,
  #finLiabTable .matrix .fin-city-cell,
  #finAreasTable .matrix .fin-city-cell {
    position: sticky; inset-inline-start: 3.2rem; z-index: 2;
    background: var(--bg);
  }
  #finAuthTable .matrix thead th:first-child, #finAuthTable .matrix thead th.fin-city-cell,
  #finLiabTable .matrix thead th:first-child, #finLiabTable .matrix thead th.fin-city-cell,
  #finAreasTable .matrix thead th:first-child, #finAreasTable .matrix thead th.fin-city-cell {
    z-index: 3;
    background: var(--surface);
  }
  #finAuthTable .matrix tr.fin-row-compare .fin-city-cell,
  #finLiabTable .matrix tr.fin-row-compare .fin-city-cell,
  #finAreasTable .matrix tr.fin-row-compare .fin-city-cell {
    background: color-mix(in srgb, var(--muted) 16%, var(--bg));
  }

  /* plan-timeline.html/plan-compare.html's per-plan list (renderPlanListHtml,
     shared by both - see src/plan-render.js): same pinned-identity-column
     idiom as #finAuthTable above, this table's own two identity columns
     (the ▾/▴ toggle, then שם תכנית) stay put while מספר תכנית/סטטוס/ימים/
     שטח scroll under them. Scoped to .plan-list-wrap specifically (not
     every .matrix.preview.expandable table site-wide, which committees.js/
     companies.js/tree-canopy.js also use with different column layouts).
     Excludes tr.detail-row - its own <td colspan="6"> is one single cell
     spanning the whole row, not "column 1", and pinning it would clip the
     expanded step-timeline content instead of the two identity columns. */
  .plan-list-wrap .matrix thead th:nth-child(1),
  .plan-list-wrap .matrix tbody tr.has-detail > td:nth-child(1) {
    position: sticky; inset-inline-start: 0; z-index: 2;
    background: var(--bg);
  }
  .plan-list-wrap .matrix thead th:nth-child(2),
  .plan-list-wrap .matrix tbody tr.has-detail > td:nth-child(2) {
    position: sticky; inset-inline-start: 1.6rem; z-index: 2;
    background: var(--bg);
  }
  .plan-list-wrap .matrix thead th:nth-child(1),
  .plan-list-wrap .matrix thead th:nth-child(2) {
    z-index: 3;
    background: var(--surface);
  }

  /* The one button on the page meant to be found without scrolling first -
     filled rather than outlined, so it reads as the next step rather than
     one option among the portal cards above it. */
  .more summary.more-toggle {
    display: block;
    text-align: center;
    background: var(--accent);
    color: var(--bg);
    border: 1px solid var(--accent);
    border-radius: 999px;
    padding: .75rem 1rem;
    margin-block: 1.5rem;
    font-weight: 600;
  }
}

/* ---------- theme: fashion (opt-in) ----------
   The alternate look from the theme picker in the header - black, gold and
   serif, with a gold sheen on the title and on button hover/tap. Available
   at any screen size now, not forced onto phones: see src/theme.js for how
   [data-theme] gets set. */
[data-theme="fashion"] {
  --bg: #0d0b08;
  --fg: #f3ecdc;
  --muted: #b7a67f;
  --border: #3c3320;
  --accent: #ddb44f;
  --surface: #18140d;
  --danger: #d2685a;
  /* Missing from this list until now - every var(--card) consumer (score
     gauges, notices, stat tiles, etc.) fell through to whatever --card
     resolved to elsewhere (the light theme's white, or the OS-dark media
     query's forest-green #142018 if the OS itself preferred dark) instead
     of this theme's own palette - a warm near-black bg needs its own
     raised-surface tone, not a mismatched green or plain white. */
  --card: #221c12;
  --radius: 3px;
  --font-display: Georgia, "David", "Times New Roman", serif;
}

[data-theme="fashion"] body { letter-spacing: .01em; }

/* Section titles and card/portal names carry the "fashion editorial" voice:
   serif, tracked, quiet weight. Everything that is UI chrome (buttons,
   tags, labels) stays sans but gains the same tracking instead - that
   split is what a fashion-house site actually looks like. Header h1 used
   to be in this list too - split out below, since app pages now opt out
   of the whole fashion header treatment, this one included. */
[data-theme="fashion"] .section,
[data-theme="fashion"] .card h3, [data-theme="fashion"] .card h3 a,
[data-theme="fashion"] .p-name, [data-theme="fashion"] .ck-title,
[data-theme="fashion"] .drill-head h2,
[data-theme="fashion"] .ck-detail h3 {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: .03em;
}

/* The "flat, high-contrast editorial header" special case that used to
   apply to index.html's header in fashion (night) mode has been removed by
   request - every page, index.html included, now keeps the exact same
   header look/font in every theme. Picking night changes colors, not
   layout or type size, anywhere on the site. */
[data-theme="fashion"] .meta { color: #b0bec5; }
[data-theme="fashion"] .theme-pick button {
  background: #333333;
  color: #ffffff;
  border: 1px solid #555555;
  border-radius: 16px;
  padding: 4px 12px;
}

[data-theme="fashion"] .section {
  display: flex; align-items: center; gap: .7rem;
  text-transform: uppercase; letter-spacing: .18em; font-weight: 400;
  color: var(--muted);
}
[data-theme="fashion"] .section::after { content: ''; flex: 1; block-size: 1px; background: var(--border); }

/* Hairline borders + a soft gold lift on the surfaces that matter - cards,
   portals, stat tiles, the explorer panel. Status colour on the leading
   edge (.card.api, .stat, tr.row) is left alone: it's the one thing on the
   page carrying meaning, not decoration. */
[data-theme="fashion"] .card, [data-theme="fashion"] .portal,
[data-theme="fashion"] .ckan, [data-theme="fashion"] .explorer, [data-theme="fashion"] .drill,
[data-theme="fashion"] .matrix-wrap, [data-theme="fashion"] .ck-card {
  background: linear-gradient(180deg, var(--surface), var(--bg));
  border-color: var(--border);
}
/* .stat gets its own flat panel per request, instead of the gradient lift
   every other surface above gets - deliberately placed AFTER that shared
   rule (same [data-theme="fashion"] .x specificity throughout this file,
   so source order is the tiebreak) rather than relying on being edited
   in place, since a future edit to the shared rule shouldn't silently
   swallow this one back. */
[data-theme="fashion"] .stat {
  background: #242424;
  border-color: #383838;
  border-radius: 8px;
  color: #ffffff;
}
[data-theme="fashion"] .portal:hover, [data-theme="fashion"] .ck-card:hover {
  border-color: var(--accent);
  box-shadow: 0 6px 20px -12px color-mix(in srgb, var(--accent) 70%, transparent);
}
[data-theme="fashion"] .portal.active, [data-theme="fashion"] .stat.active {
  box-shadow: inset 0 0 0 1px var(--accent), 0 0 16px -6px color-mix(in srgb, var(--accent) 60%, transparent);
}

[data-theme="fashion"] .tag, [data-theme="fashion"] .badge, [data-theme="fashion"] .drill-scope,
[data-theme="fashion"] .ck-n, [data-theme="fashion"] .f-tag {
  text-transform: uppercase;
  letter-spacing: .05em;
}
[data-theme="fashion"] .badge.ok { box-shadow: 0 0 10px -4px color-mix(in srgb, #5fce8f 70%, transparent); }

/* Buttons: tracked uppercase, thin gold hairline, a sheen that sweeps on
   hover for a mouse and on :active for a thumb - a touch has no hover. */
[data-theme="fashion"] button, [data-theme="fashion"] .ex-method, [data-theme="fashion"] .ck-crumb {
  position: relative;
  overflow: hidden;
  text-transform: uppercase;
  letter-spacing: .07em;
}
[data-theme="fashion"] button::after, [data-theme="fashion"] .ex-method::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 30%, color-mix(in srgb, var(--accent) 55%, transparent) 50%, transparent 70%);
  background-size: 250% 100%;
  background-position: 150% 0;
  transition: background-position .7s ease;
  pointer-events: none;
}
[data-theme="fashion"] button:hover:not(:disabled)::after, [data-theme="fashion"] button:active:not(:disabled)::after,
[data-theme="fashion"] .ex-method:hover::after, [data-theme="fashion"] .ex-method:active::after { background-position: -50% 0; }

[data-theme="fashion"] button:hover:not(:disabled), [data-theme="fashion"] button:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 4px 16px -10px color-mix(in srgb, var(--accent) 70%, transparent);
}

[data-theme="fashion"] .ck-open, [data-theme="fashion"] .ck-dl, [data-theme="fashion"] .drill-dl,
[data-theme="fashion"] .pager .pg.cur {
  border-color: var(--accent);
  box-shadow: 0 4px 14px -8px color-mix(in srgb, var(--accent) 65%, transparent);
}

[data-theme="fashion"] input[type="search"], [data-theme="fashion"] input[type="text"], [data-theme="fashion"] select {
  background: color-mix(in srgb, var(--surface) 70%, var(--bg));
}
[data-theme="fashion"] input[type="search"]:focus, [data-theme="fashion"] input[type="text"]:focus,
[data-theme="fashion"] select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}

[data-theme="fashion"] .lead { font-family: var(--font-display); line-height: 1.7; }

/* ---------- theme: zebra (opt-in) ----------
   Third theme picker option, alongside the default "יום" (day - unset
   data-theme) and "לילה" (night - [data-theme="fashion"]) above: a strict
   black/white/gray look, no hue anywhere - even --danger is a plain red-gray
   rather than the forest theme's berry, since a coloured accent would break
   the monochrome premise. Status colour (badge ok/warn/bad/limited, chart
   bars) is deliberately left alone here too, same reasoning as the fashion
   theme above: it carries meaning, not mood, so every theme leaves it as-is. */
[data-theme="zebra"] {
  --bg: #ffffff;
  --fg: #111111;
  --muted: #5c5c5c;
  --border: #cfcfcf;
  --accent: #111111;
  --surface: #f0f0f0;
  --danger: #a30000;
  --card: #ffffff;
  --radius: 6px;
}

/* The literal zebra stripe, as a band under an otherwise flat black header -
   the whole header can't be striped edge-to-edge (text over alternating
   black/white would be unreadable), so the stripe is confined to a band via
   a positioned ::after rather than the header's own background. */
[data-theme="zebra"] header.site {
  position: relative;
  border-radius: 0;
  background: #000;
  box-shadow: none;
  padding-block-end: calc(1.1rem + 10px);
}
[data-theme="zebra"] header.site::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: 10px;
  background: repeating-linear-gradient(135deg, #fff 0 14px, #000 14px 28px);
}
[data-theme="zebra"] header.site h1 { color: #fff; }
[data-theme="zebra"] header.site a { color: #fff; text-decoration: underline; }
[data-theme="zebra"] header.site a:hover { color: #ccc; }
[data-theme="zebra"] header.site .site-by { color: #cccccc; }
[data-theme="zebra"] header.site .meta { color: #cccccc; }
[data-theme="zebra"] header.site .theme-pick button {
  background: rgba(255, 255, 255, .12);
  color: #fff;
  border-color: rgba(255, 255, 255, .4);
}
[data-theme="zebra"] header.site .theme-pick button[aria-pressed="true"] {
  background: #fff;
  color: #000;
  border-color: #fff;
}

[data-theme="zebra"] .card,
[data-theme="zebra"] .portal,
[data-theme="zebra"] .stat,
[data-theme="zebra"] .ck-card {
  box-shadow: none;
  border-width: 1px;
  border-color: #000;
}
[data-theme="zebra"] .card h3 a,
[data-theme="zebra"] .p-open,
[data-theme="zebra"] .drill-home,
[data-theme="zebra"] .cm-doclist a {
  text-decoration: underline;
}

[data-theme="zebra"] button,
[data-theme="zebra"] .ex-method,
[data-theme="zebra"] .ck-crumb {
  border-color: #000;
}
[data-theme="zebra"] button:hover:not(:disabled),
[data-theme="zebra"] button:focus-visible {
  background: #000;
  color: #fff;
  border-color: #000;
}
[data-theme="zebra"] .ck-open,
[data-theme="zebra"] .ck-dl,
[data-theme="zebra"] .drill-dl,
[data-theme="zebra"] .pager .pg.cur {
  border-color: #000;
}

/* ---------- accidents/committees/finance/companies/welfare/blue-lines ----------
   These pages each used to carry their own --accent mood (warning orange,
   neutral gray, gold, lemon, terracotta, blue) plus, for accidents and
   committees, a striped header background. Removed by explicit request: the
   whole site now shares one scheme (see :root and header.site above),
   matching the reference page exactly rather than varying per page. */

/* Centered on this page specifically - the map's header stays a normal
   start-aligned row with a byline/theme-pick/probed-stamp cluster; this
   page's header only has the title and controls, so a centered title reads
   as a page heading rather than a squeezed-in item in a row. */
body.accidents-page header.site .wrap { justify-content: center; text-align: center; }
body.accidents-page header.site h1 { inline-size: 100%; }

.acc-year-pick { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-block-end: 1.25rem; }
/* Same fix as .cm-map-exit-fullscreen[hidden]/#trStopConfirm[hidden]
   elsewhere in this file - this class's own `display: flex` is author-origin
   and beats the UA [hidden]{display:none} rule regardless of specificity,
   so an .acc-year-pick row with the `hidden` attribute set stays visually
   flex-displayed unless explicitly overridden here. arnona-compare.js is the
   first caller that actually toggles .acc-year-pick rows via .hidden at
   runtime (every other page's .acc-year-pick rows are permanently visible
   filter controls) - confirmed live, computed display stayed "flex" with
   hidden=true until this rule was added. */
.acc-year-pick[hidden] { display: none; }
/* inline-flex, not the default inline flow: a checkbox/radio followed by its
   label text needs the checkbox to land first (the RTL start edge) with the
   text immediately after it - relying on plain bidi reordering of a replaced
   form control next to text is inconsistent across engines. This also keeps
   a lone text label (blAddress/blRadius, no nested input) unaffected, since
   inline-flex with a single child renders identically to inline. */
.acc-year-pick label { font-size: .9rem; color: var(--muted); display: inline-flex; align-items: center; gap: .4rem; }
.acc-year-pick select,
/* Text/number inputs only - a checkbox/radio must keep its native intrinsic
   size, not the 16rem search-field width below (that rule used to apply to
   every input here, forcing each checkbox's own flex item to claim a
   256px-wide box and pushing every option onto its own line). */
.acc-year-pick input:not([type="checkbox"]):not([type="radio"]) {
  font: inherit;
  font-size: .9rem;
  padding: .35rem .6rem;
  color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.acc-year-pick input:not([type="checkbox"]):not([type="radio"]) { min-inline-size: 16rem; }

/* blue-lines.html's four display-option checkboxes, stacked one per line -
   overrides .cm-filters .acc-year-pick's flex-wrap:nowrap (needs the ID's
   higher specificity to win). A single scrolling row was tried first, but
   with the longest label (תחום השפעת מטרו...) that meant most of the row
   was scrolled out of view rather than readable at a glance - a plain
   vertical stack keeps every option fully visible without scrolling. */
#blDisplayOpts { flex-direction: column; align-items: flex-start; flex-wrap: wrap; gap: .5rem; }

/* blue-lines.html's search-mode row: on desktop, both the address radio+
   field and the plan radio+field sit in one row - the inactive field is
   disabled rather than removed, so switching modes doesn't reflow anything
   (see updateSearchModeFields() in blue-lines.js). Wraps normally on
   mobile, since two 16rem-min-width text inputs plus their radio labels
   can't fit one row on a phone regardless - and there, the disabled field
   is hidden outright rather than shown as a control nobody can use. */
#blSearchRow { flex-wrap: wrap; }
#blSearchRow input:disabled { opacity: .45; }
@media (min-width: 641px) {
  /* flex-basis:100% - its own full-width line within .cm-filters, so
     רדיוס/checkboxes always wrap to the next line rather than packing in
     beside it when there happens to be room. */
  #blSearchRow { flex-basis: 100%; flex-wrap: nowrap; }
}
@media (max-width: 640px) {
  #blSearchRow input:disabled { display: none; }
}

/* The city field's own suggestion dropdown (accidents.js), standing in for a
   native <datalist> - that popup is OS/browser-drawn and ignores dir="rtl"
   (shows up left-anchored and LTR on Linux/GTK Chrome), so it can't be fixed
   from here. .ac-wrap just gives the menu something positioned to hang off. */
.ac-wrap { position: relative; inline-size: 100%; }
.ac-menu {
  position: absolute;
  inset-inline: 0;
  top: 100%;
  z-index: 20;
  margin: .25rem 0 0;
  padding: .25rem;
  list-style: none;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  max-block-size: 16rem;
  overflow-y: auto;
  box-shadow: 0 4px 12px rgba(0, 0, 0, .12);
}
.ac-menu li { padding: .4rem .6rem; border-radius: 6px; cursor: pointer; text-align: start; }
.ac-menu li:hover, .ac-menu li.active { background: var(--surface); }

/* Shown in the city panel before a city is picked. */
.acc-hint { color: var(--muted); font-size: .9rem; margin: .5rem 0; }

[data-theme="fashion"] .more summary.more-toggle {
  background: linear-gradient(180deg, var(--accent), color-mix(in srgb, var(--accent) 80%, #000));
  text-transform: uppercase;
  letter-spacing: .1em;
  font-weight: 400;
}

/* blue-lines.html/area-cleanup.html: the composited map canvas. Native pixel
   size is fixed (matches the export/basemap resolution), scaled down
   responsively via CSS rather than re-rendered - a canvas's CSS size and its
   drawing-buffer size are independent, so this never blurs the pixels that
   matter. */
.bl-map-wrap { text-align: center; margin-block-end: 1rem; }
#blCanvas, #acCanvas {
  max-inline-size: 100%;
  block-size: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* area-cleanup.html's attached-photo strip (src/area-cleanup.js addPhotos) -
   each thumbnail is a plain <img> (so a phone photo's own EXIF orientation
   renders the same way it will once baked into the PDF page, see
   photoToPage) with a small ✕ overlaid in the corner rather than a separate
   row of remove buttons below, since a photo removed here is removed from
   the PDF the same click builds. */
.ac-photo-thumbs {
  display: flex; flex-wrap: wrap; gap: .6rem; justify-content: center;
  margin-block-end: .75rem;
}
.ac-photo-thumb { position: relative; display: block; inline-size: 5.5rem; block-size: 5.5rem; }
.ac-photo-thumb img {
  inline-size: 100%; block-size: 100%; object-fit: cover;
  border: 1px solid var(--border); border-radius: var(--radius);
}
.ac-photo-remove {
  position: absolute; inset-block-start: -.4rem; inset-inline-end: -.4rem;
  inline-size: 1.4rem; block-size: 1.4rem; padding: 0; line-height: 1;
  border-radius: 999px; border: 1px solid var(--border);
  background: var(--card); color: var(--danger); cursor: pointer;
}

/* pdf-to-image.html's per-page result grid - one converted page per card,
   preview image sized to fit rather than cropped (unlike .ac-photo-thumb
   above, this IS the actual export, not a square avatar). */
.pti-grid { display: flex; flex-wrap: wrap; gap: .8rem; }
.pti-thumb {
  display: flex; flex-direction: column; align-items: center; gap: .4rem;
  inline-size: 11rem; padding: .5rem; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--surface);
}
.pti-thumb img {
  inline-size: 100%; max-block-size: 14rem; object-fit: contain;
  border: 1px solid var(--border); border-radius: var(--radius); background: #fff;
}
.pti-thumb button { font-size: .78rem; word-break: break-all; }
.pti-thumb-error { color: var(--danger); font-size: .85rem; justify-content: center; text-align: center; }

/* area-cleanup.html is meant to be used one-handed on a phone, standing
   somewhere pointing a camera-adjacent screen at a problem spot - not read
   carefully at a desk - so its controls and result text get a real size
   bump on mobile rather than the site's normal (desk-sized) touch targets. */
@media (max-width: 640px) {
  .area-cleanup-page button, .area-cleanup-page input[type="text"] {
    font-size: 1.15rem;
    padding: .9rem 1.15rem;
  }
  .area-cleanup-page #acResult, .area-cleanup-page .acc-hint {
    font-size: 1.05rem;
  }
  .area-cleanup-page h2 { font-size: 1.3rem; }
}

.ac-address-row { display: flex; flex-direction: column; align-items: stretch; flex-basis: 100%; }
/* On desktop, align-items:stretch above otherwise stretches the submit
   button to the full width of the address input above it - fine (even
   wanted) on mobile's big one-handed touch targets, but on a desk-sized
   screen it reads as a giant button for two words. Shrinking it back to its
   own natural pill size (.drill-dl's own small font/padding, unstretched). */
@media (min-width: 641px) {
  .ac-address-row .ac-submit { align-self: center; inline-size: max-content; }
}

/* tree-canopy.html's city/neighborhood/street level picker - same pill
   shape as .ck-open, but only the active one is filled; the other two stay
   outlined so it reads as a 3-way toggle, not three buttons. */
.tc-level-btn {
  font: inherit; font-size: .85rem; padding: .4rem 1rem; cursor: pointer;
  color: var(--fg); background: var(--card); border: 1px solid var(--border); border-radius: 999px;
}
.tc-level-btn:hover { border-color: var(--accent); }
.tc-level-btn.active {
  color: var(--bg); background: var(--accent); border-color: var(--accent); font-weight: 600;
}
/* A trailing "(...)" qualifier (mortality-compare.js's metricButtonLabel) on
   its own line, smaller/muted, so it doesn't read as run-on with the main
   label or a neighboring button's own text. */
.cm-metric-qualifier { display: block; font-size: .75em; opacity: .75; font-weight: 400; }
.tc-level-btn.active .cm-metric-qualifier { opacity: .9; }

/* The leaderboard shows up to 30 rows (vs. the usual 10) - scrolls in its
   own box, same "long content, fixed-height box" treatment as
   .matrix-wrap.scroll elsewhere on the site, so the page itself doesn't
   grow to fit whichever level currently has the longest leaderboard. */
.tc-board-scroll { max-block-size: 32rem; overflow-y: auto; }
.tc-board-scroll .acc-hbars { padding-inline-end: .3rem; }
/* Same scrolling idiom as .tc-board-scroll above, capped to ~15 visible
   rows instead of 32rem (user request) - used by police-compare.html's
   "דירוג לפי סוג עבירה" board and mortality-compare.html's own #cityBoardCharts,
   both per-metric city leaderboards that can run to 100+ cities. */
.tc-board-scroll-15 { max-block-size: 28.5rem; }
/* The caption (which entity/metric this ranks) stays visible while
   scrolling through up to ~27,700 rows, instead of scrolling away after
   the first screenful. */
.tc-board-scroll figcaption { position: sticky; inset-block-start: 0; background: var(--bg); padding-block: .3rem; z-index: 1; }

/* police-compare.html's own "דירוג לפי סוג עבירה" category picker - a
   fixed 3-column table/grid instead of .cm-filters's own flex-wrap (which
   packs a variable number of pills per row depending on each label's own
   width) - 13 options read better as a stable NxM grid than a ragged wrap
   (user request). Scoped to this one filter group by ID, not a change to
   .cm-filters itself (every other filter row on the site still wraps).
   Desktop only (user request) - the longest option ("נגד אדם (רצח,
   הריגה)") wraps to 2 lines inside its own cell on a narrow phone screen
   while its neighbors stay 1 line, an unevenness that reads worse than
   just letting mobile keep the plain flex-wrap it had before. */
@media (min-width: 641px) {
  #pcCategoryPick { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; }
  #pcCategoryPick .tc-level-btn { text-align: center; }
}

/* One drill-in group per compared city (up to 4), each tagged with the same
   color swatch used for that city everywhere else on the page. */
.tc-drill-group { display: inline-flex; align-items: center; gap: .4rem; flex-wrap: wrap; margin-inline-end: 1rem; }

/* .acc-hbar-y's shared 8rem width (see charts.js/renderHBarChart) truncates
   most neighborhood/street labels here - they carry a city name alongside
   the name itself ("מעוז אביב, תל אביב - יפו"), routinely longer than any
   label the chart was originally sized for elsewhere on the site. Widened
   only for this page rather than changing the shared 8rem for every other
   page's (shorter) labels. */
.tree-canopy-page .acc-hbar-y { flex-basis: 17rem; }
@media (max-width: 640px) {
  .tree-canopy-page .acc-hbar-y { flex-basis: 9rem; }
}

/* police-compare.html (also .tree-canopy-page - shares that page shell)
   shows plain city/neighborhood names in these 2 sections, not the long
   combined labels the 9rem mobile width above was sized for - .acc-hbar-y's
   own text-align:end sits a short name against the box's INNER edge (by the
   bar), not the row's own right edge, leaving a bare gap before it on a
   narrow phone screen. Flipped to start so it hugs the right edge instead -
   safe for longer labels too, since text-overflow:ellipsis truncation is
   unaffected by text-align (user request, mobile only). #pcCompareSection
   isn't listed here - it gets its own always-on fix below instead. */
@media (max-width: 640px) {
  #pcBoardSection .acc-hbar-y, #pcCategoryBoardChart .acc-hbar-y { text-align: start; }
}

/* mortality-compare.html's own #cityBoardCharts - same gap-before-a-short-
   name issue as police-compare.html above (also .tree-canopy-page), same
   fix. Unlike police-compare's mobile-only fix, this one's unconditional -
   the reserved label column is wide enough (17rem desktop) that the gap
   shows at any width, not just on a narrow phone (user request: "all
   views"). */
#cityBoardCharts .acc-hbar-y { text-align: start; }

/* #pcCompareSection's own leaderboard-style charts (compare bars, category
   breakdown, single-city neighborhood board): instead of a fixed label
   column width, shrink-wrap it to the longest city/category name actually
   on screen, so the bar starts a small fixed gap after that name rather
   than a wide reserved column leaving shorter names stranded with visible
   empty space before the bar (user request: "start 2 places after the
   longest city name"). `.acc-hbar` normally lays out each row as its OWN
   flex row (see charts.js's renderHBarChart); `display:contents` erases
   that wrapper from the box tree so its 3 children (name/track/value)
   become direct grid items instead, letting `.acc-hbars`'s own
   grid-template-columns size the label column to the widest label across
   EVERY row at once (same idea as a normal HTML <table>'s auto column
   sizing) - not achievable with per-row flex-basis, which only sees one
   row at a time. Column order matches the page's own dir=rtl (name column
   first = rightmost, value column last = leftmost), same visual order this
   already had under flexbox. */
#pcCompareSection .acc-hbars {
  display: grid;
  /* minmax(0, 1fr), not bare 1fr - a bare 1fr track won't shrink below the
     track's own min-content size, so the whole row silently overflows its
     container instead of the middle (bar) column actually shrinking. */
  grid-template-columns: max-content minmax(0, 1fr) max-content;
  column-gap: 1.2rem;
  row-gap: .4rem;
  align-items: center;
}
#pcCompareSection .acc-hbar { display: contents; }
#pcCompareSection .acc-hbar-y { flex: unset; text-align: start; }
#pcCompareSection .acc-hbar-group-header { grid-column: 1 / -1; }

/* The 4 pick fields fill column-by-column (grid-auto-flow: column) rather
   than row-by-row: pick 1 sits directly above pick 2, and pick 3 directly
   above pick 4, instead of 1/2 sharing the top row and 3/4 the bottom one. */
#tcPicks {
  display: grid;
  grid-template-columns: repeat(2, minmax(14rem, 1fr));
  grid-template-rows: repeat(2, auto);
  grid-auto-flow: column;
  gap: .5rem 1.5rem;
}
@media (max-width: 640px) {
  #tcPicks { grid-template-columns: 1fr; grid-auto-flow: row; }
}

/* canopy-map.html - the SVG (always drawn) and the optional OSM basemap
   canvas share exactly one footprint, the canvas absolutely positioned
   behind the SVG rather than the two sitting in normal flow, so toggling
   the basemap on/off never reflows the shapes above it. */
.cm-map-wrap {
  /* 30% smaller than the original 45rem (user request) - both this cap
     and .cm-leaflet-map's own max-block-size below are scaled by the same
     .7 factor, in both this base rule and the desktop media query further
     down, so the map shrinks proportionally at every breakpoint rather
     than just getting shorter or just narrower. */
  position: relative; max-inline-size: 31.5rem; margin-inline: auto;
  border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
}
/* Leaflet mounts itself into this div (see initMap() in canopy-map.js) -
   same fixed-aspect-ratio + vh-cap box the old hand-rolled #cmSvg used
   (Israel's own bbox is ~1:2.9 tall/narrow, a picked city's closer to 1:1 -
   letting the box's own height track whatever's shown, e.g. block-size:
   auto, previously ballooned to ~2900px tall on the national view alone),
   but no cursor/touch-action rules of its own - Leaflet manages its own
   drag cursor and gesture handling internally. */
.cm-leaflet-map { display: block; inline-size: 100%; aspect-ratio: 1 / 1; max-block-size: 45.5vh; }
/* Long-press on a touch device is this page's own "open compare page"
   gesture (see wireFeature() in canopy-map.js) - without this, the SAME
   touch-and-hold also triggers the phone's own native image/selection
   callout (Leaflet's tiles are plain <img> elements, its shapes real SVG
   <path>s) - a popup that lands whereever the OS puts it, over whichever
   control happens to sit there, well before our own 550ms timer fires.
   -webkit-touch-callout covers Safari's version; user-select covers the
   Android text/shape "selection handles" flavor of the same problem. */
.cm-leaflet-map, .cm-leaflet-map img, .cm-leaflet-map svg, .cm-leaflet-map path {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
  user-select: none;
}
.cm-map-wrap.cm-map-fullscreen .cm-leaflet-map { aspect-ratio: auto; max-block-size: none; inline-size: 100%; block-size: 100%; }
/* Desktop has the screen real estate to spare - x1.5 both the width cap
   (.cm-map-wrap's own max-inline-size) and the height cap together, so the
   1:1 aspect ratio can actually grow into the extra width rather than
   staying clipped at the base 45.5vh ceiling. Mobile keeps the smaller size -
   this page's own embedded (non-fullscreen) map is already a tight fit
   next to the rest of the controls on a narrow screen. */
@media (min-width: 641px) {
  .cm-map-wrap:not(.cm-map-fullscreen) { max-inline-size: 47.25rem; }
  .cm-map-wrap:not(.cm-map-fullscreen) .cm-leaflet-map { max-block-size: 68.25vh; }
}
/* Per-feature style className (see the GeoJSON layer's own `style` callback
   in canopy-map.js) - Leaflet already adds its own leaflet-interactive
   class to every clickable vector layer; this is just the hook for OUR
   hover styling, same look the old hand-rolled #cmSvg path:hover had. */
.cm-leaflet-shape:hover, .cm-leaflet-shape:focus-visible { stroke: var(--fg) !important; stroke-width: 1.2 !important; outline: none; }
/* Leaflet's own L.tileLayer `className` option (see updateTileLayer() in
   canopy-map.js) - Esri's World Topo Map ships noticeably paler/lower-
   contrast than the street/aerial sources, same reasoning and same values
   as geo-utils.js's own canvas-based contrast boost for the OLDER (still
   used by blue-lines.js/area-cleanup.html/trip-report.html) address-lookup
   basemap stitcher - this is the live-tile-layer equivalent of that fix. */
.cm-tile-topo { filter: contrast(1.35) saturate(1.15); }
/* Once a real basemap (street/aerial/topo tiles) is showing underneath, the
   heat/canopy blob rasters compete with the tile imagery's own colors and
   read as washed out. A contrast INCREASE (tried first, same idiom as
   .cm-tile-topo above) made this worse, not better - confirmed live: most
   of this palette's own pixels are already lighter than mid-gray, so
   pushing contrast up pushes them further toward white instead of making
   them pop. Contrast below 1 pulls every pixel back toward mid-gray
   instead, which darkens (and so makes more visible) exactly those pale
   pixels; saturate still boosts the actual hue once it's no longer so
   close to white. Scoped by the .cm-osm-active class updateTileLayer()
   toggles on the map container (see canopy-map.js) rather than baked into
   the overlay images at creation time, since those images are cached/reused
   across a basemap toggle - a pure-CSS ancestor class picks up every
   already-added overlay too, not just ones created after the toggle. */
/* 25% stronger color across the board - saturate(1.25) alone against the
   plain page background (no basemap, the default view), stacked into the
   .cm-osm-active contrast fix's own saturate below (1.5 * 1.25 = 1.875)
   once a basemap is showing underneath. */
.leaflet-cmBlob-pane img { filter: saturate(1.25); }
.cm-osm-active .leaflet-cmBlob-pane img { filter: contrast(.7) saturate(1.875); }
/* Interactive strength sliders (cmHeatOpacity/cmCanopyOpacity in canopy-map.js)
   - a plain opacity multiplier on top of the baked-in PNG alpha, independent
   of the filter rules above (different CSS property, no conflict). className
   set per-layer at creation time (updateBlobOverlays() in canopy-map.js), not
   a data attribute or inline style - Leaflet's own imageOverlay sets no
   opacity of its own, so this is a clean, uncontested hook. Custom properties
   default to 1 (full strength, today's look) so the sliders are opt-in fades,
   never a silent behavior change for anyone not touching them. */
.cm-blob-heat { opacity: var(--cm-heat-opacity, 1); }
.cm-blob-canopy { opacity: var(--cm-canopy-opacity, 1); }
/* Same shape as trip-report.html's .tr-sensitivity-row (label + %-value
   span + range input, centered) - a new cm-prefixed class rather than
   reusing .tr-sensitivity-row directly, matching this page's own naming
   for everything else (cm-*), not trip-report's. Two side by side here
   (heat/canopy), each still full-width within its own half. */
.cm-opacity-control { text-align: center; max-inline-size: 20rem; margin-inline: auto; }
.cm-opacity-control label { font-weight: 600; }
/* margin-block .4rem -> .28rem (30% less, user request) - shrinks the
   section's own vertical footprint, the only real "height" a native
   range input's own spacing controls. */
.cm-opacity-control input[type="range"] { width: 100%; margin-block: .28rem; }
/* Side-by-side half-width pair before the map itself (עוצמת השכבות /
   רקע מפה) - flex-wrap so the two stack full-width on a narrow screen
   instead of squeezing to unusable width, matching this page's general
   mobile-stacking approach elsewhere. Each .acc-section's own default
   margin-block-end still applies to the row as a whole; zeroed here on
   the children so it doesn't ALSO add space between the two columns
   themselves. */
.cm-half-row { display: flex; flex-wrap: wrap; gap: 1.5rem; margin-block-end: 2.5rem; }
.cm-half-row > .acc-section { flex: 1 1 18rem; margin-block-end: 0; }

/* z-index needed: #cmMap (the Leaflet container) has no z-index of its own,
   so it never becomes a stacking context - its internal .leaflet-map-pane
   (explicit z-index: 400) escapes into THIS div's own stacking context
   (.cm-map-wrap) and paints above these buttons despite them being later
   in DOM order, since an auto z-index sibling always loses to an explicit
   one. 1000 matches Leaflet's own default control z-index. */
.cm-zoom-controls { position: absolute; z-index: 1000; inset-block-start: .5rem; inset-inline-end: .5rem; display: flex; flex-direction: column; gap: .25rem; }
.cm-zoom-controls button {
  inline-size: 2rem; block-size: 2rem; border-radius: 6px; border: 1px solid var(--border);
  background: var(--card); color: var(--fg); font-size: 1.1rem; line-height: 1; cursor: pointer;
}
.cm-zoom-controls button:hover { border-color: var(--accent); }
/* #cmTopoQuickToggle only - the other zoom-control buttons are momentary
   actions with no on/off state of their own, so this class is otherwise
   unused; pressed reads the same way .tc-level-btn.active already does
   elsewhere on this page (solid accent), for the same "this is currently
   selected" meaning. */
.cm-zoom-controls button.active { background: var(--accent); color: var(--bg); border-color: var(--accent); }

/* Mobile fullscreen takeover (canopy-map.js's enterMapFullscreen/
   exitMapFullscreen) - a tap on the map on a narrow viewport adds
   .cm-map-fullscreen here instead of navigating anywhere or replacing any
   element, so the SAME Leaflet map instance (mapWrap's #cmMap, see
   initMap()) just gets a bigger box - map.invalidateSize() is called right
   after so Leaflet re-measures its own container - the small embedded map
   (max 65vh, further squeezed by the page's other sections) is cramped for
   anything past a glance on a phone; fullscreen gives pan/zoom/tap-to-
   select actual room to work with. inset:0 + a high z-index lifts it above
   the whole page (including the site header) rather than just its own
   section. */
.cm-map-wrap.cm-map-fullscreen {
  position: fixed; inset: 0; z-index: 1000; max-inline-size: none; margin: 0;
  border: none; border-radius: 0; background: var(--bg);
}
.cm-map-exit-fullscreen {
  position: absolute; inset-block-start: .6rem; inset-inline-start: .6rem; z-index: 1001;
  inline-size: 2.6rem; block-size: 2.6rem; border-radius: 50%; border: 1px solid var(--border);
  background: var(--card); color: var(--fg); font-size: 1.3rem; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .25);
}
.cm-map-exit-fullscreen:hover { border-color: var(--accent); }
/* Same fix as #trStopConfirm[hidden] elsewhere in this file - this class's
   own `display: flex` ties the UA [hidden] rule's specificity, and author
   CSS wins ties regardless of the hidden attribute being set, so without
   this override the button stayed visible even while `hidden` (confirmed
   live: it showed up in the map's top corner before this rule existed). */
.cm-map-exit-fullscreen[hidden] { display: none; }

/* Press-and-hold submenu on a city/neighborhood shape (canopy-map.js's own
   showContextMenu()) - a plain <ul> positioned at the cursor/touch point
   via inline left/top (JS-set, clamped to stay inside the viewport),
   styled like a small floating card. */
.cm-context-menu {
  position: fixed; z-index: 1002; margin: 0; padding: .3rem; list-style: none;
  min-inline-size: 12rem; border-radius: 8px; border: 1px solid var(--border);
  background: var(--card); box-shadow: 0 4px 16px rgba(0, 0, 0, .3);
}
.cm-context-menu button {
  display: block; inline-size: 100%; text-align: start; padding: .5rem .7rem;
  border: none; border-radius: 6px; background: none; color: var(--fg);
  font-size: .9rem; cursor: pointer;
}
.cm-context-menu button:hover, .cm-context-menu button:focus-visible { background: var(--surface); outline: none; }
/* Plain data-preview rows (showContextMenu's own {info} item shape) - not
   a button, just a quick "what does this city/neighborhood look like"
   readout above the actionable rows, so the numbers are visible without
   navigating anywhere. */
.cm-context-menu-info {
  padding: .3rem .7rem; color: var(--muted); font-size: .82rem;
  border-block-end: 1px solid var(--border); margin-block-end: .2rem;
}
.cm-context-menu-info:first-child { font-weight: 600; color: var(--fg); }

.cm-legend { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; margin-block-start: .8rem; font-size: .85rem; }
.cm-legend-scale { display: inline-flex; align-items: center; gap: .4rem; }
.cm-legend-bar { inline-size: 8rem; block-size: .7rem; border-radius: 3px; border: 1px solid var(--border); }
.cm-legend-nodata { display: inline-flex; align-items: center; gap: .35rem; color: var(--muted); }
.cm-legend-metric { color: var(--muted); }

.cm-osm-toggle { display: inline-flex; align-items: center; gap: .5rem; cursor: pointer; }

/* canopy-map.html's street/aerial-photo basemap choice, shown only once the
   "רקע מפה אמיתי" checkbox above it is on - same pill shape as
   .tc-level-btn/.cm-level-btn, exclusive (radio-like) between the two. */
.cm-basemap-kind-row { margin-block-start: .6rem; }

/* Mobile-only layout simplification for canopy-map.html (user request) -
   the embedded mobile view is much tighter on vertical space than desktop,
   so several sections get thinner/reordered/hidden here that stay as-is
   on desktop. */
@media (max-width: 640px) {
  /* חום/עצים sliders thinner and closer together - beyond the existing
     30% reduction (.28rem, all breakpoints), tightened further just for
     this narrow view. */
  /* block-size 16px -> 8px (50% thinner, user request) - plain unstyled
     range inputs do respect an explicit height cross-browser, no
     -webkit-appearance reset/custom track needed. label font-size matched
     to the basemap buttons' own mobile size (.82rem, see
     .cm-basemap-kind-row .cm-basemap-btn below) instead of the larger
     default. */
  .cm-opacity-control input[type="range"] { margin-block: .15rem; block-size: 8px; }
  .cm-opacity-control label { font-size: .82rem; }
  .cm-opacity-control { margin-block-end: .3rem; }

  /* "רקע מפה" heading + its explanation hidden - the three basemap
     buttons themselves stay (just shorter labels now, see
     canopy-map.html), freeing the row up for the buttons alone. */
  #osmH, #cmOsmRow > .acc-hint { display: none; }
  /* Shortened labels (רחובות/אוויר/טופוגרפית) should already fit one row,
     but nowrap + tighter padding/font-size makes sure a narrow phone
     doesn't still wrap them - three buttons stacked top-to-bottom would
     be a much worse mobile result than one tight row. */
  .cm-basemap-kind-row { flex-wrap: nowrap; gap: .4rem; margin-block-start: 0; }
  .cm-basemap-kind-row .cm-basemap-btn { padding-inline: .5rem; font-size: .82rem; }

  /* "המפה" heading removed; #cmMapSection's own children reordered via
     flex so the map itself comes first, the reset button lands
     immediately after it, and the "186 ערים..." hint (#cmHint) moves to
     after the map instead of before it - all user-requested. A visual
     reorder only, not a DOM move, so canopy-map.js's plain
     getElementById lookups are unaffected regardless of source order. */
  #mapH { display: none; }
  #cmMapSection { display: flex; flex-direction: column; }
  /* Same [hidden] override this file already needed twice elsewhere
     (.cm-map-exit-fullscreen[hidden]/.acc-year-pick[hidden]) - an
     author `display` value on the same element as the `hidden`
     attribute beats the UA stylesheet's own un-!important'd
     `[hidden]{display:none}` rule by specificity, so without this,
     street level's `mapSection.hidden = true` (renderMap() in
     canopy-map.js) would stop actually hiding the section on mobile. */
  #cmMapSection[hidden] { display: none; }
  /* inline-size:100% explicit, not left to the flex-item default `auto` -
     .cm-map-wrap's own child (#cmMap) is width:100% of ITS parent, and an
     auto-sized flex item with a percentage-sized child is a well-known
     circular-dependency trap several browsers resolve by collapsing both
     to zero width (confirmed live: the map went fully invisible on mobile
     once #cmMapSection became a flex container - real regression this
     introduced, not a pre-existing bug). An explicit 100% here gives the
     flex item a definite size to resolve against instead of an auto one. */
  #cmMapSection > .cm-map-wrap { order: 1; inline-size: 100%; }
  #cmMapSection > #cmFullReset { order: 2; }
  #cmMapSection > #cmHint { order: 3; }
  #cmMapSection > .acc-hint { order: 4; }
  #cmMapSection > #cmLegend { order: 5; }
  #cmMapSection > #cmBlobRow { order: 6; }
  #cmMapSection > #cmCanopyBlobRow { order: 7; }

  /* Comparison-only sections (need 2+ cities picked to say anything
     meaningful) hidden on mobile - keeps the mobile view focused on the
     single-city map instead of sparse/empty comparison UI that's more
     awkward to use on a small screen anyway. */
  #cmChipsSection, #cmDetailSection { display: none; }
}

/* canopy-map.html's "back to the original map" button - same pill shape as
   .tc-level-btn, but never filled/active (it's an action, not a toggle
   with a current-state reading). */
.cm-full-reset {
  font: inherit; font-size: .85rem; padding: .4rem 1rem; cursor: pointer; margin-block-end: .5rem;
  color: var(--fg); background: var(--card); border: 1px solid var(--border); border-radius: 999px;
}
.cm-full-reset:hover { border-color: var(--accent); }

/* canopy-map.html's selection chips - one per picked city/neighborhood/
   street (up to 4), border color matching the same PICK_COLORS hue used
   for that entity's map-highlight stroke and its rows across all three
   detail charts, so the same color means the same entity everywhere. */
.cm-chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.cm-chip {
  display: inline-flex; align-items: center; gap: .4rem; padding: .3rem .6rem;
  border: 1.5px solid; border-radius: 999px; background: var(--card); font-size: .85rem;
}
.cm-chip-remove {
  font: inherit; font-size: .75rem; border: none; background: none; color: var(--muted);
  cursor: pointer; padding: 0; line-height: 1;
}
.cm-chip-remove:hover { color: var(--danger); }

.cm-detail-link { display: block; font-size: .85rem; margin-block: .3rem 1rem; }

/* Intro paragraph collapses behind a normal disclosure triangle, open or
   closed on any width - unlike .more-toggle (index.html's "continue" section)
   this stays clickable after opening, since here the point is a plain
   expand/collapse a visitor can toggle back, not a one-way reveal. */
.lead-details summary {
  cursor: pointer; color: var(--accent); font-weight: 600; font-size: .95rem;
  margin-block-end: .4rem;
}
.lead-details[open] summary { margin-block-end: .6rem; }

/* apps.html's feedback section: always visible, no toggle - same look as
   .lead-details summary (color/weight/size) minus cursor:pointer, since
   there's nothing to click here. */
.plain-section-h { cursor: default; color: var(--accent); font-weight: 600; font-size: .95rem; margin: 0 0 .4rem; }

/* apps.html's embed snippet: the <pre> scrolls on its own (already had
   overflow-x:auto inline) so the copy button stays put beside it rather
   than sliding out of view with a long iframe line. */
.embed-code-wrap { display: flex; align-items: flex-start; gap: .6rem; flex-wrap: wrap; }
.embed-code-wrap pre { flex: 1 1 auto; min-inline-size: 0; margin: 0; }

/* apps.html's feedback form: name/email side by side on anything roomier
   than a phone (matches the two-column pattern already used for cmFrom/
   cmTo in committees.html's own filter bar), stacked below the comment box
   which always gets the full width to itself. */
.feedback-form label { display: block; font-weight: 500; margin-block: .5rem .3rem; }
.feedback-form-row { display: flex; gap: .8rem; flex-wrap: wrap; }
.feedback-form-row > div { flex: 1 1 220px; }
.feedback-form button { margin-block-start: .8rem; }

/* Mobile only, this page only: the drill-in section drops entirely, since
   "צלילה פנימה" assumes room for a button row per compared city a phone-
   width screen doesn't have to spare. Links turn light blue here too,
   closer to the familiar mobile-web link color than --accent's green,
   which reads as body text at this size. */
@media (max-width: 640px) {
  .tree-canopy-page a, .tree-canopy-page a:visited { color: #4fc3f7; }
  .tree-canopy-page #tcDrillSection { display: none; }
}

/* Mobile only: a brief "✓ נטען" beside a pick field once it resolves to a
   real city/neighborhood/street (src/tree-canopy.js showPickConfirm) - the
   comparison itself often sits below the fold on a phone, so a valid pick
   otherwise gives no feedback at all until the visitor scrolls down.
   Desktop sees the chart update right there already, so this stays
   entirely out of layout there. */
.tc-pick-confirm { display: none; }
@media (max-width: 640px) {
  .tc-pick-confirm {
    display: inline-block; font-size: .78rem; font-weight: 600; color: var(--accent);
    opacity: 0; transition: opacity .25s ease;
  }
  .tc-pick-confirm.tc-pick-confirm-show { opacity: 1; }
}

/* ---------- trip-report.html ---------- */

/* .fin-export-row's own `display: flex` ties the UA [hidden] rule's
   specificity and was declared later, so it wins - hidden alone doesn't
   hide this row without this override. */
#trStopConfirm[hidden] { display: none; }

/* Resuming is the expected/common path (a reload mid-trip, not a deliberate
   stop) so it gets its own line and a much bigger target; declining is the
   rarer path and stays at the normal .drill-dl size, on the line below -
   same visual weight as "abandon and save" deserves, not equal footing
   with "just continue what I was already doing". */
.tr-resume-actions { display: flex; flex-direction: column; align-items: center; gap: .6rem; margin-block-start: .6rem; }
.tr-resume-actions .tr-resume-yes { font-size: 1.15rem; font-weight: 600; padding: .85rem 2.2rem; }

.tr-vehicle-pick { display: flex; gap: 1rem; justify-content: center; margin-block: 1rem; }
.tr-vehicle-opt {
  display: flex; align-items: center; gap: .4rem; padding: .6rem 1.2rem;
  border: 1px solid var(--border); border-radius: .6rem; cursor: pointer; font-weight: 600;
}
.tr-vehicle-opt:has(input:checked) { border-color: var(--accent); background: var(--surface); }
.tr-start-btn { font-size: 1.1rem; padding: .8rem 2rem; }
.tr-history-btn-lg { font-size: 1rem; padding: .7rem 1.7rem; }
.tr-bus-line-row { text-align: center; margin-block-end: 1rem; }
.tr-bus-line-row input { width: 6rem; padding: .3rem .5rem; margin-inline-start: .3rem; }
.tr-bus-line-row .acc-hint { display: block; margin-top: .3rem; }
.tr-sensitivity-row { text-align: center; margin-block-end: 1rem; max-inline-size: 28rem; margin-inline: auto; }
.tr-sensitivity-row label { font-weight: 600; }
.tr-sensitivity-row input[type="range"] { width: 100%; margin-block: .5rem; }
.tr-sensitivity-row .acc-hint { display: block; }

.tr-topbar {
  display: flex; flex-wrap: wrap; gap: 1rem; justify-content: center; align-items: baseline;
  font-weight: 600; margin-block-end: 1rem;
}
.tr-badge { font-size: 1.1rem; }
.tr-speed-row { display: flex; align-items: center; gap: .5rem; }
/* A real speed-limit road sign (תמרור) - red ring, white face, bare number,
   no unit/label - the same reason no real dashboard captions its own speed-
   limit sign either: the shape already says what it is. Current speed gets
   the same circular treatment (its own accent-colored ring, not red - that
   color means "this is the legal limit", not "this is what you're doing"),
   with the קמ"ש unit as a small label between the two circles rather than
   inside either one. */
.tr-sign {
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 3.38rem; block-size: 3.38rem; border-radius: 50%;
  background: #fff; border: 4px solid #d21f1f; color: #111;
  font-size: 1.5rem; font-weight: 700; line-height: 1; flex: none;
}
.tr-sign-speed { border-color: var(--accent); }
.tr-speed-unit { font-size: .7rem; color: var(--muted); font-weight: 400; }
/* Only ever shown alongside a 30 limit (see trip-report.js's onPosition) -
   a school existing nearby is never itself treated as a speed limit,
   Israeli law only actually limits a road there when a real sign is
   posted, so this reads as "this 30 is a school zone", not "30 because
   school". */
.tr-school-badge {
  font-size: .78rem; font-weight: 600; color: #b8860b;
  background: color-mix(in srgb, #b8860b 12%, transparent);
  border: 1px solid #b8860b; border-radius: 999px; padding: .25rem .6rem;
}
/* Just the clock-face time (no date - see formatStartTime) plus the
   elapsed-duration line stacked right under it (no "התחלה:" label - the
   position in the topbar already says what it is). Hidden until the
   screen-stay-on warning above it has shrunk (.tr-warning-shrink, see
   trip-report.js's 30s timer) - loud for the trip's first 30s is exactly
   the moment this smaller info is least worth the visual competition. */
.tr-start-time {
  display: none; flex-direction: column; align-items: center; line-height: 1.3;
  font-size: .85rem; color: var(--muted); font-weight: 400;
}
#trScreenWarning.tr-warning-shrink ~ .tr-topbar .tr-start-time { display: flex; }
.tr-start-time #trStartTime { font-size: 1rem; font-weight: 600; color: var(--fg); }
.tr-start-time .tr-elapsed { font-weight: 600; }

/* Loud on purpose for its first 30s (a trip just started, worth a real
   glance), then recedes to a quiet persistent reminder rather than
   competing with the live info below it for the rest of the drive. Sticky
   so it stays at the very top of the viewport through scrolling instead of
   being scrolled past once the page fills up (map, stats, etc). Sized to
   fit the whole line without wrapping - a two-line sticky banner would eat
   even more permanent space than this already does. */
.tr-screen-warning {
  position: sticky; top: 0; z-index: 5;
  text-align: center; font-weight: 700; font-size: .95rem;
  background: var(--card); border-bottom: 1px solid var(--border);
  padding: .5rem; margin: 0 0 1rem;
  transition: font-size .3s ease, font-weight .3s ease, padding .3s ease, color .3s ease;
}
.tr-screen-warning.tr-warning-shrink { font-size: .8rem; font-weight: 400; color: var(--muted); padding: .3rem; }

/* Icon-only pause/stop - a driving screen is glanced at, not read; a bare
   glyph this size reads faster than a labelled pill button would. */
.tr-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 4.5rem; height: 4.5rem; border-radius: 50%; font-size: 2.2rem; line-height: 1;
  border: 2px solid var(--border); background: var(--card); cursor: pointer;
  transition: transform .15s ease, border-color .15s ease;
}
.tr-icon-btn:hover:not(:disabled) { border-color: var(--accent); transform: scale(1.08); }
.tr-newtrip-btn { font-size: 1.3rem; padding: .9rem 1.8rem; }

/* Conic-gradient dial - plain CSS, no chart library, matching every other
   visual on this site. --score-deg (set in JS on every render) is the score
   as an angle out of 360°; the band class only picks the gradient's own
   color, so a dial reading 40 in the red band still visibly differs from
   one reading 95 in green, at a glance and without reading the number. */
.tr-score-row { display: flex; gap: 1.5rem; align-items: center; justify-content: center; flex-wrap: wrap; margin-block-end: 1.5rem; }
.tr-score-gauge {
  --score-deg: 360deg;
  width: 93px; height: 93px; border-radius: 50%;
  background: conic-gradient(var(--tr-score-color, var(--accent)) var(--score-deg), var(--border) var(--score-deg));
  display: flex; align-items: center; justify-content: center;
}
.tr-score-gauge.sc-great { --tr-score-color: #2e7d46; }
.tr-score-gauge.sc-good  { --tr-score-color: #8bc34a; }
.tr-score-gauge.sc-fair  { --tr-score-color: #ff8800; }
.tr-score-gauge.sc-poor  { --tr-score-color: #dd0000; }
.tr-score-inner {
  width: 72px; height: 72px; border-radius: 50%; background: var(--card);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.tr-score-inner #trScoreNum { font-size: 1.6rem; font-weight: 700; line-height: 1; }
/* Calm, silent "an event just logged" feedback - a brief ring pulse on the
   gauge already on screen, not a new element and not a color anyone would
   mistake for the score itself changing color. */
@keyframes tr-pulse { 0%, 100% { box-shadow: none; } 35% { box-shadow: 0 0 0 10px rgba(221, 0, 0, 0.35); } }
.tr-score-pulse { animation: tr-pulse 1.4s ease; }
.tr-score-max { font-size: .8rem; color: var(--muted); }
.tr-score-meta { max-width: 26rem; }
.tr-score-label { font-size: 1.2rem; font-weight: 700; }

.tr-map-wrap { display: flex; justify-content: center; margin-block-end: .5rem; position: relative; }
.tr-map-wrap canvas { max-width: 100%; height: auto; aspect-ratio: 1 / 1; border-radius: .5rem; border: 1px solid var(--border); }
.tr-map-sensitivity {
  position: absolute; top: .5rem; inset-inline-end: .5rem; background: rgba(255,255,255,.85);
  color: #24331f; font-size: .8rem; font-weight: 600; padding: .2rem .5rem; border-radius: .4rem;
}
.tr-autopan-toggle { display: block; text-align: center; font-size: .85rem; color: var(--muted); margin-block-end: 2rem; }

.tr-problem-meter {
  display: flex; height: 22px; border-radius: .4rem; overflow: hidden; border: 1px solid var(--border);
  margin-block-end: .6rem;
}
.tr-meter-seg { height: 100%; }
.tr-meter-unknown {
  background: repeating-linear-gradient(45deg, var(--border), var(--border) 4px, transparent 4px, transparent 8px);
}
.tr-legend { display: flex; flex-wrap: wrap; gap: .8rem; font-size: .8rem; color: var(--muted); margin-block-end: 1.5rem; }
.tr-legend-item { display: inline-flex; align-items: center; gap: .3rem; }
.tr-legend-swatch { width: .8rem; height: .8rem; border-radius: .2rem; display: inline-block; }
.tr-legend-swatch-unknown {
  background: repeating-linear-gradient(45deg, var(--border), var(--border) 2px, transparent 2px, transparent 4px);
}

/* Three groups (חריגות וקופצנות / אירועי נהיגה / נתוני נסיעה) instead of one
   flat row of six, per the user's own chosen layout - grouping is conveyed
   by row/spacing alone now, with no text header per group, so the tiles
   themselves grow to fill the space that freed up and center their
   content instead of the site-wide .stat default's start-aligned text. */
.tr-stats-group { margin-block-end: .9rem; }
.tr-stats-group:last-child { margin-block-end: 1.5rem; }
.tr-stats-group .tr-stats-row { margin-block-end: 0; }
.tr-stats-row { grid-template-columns: repeat(auto-fit, minmax(6.5rem, 1fr)); gap: .6rem; margin-block-end: 1.5rem; }
.tr-stats-row .stat { padding: .9rem 1rem; align-items: center; text-align: center; }
.tr-stats-row .stat-n { font-size: 1.9rem; }
.tr-stats-row .stat-l { font-size: .8rem; }

.tr-complete-summary p { margin-block: .4rem; }
.tr-complete-score { font-size: 1.3rem; }
.tr-complete-score.sc-great, .tr-complete-score.sc-good { color: #2e7d46; }
.tr-complete-score.sc-fair { color: #ff8800; }
.tr-complete-score.sc-poor { color: #dd0000; }

.tr-event-log { list-style: none; padding: 0; margin: 0 0 1.5rem; }
.tr-event-log li {
  display: flex; gap: .8rem; padding: .5rem 0; border-bottom: 1px solid var(--border); font-size: .9rem;
}
.tr-ev-type { font-weight: 600; }
.tr-ev-time { color: var(--muted); font-variant-numeric: tabular-nums; }

.tr-history-list { list-style: none; padding: 0; margin: 0 0 1.5rem; }
.tr-history-item {
  border: 1px solid var(--border); border-radius: .6rem; padding: .8rem 1rem; margin-block-end: .8rem;
}
.tr-history-info { display: flex; flex-wrap: wrap; gap: .6rem; justify-content: space-between; margin-block-end: .6rem; }
.tr-history-date { font-weight: 600; }

/* Civic-category pages only (.civic-app-page - accidents.html,
   area-cleanup.html, trip-report.html; tree-plans/trees are external, no
   local page to mark): the app-context strip is 30% bigger here than the
   4.6rem/2.3rem site-wide default, and always exactly two rows (grid with
   two explicit rows, auto-flowing into columns) rather than whatever
   flex-wrap happens to land at the current width - a fixed, predictable
   shape instead of a variable one. */
.civic-app-page .app-siblings {
  display: grid; grid-template-rows: repeat(2, auto); grid-auto-flow: column; gap: .5rem;
  justify-content: start;
}
.civic-app-page .app-sibling { inline-size: 5.98rem; }
.civic-app-page .app-sibling-icon { font-size: 2.99rem; }

/* Whole civic group again (not trip-report.html alone anymore) - measured
   128px tall at the sizing above; 90px is ~30% shorter, matching what
   trip-report.html already had on its own. Width stays the group's own
   5.98rem; icon/label shrink just enough to still fit comfortably
   (centered) in the shorter box rather than overflowing it. */
.civic-app-page .app-sibling { block-size: 90px; padding-block: .2rem; }
.civic-app-page .app-sibling-icon { font-size: 2rem; }
.civic-app-page .app-sibling-label { font-size: .55rem; }

/* trip-report.html specifically renders its siblings row with includeSelf:
   false (see renderAppContext/apps.js) - one fewer tile than every other
   civic-app-page, and by request should read as a single row rather than
   inheriting the two-row grid shape above (which exists for the OTHER
   civic pages, still with their full tile count). Overrides only for this
   page, not the whole civic-app-page group. */
.trip-report-page .app-siblings { grid-template-rows: repeat(1, auto); }

/* vehicle-lookup.html's own plate-number field - the shared input[type="text"]
   rule above sets inline-size:100%, which overrides the size="10" attribute
   on #vlPlate entirely (a CSS width always wins over `size`'s suggested
   width) and stretched it across the whole .controls row, pushing the
   "בדיקה" button onto its own line below instead of beside it. inline-size:
   auto here lets size="10" (an Israeli plate is at most 8 digits) govern
   the width instead - .controls is a flex row under the page's own
   dir=rtl, so with the input back to its natural width it's the first
   child and sits at the row's right edge already, no positioning override
   needed (user request: "10 places", "to the right"). */
#vlPlate { inline-size: auto; }

/* vehicle-lookup.html's own "download PDF" button (#vlPdfBtn) is really
   just window.print() - no bundled PDF library, this site's own build
   check asserts no external asset anywhere (see tools/verify.sh) - so
   "PDF with only the vehicle info" (user request) is a print stylesheet:
   everything except the result section's own cards is hidden, and the
   button hides itself too (printing a button makes no sense). The
   "מה יש כאן" notice, search form, and dealers table are unrelated to "the
   vehicle info" a result card already is. */
@media print {
  .vehicle-lookup-page header.site,
  .vehicle-lookup-page #fileproto,
  .vehicle-lookup-page #appContext,
  .vehicle-lookup-page details.notice,
  .vehicle-lookup-page section[aria-labelledby="qH"],
  .vehicle-lookup-page section[aria-labelledby="dealersH"],
  .vehicle-lookup-page .fin-export-row {
    display: none !important;
  }
}

/* ---------- noise-radar.html ----------
   The live capture screen and the final result share one layout: chart on
   one side, status/instruction text on the other, side by side on desktop
   and stacked (chart first) on mobile - same wrap-to-column idiom as the
   compare pages' own side-by-side blocks. */
.nr-beta-tag { font-size: .7rem; font-weight: 400; color: rgb(255 255 255 / 75%); }
.nr-stage { display: flex; gap: 1.5rem; align-items: flex-start; flex-wrap: wrap; }
.nr-chart-wrap { flex: 0 0 min(320px, 100%); inline-size: min(320px, 100%); }
.nr-chart { display: block; inline-size: 100%; block-size: auto; aspect-ratio: 1; }
.nr-readout { flex: 1 1 16rem; min-inline-size: 14rem; display: flex; flex-direction: column; gap: .5rem; }
.nr-error-text { color: var(--danger); }

/* Live hot/cold gauge (see liveLoop() in noise-radar.js) - a big number +
   label the user watches while walking around, not a one-shot readout, so
   it's sized to be readable at a glance without staring at the phone. The
   fill's color rides the same low/mid/high accent-to-bg mix idiom as
   BAND_COLOR below, so "hot" reads as "full strength accent", consistent
   with the radar chart's own densest band. */
.nr-gauge-label { font-size: 1.3rem; font-weight: 700; }
.nr-gauge-value { font-size: 3rem; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.nr-gauge-track { inline-size: 100%; block-size: 1.1rem; border-radius: 999px; background: color-mix(in srgb, var(--muted) 20%, var(--bg) 80%); overflow: hidden; border: 1px solid var(--border); }
.nr-gauge-fill { block-size: 100%; inline-size: 0%; background: var(--accent); transition: inline-size .12s linear; }

.nr-band { transition: d .2s ease; }
.nr-grid-ring { fill: none; stroke: var(--border); stroke-dasharray: 2 3; }
.nr-hub { fill: var(--card); stroke: var(--border); }
.nr-target-outline { fill: none; stroke: var(--accent); stroke-width: 2; stroke-dasharray: 4 3; }
.nr-needle { stroke: var(--danger); stroke-width: 2; stroke-linecap: round; }

.nr-summary table { margin-block-start: .5rem; }
.nr-legend { list-style: none; margin: .75rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .3rem; color: var(--muted); font-size: .9rem; }
.nr-legend li { display: flex; align-items: center; gap: .5rem; }
.nr-legend .acc-legend-swatch.nr-band-low { background: var(--accent); }
.nr-legend .acc-legend-swatch.nr-band-mid { background: color-mix(in srgb, var(--accent) 55%, var(--bg) 45%); }
.nr-legend .acc-legend-swatch.nr-band-high { background: color-mix(in srgb, var(--accent) 25%, var(--bg) 75%); }

@media (max-width: 640px) {
  .nr-stage { flex-direction: column; align-items: stretch; }
  .nr-chart-wrap { inline-size: min(280px, 100%); margin-inline: auto; }
}
