/* ============================================================================
 * CAUGHT — visual design system
 *
 * One rule runs through this file: the evidence is loud, the interface is
 * quiet. A case about a boat dredging a protected reef does not need a
 * shouting UI to be taken seriously — it needs a calm one, so the finding is
 * the only thing raising its voice.
 *
 * Everything below is built from the token block. Change a token, change the
 * whole app; do not hardcode a colour, radius or shadow past this point.
 * ========================================================================== */

:root {
  /* --- Ink. Four steps, deep slate-navy rather than black: it sits better
   *     against a near-white sea and reads softer at small sizes. --- */
  --ink:        #101a24;
  --ink-2:      #3d4c5e;
  --ink-3:      #5a6879;   /* ≥4.5:1 on white — safe for 11–12px labels */
  --ink-4:      #69778a;   /* lightest text that still clears 4.5:1 on white */

  /* --- Surfaces --- */
  --bg:         #f7f9fb;
  --surface:    #ffffff;
  --surface-2:  #f2f5f8;
  --surface-3:  #e8edf2;
  --line:       #e4e9ef;
  --line-soft:  #eef2f6;
  --sea:        #eef4f8;   /* map canvas */

  /* --- Header. Light and translucent by default. To go back to the old
   *     deep-sea bar, flip these four tokens (nothing else references the
   *     header's colours):
   *       --header-bg: rgba(14,26,36,0.88); --header-ink: #eef3f7;
   *       --header-ink-2: #93a3b3;          --header-line: #1e2c39;   --- */
  --header-bg:    rgba(255,255,255,0.78);
  --header-ink:   var(--ink);
  --header-ink-2: var(--ink-3);
  --header-line:  var(--line);

  /* --- Accent. A muted North-Atlantic blue: 5.4:1 on white, so it carries
   *     link text as well as buttons. --- */
  --accent:      #2f6f9f;
  --accent-ink:  #255a82;
  --accent-soft: #ecf2f7;
  --accent-line: #cfe0ed;
  --accent-ring: rgba(47,111,159,0.20);

  /* --- Case status. Three families, each a solid / ink / tint / hairline set.
   *     Desaturated on purpose — a soft rose still reads as "serious" when
   *     everything around it is grey, and it stops the case list looking like
   *     a hazard sign. --- */
  --caught:      #c0524c;
  --caught-ink:  #8e332e;
  --caught-soft: #fbefee;
  --caught-line: #eed6d3;

  --review:      #c68f3c;
  --review-ink:  #8a5f1c;
  --review-soft: #fcf6ea;
  --review-line: #eee1c8;

  --ok:          #4f8f6d;
  --ok-ink:      #2f6b4c;
  --ok-soft:     #edf5f0;
  --ok-line:     #d2e3d9;

  --port:        #8b84c4;
  --port-ink:    #4f4884;
  --port-soft:   #f1f0f9;
  --port-line:   #ddd9ef;

  /* --- Radii --- */
  --r-xs: 6px;  --r-sm: 8px;  --r-md: 10px;
  --r-lg: 14px; --r-xl: 20px; --r-pill: 999px;

  /* --- Shadows. Layered and low-opacity — one tight contact shadow plus one
   *     wide ambient, never a single hard drop. --- */
  --shadow-xs: 0 1px 2px rgba(16,26,36,0.05);
  --shadow-sm: 0 1px 2px rgba(16,26,36,0.04), 0 2px 8px rgba(16,26,36,0.05);
  --shadow-md: 0 2px 4px rgba(16,26,36,0.04), 0 8px 24px rgba(16,26,36,0.08);
  --shadow-lg: 0 8px 24px -8px rgba(16,26,36,0.16), 0 32px 64px -16px rgba(16,26,36,0.28);

  /* --- Type --- */
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

  /* --- Motion. One easing curve everywhere (a decelerating one — things
   *     arrive, they don't bounce). --- */
  --ease: cubic-bezier(0.32, 0.72, 0, 1);
  --fast: 0.15s var(--ease);
  --slow: 0.28s var(--ease);
}

* { box-sizing: border-box; }

