/* Traffic Violence Dashboard: a dashboard built on brand.css tokens and ui.css.

   A plain dark ground (no nebula), the title without the gradient, and color
   kept for the two modes. The mode colors are validated as a pair on --ob-bg
   (lightness band, color-vision separation, contrast), and never carry
   meaning alone: every dot sits beside a word.

   Layout: three columns when wide (summary and filters | map or trends |
   people and detail), each scrolling on its own inside the viewport. Below
   1200px it becomes one scrolling column with Map / People / Trends tabs, and
   a person's detail opens full screen. */

:root {
  /* The two modes keep their colors in both themes: the pair passes the
     lightness, color-vision and contrast checks on #030712 and on white. */
  --sd-ped: #ea580c;
  --sd-bike: #3b82f6;
  --sd-mixed: #6b7280;             /* a stack of both modes */
  --sd-side-w: 22rem;
  --sd-panel-w: 24rem;
}

/* The site's light and dark theme (src/scripts/theme.js sets data-map-theme
   on <html> before first paint; brand.css holds the shared light tokens, the
   header's included). Below are the dashboard's own colors in each. */
.sd-app, .sd-about {
  /* Set here, not only on <body>: an inherited color is resolved where it is
     declared, so text would otherwise keep the dark theme's ink in light. */
  color: var(--ob-fg);
  color-scheme: dark;
  --sd-line: var(--ob-border);
  --sd-raise: #0b1120;
  /* The side columns are raised off the map: their own surface, a firmer
     edge, and a shadow cast onto it. The dark basemap is near black, so the
     dark surface is a step lighter than the page. */
  --sd-shell: #0f1729;
  --sd-edge: rgba(148, 163, 184, 0.28);
  --sd-cast: rgba(0, 0, 0, 0.7);
  --sd-text2: #d1d5db;
  --sd-link-line: rgba(249, 250, 251, 0.35);
  --sd-map-bg: #0b0f19;
  --sd-tip: #111827;
  --sd-hover: rgba(255, 255, 255, 0.04);
  --sd-control-hover: #1f2937;
  --sd-disabled: #4b5563;
  --sd-rate-bg: rgba(192, 132, 252, 0.08);
  --sd-stroke: #030712;            /* a dot's outline */
  --sd-grid: rgba(148, 163, 184, 0.12);
  /* Bike network: the census map's dark-theme greens, drawn thin under the dots. */
  --sd-track: #86efac;
  --sd-lane: #14b8a6;
}

html[data-map-theme="light"] body.sd-page { background: var(--ob-bg); }
html[data-map-theme="light"] .sd-app,
html[data-map-theme="light"] .sd-about {
  color-scheme: light;
  --sd-raise: #ffffff;
  --sd-shell: #ffffff;
  --sd-edge: rgba(15, 23, 42, 0.2);
  --sd-cast: rgba(15, 23, 42, 0.28);
  --sd-text2: #374151;
  --sd-link-line: rgba(17, 24, 39, 0.35);
  --sd-map-bg: #e8eaed;
  --sd-tip: #ffffff;
  --sd-hover: rgba(15, 23, 42, 0.04);
  --sd-control-hover: #f1f3f5;
  --sd-disabled: #a1a8b3;
  --sd-rate-bg: rgba(126, 34, 206, 0.06);
  --sd-stroke: #1f2937;
  --sd-grid: rgba(15, 23, 42, 0.08);
  /* The census map's light-theme greens. */
  --sd-track: #166534;
  --sd-lane: #0891b2;
}
.sd-theme { display: flex; align-items: center; gap: 0.6rem; }

/* Other pages get border-box from Tailwind's preflight; this one loads no Tailwind. */
.sd-page *, .sd-page *::before, .sd-page *::after { box-sizing: border-box; }
/* `hidden` must win over the display a component sets (the legend's rows are flex). */
.sd-page [hidden] { display: none !important; }

.sd-page {
  margin: 0;
  background: var(--ob-bg);
  color: var(--ob-fg);
  font-family: var(--ob-font);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
.sd-page p, .sd-page h1, .sd-page h2, .sd-page h3, .sd-page ul, .sd-page ol, .sd-page dl { margin: 0; }
.sd-page a { color: inherit; text-decoration-color: var(--sd-link-line, rgba(249, 250, 251, 0.35)); text-underline-offset: 0.2em; }
.sd-page a:hover { text-decoration-color: currentColor; }
.sd-page :focus-visible { outline: 2px solid var(--ob-purple); outline-offset: 2px; border-radius: 4px; }

/* --- shell --------------------------------------------------------------- */

.sd-app {
  display: grid;
  grid-template-columns: var(--sd-side-w) minmax(0, 1fr) var(--sd-panel-w);
  /* The left column's foot (theme, method, downloads) stays in view below
     its scrolling part; the map and the people run the full height. */
  grid-template-rows: minmax(0, 1fr) auto;
  height: calc(100dvh - var(--ob-bar-h));
}
.sd-side, .sd-panel, .sd-side-foot { background: var(--sd-shell); position: relative; z-index: 1000; }
.sd-side, .sd-panel { overflow-y: auto; overscroll-behavior: contain; }
.sd-side, .sd-side-foot { grid-column: 1; border-right: 1px solid var(--sd-edge); box-shadow: 8px 0 22px -6px var(--sd-cast); }
.sd-side { grid-row: 1; padding: 1.25rem 1.25rem 1rem; display: flex; flex-direction: column; gap: 1rem; }
/* The column scrolls; its blocks keep their height rather than shrinking to fit (which clipped the stats). */
.sd-side > * { flex-shrink: 0; }
.sd-panel { grid-column: 3; grid-row: 1 / 3; border-left: 1px solid var(--sd-edge); box-shadow: -8px 0 22px -6px var(--sd-cast); }
.sd-main { grid-column: 2; grid-row: 1 / 3; position: relative; display: flex; flex-direction: column; min-width: 0; min-height: 0; }

/* The view switch floats over the top of the map or trends. */
.sd-tabs { grid-column: 2; grid-row: 1; align-self: start; justify-self: center; margin-top: 0.75rem; z-index: 600; box-shadow: var(--ob-panel-shadow); }
.sd-tab--people { display: none; }
/* ob-seg styles aria-pressed; these are tabs, so the same look follows aria-selected. */
.sd-tabs button[aria-selected="true"] { background: var(--ob-purple); color: var(--ob-on-accent); font-weight: 600; }
/* The shared focus ring is the accent, which vanishes on a pressed (accent) button. */
.ob-seg button[aria-pressed="true"]:focus-visible,
.sd-tabs button[aria-selected="true"]:focus-visible { outline-color: var(--ob-on-accent); }
/* Controls inside a card are secondary to the view switch: a quieter pressed state. */
.sd-card-head .ob-seg button[aria-pressed="true"] { background: var(--sd-control-hover); color: var(--ob-fg);
  box-shadow: inset 0 -2px 0 var(--ob-purple); }
.sd-card-head .ob-seg button[aria-pressed="true"]:focus-visible { outline-color: var(--ob-purple); }
.sd-card-controls { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.sd-view { flex: 1; min-height: 0; }
.sd-app:not([data-view="map"]) .sd-view--map { display: none; }
.sd-app:not([data-view="trends"]) .sd-view--trends { display: none; }

/* --- type ---------------------------------------------------------------- */

.sd-head { display: flex; flex-direction: column; gap: 0.35rem; }
.sd-head .sd-lead { margin-top: 0.4rem; }
.sd-title { font-size: 1.6rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1.15; text-wrap: balance; margin-top: 0.3rem; }
.sd-title--sm { font-size: 1.25rem; margin: 0; }
.sd-lead { margin-top: 0.75rem; font-size: 0.95rem; color: var(--sd-text2); }
.sd-h { font-size: 1rem; font-weight: 700; letter-spacing: -0.005em; }
.sd-note { font-size: 0.8rem; color: var(--ob-muted); line-height: 1.5; }
/* The credit under the lead: BikinginLA's reporting, with its share of the riders' sources. */
.sd-credit { margin: 0.5rem 0 0; padding-left: 0.7rem; border-left: 2px solid var(--ob-purple); font-size: 0.85rem; line-height: 1.5; color: var(--sd-text2); }
.sd-credit a { color: var(--ob-fg); font-weight: 600; }
.sd-linkbtn { background: none; border: 0; padding: 0; color: inherit; font: inherit; cursor: pointer;
  text-decoration: underline; text-decoration-color: var(--sd-link-line); text-underline-offset: 0.2em; }
.sd-linkbtn:hover { text-decoration-color: currentColor; }

/* --- readout: what the map and list show, in a few lines ------------------ */

.sd-readout { display: flex; flex-direction: column; gap: 0.35rem; padding: 0.8rem 0.9rem;
  border: 1px solid var(--sd-line); border-radius: var(--ob-radius-sm); background: var(--sd-shell); }
.sd-page .sd-readout p { margin: 0; }
.sd-scope { font-size: 0.72rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ob-muted);
  text-wrap: balance; }
.sd-big { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 0.4rem; line-height: 1.05; }
#sd-count { font-size: 2.6rem; font-weight: 750; letter-spacing: -0.03em; }
.sd-big-unit { font-size: 1rem; font-weight: 600; }
.sd-atleast { font-size: 0.85rem; font-weight: 500; color: var(--ob-muted); }
.sd-pace { font-size: 0.85rem; color: var(--ob-muted); }
.sd-pace strong { color: var(--ob-fg); font-weight: 600; }
.sd-pace .up { color: var(--sd-ped); }
:root[data-map-theme="light"] .sd-pace .up { color: #c2410c; }
.sd-split { display: flex; flex-direction: column; gap: 0.35rem; margin-top: 0.2rem; }
.sd-split-bar { display: flex; height: 0.5rem; border-radius: 999px; overflow: hidden; background: var(--sd-line); }
.sd-split-bar span { display: block; height: 100%; transition: flex-basis 0.3s ease, opacity 0.2s; }
.sd-split-ped { background: var(--sd-ped); }
.sd-split-bike { background: var(--sd-bike); }
.sd-split-keys { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.1rem 0.5rem; }
.sd-split-key { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.15rem 0; background: none; border: 0;
  color: inherit; font: inherit; font-size: 0.85rem; cursor: pointer; border-radius: 4px; }
.sd-split-key strong { font-weight: 700; }
.sd-split-key:hover { text-decoration: underline; text-underline-offset: 0.2em; }
.sd-split-key[aria-pressed="true"] { font-weight: 600; }
.sd-split.has-mode .sd-split-key[aria-pressed="false"], .sd-split.has-mode .sd-split-bar .is-off { opacity: 0.75; }
.sd-split.has-mode .sd-split-bar .is-off { opacity: 0.35; }
.sd-nowrap { white-space: nowrap; }
.sd-wide { font-size: 0.78rem; color: var(--ob-muted); border-top: 1px solid var(--sd-line); padding-top: 0.4rem; margin-top: 0.15rem !important; }
@media (prefers-reduced-motion: reduce) { .sd-split-bar span { transition: none; } }

/* --- stats (the trends view's condition tiles) ------------------------------ */

.sd-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--sd-line);
  border: 1px solid var(--sd-line); border-radius: var(--ob-radius-sm); overflow: hidden; }
.sd-stat { background: var(--sd-shell); padding: 0.7rem 0.8rem; display: flex; flex-direction: column; }
/* Each number sits at the foot of its tile, so they line up however many
   lines a label takes ("Biking & scooters" wraps). */