html, body {
  height: 100%; margin: 0;
  font-family: var(--font);
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
/* Column flex so <main> fills whatever height the header leaves — robust even
 * when the header wraps to multiple lines on mobile. */
body { display: flex; flex-direction: column; }
/* Size the app to the VISIBLE screen. On iOS Safari/in-app browsers, 100% and
 * 100vh can resolve to the height with the toolbars hidden, so with them showing
 * the bottom of the app sits under the toolbar and the page has to scroll.
 * 100dvh tracks the toolbars. (Seen 2026-09-13 when the domain moved: a Home
 * Screen icon for caught.fly.dev had been opening full-screen, and the redirect
 * to caught.org.uk put Safari's toolbars back.) The 100% above is the fallback. */
@supports (height: 100dvh) {
  body { height: 100dvh; }
}

/* Numbers in a case list are read as a column, so they line up. */
table, .case-chip, .vote-count, .cat-count, .tv-facts, .ed-row { font-variant-numeric: tabular-nums; }

/* One visible focus treatment for the whole app. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

/* Thin, self-effacing scrollbars — the panel scrolls a lot. */
.tab-panel, .modal-inner, .alerts-zone-list {
  scrollbar-width: thin;
  scrollbar-color: var(--surface-3) transparent;
}
.tab-panel::-webkit-scrollbar, .modal-inner::-webkit-scrollbar, .alerts-zone-list::-webkit-scrollbar { width: 8px; height: 8px; }
.tab-panel::-webkit-scrollbar-thumb, .modal-inner::-webkit-scrollbar-thumb, .alerts-zone-list::-webkit-scrollbar-thumb {
  background: var(--surface-3); border-radius: var(--r-pill); border: 2px solid transparent; background-clip: padding-box;
}
.tab-panel::-webkit-scrollbar-track, .modal-inner::-webkit-scrollbar-track { background: transparent; }


/* ===========================================================================
 * HEADER
 * Three tight rows: identity + navigation, the feed status line, the case
 * counters. The colour legend used to live up here too; it now floats over
 * the map (see .legend), which bought the header a whole row of quiet.
 * ========================================================================= */

header {
  display: flex; align-items: flex-start; justify-content: space-between;
  padding: 12px 20px 11px;
  gap: 20px;
  background: var(--header-bg);
  color: var(--header-ink);
  border-bottom: 1px solid var(--header-line);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  position: relative; z-index: 900;
}
header .title { display: flex; flex-direction: column; gap: 4px; min-width: 0; }

header h1 {
  font-size: 17px; margin: 0; font-weight: 700;
  letter-spacing: 0.18em; line-height: 1.1;
}
header h1 .subbrand {
  font-size: 12.5px; font-weight: 400; color: var(--header-ink-2);
  letter-spacing: 0; margin-left: 8px;
}
header .tagline {
  font-size: 12px; margin: 0; color: var(--header-ink-2);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  letter-spacing: 0.01em;
}
header .tagline .tagline-text { letter-spacing: 0.02em; }
header .tagline b { font-weight: 600; color: var(--ink-2); }

/* Header navigation: quiet text links, separated by hairline dots rather than
 * underlines — three underlined buttons in a row read as clutter. */
.header-nav { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
header .tagline .link-btn, .header-nav .link-btn {
  color: var(--accent); text-decoration: none; font-weight: 500;
  margin: 0; padding: 2px 0; border-radius: var(--r-xs);
  transition: color var(--fast);
}
header .tagline .link-btn:hover, .header-nav .link-btn:hover { color: var(--accent-ink); text-decoration: underline; }

/* Buttons that should read as links, everywhere else. */
.link-btn {
  background: none; border: 0; padding: 0; color: var(--accent);
  font: inherit; cursor: pointer; text-decoration: underline;
  text-underline-offset: 2px; transition: color var(--fast);
}
.link-btn:hover { color: var(--accent-ink); }

/* Feed status. One line, small, deliberately undramatic — a green dot is
 * enough to say "live"; it does not need a badge. */
header .status {
  font-size: 11.5px; margin: 1px 0 0; color: var(--header-ink-2);
  display: flex; gap: 14px; flex-wrap: wrap; align-items: center;
}
header .status strong { font-weight: 600; color: var(--ink-2); }
header .status .src { display: inline-flex; align-items: center; gap: 5px; }
header .status .dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; flex: none; }
header .status .dot.live { background: #34c07f; box-shadow: 0 0 0 3px rgba(52,192,127,0.16); }
header .status .dot.dead { background: var(--ink-4); }
header .status .dot.off  { background: transparent; box-shadow: inset 0 0 0 1px var(--ink-4); }

/* --- Case counters. The one place in the header allowed any colour. --- */
.case-summary { margin: 7px 0 0; display: flex; gap: 7px; flex-wrap: wrap; }
.case-chip {
  border: 1px solid transparent; border-radius: var(--r-pill);
  padding: 4px 13px 4px 11px;
  font-size: 12px; font-weight: 500; cursor: pointer; line-height: 1.45;
  font-family: inherit; letter-spacing: 0.01em;
  transition: transform var(--fast), box-shadow var(--fast), filter var(--fast);
}
.case-chip b { font-size: 13px; font-weight: 700; margin-right: 2px; }
.case-chip:hover { transform: translateY(-1px); box-shadow: var(--shadow-xs); }
.case-chip:active { transform: translateY(0); }
.chip-caught   { background: var(--caught-soft); color: var(--caught-ink); border-color: var(--caught-line); }
.chip-inv      { background: var(--review-soft); color: var(--review-ink); border-color: var(--review-line); }
.chip-ongoing  { background: var(--surface-2);   color: var(--ink-2);      border-color: var(--line); }
.chip-resolved { background: var(--ok-soft);     color: var(--ok-ink);     border-color: var(--ok-line); }


/* ===========================================================================
 * MAP LEGEND — a floating card over the sea, Apple-Maps style, instead of a
 * row of filled pills in the header. Dots carry the colour; the label carries
 * the meaning; neither shouts.
 * ========================================================================= */

.legend {
  position: absolute; left: 12px; bottom: 12px; z-index: 600;
  display: flex; flex-direction: column; gap: 7px;
  padding: 10px 13px;
  background: rgba(255,255,255,0.82);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border: 1px solid rgba(16,26,36,0.06);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  font-size: 11.5px; color: var(--ink-2);
  pointer-events: none;
}
.legend-row { display: flex; align-items: center; gap: 12px; }
.legend-label {
  font-size: 10px; font-weight: 600; color: var(--ink-3);
  text-transform: uppercase; letter-spacing: 0.07em;
  width: 38px; flex: none;
}
.legend .key { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.legend .key::before {
  content: ''; width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--dot, var(--ink-4));
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--dot, var(--ink-4)) 20%, transparent);
}
.key-clean    { --dot: #4f8f6d; }
.key-probable { --dot: #c68f3c; }
.key-caught   { --dot: #c0524c; }
/* Zone keys use a square swatch — zones are areas, boats are points. The
 * restricted-water swatch is painted at the same strength as the wash on the
 * map (see strictPane's opacity in app.js), with a hairline so it's findable
 * on the legend's own pale card. */
.legend .key-zone::before { border-radius: 3px; }
.key-notake::before {
  background: rgba(192,82,76,0.30) !important;
  box-shadow: inset 0 0 0 1px rgba(192,82,76,0.55) !important;
}
.key-port { --dot: #8b84c4; }
.legend-sep { width: 1px; height: 13px; background: var(--line); margin: 0 2px; }

/* Legacy badge classes, kept so nothing that still emits them breaks. */
.badge { padding: 3px 9px; border-radius: var(--r-pill); font-size: 11.5px; }
.badge.clean    { background: var(--ok-soft);     color: var(--ok-ink); }
.badge.probable { background: var(--review-soft); color: var(--review-ink); }
.badge.caught   { background: var(--caught-soft); color: var(--caught-ink); }
.badge-zone     { padding: 3px 9px; border-radius: var(--r-pill); color: #fff; font-size: 11px; }


/* ===========================================================================
 * LAYOUT
 * ========================================================================= */

main { display: grid; grid-template-columns: 1fr 484px; flex: 1 1 auto; min-height: 0; }

#map-wrap { position: relative; }
/* Near-white sea — the figure-ground is inverted from a normal map: water is
 * the canvas, land is the plain quiet silhouette drawn over it. */
#map { height: 100%; width: 100%; background: var(--sea); }

/* Leaflet's own chrome, brought into the system. */
.leaflet-control-zoom, .leaflet-control-layers {
  border: 1px solid rgba(16,26,36,0.06) !important;
  border-radius: var(--r-md) !important;
  box-shadow: var(--shadow-sm) !important;
  overflow: hidden;
}
/* background-COLOR only — the layers toggle carries its icon as a
 * background-image, and the shorthand would wipe it. */
.leaflet-control-zoom a, .leaflet-control-layers-toggle {
  background-color: rgba(255,255,255,0.86) !important;
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  color: var(--ink-2) !important; border-color: rgba(16,26,36,0.06) !important;
}
.leaflet-control-zoom a:hover { background-color: #fff !important; color: var(--ink) !important; }
.leaflet-control-layers-expanded {
  background-color: rgba(255,255,255,0.94) !important;
  padding: 10px 14px 10px 11px !important;
  font-size: 12.5px; color: var(--ink-2);
}
.leaflet-control-layers-expanded label { padding: 2px 0; }
.leaflet-control-layers-separator { border-top: 1px solid var(--line) !important; }
.leaflet-container { font-family: var(--font); }
.leaflet-control-attribution {
  background: rgba(255,255,255,0.7) !important;
  font-size: 10px !important; color: var(--ink-4) !important;
  border-radius: var(--r-xs) 0 0 0; padding: 2px 7px !important;
}
.leaflet-control-attribution a { color: var(--ink-3) !important; }
.leaflet-popup-content-wrapper {
  border-radius: var(--r-lg) !important;
  box-shadow: var(--shadow-md) !important;
  font-family: var(--font);
}

#side {
  background: var(--bg);
  border-left: 1px solid var(--line);
  display: flex; flex-direction: column; min-height: 0;
}


/* ===========================================================================
 * TABS — a segmented control, not a filing cabinet.
 * ========================================================================= */

.tabs {
  display: flex; gap: 3px;
  margin: 12px 14px 10px;
  padding: 3px;
  background: var(--surface-2);
  border-radius: var(--r-md);
}
.tab {
  flex: 1; padding: 7px 10px; border: 0; background: transparent;
  cursor: pointer; font-weight: 500; font-size: 13px; color: var(--ink-3);
  font-family: inherit; border-radius: var(--r-sm);
  transition: color var(--fast), background var(--fast), box-shadow var(--fast);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tab:hover { color: var(--ink); }
/* Label halves that survive or vanish with the viewport (see the mobile block). */
.nav-short { display: none; }
.tab.active {
  background: var(--surface); color: var(--ink); font-weight: 600;
  box-shadow: var(--shadow-xs);
}
.tab-panel { display: none; flex: 1; overflow: auto; }
.tab-panel.active { display: block; }


/* ===========================================================================
 * TABLES — the case list. Airier rows, hairline rules, and status carried by
 * a coloured edge rather than a tinted row: a list of twenty tinted rows is a
 * list you stop reading.
 * ========================================================================= */

table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 11px 14px; border-bottom: 1px solid var(--line-soft); }
/* Solid, not translucent: a blurred sticky header sounds nice until a blue
 * button scrolls under it and tints the column labels. */
th {
  position: sticky; top: 0; z-index: 2;
  background: var(--bg);
  font-weight: 600; font-size: 10.5px; color: var(--ink-3);
  text-transform: uppercase; letter-spacing: 0.06em;
  padding-top: 8px; padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
}
td { color: var(--ink-2); }
tr.row-bad td   { background: var(--caught-soft); }
tr.row-worst td { background: var(--caught-soft); }

/* Boats table: a 3px coloured edge gives an at-a-glance status read down the
 * list. Only CAUGHT gets a tint, and a barely-there one. */
tr.boat-caught td { background: color-mix(in srgb, var(--caught-soft) 55%, transparent); }
tr.boat-caught   td:first-child { box-shadow: inset 3px 0 0 var(--caught); }
tr.boat-probable td:first-child { box-shadow: inset 3px 0 0 var(--review); }
tr.boat-clean    td:first-child { box-shadow: inset 3px 0 0 var(--ok); }
/* Case-count cells in the Boats table */
.cnt-caught   { color: var(--caught-ink); font-weight: 600; }
.cnt-probable { color: var(--review-ink); font-weight: 600; }

tr:hover td { background: var(--surface-2); }
tr.clickable { cursor: pointer; }
tr.clickable td { transition: background var(--fast); }

button.link {
  background: none; border: 0; color: var(--accent); cursor: pointer;
  font-size: 12px; padding: 0; font-family: inherit;
}
button.link:hover { color: var(--accent-ink); text-decoration: underline; }

/* --- Category headers in the case table. The old CAUGHT band was near-black
 *     maroon; a soft rose with a solid dot says the same thing without
 *     turning a third of the panel into a warning label. --- */
tr.category-header { cursor: pointer; user-select: none; }
tr.category-header > td {
  background: var(--surface-2); font-weight: 600; font-size: 13px;
  padding: 11px 14px; border-bottom: 1px solid var(--line);
  color: var(--ink); transition: background var(--fast);
}
tr.category-header.cat-caught > td        { background: var(--caught-soft); color: var(--caught-ink); }
tr.category-header.cat-caught .cat-count  { background: rgba(142,51,46,0.10); color: var(--caught-ink); }
tr.category-header.cat-probable > td      { background: var(--review-soft); color: var(--review-ink); }
tr.category-header.cat-probable .cat-count { background: rgba(138,95,28,0.10); color: var(--review-ink); }
tr.category-header.cat-investigation > td { background: var(--caught-soft); color: var(--caught-ink); }
tr.category-header.cat-ongoing > td       { background: var(--review-soft); color: var(--review-ink); }
tr.category-header.cat-resolved > td      { background: var(--ok-soft); color: var(--ok-ink); }
tr.category-header.cat-resolved .cat-count { background: rgba(47,107,76,0.10); color: var(--ok-ink); }
tr.category-header:hover > td { filter: brightness(0.985); }
tr.category-header .cat-toggle {
  display: inline-block; width: 14px; text-align: center;
  color: currentColor; opacity: 0.55; font-size: 11px;
}
tr.category-header .cat-count {
  display: inline-block; margin-left: 8px;
  padding: 1px 9px; border-radius: var(--r-pill);
  background: rgba(16,26,36,0.07); font-size: 11px; font-weight: 700;
}
tr.category-header .cat-sub {
  margin-left: 12px; font-weight: 400; font-size: 11px;
  opacity: 0.8; letter-spacing: 0.01em;
}


/* ===========================================================================
 * INLINE TAGS — registration, source attribution, flags.
 * All share one shape: pill, 10–11px, semibold, tinted rather than filled.
 * ========================================================================= */

.mmo-ok  { color: var(--ok-ink);     font-weight: 700; cursor: help; }
.mmo-bad { color: var(--caught-ink); font-weight: 700; cursor: help; }

.regno {
  display: inline-block; margin-left: 5px;
  background: var(--surface-2); color: var(--ink-3);
  padding: 1px 7px; border-radius: var(--r-xs);
  font-family: var(--mono); font-size: 10.5px; font-weight: 600;
}
/* GFW-derived vessel (satellite case, no live AIS) tag in the Boats list */
.src-gfw {
  display: inline-block; margin-left: 5px;
  background: var(--accent-soft); color: var(--accent-ink);
  padding: 1px 7px; border-radius: var(--r-xs);
  font-size: 10px; font-weight: 700; white-space: nowrap;
}
.boat-gfw-note { color: var(--ink-4); font-size: 12px; cursor: help; }

.src-tag {
  display: inline-block; padding: 0 6px; border-radius: var(--r-xs);
  font-family: var(--mono); font-size: 10px; font-weight: 700; line-height: 17px;
}
.src-tag.src-aisstream  { background: var(--ok-soft); color: var(--ok-ink); }
.src-tag.src-datalastic { background: var(--review-soft); color: var(--review-ink); }
.src-tag.src-open       { background: var(--surface-2); color: var(--ink-3); font-weight: 500; }
.src-tag.src-none       { background: var(--surface-2); color: var(--ink-3); }
.src-arrow { margin: 0 5px; color: var(--ink-4); font-size: 11px; }
.src-note  { color: var(--review-ink); font-weight: 600; font-size: 11px; }

.flag-tag {
  display: inline-block; padding: 1px 7px; margin-right: 4px;
  border-radius: var(--r-pill); font-size: 10px; font-weight: 700; line-height: 16px;
  letter-spacing: 0.01em;
}
.flag-tag.flag-port    { background: var(--port-soft);   color: var(--port-ink); }
.flag-tag.flag-mpa     { background: var(--caught-soft); color: var(--caught-ink); }
.flag-tag.flag-unusual { background: var(--review-soft); color: var(--review-ink); }
.flag-tag.flag-sat-ok  { background: var(--ok-soft);     color: var(--ok-ink); }
.flag-tag.flag-sat-bad { background: var(--caught-soft); color: var(--caught-ink); }
/* Strict no-fishing zone — the evidence-grade flag. It earns a solid fill. */
.flag-tag.flag-strict  { background: var(--caught); color: #fff; }
/* CAUGHT — satellite-confirmed violation. Top of the hierarchy. */
.flag-tag.flag-caught  { background: var(--caught-ink); color: #fff; }
.flag-tag.flag-darktarget { background: var(--accent-soft); color: var(--accent-ink); }


/* ===========================================================================
 * SUPPORT / FEEDBACK PANE
 * ========================================================================= */

.support-pane { padding: 6px 20px 24px; color: var(--ink); line-height: 1.6; }
.support-pane h2 { margin: 8px 0 12px; font-size: 19px; font-weight: 700; letter-spacing: -0.01em; }
.support-pane h3 {
  margin: 26px 0 8px; font-size: 11px; color: var(--ink-3);
  text-transform: uppercase; letter-spacing: 0.07em; font-weight: 600;
}
.support-pane p, .support-pane ul { font-size: 13.5px; color: var(--ink-2); margin: 8px 0; }
.support-pane ul { padding-left: 20px; }
.support-pane li { margin: 6px 0; }
.support-pane b { color: var(--ink); font-weight: 600; }
.support-pane .fineprint {
  font-size: 11.5px; color: var(--ink-3); line-height: 1.55;
  border-top: 1px solid var(--line); padding-top: 14px; margin-top: 24px;
}
/* Ko-fi coral, dropped to the darkest shade that still reads as coral — white
 * label text on the original was 2.9:1. */
.donate-btn {
  display: inline-block; margin: 12px 0 4px;
  background: #bf5449; color: #fff;
  padding: 11px 20px; border-radius: var(--r-md);
  text-decoration: none; font-weight: 600; font-size: 14px;
  box-shadow: var(--shadow-sm);
  transition: background var(--fast), transform var(--fast), box-shadow var(--fast);
}
.donate-btn:hover { background: #a8483f; transform: translateY(-1px); box-shadow: var(--shadow-md); }
.donate-btn:active { transform: translateY(0); }

a.ext { font-size: 12px; color: var(--accent); margin-left: 8px; text-decoration: none; font-weight: 500; }
a.ext:hover { text-decoration: underline; }


/* ===========================================================================
 * MODALS — sheets, not dialog boxes. Blurred scrim, large radius, real
 * padding, and a soft circular close button in the corner.
 * ========================================================================= */

.modal {
  position: fixed; inset: 0; z-index: 9999;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgba(12,20,28,0.34);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  backdrop-filter: blur(14px) saturate(140%);
  animation: modal-scrim var(--slow) both;
}
.modal.hidden { display: none; }
/* Generic hide, used by every `classList.toggle('hidden', …)` in app.js. */
.hidden { display: none !important; }

.modal-inner {
  background: var(--surface); border-radius: var(--r-xl);
  padding: 30px 34px; min-width: 520px; max-width: 640px;
  max-height: min(84vh, 880px); max-height: min(84dvh, 880px); overflow: auto; position: relative;
  box-shadow: var(--shadow-lg);
  border: 1px solid rgba(16,26,36,0.05);
  animation: modal-rise var(--slow) both;
}
@keyframes modal-scrim { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-rise  { from { opacity: 0; transform: translateY(12px) scale(0.985); } to { opacity: 1; transform: none; } }

.modal h2 { margin: 0 0 16px; font-size: 22px; font-weight: 700; letter-spacing: -0.02em; }
.modal h3 { letter-spacing: -0.005em; }

/* Every modal's close button, one treatment. */
#modal-close, .alerts-modal #alerts-close, .auth-modal #auth-close, .about-modal #about-close {
  position: absolute; top: 16px; right: 16px;
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0;
  background: var(--surface-2); border: 0; border-radius: 50%;
  font-size: 17px; line-height: 1; cursor: pointer; color: var(--ink-3);
  transition: background var(--fast), color var(--fast);
}
#modal-close:hover, .alerts-modal #alerts-close:hover,
.auth-modal #auth-close:hover, .about-modal #about-close:hover {
  background: var(--surface-3); color: var(--ink);
}

.event-row { padding: 12px 0; border-bottom: 1px solid var(--line-soft); }
.event-row .meta { color: var(--ink-3); font-size: 12px; }
.event-row .mpa  { color: var(--caught-ink); font-weight: 600; }
.mini-map { height: 200px; width: 100%; margin-top: 8px; background: var(--sea); border-radius: var(--r-md); }

/* Triangle/circle SVG markers have no chrome from Leaflet — clear the defaults. */
.leaflet-div-icon.boat-icon, .boat-icon { background: transparent; border: 0; }

/* Case pins on the map */
.event-pin { background: transparent !important; border: 0 !important; }
.event-pin-inner {
  display: inline-block; padding: 3px 9px; border-radius: var(--r-pill);
  font-size: 11px; font-weight: 600; color: #fff;
  box-shadow: var(--shadow-md);
}
.event-pin-inner.off { background: var(--ok); }
.event-pin-inner.on  { background: var(--caught); }


/* ===========================================================================
 * ABOUT MODAL — the longest read on the site, so it gets book typography:
 * a measure that doesn't run wide, generous leading, quiet headings.
 * ========================================================================= */

.about-modal { min-width: 520px; max-width: 660px; line-height: 1.65; }
.about-modal h2 { margin-top: 0; }
.about-modal h3 {
  margin: 30px 0 8px; font-size: 11px; color: var(--ink-3);
  text-transform: uppercase; letter-spacing: 0.07em; font-weight: 600;
}
.about-modal p, .about-modal ul, .about-modal ol { font-size: 14px; color: var(--ink-2); margin: 10px 0; }
.about-modal ul, .about-modal ol { padding-left: 22px; }
.about-modal li { margin: 6px 0; }
.about-modal b, .about-modal strong { color: var(--ink); font-weight: 600; }
.about-modal ol.workflow > li { margin: 12px 0; }
.about-modal ol.workflow ul { margin-top: 6px; }
.about-modal a { color: var(--accent); text-decoration-color: var(--accent-line); text-underline-offset: 2px; }
.about-modal a:hover { color: var(--accent-ink); }
.about-modal .fineprint {
  font-size: 11.5px; color: var(--ink-3); line-height: 1.55;
  border-top: 1px solid var(--line); padding-top: 14px; margin-top: 24px;
}
/* Callouts: a tinted card with a coloured spine. */
.about-modal .gfw-credit, .about-modal .triage-callout {
  border-radius: var(--r-md); padding: 14px 18px; margin: 16px 0;
  font-size: 13.5px; color: var(--ink); line-height: 1.6;
}
.about-modal .gfw-credit { background: var(--ok-soft); border-left: 3px solid var(--ok); }
.about-modal .gfw-credit b { color: var(--ok-ink); }
.about-modal .gfw-credit a { color: var(--ok-ink); font-weight: 600; }
.about-modal .triage-callout { background: var(--accent-soft); border-left: 3px solid var(--accent); }
.about-modal .triage-callout strong { color: var(--accent-ink); }

/* Case-throughput chart (About modal) */
.case-chart { margin: 12px 0 6px; }
.case-chart svg {
  display: block; background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--r-md);
}
.cc-legend { display: flex; gap: 16px; font-size: 12px; color: var(--ink-2); margin-bottom: 8px; flex-wrap: wrap; }
.cc-key { display: inline-flex; align-items: center; gap: 6px; }
.cc-dot { width: 9px; height: 9px; border-radius: 3px; display: inline-block; }


/* ===========================================================================
 * CASE DETAIL — the expansion under a clicked case row. This is the app's
 * real content surface, so it's a card: white, lifted, breathing.
 * ========================================================================= */

tr.expanded-row > td {
  padding: 0; background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
.event-details {
  padding: 16px 18px;
  font-size: 13px; color: var(--ink);
  line-height: 1.55;
}
/* Bottom-sheet chrome — only shown when the expansion becomes a sheet on mobile. */
.sheet-handle, .sheet-close, .sheet-title { display: none; }

.event-details .ed-title { font-weight: 700; font-size: 15px; margin-bottom: 12px; letter-spacing: -0.01em; }
.event-details .ed-flag  { color: var(--ink-4); font-weight: 400; font-size: 11px; margin-left: 5px; }
/* Label / value rows. A fixed label column with the value left-aligned beside
 * it — the old right-aligned flex looked tidy on "0.58 h" and ragged on a
 * three-line zone name, and zone names are the ones people actually read. */
.event-details .ed-row {
  display: grid; grid-template-columns: minmax(88px, 116px) 1fr; gap: 16px;
  padding: 7px 0; color: var(--ink-3); font-size: 12.5px;
  border-bottom: 1px solid var(--line-soft);
  align-items: baseline;
}
.event-details .ed-row span:last-child { color: var(--ink); font-weight: 600; text-align: left; }

/* Verdict / evidence blocks. Every one is a tinted card with a coloured spine
 * — same shape, different family, so the eye learns the pattern once. */
.event-details .ed-hit {
  margin-top: 12px; padding: 11px 14px; border-radius: var(--r-md);
  font-size: 12.5px; line-height: 1.55;
}
.event-details .ed-hit.ed-mpa  { background: var(--caught-soft); color: var(--caught-ink); }
.event-details .ed-hit.ed-port { background: var(--port-soft);   color: var(--port-ink); }
.event-details .ed-hit.ed-strict {
  background: var(--caught-soft); color: var(--caught-ink);
  border-left: 3px solid var(--caught);
  padding: 13px 16px; font-size: 13.5px; font-weight: 600;
}
.event-details .ed-hit.ed-strict .ed-sub { color: var(--caught-ink); opacity: 0.85; font-weight: 400; }
.event-details .ed-ok { margin-top: 8px; color: var(--ink-3); font-size: 12px; }
.event-details .ed-hit.ed-sat-ok  { background: var(--ok-soft);     color: var(--ok-ink); }
.event-details .ed-hit.ed-sat-bad { background: var(--caught-soft); color: var(--caught-ink); }

/* CAUGHT evidence block. It used to be a near-black maroon panel with white
 * text — the loudest thing on the site. It is now the same soft card as its
 * siblings, distinguished by a solid spine and a heavier title. Being right
 * is what makes it serious; the styling doesn't have to. */
.event-details .ed-hit.ed-caught {
  background: var(--caught-soft); color: var(--caught-ink);
  border-left: 3px solid var(--caught);
  padding: 14px 16px; border-radius: var(--r-md); font-size: 13px;
  box-shadow: none;
}
.event-details .ed-hit.ed-caught .ed-sub { color: var(--caught-ink); opacity: 0.85; }
.event-details .ed-caught .ed-evidence { margin-top: 10px; }
.event-details .ed-caught .ed-row {
  border-bottom-color: rgba(142,51,46,0.14); color: var(--caught-ink);
}
.event-details .ed-caught .ed-row span:last-child { color: var(--caught-ink); }

.event-details .ed-imagery { margin-top: 12px; padding-top: 10px; border-top: 1px solid rgba(142,51,46,0.14); }
.event-details .ed-imagery-title {
  font-size: 10.5px; font-weight: 600; color: var(--caught-ink); opacity: 0.8;
  text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 6px;
}
.event-details .ed-img-link {
  display: block; color: var(--caught-ink); font-size: 12.5px; font-weight: 600;
  text-decoration: none; padding: 4px 0;
}
.event-details .ed-img-link:hover { text-decoration: underline; }
.event-details .ed-photo-note { color: var(--caught-ink) !important; opacity: 0.8; margin-top: 8px; }

/* Sentinel-imagery review block in the case expansion */
.event-details .lead-imagery { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.event-details .lead-imagery-title { font-size: 12.5px; font-weight: 700; color: var(--ink); margin-bottom: 8px; }
.event-details .lead-img-link {
  display: block; color: var(--accent); font-size: 13px; font-weight: 600;
  text-decoration: none; padding: 5px 0;
}
.event-details .lead-img-link:hover { color: var(--accent-ink); text-decoration: underline; }
.event-details .lead-imagery-note { color: var(--ink-3); font-size: 11.5px; margin-top: 8px; line-height: 1.5; }

/* GFW cross-checks block (disabling / radar / loitering / encounters) */
.event-details .ed-corro { margin-top: 12px; padding-top: 10px; border-top: 1px solid rgba(142,51,46,0.14); }
.event-details .ed-corro-title {
  font-size: 10.5px; font-weight: 600; color: var(--caught-ink); opacity: 0.8;
  margin-bottom: 5px; text-transform: uppercase; letter-spacing: 0.06em;
}
.event-details .ed-corro-row { font-size: 12px; color: var(--caught-ink); padding: 3px 0; }
.event-details .ed-sat-bad .ed-corro, .event-details .ed-darktarget .ed-corro { border-top-color: var(--line); }
.event-details .ed-sat-bad .ed-corro-title { color: var(--caught-ink); }
.event-details .ed-sat-bad .ed-corro-row   { color: var(--caught-ink); }
.event-details .ed-darktarget .ed-corro-title { color: var(--accent-ink); }
.event-details .ed-darktarget .ed-corro-row   { color: var(--accent-ink); }

/* Radar dark-target panel (blue — radar, not AIS) */
.event-details .ed-hit.ed-darktarget {
  background: var(--accent-soft); color: var(--accent-ink);
  border-left: 3px solid var(--accent);
}

/* Sentinel-1 chip */
.event-details .ed-s1chip { margin-top: 12px; }
.event-details .ed-s1-head { font-size: 12px; margin-bottom: 8px; }
.event-details .ed-s1-img {
  display: block; width: 100%; max-width: 320px; border-radius: var(--r-md);
  margin: 8px 0; background: #0b1424; image-rendering: pixelated;
  box-shadow: var(--shadow-sm);
}
.event-details .ed-s1-loading, .event-details .ed-s1-none { font-size: 11px; color: var(--ink-3); }

/* Confidence badge on a CAUGHT panel */
.event-details .ed-conf {
  display: inline-block; padding: 2px 9px; border-radius: var(--r-pill);
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.05em; vertical-align: middle;
}
.event-details .ed-conf-hi  { background: rgba(142,51,46,0.12); color: var(--caught-ink); }
.event-details .ed-conf-med { background: rgba(138,95,28,0.12); color: var(--review-ink); }

/* Evidence-pack button */
.event-details .ed-pack-btn {
  display: inline-block; margin-top: 14px; padding: 8px 14px; border-radius: var(--r-md);
  background: var(--surface); color: var(--caught-ink); font-weight: 600; font-size: 12.5px;
  text-decoration: none; border: 1px solid var(--caught-line);
  transition: background var(--fast), border-color var(--fast);
}
.event-details .ed-pack-btn:hover { background: var(--caught-soft); border-color: var(--caught); }
.event-details .ed-sub { font-size: 11.5px; opacity: 0.85; display: block; margin-top: 4px; }

/* Collapsible long list (MPAs / ports) — built on HTML5 <details> */
.event-details .ed-collapse { padding: 0; }
.event-details .ed-collapse summary {
  list-style: none; cursor: pointer;
  padding: 7px 9px; border-radius: var(--r-sm);
  transition: background var(--fast);
}
.event-details .ed-collapse summary:hover { background: var(--surface-2); }
.event-details .ed-collapse summary::-webkit-details-marker { display: none; }
.event-details .ed-collapse summary::before {
  content: '›'; display: inline-block; transition: transform var(--fast);
  margin-right: 7px; color: var(--ink-4); font-weight: 600;
}
.event-details .ed-collapse[open] summary::before { transform: rotate(90deg); }
.event-details .ed-collapse .ed-list { padding: 4px 12px 10px 24px; font-size: 11.5px; line-height: 1.55; }
.event-details .ed-hint { color: var(--ink-4); font-weight: 400; font-size: 11px; }


/* ===========================================================================
 * NETTED EVENTS — case chrome
 * ========================================================================= */

.lead-conf {
  display: inline-block; padding: 2px 9px; border-radius: var(--r-pill);
  font-size: 11px; font-weight: 600;
}
.lead-conf-caught   { background: var(--caught-soft); color: var(--caught-ink); }
.lead-conf-probable { background: var(--review-soft); color: var(--review-ink); }
.lead-conf-resolved { background: var(--ok-soft);     color: var(--ok-ink); }
.lead-links a, .lead-evlink { margin-right: 8px; white-space: nowrap; }

/* The single, prominent "Review case" action. */
.lead-action { margin: 14px 0; }
.review-case-btn {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--accent); color: #fff; font-weight: 600; font-size: 13px;
  padding: 10px 18px; border-radius: var(--r-md); text-decoration: none;
  white-space: nowrap; box-shadow: var(--shadow-xs);
  transition: background var(--fast), transform var(--fast), box-shadow var(--fast);
}
.review-case-btn:hover { background: var(--accent-ink); transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.review-case-btn:active { transform: translateY(0); }

.reviewed-tag { font-size: 11px; cursor: help; }
.lead-flag {
  font-size: 10px; padding: 2px 7px; border-radius: var(--r-pill);
  cursor: help; white-space: nowrap; vertical-align: middle; font-weight: 600;
}
.flag-gearamb  { background: var(--review-soft); color: var(--review-ink); }
.flag-marginal { background: var(--surface-3);   color: var(--ink-3); }

/* Gear (verified) — the CAUGHT database's own verdict, and the row a reviewer
 * should read first. Colour-coded UNLIKE the movement check, and deliberately so:
 * this row genuinely does decide the case. Confirmed bottom-towed gear is the
 * thing these closures ban, and permitted gear means there is nothing to answer.
 * All three reuse the existing status tokens so the panel keeps one palette. */
.vg-towed     { color: var(--caught-ink); cursor: help; }
.vg-permitted { color: var(--ok-ink);     cursor: help; }
.vg-ambiguous { color: var(--review-ink); cursor: help; }
/* "Not yet researched" must read as an ABSENCE of evidence, not as a finding —
 * muted, never coloured, so it can't be mistaken for a verdict either way. */
.vg-unknown   { color: var(--ink-3); font-style: italic; cursor: help; }
/* The gear citation's disclosure control. It was a <span title> until
 * 2026-08-31: it LOOKED interactive but was inert on click, and a native title
 * tooltip never fires on a touch device, so on a phone the evidence behind our
 * strongest gear claim was unreachable. Now a real button — hence the reset of
 * the UA button styling, a pointer cursor, and a visible focus ring for keyboard
 * users. Kept visually identical to the old affordance so nothing else moves. */
.vg-cite {
  font-size: 10px; color: var(--ink-3); cursor: pointer;
  border: 0; border-bottom: 1px dotted currentColor;
  background: none; font-family: inherit; line-height: inherit;
  /* Vertical padding with a matching negative margin grows the TAP TARGET from
   * 45x17 to 45x29 without moving anything on the page. This control is only
   * reachable by tapping — the touch case is the one that was broken — and a
   * 17 px-high target is not a fair thing to ask of a finger. */
  padding: 6px 2px; margin: -6px 0 -6px 2px;
}
.vg-cite:hover { color: var(--ink); }
.vg-cite:focus-visible { outline: 2px solid var(--accent, currentColor); outline-offset: 2px; }
.vg-cite[aria-expanded="true"] { color: var(--ink); border-bottom-style: solid; }

/* The citation itself. Its own block under the verdict, normal weight so a long
 * prose citation never competes with the verdict line above it. */
.vg-source {
  display: block; margin-top: 4px; font-size: 11px; font-weight: 400;
  color: var(--ink-2); line-height: 1.45;
}
.vg-source b { font-weight: 600; color: var(--ink-3); }
.vg-source a { color: inherit; }

/* Movement check — fished here vs. passed through (transitAnalysis.js).
 * Deliberately NOT colour-coded like a verdict: green would read as "cleared"
 * and red as "guilty", and this check decides neither. */
.event-details .lead-transit span:last-child { font-weight: 400; }
.lead-transit .tv-badge {
  display: inline-block; font-size: 11px; font-weight: 600;
  padding: 2px 9px; border-radius: var(--r-pill); white-space: nowrap;
  vertical-align: middle; cursor: help;
}
.tv-fishing { background: var(--caught-soft); color: var(--caught-ink); }
.tv-transit { background: var(--accent-soft); color: var(--accent-ink); }
.tv-unclear { background: var(--surface-3);   color: var(--ink-3); }
.lead-transit .tv-facts { font-size: 11.5px; color: var(--ink-3); margin-top: 4px; }
.lead-transit .tv-reasons {
  margin: 6px 0 0; padding-left: 18px; font-size: 11.5px;
  color: var(--ink-3); line-height: 1.55; text-align: left;
}
.lead-transit .tv-reasons li { margin: 3px 0; }
.lead-transit .tv-demoted {
  margin-top: 7px; font-size: 11.5px; color: var(--accent-ink); text-align: left;
  border-left: 2px solid var(--accent-line); padding-left: 9px;
}

/* --- "Write to your MP" — the political-pressure step. Sits below the vote
 *     panel: reviewing the case comes first, acting on it second. --- */
.lead-mp {
  margin-top: 14px; border: 1px solid var(--ok-line); border-radius: var(--r-md);
  background: var(--ok-soft); font-size: 12.5px; color: var(--ok-ink);
  overflow: hidden;
}
.lead-mp summary {
  list-style: none; cursor: pointer; font-weight: 600;
  padding: 10px 13px; color: var(--ok-ink);
}
.lead-mp summary::-webkit-details-marker { display: none; }
.lead-mp summary::before { content: '›'; display: inline-block; margin-right: 8px; transition: transform var(--fast); }
.lead-mp[open] summary::before { transform: rotate(90deg); }
.lead-mp .mp-blurb, .lead-mp .mp-privacy, .lead-mp .mp-edit-hint { margin: 0 13px 10px; line-height: 1.55; }
.lead-mp .mp-privacy, .lead-mp .mp-edit-hint { color: var(--ok-ink); opacity: 0.75; font-size: 11.5px; }
.mp-form { display: flex; gap: 8px; margin: 0 13px 10px; flex-wrap: wrap; }
.mp-postcode {
  flex: 1 1 140px; min-width: 0; padding: 8px 11px; border-radius: var(--r-sm);
  border: 1px solid var(--ok-line); background: var(--surface); font-family: inherit;
  font-size: 12.5px; color: var(--ink); text-transform: uppercase;
  transition: border-color var(--fast), box-shadow var(--fast);
}
.mp-postcode:focus { outline: 0; border-color: var(--ok); box-shadow: 0 0 0 3px rgba(79,143,109,0.16); }
.mp-find {
  padding: 8px 14px; border-radius: var(--r-sm); border: 0; cursor: pointer;
  background: var(--ok-ink); color: #fff; font-weight: 600; font-size: 12.5px;
  font-family: inherit; transition: background var(--fast);
}
.mp-find:hover { background: #275a3f; }
.mp-find:disabled { background: var(--ink-4); cursor: default; }
.mp-status { margin: 0 13px; min-height: 14px; font-size: 11.5px; color: var(--ok-ink); opacity: 0.8; }
.mp-result { margin: 0 13px 13px; }
.mp-who { margin: 6px 0 8px; font-size: 13px; }
.mp-letter {
  width: 100%; box-sizing: border-box; padding: 11px; border-radius: var(--r-sm);
  border: 1px solid var(--ok-line); background: var(--surface); font-family: inherit;
  font-size: 12.5px; line-height: 1.6; color: var(--ink); resize: vertical;
  transition: border-color var(--fast), box-shadow var(--fast);
}
.mp-letter:focus { outline: 0; border-color: var(--ok); box-shadow: 0 0 0 3px rgba(79,143,109,0.16); }
.mp-actions { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.mp-send, .mp-copy {
  padding: 8px 14px; border-radius: var(--r-sm); border: 0; cursor: pointer;
  font-weight: 600; font-size: 12.5px; text-decoration: none; display: inline-block;
  font-family: inherit; transition: background var(--fast);
}
.mp-send { background: var(--ok-ink); color: #fff; }
.mp-send:hover { background: #275a3f; }
.mp-copy { background: var(--surface); color: var(--ok-ink); border: 1px solid var(--ok-line); }
.mp-copy:hover { background: var(--ok-soft); }
.mp-devolved {
  margin-top: 12px; padding: 11px 13px; border-radius: var(--r-sm);
  background: var(--surface); border: 1px solid var(--ok-line); line-height: 1.6;
}
.mp-devolved a { display: inline-block; margin-top: 4px; }

/* --- Zone restriction class — the legal crux of every case. Badge in the
 *     case list, full-width banner in the expanded review panel. --- */
.zone-class-badge {
  display: inline-block; font-size: 10px; font-weight: 700;
  padding: 2px 8px; border-radius: var(--r-pill); white-space: nowrap;
  vertical-align: middle; cursor: help;
}
.zone-class-banner {
  display: block; margin: 12px 0 4px; padding: 10px 14px;
  border-radius: var(--r-md); font-size: 13px; font-weight: 600; cursor: help;
}
.zc-notake { background: var(--caught-soft); color: var(--caught-ink); border: 1px solid var(--caught-line); }
.zc-gear   { background: var(--review-soft); color: var(--review-ink); border: 1px solid var(--review-line); }

.lead-chip .ed-img-link { color: var(--accent); }

/* --- "How to verify this case" --- */
.lead-verify {
  margin-top: 14px; border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); font-size: 12.5px; color: var(--ink-2); overflow: hidden;
}
.lead-verify summary {
  list-style: none; cursor: pointer; font-weight: 600;
  padding: 10px 13px; color: var(--ink);
}
.lead-verify summary::-webkit-details-marker { display: none; }
.lead-verify summary::before { content: '›'; display: inline-block; margin-right: 8px; color: var(--ink-4); transition: transform var(--fast); }
.lead-verify[open] summary::before { transform: rotate(90deg); }
.lead-verify ol { margin: 0; padding: 0 16px 10px 30px; }
.lead-verify li { margin: 7px 0; line-height: 1.55; }
.lead-verify-rule {
  margin: 0 13px 13px; padding: 11px 13px; border-radius: var(--r-sm);
  background: var(--surface-2); line-height: 1.6;
}


/* ===========================================================================
 * REVIEWER VERDICT PANEL — the crowd vote.
 * ========================================================================= */

.lead-review {
  margin-top: 14px; padding: 14px; border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--shadow-xs);
}
.lead-review-title {
  font-size: 10.5px; font-weight: 600; color: var(--ink-3);
  text-transform: uppercase; letter-spacing: 0.07em; margin-bottom: 10px;
}
.rv-reason-wrap { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.rv-reason, .rv-note {
  flex: 1 1 180px; min-width: 0; padding: 8px 11px; border-radius: var(--r-sm);
  border: 1px solid var(--line); background: var(--surface);
  font-family: inherit; font-size: 12.5px; color: var(--ink);
  transition: border-color var(--fast), box-shadow var(--fast);
}
.rv-note { flex-basis: 160px; }
.rv-reason:focus, .rv-note:focus { outline: 0; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.vote-recorded { margin-top: 8px; color: var(--ink-3); }
.vote-recorded b { color: var(--ink); }
.lead-review-btns { display: flex; gap: 8px; flex-wrap: wrap; }
.rv-btn {
  border: 0; border-radius: var(--r-sm); padding: 8px 13px;
  font-size: 12.5px; font-weight: 600; cursor: pointer; font-family: inherit;
  transition: filter var(--fast), background var(--fast), transform var(--fast);
}
.rv-btn:active { transform: scale(0.98); }
.rv-btn.rv-caught   { background: var(--caught); color: #fff; }
.rv-btn.rv-probable { background: var(--review-soft); color: var(--review-ink); }
.rv-btn.rv-resolved { background: var(--ok-soft); color: var(--ok-ink); }
.rv-btn.rv-clear    { background: var(--surface-2); color: var(--ink-3); font-weight: 500; }
.rv-btn:hover { filter: brightness(0.96); }
.lead-review-status { display: inline-block; margin-top: 8px; font-size: 12.5px; color: var(--ink-3); }
.lead-review-status.err { color: var(--caught-ink); font-weight: 600; }
.vote-tally {
  display: flex; align-items: center; gap: 16px; margin-bottom: 10px;
  font-size: 13px; flex-wrap: wrap;
}
.vote-count { color: var(--ink-3); }
.vote-count b { font-size: 15px; }
.vote-caught b  { color: var(--caught-ink); }
.vote-resolve b { color: var(--ok-ink); }
.vote-verdict { font-weight: 600; color: var(--ink); }
.vote-undo { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
.rv-undo {
  border: 0; background: none; padding: 2px 0; cursor: pointer;
  font-family: inherit; font-size: 11.5px; color: var(--ink-4);
  text-decoration: underline; text-underline-offset: 2px;
}
.rv-undo:hover { color: var(--ink-2); }
.vote-seed { margin-top: 8px; color: var(--ink-3); font-size: 11.5px; }
.rv-voted { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding: 4px 0; }
.rv-voted-label { font-size: 13px; color: var(--ok-ink); }
.rv-voted-label b { color: var(--ok-ink); font-weight: 700; }
.rv-btn.rv-retract { background: var(--surface-2); color: var(--ink-3); font-weight: 500; }
.rv-undo.rv-clear-admin { color: var(--review-ink); }
.gfw-legend { color: #d98a3c; font-weight: 600; }

/* Signed-out state of a case's vote panel. The tally above it stays visible —
   reading a case is never gated, only writing to it. */
.rv-signin { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding: 2px 0; }
.rv-signin-note { font-size: 12.5px; color: var(--ink-3); flex: 1 1 220px; line-height: 1.5; }
.rv-btn.rv-signin-btn { background: var(--accent); color: #fff; padding: 9px 15px; }
.rv-btn.rv-signin-btn:hover { background: var(--accent-ink); filter: none; }

/* Sea state on a case — a note under the conditions line, not an alarm. */
.sea-note { color: var(--ink-3); font-size: 11.5px; line-height: 1.45; display: inline-block; margin-top: 3px; }


/* ===========================================================================
 * FORMS & BUTTONS — one primary, one secondary, one danger. That's the set.
 * ========================================================================= */

#feedback-text {
  width: 100%; padding: 12px; border: 1px solid var(--line); border-radius: var(--r-md);
  font: inherit; font-size: 13.5px; resize: vertical; min-height: 110px;
  box-sizing: border-box; background: var(--surface); color: var(--ink);
  transition: border-color var(--fast), box-shadow var(--fast);
}
#feedback-text:focus { outline: 0; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
#feedback-text::placeholder { color: var(--ink-4); }

.feedback-actions { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 12px; }
.feedback-actions .primary, .auth-actions .primary {
  background: var(--accent); color: #fff; border: 0; border-radius: var(--r-md);
  padding: 10px 18px; font-weight: 600; font-size: 14px; font-family: inherit;
  cursor: pointer; box-shadow: var(--shadow-xs);
  transition: background var(--fast), transform var(--fast), box-shadow var(--fast);
}
.feedback-actions .primary:hover, .auth-actions .primary:hover {
  background: var(--accent-ink); transform: translateY(-1px); box-shadow: var(--shadow-sm);
}
.feedback-actions .primary:active, .auth-actions .primary:active { transform: translateY(0); }
.feedback-actions .primary:disabled, .auth-actions .primary:disabled {
  background: var(--ink-4); cursor: default; transform: none; box-shadow: none;
}
#feedback-status { font-size: 13px; color: var(--ink-3); }
#feedback-status.ok  { color: var(--ok-ink); }
#feedback-status.err { color: var(--caught-ink); }

.secondary-btn {
  background: var(--surface-2); color: var(--ink); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 9px 16px; font-weight: 600;
  font-family: inherit; font-size: 14px; cursor: pointer;
  transition: background var(--fast), border-color var(--fast);
}
.secondary-btn:hover { background: var(--surface-3); border-color: var(--surface-3); }
.secondary-btn:disabled { opacity: 0.5; cursor: default; }

.danger-btn {
  background: var(--surface); color: var(--caught-ink); border: 1px solid var(--caught-line);
  border-radius: var(--r-md); padding: 9px 16px; font-weight: 600;
  font-family: inherit; font-size: 13px; cursor: pointer; white-space: nowrap;
  transition: background var(--fast), border-color var(--fast);
}
.danger-btn:hover { background: var(--caught-soft); border-color: var(--caught); }


/* ===========================================================================
 * EMAIL-ALERT SIGNUP MODAL
 * ========================================================================= */

.alerts-modal { max-width: 580px; }
.alerts-modal p { font-size: 14px; line-height: 1.6; color: var(--ink-2); }
.alerts-field { display: block; font-weight: 600; font-size: 13px; margin: 18px 0 6px; color: var(--ink); }
.alerts-modal input[type="email"], .alerts-modal input[type="search"] {
  width: 100%; box-sizing: border-box; padding: 11px 13px;
  border: 1px solid var(--line); border-radius: var(--r-md);
  font-size: 15px; font-family: inherit; margin-bottom: 6px;
  background: var(--surface); color: var(--ink);
  transition: border-color var(--fast), box-shadow var(--fast);
}
.alerts-modal input:focus { outline: 0; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.alerts-scope { display: flex; flex-direction: column; gap: 10px; margin: 18px 0; }
.alerts-scope label {
  cursor: pointer; display: flex; align-items: center; gap: 9px;
  padding: 11px 14px; border: 1px solid var(--line); border-radius: var(--r-md);
  font-size: 13.5px; color: var(--ink-2); background: var(--surface);
  transition: border-color var(--fast), background var(--fast);
}
.alerts-scope label:hover { border-color: var(--accent-line); background: var(--accent-soft); }
.alerts-scope label b { color: var(--ink); font-weight: 600; }
.alerts-scope input[type="radio"] { accent-color: var(--accent); width: 16px; height: 16px; }
.alerts-zone-list {
  max-height: 240px; overflow-y: auto; border: 1px solid var(--line);
  border-radius: var(--r-md); padding: 8px 12px; font-size: 13px;
  background: var(--surface-2);
}
.az-item { display: block; padding: 5px 0; cursor: pointer; color: var(--ink-2); }
.az-item input { margin-right: 8px; accent-color: var(--accent); }
.az-tag { color: var(--ink-4); font-size: 11px; }
.alerts-picked { margin: 8px 0 0; font-size: 12px; color: var(--ink-3); }
#alerts-status.ok  { color: var(--ok-ink); }
#alerts-status.err { color: var(--caught-ink); }
.alerts-signed-out {
  background: var(--accent-soft); border: 1px solid var(--accent-line);
  border-radius: var(--r-md); padding: 13px 16px; font-size: 13.5px; color: var(--ink-2);
}
.alerts-identity { font-size: 13.5px; color: var(--ink-2); }


/* ===========================================================================
 * ACCOUNTS — sign-in / sign-up modal and the account panel
 * ========================================================================= */

.auth-modal { max-width: 540px; }
.auth-modal p { font-size: 14px; line-height: 1.6; color: var(--ink-2); }
.auth-modal input[type="email"], .auth-modal input[type="password"], .auth-modal input[type="text"] {
  width: 100%; box-sizing: border-box; padding: 11px 13px;
  border: 1px solid var(--line); border-radius: var(--r-md);
  font-size: 15px; font-family: inherit; margin-bottom: 8px;
  background: var(--surface); color: var(--ink);
  transition: border-color var(--fast), box-shadow var(--fast);
}
.auth-modal input:focus { outline: 0; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.auth-modal input::placeholder { color: var(--ink-4); }
/* The code is the one field people read back digit by digit off a phone. */
.auth-code-input {
  font-size: 26px !important; letter-spacing: 10px; text-align: center;
  font-variant-numeric: tabular-nums; font-weight: 600; padding: 14px !important;
}
.auth-why {
  background: var(--review-soft); border: 1px solid var(--review-line);
  border-radius: var(--r-md); padding: 12px 15px; font-size: 13.5px;
  color: var(--review-ink); margin: 0 0 18px; line-height: 1.55;
}
.auth-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 14px; }
.auth-alt { font-size: 13px; color: var(--ink-3); margin-top: 16px; line-height: 1.6; }
.auth-signed-in {
  background: var(--ok-soft); border: 1px solid var(--ok-line);
  border-radius: var(--r-md); padding: 12px 15px; color: var(--ok-ink);
}
.auth-block { border-top: 1px solid var(--line); margin-top: 22px; padding-top: 18px; }
.auth-block h3 { margin: 0 0 8px; font-size: 15px; font-weight: 600; }
.auth-block-note { font-size: 12.5px; color: var(--ink-3); margin: 0 0 12px; line-height: 1.55; }
.auth-danger { display: flex; gap: 10px; align-items: center; margin-top: 12px; flex-wrap: wrap; }
.auth-danger input { flex: 1 1 200px; margin-bottom: 0 !important; }
#auth-status { font-size: 13px; color: var(--ink-3); }
#auth-status.ok  { color: var(--ok-ink); }
#auth-status.err { color: var(--caught-ink); }
.auth-modal .fineprint, .alerts-modal .fineprint {
  font-size: 11.5px; color: var(--ink-3); line-height: 1.55;
  border-top: 1px solid var(--line); padding-top: 14px; margin-top: 20px;
}


/* ===========================================================================
 * MOBILE — map and case list stay SIDE BY SIDE (map left, list right), just
 * narrower. A tapped case becomes a bottom sheet over the map.
 * ========================================================================= */

@media (max-width: 800px) {
  /* Compact banner: brand + navigation + case chips only. The subbrand,
   * tagline prose, source-status strip and the map legend are desktop
   * niceties — on a phone they cost two or three rows of map. */
  header {
    flex-wrap: wrap;
    gap: 2px 10px;
    padding: 9px 14px;
  }
  header h1 { font-size: 15px; letter-spacing: 0.14em; }
  header .subbrand, header .tagline-text, header .status, .legend { display: none; }
  header .title { flex-direction: row; align-items: baseline; gap: 12px; flex-wrap: wrap; }
  header .tagline { margin: 0; gap: 12px; }
  .case-summary { flex-basis: 100%; margin: 7px 0 1px; gap: 6px; }
  .case-chip { padding: 3px 11px; font-size: 11.5px; }
  .case-chip b { font-size: 12px; }

  /* The sea is the show: map two thirds, case index one third. That leaves the
   * index ~125px on a 375px phone, which is too narrow to be a table and too
   * narrow for full-length labels — so below the breakpoints further down it
   * stops being a table, sheds label text, and clamps the long zone names.
   * The index is a way in to a case, not the case itself; the detail still
   * opens full-width as a sheet. minmax(0,…) stops the table's min-content
   * width from stealing space back off the map. */
  main { grid-template-columns: 2fr minmax(0, 1fr); grid-template-rows: 1fr; }
  #side { border-top: 0; min-width: 0; }

  .tabs { margin: 8px 7px 6px; padding: 2px; gap: 2px; }
  .tab { flex: 1 1 auto; padding: 8px 3px; font-size: 11.5px; min-width: 0; text-overflow: clip; }
  .header-nav { gap: 12px; }

  /* Collapse low-priority columns so the table fits without horizontal
   * scroll. Everything hidden lives in the row's expansion. */
  .tab-panel { overflow: auto; }
  table { font-size: 12px; min-width: 0; width: 100%; table-layout: auto; }
  th, td { overflow-wrap: break-word; padding: 9px 7px; }
  /* Keep the expansion's label column intact — without this the flex layout
   * squeezes labels into letter-per-line columns at panel widths. */
  .event-details .ed-row > span:first-child { flex-shrink: 0; }

  /* Tapped case = full-width bottom sheet over the map. */
  tr.expanded-row > td { padding: 0; border: 0; background: none; }
  .expanded-row .event-details {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 1600;
    margin: 0; max-height: 85vh; max-height: 85dvh; overflow-y: auto;
    background: var(--bg);
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    padding: 10px 18px calc(18px + env(safe-area-inset-bottom));
    box-shadow: 0 -4px 32px rgba(16,26,36,0.22), 0 0 0 100vmax rgba(12,20,28,0.42);
    animation: sheet-up var(--slow) both;
  }
  @keyframes sheet-up { from { transform: translateY(14px); opacity: 0; } to { transform: none; opacity: 1; } }
  .sheet-handle {
    display: block; width: 38px; height: 5px; border-radius: var(--r-pill);
    background: var(--surface-3); margin: 2px auto 14px;
  }
  .sheet-close {
    display: flex; align-items: center; justify-content: center;
    position: absolute; top: 12px; right: 14px; width: 34px; height: 34px;
    border: 0; border-radius: 50%; background: var(--surface-2); color: var(--ink-3);
    font-size: 15px; line-height: 1; cursor: pointer;
  }
  .sheet-title { display: block; font-weight: 700; font-size: 16px; color: var(--ink); margin: 0 44px 12px 0; letter-spacing: -0.01em; }

  .event-details .ed-secondary { display: none; }
  .event-details .lead-verify { display: none; }
  .lead-action { margin: 14px 0; }
  /* Higher specificity than the base .review-case-btn rule. */
  .event-details .review-case-btn {
    display: flex; width: 100%; justify-content: center; text-align: center;
    box-sizing: border-box; white-space: normal; padding: 13px 14px; font-size: 15px;
  }
  .lead-review { margin-top: 12px; padding: 12px; }
  /* Keep the verbose seed line hidden on mobile, but DO show the "anyone can
   * vote" hint so a tapped vote is never a surprise. */
  .lead-review .vote-seed { display: none; }
  .rv-btn { padding: 10px 14px; }

  /* The "CAUGHT" header word alone forces a horizontal scrollbar at 1/3
   * width — swap it for the icon; the cells underneath stay numeric. */
  #tab-boats thead th:nth-child(3) { font-size: 0; }
  #tab-boats thead th:nth-child(3)::before { content: '🎣'; font-size: 13px; }

  /* Boats table — at 1/3 width keep just Name/reg and CAUGHT count. */
  #tab-boats thead tr th:nth-child(1),
  #tab-boats thead tr th:nth-child(4),
  #tab-boats thead tr th:nth-child(5),
  #tab-boats thead tr th:nth-child(6),
  #tab-boats tbody tr.clickable td:nth-child(1),
  #tab-boats tbody tr.clickable td:nth-child(4),
  #tab-boats tbody tr.clickable td:nth-child(5),
  #tab-boats tbody tr.clickable td:nth-child(6) { display: none; }

  /* Netted-events table — at 1/3 width keep Zone and Vessel. */
  #tab-netted thead tr th:nth-child(1),
  #tab-netted thead tr th:nth-child(4),
  #tab-netted tbody tr.clickable td:nth-child(1),
  #tab-netted tbody tr.clickable td:nth-child(4) { display: none; }

  tr.category-header .cat-sub { display: none; }
  tr.category-header > td { padding: 10px 8px; font-size: 12px; }

  /* Modals: shrink to screen and avoid the keyboard fighting them. */
  .modal { padding: 12px; align-items: flex-end; }
  .modal-inner, .feedback-modal, .about-modal {
    min-width: 0; width: 100%; max-height: 88vh; max-height: 88dvh;
    padding: 24px 20px; border-radius: var(--r-xl);
  }
  header .tagline { font-size: 11.5px; }
  .support-pane { padding: 4px 16px 24px; }

  /* Feedback FAB: smaller and tucked above the iOS home indicator. */
  #feedback-fab {
    right: 12px; bottom: max(12px, env(safe-area-inset-bottom));
    padding: 10px 16px; font-size: 13px;
  }
}


/* ===========================================================================
 * NARROW INDEX — three width-driven steps, each triggered by a measured
 * threshold rather than a guess about devices:
 *
 *   ≤700px  index < ~233px: two table columns start breaking words
 *           ("VENTUROUS" → "VENT / UROU / S"), so rows stop being rows.
 *   ≤560px  index < ~187px: narrower than its own tab labels and than a zone
 *           name, so labels shorten, long names clamp, type steps down.
 *
 * A narrow desktop window gets the same treatment, correctly.
 * ========================================================================= */

@media (max-width: 700px) {
  /* Nothing in the index may declare itself unbreakable, or the table grows a
   * horizontal scrollbar and the vessel name falls off the edge. */
  .zone-class-badge, .lead-flag, .flag-tag, .src-gfw, .regno { white-space: normal; }

  /* Rows stop being table rows. The column-hiding rules in the block above
   * still decide WHICH fields survive; these decide how they stack.
   *
   * The table, tbody and tr all have to go block too, not just the cells:
   * left as a table, auto table-layout keeps sizing to the widest cell's
   * min-content and the panel grows a horizontal scrollbar no matter what the
   * cells are told to do. */
  #tab-netted table, #tab-boats table,
  #tab-netted tbody, #tab-boats tbody,
  #tab-netted tr,    #tab-boats tr { display: block; width: 100%; max-width: 100%; }
  #tab-netted thead, #tab-boats thead { display: none; }
  #tab-netted tbody tr.clickable,
  #tab-boats  tbody tr.clickable {
    display: block; padding: 10px 12px;
    border-bottom: 1px solid var(--line-soft);
  }
  #tab-netted tbody tr.clickable td,
  #tab-boats  tbody tr.clickable td {
    display: block; border: 0; padding: 1px 0;
    box-shadow: none; background: none !important;
  }
  /* Tint and status edge move from the cells to the row: a stacked row has
   * padding of its own, and cell-level backgrounds leave white seams through
   * the middle of what should read as a single card. */
  #tab-netted tbody tr.clickable:hover,
  #tab-boats  tbody tr.clickable:hover { background: var(--surface-2); }
  #tab-boats tbody tr.boat-caught {
    box-shadow: inset 3px 0 0 var(--caught);
    background: color-mix(in srgb, var(--caught-soft) 55%, transparent);
  }
  #tab-boats tbody tr.boat-probable { box-shadow: inset 3px 0 0 var(--review); }
  #tab-boats tbody tr.boat-clean    { box-shadow: inset 3px 0 0 var(--ok); }
  /* Secondary line: the vessel under the zone, the case count under the name. */
  #tab-netted tbody tr.clickable td:nth-child(3) {
    color: var(--ink-3); font-size: 11.5px; margin-top: 3px;
  }
  #tab-boats tbody tr.clickable td:nth-child(3) { margin-top: 3px; font-weight: 600; }
}

@media (max-width: 560px) {
  /* An index ~125px wide on a 375px phone. Left alone, one case runs to eight
   * lines — a four-line zone name, a two-line restriction chip, a two-line
   * vessel — and four cases fill the screen. The job here is to get a case
   * back down to three lines so the list can be scanned, without dropping any
   * of the three things it has to say: where, what rule, which boat. */

  /* Labels give something up: the heart carries "Feedback", and "events" is
   * implied by the panel underneath the tab. */
  .tab .tab-text-support, .tab .tab-word { display: none; }
  .nav-long  { display: none; }
  .nav-short { display: inline; }
  .tabs { margin: 8px 5px 6px; }
  .tab { font-size: 10.5px; padding: 8px 2px; }
  .tab[data-tab="support"] { flex: 0 0 24px; }

  #tab-netted tbody tr.clickable,
  #tab-boats  tbody tr.clickable { padding: 8px 10px; }
  #tab-netted td, #tab-boats td { font-size: 11px; line-height: 1.35; }

  /* Zone name: two lines, then ellipsis. These names are long, repetitive and
   * front-loaded with the distinguishing part ("South Arran Protected Area
   * (Marine Conservation Order)"), so the first two lines carry the identity
   * and the full string stays on the row's title attribute and in the sheet. */
  #tab-netted .zone-name {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    overflow: hidden;
  }
  /* The restriction chip earns its keep — it is the only place the index says
   * which rule applies, now that the map draws every closure one colour — but
   * it gets one line, not two. */
  .zone-class-badge {
    display: inline-block; margin-top: 3px;
    font-size: 9px; padding: 1px 6px; white-space: nowrap;
    max-width: 100%; overflow: hidden; text-overflow: ellipsis;
  }
  /* Vessel: up to two lines. One line clips names like "CIDADE DE ALBUF…",
   * and the boat is the thing you scan a case list for — so short names cost
   * one line and only the long ones spend a second. */
  #tab-netted tbody tr.clickable td:nth-child(3) {
    font-size: 10.5px; margin-top: 2px;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    overflow: hidden;
  }
  #tab-boats tbody tr.clickable td:nth-child(2) {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    overflow: hidden;
  }

  /* Category bands: one line, always. "🎣 CAUGHT" plus its count overflows a
   * 124px band by about 4px, and a count orphaned onto a second line doubles
   * the height of every band. Laying the row out as flex — arrow and count
   * fixed, label free to shrink — holds it to one line at any width instead
   * of relying on a font size that happens to fit today. */
  tr.category-header > td {
    display: flex; align-items: center; gap: 4px;
    padding: 8px 7px; font-size: 11px;
  }
  tr.category-header .cat-toggle { flex: none; width: 9px; }
  tr.category-header .cat-label {
    flex: 0 1 auto; min-width: 0;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  tr.category-header .cat-count { flex: none; margin-left: 1px; padding: 0 6px; font-size: 10px; }
}


/* ===========================================================================
 * MOTION PREFERENCES
 * ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .case-chip:hover, .review-case-btn:hover, .donate-btn:hover,
  .feedback-actions .primary:hover, .auth-actions .primary:hover { transform: none; }
}

/* --- Adjudication panel + comments (2026-09-01, replaced the vote panel) --- */
.rv-verdict { margin: 4px 0 8px; font-size: 13px; }
.rv-v-caught  { color: var(--caught, #8a1010); }
.rv-v-clear   { color: var(--ok, #146b2f); }
.rv-v-review  { color: var(--warn, #8a5a00); }
.rv-factor { display: grid; grid-template-columns: 76px 1fr; gap: 4px 10px;
             align-items: start; margin: 6px 0; }
.rv-grade { font-size: 10.5px; font-weight: 700; text-transform: uppercase;
            letter-spacing: .04em; padding: 2px 6px; border-radius: 3px;
            text-align: center; align-self: start; }
.rv-grade-strong   { background: #e6f3ea; color: #146b2f; }
.rv-grade-moderate { background: #fff4e0; color: #8a5a00; }
.rv-grade-weak     { background: #fdecec; color: #8a1010; }
.rv-grade-unknown  { background: #eeeef2; color: #66667a; }
.rv-factor-q   { font-weight: 600; font-size: 12.5px; }
.rv-factor-why { grid-column: 2; color: #667; font-size: 11.5px; line-height: 1.45; }
.rv-comments { margin-top: 12px; border-top: 1px solid #eee; padding-top: 10px; }
.rv-comments-title { font-weight: 700; font-size: 12px; text-transform: uppercase;
                     letter-spacing: .04em; margin-bottom: 6px; }
.rv-comment { margin: 7px 0; }
.rv-comment-meta { color: #99a; font-size: 11px; }
.rv-comment-body { font-size: 12.5px; white-space: pre-wrap; word-break: break-word; }
.rv-comment-hidden { opacity: .55; }
.rv-comment-input { width: 100%; box-sizing: border-box; font: inherit; font-size: 12.5px;
                    padding: 6px 8px; border: 1px solid #ccd; border-radius: 4px;
                    margin: 6px 0 6px; resize: vertical; }
.mp-email-opt { display: inline-flex; align-items: center; gap: 6px; margin-left: 10px;
                font-size: 12px; color: #556; }