.sd-page .sd-stat .sd-stat-value { margin-top: auto; }       /* beats the page's p { margin: 0 } */
.sd-page .sd-stat--hero .sd-stat-value { margin-top: 0; }
.sd-stat--hero { grid-column: 1 / -1; }
.sd-stat.is-off .sd-stat-value, .sd-stat.is-off .sd-stat-label { opacity: 0.45; }   /* the mode the filter leaves out */
.sd-stat-label { font-size: 0.75rem; color: var(--ob-muted); display: flex; align-items: center; gap: 0.35rem; }
.sd-stat-value { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; }
.sd-stat--hero .sd-stat-value { font-size: 2.6rem; }
.sd-stat-note { font-size: 0.8rem; color: var(--ob-muted); }

.sd-dot { display: inline-block; width: 0.6rem; height: 0.6rem; border-radius: 50%; flex: none; }
.sd-dot--pedestrian { background: var(--sd-ped); }
.sd-dot--bicyclist { background: var(--sd-bike); }
.sd-dot--stack { background: var(--sd-mixed); box-shadow: 0 0 0 2px var(--sd-edge); }

/* --- filters ------------------------------------------------------------- */

.sd-filter-box summary { cursor: pointer; list-style: none; display: flex; align-items: center; gap: 0.4rem; }
.sd-filter-box summary::-webkit-details-marker { display: none; }
.sd-filter-box summary::before { content: '▸'; font-size: 0.8em; transition: transform 0.15s; }
.sd-filter-box[open] summary::before { transform: rotate(90deg); }
.sd-filters { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 0.6rem; }
.sd-filter-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.6rem; }
.sd-field--wide { grid-column: 1 / -1; }
.sd-field { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; }
.sd-field .ob-input { width: 100%; }
.sd-checks { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 1rem; }
.sd-check { display: flex; align-items: center; gap: 0.4rem; min-height: 2.25rem; font-size: 0.9rem; cursor: pointer; }
.sd-check input { accent-color: var(--ob-purple); width: 1.15rem; height: 1.15rem; }
.sd-checks .sd-linkbtn { margin-left: auto; font-size: 0.9rem; color: var(--ob-muted); padding: 0.55rem 0.25rem; }
.sd-side-foot { grid-row: 2; display: flex; flex-direction: column; gap: 0.4rem; padding: 0.75rem 1.25rem 1rem;
  border-top: 1px solid var(--sd-line); font-size: 0.9rem; }
.sd-filter-count { font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--ob-purple); }

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

.sd-view--map { position: relative; }
#sd-map { position: absolute; inset: 0; background: var(--sd-map-bg); touch-action: none; }   /* the pinch is handled in js/pinch.js */
/* The shared credits pill is fixed to the viewport on the full-screen maps;
   here the map is one column, so it sits in the map's own corner. */
.sd-view--map .ob-credits { position: absolute; z-index: 700; }
.sd-unmapped { position: absolute; top: var(--ob-map-inset); left: var(--ob-map-inset); z-index: 500; display: flex; align-items: center; gap: 0.5rem;
  background: var(--ob-panel); border: 1px solid var(--ob-panel-border); border-radius: 999px; box-shadow: var(--ob-panel-shadow);
  min-height: var(--ob-control-h);
  padding: 0.3rem 0.8rem 0.3rem 0.3rem; color: var(--ob-fg); font: inherit; font-size: 0.8rem; cursor: pointer; backdrop-filter: blur(6px); }
.sd-unmapped:hover { background: var(--sd-control-hover); }
/* With the person panel open the map is narrow on a small laptop, and the centered Map and
   Trends switch would sit on top of this pill, so the pill drops below the switch. */
@media (min-width: 1200px) and (max-width: 1399.98px) {
  .sd-unmapped { top: calc(var(--ob-map-inset) + 2.75rem); }
}
.sd-unmapped[aria-pressed="true"] { border-color: var(--ob-purple); box-shadow: 0 0 0 1px var(--ob-purple), var(--ob-panel-shadow); }
/* Area, not diameter, follows the count (sized in JS). Both modes, so neither color. */
.sd-unmapped-dot { display: grid; place-items: center; border-radius: 50%; flex: none; font-weight: 700; font-size: 0.8rem;
  background: var(--sd-rate-bg); border: 1px solid var(--ob-muted); color: var(--ob-fg); transition: width 0.2s, height 0.2s; }
.sd-unmapped[aria-pressed="true"] .sd-unmapped-dot { background: var(--ob-purple); border-color: var(--ob-purple); color: var(--ob-on-accent); }
.sd-unmapped-text { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.25; }
.sd-unmapped-label { color: var(--ob-muted); white-space: nowrap; }
.sd-unmapped-hint { font-size: 0.72rem; color: var(--ob-fg); }
.sd-unmapped-hint:empty { display: none; }
.sd-map-empty { position: absolute; top: 40%; left: 50%; transform: translate(-50%, -50%); z-index: 550; margin: 0;
  background: var(--ob-panel); border: 1px solid var(--ob-panel-border); border-radius: var(--ob-radius-sm);
  box-shadow: var(--ob-panel-shadow); padding: 0.75rem 1rem; text-align: center; }
.sd-map-empty:not([hidden]) { display: flex; flex-direction: column; gap: 0.4rem; align-items: center; }
.sd-legend { position: absolute; left: var(--ob-map-inset); bottom: var(--ob-map-inset); z-index: 500; background: var(--ob-panel); border: 1px solid var(--ob-panel-border);
  border-radius: var(--ob-radius-sm); padding: 0.4rem 0.75rem; font-size: 0.8rem; backdrop-filter: blur(6px); }
.sd-legend summary { cursor: pointer; color: var(--ob-muted); }
.sd-legend ul { list-style: none; margin: 0.4rem 0 0; padding: 0; display: grid; gap: 0.25rem; }
.sd-legend li { display: flex; align-items: center; gap: 0.5rem; }
.sd-layer { margin-top: 0.5rem; padding-top: 0.45rem; border-top: 1px solid var(--ob-panel-border); font-size: 0.8rem; }
.sd-bike-key { margin-top: 0.35rem !important; }
.sd-line { display: inline-block; width: 1rem; height: 0; border-top: 2.5px solid; flex: none; }
.sd-line--track { border-color: var(--sd-track); }
.sd-line--lane { border-color: var(--sd-lane); }
.sd-line--shared { border-top-style: dashed; border-color: var(--sd-lane); }
.leaflet-container { font: inherit; }
/* Leaflet's zoom buttons are white by default; these match the site's map panels. */
.leaflet-bar { border: 1px solid var(--ob-panel-border) !important; box-shadow: var(--ob-panel-shadow) !important; border-radius: var(--ob-radius-sm) !important; overflow: hidden; }
.leaflet-bar a, .leaflet-bar a:hover, .leaflet-bar a:focus { background: var(--ob-panel); color: var(--ob-fg); border-bottom-color: var(--ob-panel-border); backdrop-filter: blur(6px); }
.leaflet-bar a:hover, .leaflet-bar a:focus { background: var(--sd-control-hover); }
.leaflet-bar a.leaflet-disabled { background: var(--ob-panel); color: var(--sd-disabled); }
.leaflet-tooltip, .sd-stack-popup .leaflet-popup-content-wrapper { background: var(--sd-tip); color: var(--ob-fg); border: 1px solid var(--ob-panel-border); box-shadow: var(--ob-panel-shadow); font-size: 0.85rem; line-height: 1.35; }
.leaflet-tooltip-top::before { border-top-color: var(--sd-tip); }
.sd-stack-popup .leaflet-popup-tip { background: var(--sd-tip); }
.sd-tip-sub { color: var(--ob-muted); font-size: 0.75rem; }

/* --- trends -------------------------------------------------------------- */

/* Positioned, so hidden captions and other absolute pieces inside scroll with it
   instead of spilling below the dashboard and lengthening the page. */
.sd-view--trends { position: relative; overflow-y: auto; padding: 4.5rem 1.25rem 1.5rem; display: flex; flex-direction: column; gap: 1rem;
  /* Content fades out under the floating Map / Trends switch as it scrolls. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, transparent 2.5rem, #000 4.5rem);
  mask-image: linear-gradient(to bottom, transparent 0, transparent 2.5rem, #000 4.5rem); }
.sd-card { background: var(--sd-raise); border: 1px solid var(--sd-line); border-radius: var(--ob-radius-sm); padding: 1rem; display: flex; flex-direction: column; gap: 0.75rem; }
.sd-card-head { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.sd-card-head .sd-h { margin-right: auto; }
.sd-chart { position: relative; height: 300px; }
.sd-chart.is-empty canvas { visibility: hidden; }
.sd-trend-empty:not([hidden]) { position: absolute; inset: 0; display: flex; flex-direction: column; gap: 0.4rem;
  align-items: center; justify-content: center; margin: 0; color: var(--ob-muted); }
/* Wide tables scroll inside their card: the row labels stay put, and the
   right edge fades to say there is more. */
.sd-card .ob-table-scroll.is-scrollable { -webkit-mask-image: linear-gradient(to left, transparent 0, #000 1.5rem);
  mask-image: linear-gradient(to left, transparent 0, #000 1.5rem); }
.sd-card .ob-table th[scope="row"] { position: sticky; left: 0; background: var(--sd-raise); z-index: 1; }
.sd-conditions { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: 1px; background: var(--sd-line);
  border: 1px solid var(--sd-line); border-radius: var(--ob-radius-sm); overflow: hidden; }
.sd-conditions .sd-stat { background: var(--sd-raise); }
.sd-rate { background: var(--sd-rate-bg); }
.sd-th-sub { font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--ob-muted); }
.sd-card tfoot th, .sd-card tfoot td { border-top: 1px solid var(--ob-panel-border); font-weight: 600; }

/* --- people list --------------------------------------------------------- */

.sd-panel-head { position: sticky; top: 0; z-index: 1; background: var(--sd-shell); padding: 1rem 1rem 0.6rem; border-bottom: 1px solid var(--sd-line); }
.sd-list { list-style: none; padding: 0; }
.sd-list li + li { border-top: 1px solid var(--sd-line); }
.sd-row { display: flex; align-items: center; gap: 0.7rem; padding: 0.6rem 1rem; text-decoration: none; min-height: 44px; }
.sd-page a.sd-row { text-decoration: none; }
.sd-row:hover { background: var(--sd-hover); }
/* ui.css's row hover is a white tint, invisible on a light ground. */
html[data-map-theme="light"] .sd-app .ob-table tbody tr:hover { background: var(--sd-hover); }
.sd-row-main { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.sd-row-title { font-weight: 500; color: var(--sd-text2); }
/* A name is what the list is for: named people read first. */
.sd-row--named .sd-row-title { font-weight: 700; color: var(--ob-fg); }
.sd-nowrap { white-space: nowrap; }
.sd-row-sub { font-size: 0.8rem; color: var(--ob-muted); }
.sd-more { margin: 0.75rem auto 1.25rem; display: block; }
.sd-empty { padding: 1.5rem 1rem; display: flex; flex-direction: column; gap: 0.6rem; align-items: flex-start; color: var(--ob-muted); }
/* Muted, so names rather than badges carry the color down the list. */
.sd-badge-news { background: transparent; border: 1px solid var(--sd-edge); color: var(--ob-muted); font-weight: 500; white-space: nowrap; }

/* --- person detail ------------------------------------------------------- */

.sd-detail { padding: 0 1.1rem 2rem; display: flex; flex-direction: column; gap: 0.75rem; }
.sd-detail > div + div, #sd-detail-body { display: flex; flex-direction: column; gap: 0.75rem; }
.sd-detail-bar { position: sticky; top: 0; z-index: 1; background: var(--sd-shell); display: flex; justify-content: space-between;
  padding: 0.9rem 0 0.6rem; border-bottom: 1px solid var(--sd-line); font-size: 0.9rem; }
.sd-detail-context { display: none; }
.sd-show-map { display: none; }
.sd-detail-name { font-size: 1.6rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1.15; text-wrap: balance; margin-top: 0.25rem; }
.sd-detail-name:focus { outline: none; }
.sd-detail-sub { color: var(--ob-muted); font-size: 0.9rem; }
.sd-detail-sub .sd-dot { margin-right: 0.4rem; vertical-align: 0.05em; }
.sd-detail-sub .ob-badge { margin-left: 0.3rem; }
.sd-detail-lead { font-size: 1rem; }
.sd-story { margin: 0; border-left: 3px solid var(--sd-line); padding-left: 0.9rem; color: var(--sd-text2); }
#sd-detail-body .sd-h { margin-top: 0.75rem; }
.sd-links, .sd-sources, .sd-timeline { padding-left: 1.2rem; display: flex; flex-direction: column; gap: 0.25rem; }
.sd-sources li, .sd-links li { overflow-wrap: anywhere; }
.sd-facts { display: grid; grid-template-columns: max-content 1fr; gap: 0.3rem 1rem; font-size: 0.9rem; }
.sd-facts dt { color: var(--ob-muted); }
.sd-facts dd { margin: 0; }
.sd-cite { font-size: 0.8em; color: var(--ob-muted); white-space: nowrap; }
.sd-page a.sd-cite { text-decoration: none; }
.sd-sources li { border-radius: 4px; transition: background-color 0.6s; }
.sd-sources li.sd-flash { background: var(--sd-rate-bg); }
.sd-correct { margin-top: 0.75rem; padding: 0.9rem 1rem; border: 1px solid var(--sd-line); border-radius: var(--ob-radius-sm); font-size: 0.9rem; }

/* --- about --------------------------------------------------------------- */

.sd-about { width: min(44rem, calc(100vw - 2rem)); max-height: calc(100dvh - 4rem); padding: 0; border: 1px solid var(--ob-panel-border);
  border-radius: var(--ob-radius-panel); background: var(--sd-raise); box-shadow: var(--ob-panel-shadow); }
.sd-about::backdrop { background: rgba(3, 7, 18, 0.7); }
html[data-map-theme="light"] .sd-about::backdrop { background: rgba(15, 23, 42, 0.35); }
.sd-about-body { padding: 0 1.5rem 1.5rem; display: flex; flex-direction: column; gap: 0.7rem; }
.sd-about-bar { position: sticky; top: 0; background: var(--sd-raise); display: flex; justify-content: space-between; align-items: center;
  padding: 1.1rem 0 0.7rem; border-bottom: 1px solid var(--sd-line); }
.sd-about .sd-h { margin-top: 0.6rem; }
.sd-about ul:not(.sd-about-jump) { padding-left: 1.2rem; display: flex; flex-direction: column; gap: 0.4rem; }

/* --- narrow: one column, tabs, full-screen detail ------------------------ */

/* Wide: the left column fits a laptop screen without scrolling. Tighter
   type and spacing than the narrow filter sheet, County and Search side by
   side, and the foot on two lines. A very short window still scrolls, with
   a thin bar. */
@media (min-width: 1200px) {
  .sd-side { padding: 1rem 1.15rem 0.9rem; gap: 0.8rem; scrollbar-width: thin; scrollbar-color: var(--sd-edge) transparent; }
  .sd-head { gap: 0.2rem; }
  .sd-title { font-size: 1.45rem; }
  .sd-head .sd-lead { margin-top: 0.3rem; font-size: 0.88rem; line-height: 1.45; }
  .sd-stat { padding: 0.5rem 0.7rem; }
  .sd-readout { padding: 0.6rem 0.75rem; gap: 0.25rem; }
  .sd-split-key { font-size: 0.8rem; }
  #sd-count { font-size: 2.2rem; }
  .sd-stat-value { font-size: 1.25rem; }
  .sd-stat-note { font-size: 0.76rem; }
  #sd-lag { font-size: 0.74rem; line-height: 1.4; }
  .sd-filters { gap: 0.5rem; margin-top: 0.45rem; }
  .sd-filter-grid { gap: 0.5rem; }
  .sd-field--wide { grid-column: auto; }
  .sd-field .ob-label { font-size: 0.78rem; }
  .sd-side .ob-input { padding: 0.35rem 0.55rem; font-size: 0.88rem; min-height: 2.1rem; }
  .sd-check { font-size: 0.85rem; }
  .sd-side-foot { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 0.35rem 1rem; padding: 0.6rem 1.15rem 0.75rem; font-size: 0.85rem; }
  .sd-side-foot .sd-note { flex-basis: 100%; font-size: 0.74rem; }
}

/* A short laptop screen: the intro and the lag note give way (the About has
   both), so the stats and filters still fit. */
@media (min-width: 1200px) and (max-height: 820px) {
  .sd-head .sd-lead, #sd-lag { display: none; }
}

/* Narrow-only pieces, hidden on a wide screen. */
.sd-mbar, .sd-grab, .sd-side-close, .sd-sheet-title, .sd-mfilter, .sd-scrim { display: none; }

@media (max-width: 1199.98px) {
  /* An app, not a page: a compact bar, the map filling the screen beneath
     it, the people in a sheet over the map's lower part (peek, half, full),
     and the summary and filters in a sheet of their own. */
  .sd-app { --sd-mbar-h: 3.9rem; --sd-peek: 8.75rem;
    position: fixed; inset: var(--ob-bar-h) 0 0; height: auto; display: block; overflow: clip; }

  /* One slim row: the count for the current filters, and Map / Trends. */
  .sd-mbar { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; position: absolute; inset: 0 0 auto;
    height: var(--sd-mbar-h); padding: 0 10rem 0 1rem; background: var(--sd-shell); border-bottom: 1px solid var(--sd-edge);
    box-shadow: 0 6px 18px -8px var(--sd-cast); z-index: 1200; }
  .sd-mbar-sub { max-width: 100%; margin: 0.1rem 0 0; font-size: 0.72rem; line-height: 1.2; color: var(--ob-muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .sd-mbar-stat { max-width: 100%; min-width: 0; font-size: 0.85rem; font-weight: 600; line-height: 1.2;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .sd-mbar-stat strong { font-size: 1.15rem; font-weight: 800; letter-spacing: -0.01em; }
  .sd-mbar-least { font-weight: 400; color: var(--ob-muted); }
  .sd-mbar-scope { font-weight: 400; font-size: 0.8rem; color: var(--ob-muted); }
  .sd-mfilter { flex: none; font: inherit; font-size: 0.85rem; font-weight: 600; color: var(--ob-fg); background: var(--sd-control-hover);
    border: 1px solid var(--ob-control-border); border-radius: 999px; padding: 0.3rem 0.8rem; min-height: 32px; cursor: pointer;
    display: inline-flex; align-items: center; gap: 0.35rem; }
  .sd-mfilter-count:not(:empty) { background: var(--ob-purple); color: var(--ob-on-accent); border-radius: 999px;
    font-size: 0.72rem; min-width: 1.2rem; padding: 0 0.3rem; text-align: center; }

  .sd-tabs { position: absolute; top: calc((var(--sd-mbar-h) - 32px) / 2); right: 1rem; z-index: 1300; margin: 0; box-shadow: none; }
  .sd-tabs button { padding: 5px 12px; min-height: 32px; }
  .sd-tab--people { display: none !important; }

  .sd-main { position: absolute; inset: var(--sd-mbar-h) 0 0; }
  .sd-view--map { position: absolute; inset: 0; }
  .sd-view--trends { position: absolute; inset: 0; padding: 1rem 1rem 2rem; overflow-y: auto; -webkit-mask-image: none; mask-image: none; }
  /* Map furniture clears the sheet's peek. */
  .sd-legend, .sd-view--map .ob-credits { bottom: calc(var(--sd-peek) + 0.6rem); }
  /* An open legend is wide enough to run under the credits pill: lift it above. */
  .sd-legend[open] { bottom: calc(var(--sd-peek) + 3.4rem); }
  /* Room under the filter sheet's last lines for the sticky Show button. */
  .sd-side-foot { padding-bottom: 5.5rem; }
  /* A notice would sit over whichever sheet is open. */
  body:has(.sd-app.filters-open, .sd-app[data-sheet="half"], .sd-app[data-sheet="full"]) .sd-notice { display: none; }
  .sd-legend { left: 0.75rem; }

  /* The people sheet. */
  .sd-panel { position: absolute; left: 0; right: 0; bottom: 0; z-index: 1100; height: calc(100% - var(--sd-mbar-h) - 0.75rem);
    border: 1px solid var(--sd-edge); border-bottom: 0; border-radius: 16px 16px 0 0; box-shadow: 0 -8px 24px -8px var(--sd-cast);
    transform: translateY(calc(100% - var(--sd-peek))); transition: transform 0.28s cubic-bezier(0.2, 0.8, 0.2, 1);
    overflow-y: hidden; overscroll-behavior: contain; touch-action: pan-y; }
  .sd-app[data-sheet="half"] .sd-panel { transform: translateY(45%); overflow-y: auto; }
  .sd-app[data-sheet="full"] .sd-panel { transform: none; overflow-y: auto; }
  .sd-app.is-dragging .sd-panel { transition: none; }
  .sd-app[data-view="trends"] .sd-panel { transform: translateY(100%); visibility: hidden; }
  .sd-grab { display: flex; justify-content: center; align-items: center; position: sticky; top: 0; z-index: 3; width: 100%;
    height: 1.4rem; padding: 0; border: 0; background: var(--sd-shell); cursor: grab; touch-action: none; }
  .sd-grab span { width: 2.6rem; height: 0.3rem; border-radius: 999px; background: var(--ob-control-border); }
  .sd-panel-head { top: 1.4rem; padding-top: 0.2rem; touch-action: none; display: flex; align-items: center; gap: 0.75rem; }
  .sd-panel-title { flex: 1; min-width: 0; }
  .sd-detail-bar { top: 1.4rem; }
  .sd-detail-context, .sd-show-map { display: block; }
  .sd-detail-context { margin-top: 0.4rem; }

  /* The filters: a short sheet from the bottom, over a dimmed map, opened by
     the Filter button beside the count. Just the filters, the theme and the
     links, then the intro and credit below them; the stats are for the wide layout
     (the bar has the count). */
  .sd-scrim:not([hidden]) { display: block; position: absolute; inset: 0; z-index: 1350; background: rgba(3, 7, 18, 0.5); }
  .sd-side { position: absolute; left: 0; right: 0; bottom: 0; top: auto; max-height: 88%; z-index: 1400; border: 1px solid var(--sd-edge);
    border-bottom: 0; border-radius: 16px 16px 0 0; padding: 0 1rem; overflow-y: auto; gap: 0.75rem;
    box-shadow: 0 -8px 24px -8px var(--sd-cast);
    transform: translateY(100%); visibility: hidden; transition: transform 0.25s ease, visibility 0s linear 0.25s; }
  .sd-app.filters-open .sd-side { transform: none; visibility: visible; transition: transform 0.25s ease; }
  .sd-side .sd-readout, .sd-side #sd-lag { display: none; }
  /* The filters come first: a phone opens this sheet to filter, so the intro and
     the BikinginLA credit follow the fields (after .sd-filter-box, before the foot). */
  .sd-side .sd-head { order: 2; padding: 0.25rem 0 0.5rem; }
  .sd-side .sd-title { font-size: 1.15rem; }
  .sd-panel .sd-mkey { display: flex; align-items: center; gap: 0.35rem; margin: 0.15rem 0 0; font-size: 0.75rem; color: var(--ob-muted); }
  .sd-mkey .sd-dot + .sd-dot, .sd-mkey span + .sd-dot { margin-left: 0.5rem; }
  .sd-app:not(.is-ready) .sd-side-foot { visibility: hidden; }
  /* Touch targets of at least 44px, by padding or an invisible hit area. */
  .sd-theme .ob-seg button, .sd-mfilter, .sd-tabs button, .sd-side-close .ob-btn, .sd-sheet-title .sd-linkbtn { min-height: 44px; }
  .sd-tabs { top: calc((var(--sd-mbar-h) - 44px) / 2); }
  .sd-grab { height: 2.75rem; }
  .sd-more { min-height: 44px; }
  .sd-panel-head, .sd-detail-bar { top: 2.75rem; }
  .sd-detail-bar .sd-linkbtn, .sd-detail-bar button, .sd-linkbtn { min-height: 44px; display: inline-flex; align-items: center; }
  .leaflet-bar a { width: 44px !important; height: 44px !important; line-height: 44px !important; }
  .sd-legend summary { min-height: 44px; display: flex; align-items: center; }
  .sd-cite, a.sd-cite, .sd-list a { position: relative; }
  .sd-cite::after { content: ''; position: absolute; inset: -14px -10px; }
  .sd-mbar { padding-right: 12.5rem; }
  .sd-mbar-scope { display: block; }
  .sd-mbar-stat { white-space: normal; }
  .sd-sheet-title { display: flex; align-items: center; justify-content: space-between; order: 0; position: sticky; top: 0; z-index: 2;
    margin: 0 -1rem; padding: 1rem 1rem 0.5rem; background: var(--sd-shell); }
  .sd-sheet-title .sd-h { font-size: 1.1rem; }
  .sd-sheet-title .sd-linkbtn { font-size: 0.9rem; color: var(--ob-muted); }
  .sd-filter-box { order: 1; }
  .sd-filter-box summary { display: none; }
  .sd-filters { margin-top: 0; }
  .sd-checks .sd-linkbtn { display: none; }
  /* Inside the sheet the footer drops the desktop column's z-index (1000), which
     drew it over the sticky "Show N people" button. */
  .sd-side .sd-side-foot { order: 5; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 0.4rem 1rem; z-index: auto;
    border: 0; border-top: 1px solid var(--sd-line); box-shadow: none; padding: 0.75rem 0 0.25rem; background: none; }
  .sd-side .sd-side-foot .sd-note { flex-basis: 100%; }
  .sd-side-close { display: block; order: 99; position: sticky; bottom: 0; z-index: 2; margin: 0 -1rem; padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom, 0px));
    background: var(--sd-shell); border-top: 1px solid var(--sd-line); }
  .sd-side-close .ob-btn { width: 100%; justify-content: center; }
}
@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce) {
  .sd-panel, .sd-side { transition: none !important; }
}
@media (max-width: 520px) {
  .sd-stat--hero .sd-stat-value { font-size: 2.2rem; }
}

.sd-about-jump { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; }
.sd-about-jump a { color: var(--ob-muted); }
@media (max-width: 1199.98px) { .sd-app[data-sheet="peek"] .sd-panel { touch-action: none; } }

.sd-bars { display: grid; gap: 0.35rem; margin: 0.5rem 0; }
.sd-bar-row { display: grid; grid-template-columns: 6.5rem 1fr 3.5rem; align-items: center; gap: 0.6rem; font-size: 0.85rem; }
.sd-bars--wide .sd-bar-row { grid-template-columns: 11.5rem 1fr 3.5rem; }
@media (max-width: 480px) { .sd-bars--wide .sd-bar-row { grid-template-columns: 9rem 1fr 3rem; font-size: 0.8rem; } }
.sd-bar-track { display: flex; height: 0.9rem; border-radius: 3px; overflow: hidden; min-width: 2px; }
.sd-bar-track > span { display: block; height: 100%; }
.sd-bar-n { text-align: right; font-weight: 600; }

.sd-mkey { display: none; }

.sd-bars--season { position: relative; }
.sd-bars--season::after { content: ''; position: absolute; top: 0; bottom: 0; width: 2px; background: var(--ob-fg);
  left: calc(6.5rem + 0.6rem + (100% - 6.5rem - 3.5rem - 1.2rem) * var(--base, 71) / 100); pointer-events: none; }

.sd-page .sd-conditions .sd-stat .sd-stat-value { margin-top: 0; }
#sd-city-table td:nth-child(2) { white-space: nowrap; color: var(--ob-muted); }
.sd-uninc { text-transform: none; letter-spacing: 0; font-weight: 400; font-style: italic; color: var(--ob-muted); white-space: nowrap; }

.sd-table-controls { display: flex; flex-wrap: wrap; gap: 0.5rem; align-self: flex-start; }
.sd-table-controls [hidden] { display: none; }

/* Keyboard users can jump past the filters and map to the people. */
.sd-skip { position: absolute; left: 0.5rem; top: -3rem; z-index: 3000; padding: 0.5rem 0.8rem; background: var(--sd-raise);
  color: var(--ob-fg); border: 2px solid var(--ob-purple); border-radius: var(--ob-radius-sm); }
.sd-skip:focus { top: calc(var(--ob-bar-h) + 0.5rem); }
.sd-mbar.is-none .sd-mbar-stat strong { font-size: 1rem; }
@media (max-width: 1199.98px) {
  /* The county name column gives the numbers room. */
  .sd-card .ob-table th[scope="row"] { max-width: 8rem; white-space: normal; }
  .sd-side-foot a { display: inline-block; padding-block: 0.35rem; }
}
/* A phone on its side: the sheet and chart fit. The site bar stays, as on
   every other page (Oren, Oct 9, 2026: "show TV header"). */
@media (max-width: 1199.98px) and (max-height: 500px) {
  .sd-app { --sd-peek: 6.5rem; }
  .sd-app[data-sheet="half"] .sd-panel { transform: translateY(35%); }
  .sd-chart { height: min(360px, 60vh); }
}

.sd-row-main .sd-badge-news { align-self: flex-start; margin-top: 0.25rem; }
.sd-row-title { hyphens: manual; }

/* Sortable column heads: the whole head is the button. */
.sd-sort { all: unset; box-sizing: border-box; cursor: pointer; display: inline-block; text-align: inherit; font: inherit;
  text-transform: inherit; letter-spacing: inherit; color: inherit; padding: 0.25rem 0; }
.sd-sort:hover { text-decoration: underline; text-underline-offset: 0.2em; }
.sd-sort:focus-visible { outline: 2px solid var(--ob-purple); outline-offset: 2px; border-radius: 4px; }
.sd-sort-arrow { display: inline-block; min-width: 0.9em; margin-left: 0.15em; font-size: 0.7em; }

/* The hover tip on the time-of-year and age bars. */
.sd-tip { position: fixed; z-index: 4000; max-width: 19rem; padding: 0.55rem 0.75rem; font-size: 0.8rem; line-height: 1.4;
  background: var(--sd-raise); color: var(--ob-fg); border: 1px solid var(--sd-edge); border-radius: var(--ob-radius-sm);
  box-shadow: 0 6px 20px -6px var(--sd-cast); pointer-events: none; }
.sd-bar-row[data-tip] { border-radius: 4px; }
.sd-bar-row[data-tip]:hover, .sd-bar-row[data-tip]:focus-visible { background: var(--sd-hover); }

/* People at the same point. Zoomed out: a plain dot like the others (same
   size and outline, the newest person's mode). From zoom 11 (.sd-stack-count
   on the map): a little bigger, numbered, gray when both modes are there.
   Sized from the dots' radius (--sd-stack-d, set as the map zooms). */
.sd-stack { background: none; border: 0; }
.sd-stack span { display: grid; place-items: center; box-sizing: border-box; width: var(--sd-stack-d, 8px); height: var(--sd-stack-d, 8px);
  transform: translate(-50%, -50%); border-radius: 50%; border: 1px solid var(--sd-stroke); opacity: 0.9;
  font: 700 0 system-ui, sans-serif; color: #fff; font-variant-numeric: tabular-nums; }
.sd-stack-pedestrian span { background: var(--sd-ped); }
.sd-stack-bicyclist span { background: var(--sd-bike); }
.sd-stack-count .sd-stack span { font-size: 0.75rem; line-height: 1; border-width: 2px; border-color: var(--sd-stroke); opacity: 1; box-shadow: 0 0 0 1.5px var(--sd-edge); }
.sd-stack-count .sd-stack-mixed span { background: var(--sd-mixed); }
.sd-stack-popup .leaflet-popup-content-wrapper { border-radius: 0.5rem; }
.sd-stack-popup .leaflet-popup-content { margin: 0.5rem 0.75rem; }
.sd-stack-list a { display: block; padding: 0.3rem 0; color: inherit; text-decoration: none; border-top: 1px solid var(--sd-line); }
.sd-stack-list a:first-child { border-top: 0; }
.sd-stack-list a:hover b { text-decoration: underline; }

/* A <details> that opens, with a chevron that turns: the map legend and the
   "How to read this" notes. */
:is(.sd-legend, .sd-how) summary { list-style: none; }
:is(.sd-legend, .sd-how) summary::-webkit-details-marker { display: none; }
:is(.sd-legend, .sd-how) summary::before { content: '\25B8'; display: inline-block; margin-right: 0.35rem; transition: transform 0.15s; }
:is(.sd-legend, .sd-how)[open] summary::before { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) { :is(.sd-legend, .sd-how) summary::before { transition: none; } }

/* Long explanations sit behind a "How to read this" line. */
.sd-how { margin: 0.5rem 0 0; }
.sd-how summary { cursor: pointer; color: var(--ob-muted); font-size: 0.85rem; min-height: 1.75rem; display: flex; align-items: center; }
/* On a touch screen the checkboxes' rows, Trends' disclosures and the table's sort
   buttons are 44px, the site's touch target. */
@media (pointer: coarse) {
  .sd-check, .sd-how summary { min-height: 44px; }
  .sd-sort { min-height: 44px; display: inline-flex; align-items: center; }
}
.sd-how p { margin-top: 0.25rem; }

/* The basemap would not load: one notice, like Hard Tech's. The list and charts still work. */
.sd-notice {
  position: fixed; top: calc(var(--ob-bar-h) + 64px); left: 50%; z-index: 9980;
  transform: translateX(-50%);
  max-width: calc(100vw - 2 * var(--ob-map-inset) - 120px);
  padding: 8px 12px; font-size: 0.8125rem;
}
/* On a small laptop the pill sits below the switch (above), so the notice goes below the pill. */
@media (min-width: 1200px) and (max-width: 1399.98px) { .sd-notice { top: calc(var(--ob-bar-h) + 7.25rem); } }
/* On a phone the "not on the map" button sits top left, so the notice goes under it. */
@media (max-width: 768px) {
  .sd-notice { left: var(--ob-map-inset); transform: none; max-width: calc(100vw - 2 * var(--ob-map-inset) - 64px); top: calc(var(--ob-bar-h) + var(--ob-map-inset) + 124px); }
}
