:root {
  --bg: #FAFAF8;
  --panel: #FFFFFF;
  --ink: #14161A;
  --ink-2: #5A6068;
  --ink-3: #8A9099;
  --line: #E3E5E1;
  --accent: #1B4D3E;
  --accent-2: #7A3B2E;
  --up: #1B6E4A;
  --down: #A8452E;
  --new: #7A5AA8;
  /* A literal amber rather than a themed variable like up/down/new, since
     "trusted/reputable" isn't a state any other part of the UI needs to
     express -- but it was still hardcoded three separate places
     (.source-reputable, .tag-reputable, .report .reputable-block), so a
     dark-mode-specific adjustment could only be made once, here. */
  --reputable: #B8860B;
  --reputable-dark: #96700A;
  --map-ocean: #AFCBE3;
  --map-base-fill: #FBFBF9;
  --map-base-stroke: #C7CCD2;
  --shadow-sm: 0 1px 2px rgba(20, 22, 26, 0.04), 0 2px 8px rgba(20, 22, 26, 0.06);
  --shadow-md: 0 2px 4px rgba(20, 22, 26, 0.05), 0 6px 16px rgba(20, 22, 26, 0.08);
  /* One font, everywhere -- Cambria is a Windows/Office system font (not
     available from Google Fonts to self-host), so Georgia is the fallback:
     metrically similar serif, available basically everywhere else. */
  --sans: 'Cambria', Georgia, 'Times New Roman', serif;
  --mono: 'Cambria', Georgia, 'Times New Roman', serif;
  --serif: 'Cambria', Georgia, 'Times New Roman', serif;
  /* Adjusted live by the "A-"/"A+" nav buttons (base.html) via
     document.documentElement.style, saved to localStorage. zoom (not a
     root font-size) is what actually scales the whole page uniformly here,
     since every component in this file sets its own font-size in fixed px
     rather than rem -- changing the root font-size alone wouldn't cascade. */
  --font-scale: 1;
}

/* Dark mode follows the OS/browser setting automatically by default, but
   the toggle button (base.html) can force it either way by setting
   data-theme on <html> — :not([data-theme="light"]) below means an
   explicit "light" choice always wins over the OS preference, and the
   explicit [data-theme="dark"] block further down always wins too, since
   an attribute selector outranks a bare :root regardless of media query.
   Every component reads colors through these variables, so redefining
   just the ~15 here re-themes the entire site either way. Shadows go a
   bit more pronounced than light mode's, since a soft shadow barely reads
   against a dark background otherwise. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #16181C;
    --panel: #1E2126;
    --ink: #EDEEF0;
    --ink-2: #A8ADB5;
    --ink-3: #6E7480;
    --line: #2E323A;
    --accent: #4FA383;
    --accent-2: #C77B5F;
    --up: #4FBE85;
    --down: #E0715A;
    --new: #A98AE0;
    --reputable: #D9A441;
    --reputable-dark: #F0C070;
    /* Land needs to read clearly lighter than ocean (same relationship as
       light mode's #FBFBF9 land vs #AFCBE3 ocean) -- the original dark
       values here (#1C2B3A ocean, #23272E land) were only ~2 points apart
       in perceived brightness, so the whole map read as a near-uniform
       dark blob with no visible coastline. */
    --map-ocean: #16202B;
    --map-base-fill: #2A2F38;
    --map-base-stroke: #454C58;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(0, 0, 0, 0.25);
    --shadow-md: 0 2px 4px rgba(0, 0, 0, 0.3), 0 6px 20px rgba(0, 0, 0, 0.35);
  }
}

:root[data-theme="dark"] {
  --bg: #16181C;
  --panel: #1E2126;
  --ink: #EDEEF0;
  --ink-2: #A8ADB5;
  --ink-3: #6E7480;
  --line: #2E323A;
  --accent: #4FA383;
  --accent-2: #C77B5F;
  --up: #4FBE85;
  --down: #E0715A;
  --new: #A98AE0;
  --reputable: #D9A441;
  --reputable-dark: #F0C070;
  --map-ocean: #16202B;
  --map-base-fill: #2A2F38;
  --map-base-stroke: #454C58;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(0, 0, 0, 0.25);
  --shadow-md: 0 2px 4px rgba(0, 0, 0, 0.3), 0 6px 20px rgba(0, 0, 0, 0.35);
}

* { box-sizing: border-box; }

/* A real gap found while checking dark mode: several links (auth-page
   "back to sign in", "search the web" on profile pages, the watchlist
   empty-state link) had no color rule anywhere, so they fell back to the
   browser's default link blue — jarring in light mode, much more so
   against a dark background. This baseline covers every link that isn't
   more specifically styled below; class selectors (.topnav a, .event-name
   a, etc.) all win the specificity tie against this bare element selector,
   so nothing already correctly styled is affected. */
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* A real bug found this session: any element given both the `hidden`
   attribute AND a class that sets its own `display` (e.g. `display: flex`
   on .map-legend-list) silently ignores `hidden` — the class and the
   browser's built-in `[hidden] { display: none }` have equal specificity,
   and the author stylesheet wins the tie, so the element stayed visible
   and toggling it back and forth had no visible effect either way. This
   forces `hidden` to always win, everywhere, regardless of what other
   display-setting classes an element has. */
[hidden] { display: none !important; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 1.5rem;
  /* Scales the whole page uniformly (text, spacing, images) exactly like
     the browser's own zoom -- see the --font-scale comment above for why
     this is used instead of resizing individual rules. */
  zoom: var(--font-scale);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

.topnav {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 0.9rem 3rem;
  border-bottom: 1px solid transparent;
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  position: sticky;
  top: 0;
  z-index: 100;
  transition: border-color 0.2s, box-shadow 0.2s;
}

.topnav.is-scrolled {
  border-bottom-color: var(--line);
  box-shadow: var(--shadow-sm);
}

.topnav-brand-link {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: inherit;
  text-decoration: none;
  margin-right: 0.5rem;
}

.topnav-brand-link:hover {
  text-decoration: none;
}

.topnav-logo {
  height: 22px;
  width: 22px;
  border-radius: 4px;
}

.topnav-brand {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: -0.005em;
}

.topnav a {
  font-size: 13px;
  color: var(--ink-2);
  text-decoration: none;
  padding: 4px 2px;
  border-bottom: 2px solid transparent;
}

.topnav a:hover { color: var(--ink); }

.topnav a.active {
  color: var(--ink);
  font-weight: 500;
  border-bottom-color: var(--accent);
}

/* "Explore" nav dropdown — same toggle + absolute popup anchor pattern as
   .week-picker-wrap/.calendar-popup, just for a static list of links. */
.nav-dropdown-wrap { position: relative; }

.nav-dropdown-toggle {
  background: none;
  border: none;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
  padding: 4px 2px;
  border-bottom: 2px solid transparent;
}

.nav-dropdown-toggle:hover { color: var(--ink); }

.nav-dropdown-toggle.active {
  color: var(--ink);
  font-weight: 500;
  border-bottom-color: var(--accent);
}

/* Two columns side by side (verticals, cross-cutting topics) instead of
   one long stacked list -- with 13 verticals + 4 topics, a single column
   ran well past screen height. */
.nav-dropdown-popup {
  position: absolute;
  top: calc(100% + 10px);
  left: 0;
  z-index: 50;
  padding: 8px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--shadow-md);
  display: flex;
  align-items: flex-start;
}

/* flex: 0 0 auto (not flex: 1) so each column sizes to its own longest
   label instead of splitting the popup's width evenly -- Verticals has
   entries like "FinTech, InsurTech, LegalTech (Financial Services)" while
   Cross sector topics is three short words, so an even split either
   wrapped the long labels onto two lines or left the short column mostly
   empty. white-space: nowrap is what actually stops the wrapping; the
   auto-sized flex-basis is what gives it the room to do that without
   forcing the whole popup absurdly wide for the short column's sake. */
.nav-dropdown-col {
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  white-space: nowrap;
}

.nav-dropdown-divider-v {
  align-self: stretch;
  width: 1px;
  background: var(--line);
  margin: 4px 8px;
}

.nav-dropdown-popup a {
  padding: 6px 8px;
  border-radius: 5px;
  border-bottom: none !important;
  font-size: 13px;
}

.nav-dropdown-popup a:hover { background: var(--bg); }

.nav-dropdown-popup a.active { color: var(--accent); font-weight: 500; }

.nav-dropdown-heading {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 6px 8px 2px;
}

.shell {
  display: grid;
  grid-template-columns: 200px 1fr;
  max-width: 1080px;
  margin: 0 auto;
  min-height: 100vh;
}

.shell-empty { grid-template-columns: minmax(0, 1fr); }

/* min-width: 0 overrides the grid item default of "auto", which sizes to
   the max-content width of whatever's inside (long headings, several
   toolbar buttons in a row) — without it, that content silently forces the
   whole page wider than the viewport on narrow screens instead of wrapping,
   a classic CSS grid blowout. */
.main { padding: 2.5rem 3rem 4rem; min-width: 0; }

/* Dashboards (World/DefenceTech) use shell-empty now that the archive is a
   dropdown instead of a sidebar — give the content a readable max-width
   rather than letting it stretch edge-to-edge on wide screens. Pages that
   want a different width (login, search) set their own inline style, which
   always wins over this. */
.shell-empty .main { max-width: 1320px; margin: 0 auto; width: 100%; box-sizing: border-box; }

.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 1.75rem;
}

.toolbar-search { flex: 1 1 220px; display: flex; gap: 6px; min-width: 0; }

/* Not combined into one selector with .week-select: giving .week-select the
   same "width: 100%" made it become the item's flex-basis (since flex-basis
   is "auto" here), so it claimed the whole toolbar's width and crushed the
   search box down to a few pixels. */
.toolbar-search input {
  flex: 1;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-family: var(--sans);
  font-size: 13px;
  background: var(--panel);
  color: var(--ink);
}

.toolbar-search button {
  padding: 7px 14px;
  border: 1px solid var(--accent);
  border-radius: 6px;
  background: var(--accent);
  color: white;
  font-family: var(--sans);
  font-size: 13px;
  cursor: pointer;
}

.week-select {
  flex: 0 0 auto;
  min-width: 200px;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-family: var(--sans);
  font-size: 13px;
  background: var(--panel);
  color: var(--ink);
}

/* Used as a plain link on the vertical/topic pages' window-length toggle
   ("Last 4 weeks" / "This week only") -- same look as the dropdowns beside
   it, with .active marking whichever window is currently selected. */
a.week-select.active {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 500;
}

/* "Jump to week" calendar — a Windows-taskbar-clock-style flyout: click the
   month/year title to zoom out to a month grid, click that title to zoom
   out again to a year grid. .week-picker-wrap just gives the popup a
   positioning anchor; the button inside it reuses .week-select's look so
   it sits in the toolbar exactly like the old dropdown did. */
.week-picker-wrap { position: relative; flex: 0 0 auto; }

.week-picker-wrap > button.week-select {
  cursor: pointer;
  text-align: left;
  font-family: var(--sans);
}

.calendar-popup {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 50;
  width: 260px;
  padding: 12px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--shadow-md);
}

.calendar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}

.calendar-nav {
  background: none;
  border: none;
  font-size: 15px;
  color: var(--ink-2);
  cursor: pointer;
  padding: 2px 8px;
  border-radius: 4px;
}

.calendar-nav:hover { background: var(--bg); color: var(--ink); }

.calendar-title {
  background: none;
  border: none;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  padding: 2px 6px;
  border-radius: 4px;
}

.calendar-title:hover { background: var(--bg); }

.calendar-dow {
  display: flex;
  margin-bottom: 4px;
}

.calendar-dow span {
  flex: 1;
  text-align: center;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--ink-3);
}

.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}

.calendar-grid-months, .calendar-grid-years { grid-template-columns: repeat(4, 1fr); gap: 4px; }

.calendar-day {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  border-radius: 5px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-3);
}

.calendar-day.empty { visibility: hidden; }

.calendar-day.muted { cursor: default; }

.calendar-day.has-data {
  color: var(--ink);
  cursor: pointer;
  transition: background-color 0.1s ease;
}

.calendar-day.has-data:hover { background: var(--bg); }

.calendar-day.in-active-week {
  background: color-mix(in srgb, var(--accent) 14%, var(--panel));
  color: var(--accent);
  font-weight: 600;
}

.calendar-cell {
  padding: 8px 4px;
  background: none;
  border: none;
  border-radius: 5px;
  font-family: var(--sans);
  font-size: 12px;
  color: var(--ink);
  cursor: pointer;
  transition: background-color 0.1s ease;
}

.calendar-cell:hover { background: var(--bg); }

.calendar-cell.is-current { color: var(--accent); font-weight: 600; }

/* A shortcut back to the latest available week, always visible regardless
   of how far the day/month/year navigation has wandered — matches the
   "Today" shortcut in most calendar widgets, except it jumps straight to
   that week's report rather than just re-centering the calendar's view,
   since every other action in this popup already navigates on click. */
.calendar-today {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding-top: 10px;
  border: none;
  border-top: 1px solid var(--line);
  background: none;
  font-family: var(--sans);
  font-size: 12px;
  color: var(--accent);
  text-align: center;
  cursor: pointer;
}

.calendar-today:hover { text-decoration: underline; }

.head { margin-bottom: 2rem; }

/* templates/empty.html's icon (icons.empty_icon()) -- muted and modestly
   sized so a "nothing here yet" page reads as designed rather than a bare
   heading with no visual anchor, without competing with the heading for
   attention the way a large illustration would. */
.empty-state-icon {
  display: block;
  width: 40px;
  height: 40px;
  margin-bottom: 0.75rem;
  stroke: var(--ink-3);
  stroke-width: 1.3;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.head-label {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 0.4rem;
}

/* A small recurring "masthead" mark — the same accent color as the active
   nav tab's underline, so the two echo each other as one shared visual
   motif across the site rather than two unrelated design choices. Tied to
   .head-label rather than .head h1 so it appears on every page's header
   (profile pages, admin, watchlist, etc.) via this one rule, without
   touching every template. */
.head-label::after {
  content: '';
  display: block;
  width: 36px;
  height: 3px;
  margin-top: 8px;
  background: var(--accent);
  border-radius: 2px;
}

.head h1 {
  font-family: var(--serif);
  font-size: 32px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 0.3rem;
}

.head-top-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.head-top-row h1 { margin: 0 0 0.3rem; }

.head-title-link { color: inherit; text-decoration: none; }
.head-title-link:hover { text-decoration: underline; }

.planner-view-plan-btn {
  flex-shrink: 0;
  padding: 8px 14px;
  background: var(--accent);
  color: white;
  border-radius: 6px;
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}

.planner-view-plan-btn:hover { opacity: 0.9; }

.head-sub { font-size: 14px; color: var(--ink-2); }

.head-sub code {
  font-family: var(--mono);
  font-size: 13px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 1px 5px;
}

.metrics {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1fr;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  margin-bottom: 2rem;
  box-shadow: var(--shadow-sm);
}

.metric {
  display: block;
  background: var(--panel);
  padding: 1.1rem 1.25rem;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  transition: background 0.1s;
}

.metric:hover { background: var(--bg); }

.metric-label {
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 0.4rem;
}

.metric-value {
  font-family: var(--mono);
  font-size: 24px;
  font-weight: 500;
  letter-spacing: -0.02em;
}

.metric-lead .metric-value { font-size: 30px; color: var(--accent); }

.metric-delta { font-size: 12px; margin-top: 0.25rem; }
.metric-delta.up { color: var(--up); }
.metric-delta.down { color: var(--down); }
.metric-delta.flat { color: var(--ink-3); }

/* Home page -- a soft radial wash behind the header (identical light/dark
   treatment to .topnav's own color-mix blur trick above) instead of a flat
   background, so the landing page reads as a destination in its own right
   rather than another data screen. Purely decorative: ::before so it never
   affects layout or hit-testing. */
.home-shell {
  position: relative;
  overflow: hidden;
}

.home-shell::before {
  content: "";
  position: absolute;
  top: -220px;
  left: 50%;
  transform: translateX(-50%);
  width: 900px;
  height: 480px;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 14%, transparent), transparent);
  pointer-events: none;
  z-index: 0;
}

.home-header, .home-hero, .home-grid {
  position: relative;
  z-index: 1;
}

.home-header {
  margin-bottom: 1.75rem;
}

.home-header-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.home-greeting {
  font-size: 34px;
  margin: 0.2rem 0 0.3rem;
}

/* A live "is the pipeline actually fresh" signal instead of a purely
   decorative flourish -- reuses the same freshness check that already
   powers the warning banner (inject_pipeline_health), just phrased
   positively. The dot pulses gently when healthy; a stale pipeline swaps
   it to --down and drops the animation, since a stuck pulse pretending
   to be alive would be actively misleading. */
.home-pulse {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--ink-3);
  white-space: nowrap;
}

.home-pulse-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--up);
  animation: home-pulse-beat 2.4s ease-in-out infinite;
}

.home-pulse-dot.is-stale {
  background: var(--down);
  animation: none;
}

@keyframes home-pulse-beat {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 color-mix(in srgb, var(--up) 40%, transparent); }
  50% { opacity: 0.7; box-shadow: 0 0 0 4px transparent; }
}

.home-spotlight {
  font-size: 14px;
  color: var(--ink-2);
  margin-top: 0.2rem;
}

.home-jump {
  display: flex;
  gap: 8px;
  margin-top: 1.1rem;
  max-width: 420px;
}

.home-jump input {
  flex: 1;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-family: var(--sans);
  font-size: 14px;
  background: var(--panel);
  color: inherit;
}

.home-jump button {
  padding: 9px 16px;
  background: var(--accent);
  color: white;
  border: none;
  border-radius: 6px;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
}

/* The featured card -- Overall debrief is where every session actually
   starts, so it gets a full-width row of its own above the grid of
   everything else, not just a same-sized tile lost among eight others. */
.home-hero {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 22px 26px;
  margin-bottom: 1rem;
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 10%, var(--panel)), var(--panel));
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
  color: inherit;
  transition: box-shadow 0.15s, transform 0.15s;
}

.home-hero:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
  text-decoration: none;
}

.home-hero-icon {
  flex: 0 0 auto;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--accent);
}

/* home_icon()'s <svg> defaults to class="home-tile-icon" wherever it's
   used (the hero card and every grid tile) -- same stroke-only treatment
   as .area-icon above, just without that rule's own fixed size/margin,
   since the hero and grid icons each need their own sizing (below). */
.home-tile-icon {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.home-hero-icon svg { width: 26px; height: 26px; }

.home-hero-body { flex: 1 1 auto; min-width: 0; }

.home-hero-title {
  font-family: var(--serif);
  font-size: 20px;
  font-weight: 600;
}

.home-hero-desc {
  font-size: 13.5px;
  color: var(--ink-2);
  line-height: 1.4;
  margin-top: 4px;
  max-width: 60ch;
}

.home-hero-stat {
  display: inline-block;
  margin-top: 10px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}

.home-hero-spark {
  flex: 0 0 auto;
  width: 140px;
  height: 58px;
  display: none;
  flex-direction: column;
  gap: 2px;
}

@media (min-width: 640px) {
  .home-hero-spark { display: flex; }
}

.home-hero-spark svg { width: 100%; flex: 1; min-height: 0; }

/* The low/high of the sparkline's own range -- without this the shape is
   purely decorative, since nothing else on the hero card gives a viewer
   anything to compare it against. */
.home-sparkline-range {
  display: flex;
  justify-content: space-between;
  font-family: var(--sans);
  font-size: 10px;
  color: var(--ink-3);
  line-height: 1;
}

.home-hero-arrow {
  flex: 0 0 auto;
  font-size: 22px;
  color: var(--ink-3);
  transition: transform 0.15s;
}

.home-hero:hover .home-hero-arrow {
  transform: translateX(4px);
  color: var(--accent);
}

/* The rest of the destinations -- a button per section rather than a
   bars/table layout, since these are just links out, not data. Each
   variant class below only recolors the icon chip and stat pill, cycling
   through the same accent tokens the rest of the site already uses (no
   new colors introduced), so a tile reads as visually distinct from its
   neighbors without inventing a whole new palette just for this page. */
.home-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
  margin-top: 1.5rem;
}

/* The Explore page's two sections (Verticals, Cross sector topics) sit
   side by side in a .split, so each grid only has half the page's width
   to work with -- a smaller minimum tile width keeps 2-3 tiles per row
   instead of the columns collapsing to one tile wide. */
.home-grid-narrow { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }

.home-tile {
  position: relative;
  display: block;
  padding: 18px 20px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow-sm);
  color: inherit;
  transition: box-shadow 0.15s, transform 0.15s;
}

.home-tile-badge {
  position: absolute;
  top: 14px;
  right: 16px;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  color: white;
  background: var(--down);
}

.home-tile-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 10px;
}

.home-tile-chips .chip {
  background: var(--bg);
  font-size: 11.5px;
  padding: 2px 9px;
}

.home-tile:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-3px);
  text-decoration: none;
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
}

/* Each variant's hover border picks up its own icon color instead of the
   same shared accent every tile used before -- personality per section,
   in place of the one-size-fits-all watermark this replaced. */
.home-tile-accent2:hover { border-color: color-mix(in srgb, var(--accent-2) 45%, var(--line)); }
.home-tile-new:hover { border-color: color-mix(in srgb, var(--new) 45%, var(--line)); }
.home-tile-down:hover { border-color: color-mix(in srgb, var(--down) 45%, var(--line)); }
.home-tile-up:hover { border-color: color-mix(in srgb, var(--up) 45%, var(--line)); }

.home-tile-icon-wrap {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 10px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
}

.home-tile-icon-wrap svg {
  width: 17px;
  height: 17px;
  transition: transform 0.2s ease;
}

.home-tile:hover .home-tile-icon-wrap svg {
  transform: scale(1.15);
}

.home-tile-accent2 .home-tile-icon-wrap {
  background: color-mix(in srgb, var(--accent-2) 16%, transparent);
  color: var(--accent-2);
}

.home-tile-new .home-tile-icon-wrap {
  background: color-mix(in srgb, var(--new) 16%, transparent);
  color: var(--new);
}

.home-tile-down .home-tile-icon-wrap {
  background: color-mix(in srgb, var(--down) 14%, transparent);
  color: var(--down);
}

.home-tile-up .home-tile-icon-wrap {
  background: color-mix(in srgb, var(--up) 14%, transparent);
  color: var(--up);
}

.home-tile-title {
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 600;
}

/* The Explore page's grid is 19 items with a small inline icon each, not a
   handful of tiles with a big icon chip above the title -- a lighter
   treatment than .home-tile-icon-wrap, reusing area_icon()'s own small
   14px glyph the same way the nav dropdown does. */
.home-tile-title-inline {
  display: flex;
  align-items: center;
  gap: 8px;
}

.home-tile-desc {
  font-size: 13px;
  color: var(--ink-3);
  line-height: 1.4;
  margin-top: 6px;
}

.home-tile-stat {
  display: inline-block;
  margin-top: 10px;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-2);
  background: var(--bg);
  border: 1px solid var(--line);
}

.block { margin-bottom: 2.25rem; }

.block-title {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin: 0 0 0.9rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--line);
}

.area-color-dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: middle;
}

.bar-row {
  display: grid;
  grid-template-columns: 150px 1fr 90px 44px;
  align-items: center;
  gap: 10px;
  margin-bottom: 7px;
}

/* Negative margin cancels the padding at rest, so a clickable row's hover
   background has room to show beyond the text without nudging layout. */
.bar-row.clickable, .bar-row-wide.clickable {
  transition: background-color 0.15s ease;
  border-radius: 6px;
  margin-left: -8px;
  margin-right: -8px;
  padding-left: 8px;
  padding-right: 8px;
}

.bar-row.clickable:hover, .bar-row-wide.clickable:hover {
  background-color: var(--bg);
}

.bar-name {
  font-size: 13px;
  text-transform: capitalize;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Shared line-icon set for the focus-areas taxonomy (icons.py) -- stroke
   only, no fill, so it always matches the surrounding text color in both
   themes without a separate dark-mode rule. */
.area-icon {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
  vertical-align: -2px;
  margin-right: 5px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.75;
}

.bar-track {
  height: 6px;
  background: var(--line);
  border-radius: 3px;
  overflow: hidden;
}

.bar-fill { height: 100%; background: var(--accent); border-radius: 3px; }
.bar-fill.theater { background: var(--accent-2); }

.bar-num {
  font-family: var(--mono);
  font-size: 12px;
  text-align: right;
  color: var(--ink-2);
}

.bar-delta {
  font-family: var(--mono);
  font-size: 11px;
  text-align: right;
  color: var(--ink-3);
}

.bar-delta.is-up { color: var(--up); }
.bar-delta.is-down { color: var(--down); }
.bar-delta.is-new { color: var(--new); font-weight: 500; }

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.table th {
  text-align: left;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 0 10px 8px 0;
}

.table td {
  padding: 9px 10px;
}

/* The first column stays flush left (matching .block-title above it) —
   every other column keeps padding on both sides so two adjacent numeric
   columns always have a real gap from both directions, not just a single
   10px edge that a narrow-viewport reflow or a compare-page row with
   uneven content lengths could compress to nothing. */
.table td:first-child { padding-left: 0; }

/* Same double-line class of bug as .event-row earlier: a table with no
   <thead> (Capital by stage/region) put its first row's border-top right
   against .block-title's own border-bottom with almost no gap between
   them. Only rows after the first get a separator; a table that DOES have
   a <thead> still gets one between the header and its first data row
   (thead and tbody's <tr>s aren't siblings, so :not(:first-child) alone
   wouldn't draw that one — this second rule adds it back explicitly). */
.table tbody tr:not(:first-child) td { border-top: 1px solid var(--line); }
.table thead + tbody tr:first-child td { border-top: 1px solid var(--line); }

/* A real bug found on the compare-weeks page: two ".right" columns side by
   side (this week's figure, last week's figure) squeezed each other down
   to ~80px under auto table layout, wrapping "11 mentions · $54M" across
   4 cramped lines per cell — which is what read as merged/garbled text.
   nowrap forces auto layout to actually give these columns the width the
   content needs (shrinking the area-name column instead, which wrapping
   onto a second line handles gracefully) rather than wrapping numbers. */
.table .right { text-align: right; padding-right: 0; white-space: nowrap; }
.table .strong { font-weight: 500; }
.table .muted { color: var(--ink-2); text-transform: capitalize; }
.table .mono { font-family: var(--mono); }

/* Generous room between columns being compared makes which figure belongs
   to which week/metric obvious on its own — tried a vertical rule here
   first, but the extra breathing room reads more clearly without adding
   another line to the page. Keyed off .right rather than nth-child(2)/(3)
   so it scales to however many columns a given compare table has: the
   3-column tables (Headline, Capital by region, Cross-cutting topics) and
   the 5-column Focus areas table (area + mentions/capital x2 weeks) both
   get consistent gaps between every pair of adjacent right-aligned
   columns, not just a hardcoded 2nd/3rd column — a fixed nth-child rule
   left columns 3+ bunched together with no gap once Focus areas grew past
   3 columns, running each column's uppercase header straight into the
   next's. */
.compare-table th.right,
.compare-table td.right {
  padding-left: 32px;
}

.table tr.clickable { cursor: pointer; transition: background-color 0.15s ease; }
.table tr.clickable:hover { background-color: var(--bg); }
.table tr.clickable:hover td { color: var(--accent); }
.table tr.active td { color: var(--accent); font-weight: 500; }
.table tr[hidden] { display: none; }

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2rem;
}

.chips { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 4px 10px;
  font-size: 13px;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}

.chip-n {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--ink-3);
}

.chip-flag {
  border-color: var(--new);
  background: color-mix(in srgb, var(--new) 6%, var(--panel));
}

/* A label that's recurred often enough to be worth adding as a tracked
   area — deliberately more assertive than .chip-flag's subtle tint, since
   this is meant to actually catch the eye while scanning the section. */
.chip-watch {
  border: 1.5px solid var(--new);
  background: color-mix(in srgb, var(--new) 12%, var(--panel));
  font-weight: 600;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--new) 25%, transparent);
}

.chip-tag {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--new);
  margin-left: 4px;
}

.report h1, .report h2, .report h3, .report h4, .report h5, .report h6 {
  font-family: var(--serif);
  font-weight: 600;
  letter-spacing: -0.005em;
  margin: 1.6rem 0 0.6rem;
}

.report h1 { font-size: 19px; }
.report h2 { font-size: 16px; }
.report h3 { font-size: 14px; }
/* h4+ covers a Planner node deep enough to nest past the fixed cell/topic
   levels ("infinite layers") -- same size as h3 rather than shrinking
   further, since there's no fixed number of levels to budget sizes for. */
.report h4, .report h5, .report h6 { font-size: 14px; }
.report p { margin: 0 0 0.9rem; }
.report ul, .report ol { margin: 0 0 0.9rem; padding-left: 1.1rem; }
.report li { margin-bottom: 0.3rem; }
.report strong { font-weight: 600; }

/* --- Client-facing plan (planner_plan.html) --- */

.plan-priority-groups {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px;
  margin-bottom: 0.5rem;
}

.plan-priority-group {
  border: 1px solid var(--line);
  border-top: 3px solid var(--line);
  border-radius: 8px;
  padding: 14px 16px;
  background: var(--panel);
}

.plan-priority-group.plan-priority-a { border-top-color: var(--down); }
.plan-priority-group.plan-priority-b { border-top-color: var(--accent); }
.plan-priority-group.plan-priority-c { border-top-color: var(--ink-3); }

.plan-priority-group-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  margin-bottom: 10px;
}

.plan-priority-count {
  margin-left: auto;
  font-weight: 400;
  font-size: 12px;
  color: var(--ink-3);
}

.plan-priority-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 5px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  color: white;
  background: var(--ink-3);
  flex: 0 0 auto;
}

.plan-priority-badge.plan-priority-a { background: var(--down); }
.plan-priority-badge.plan-priority-b { background: var(--accent); }
.plan-priority-badge.plan-priority-c { background: var(--ink-3); }

.plan-priority-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.plan-priority-list li { padding-bottom: 8px; border-bottom: 1px solid var(--line); }
.plan-priority-list li:last-child { border-bottom: none; padding-bottom: 0; }

.plan-task-label { font-weight: 500; }
.plan-task-path { font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.plan-task-notes { font-size: 12px; color: var(--ink-3); margin-top: 2px; }

/* A vertical line of dots, one per completed task, newest at the top --
   the Plan page's "progress over time" view, distinct from Priority
   Overview (grouped by urgency) and Full Plan by Area (grouped by
   structure): this one's the only place order is chronological. */
.plan-timeline {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding-left: 4px;
}

.plan-timeline-item {
  position: relative;
  display: flex;
  gap: 16px;
  padding-left: 22px;
}

.plan-timeline-item::before {
  content: "";
  position: absolute;
  left: 5px;
  top: 18px;
  bottom: -22px;
  width: 1px;
  background: var(--line);
}
.plan-timeline-item:last-child::before { display: none; }

.plan-timeline-dot {
  position: absolute;
  left: 0;
  top: 4px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}

.plan-timeline-date {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin-bottom: 2px;
}

.plan-completion { margin-top: 6px; }

.plan-completion-toggle {
  border: none;
  background: none;
  padding: 2px 0;
  font-family: var(--sans);
  cursor: pointer;
  color: inherit;
}
.plan-completion-toggle:hover .plan-person-chip,
.plan-completion-toggle:hover .muted { text-decoration: underline; }

.plan-completion-form {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 6px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}
.plan-completion-form label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--ink-3);
}
.plan-completion-form select {
  padding: 5px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: inherit;
  font-family: var(--sans);
  font-size: 13px;
}

/* A task's "what I did" log -- same collapsed-toggle shape as
   .plan-completion above, but never gated on `done` (see the template):
   several contributors add to it over the life of a task, not just once
   it's finished. */
.plan-activity { margin-top: 6px; }

.plan-activity-toggle {
  border: none;
  background: none;
  padding: 2px 0;
  font-family: var(--sans);
  font-size: 13px;
  cursor: pointer;
  color: var(--ink-3);
}
.plan-activity-toggle:hover { text-decoration: underline; }

.plan-activity-body {
  margin-top: 6px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
}

.plan-activity-list {
  margin: 0 0 8px;
  padding-left: 18px;
  font-size: 13px;
  color: var(--ink-2);
}
.plan-activity-list li + li { margin-top: 4px; }

.plan-activity-form { display: flex; gap: 8px; }
.plan-activity-form input {
  flex: 1;
  padding: 5px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: inherit;
  font-family: var(--sans);
  font-size: 13px;
}
.plan-activity-form button {
  padding: 5px 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: inherit;
  font-family: var(--sans);
  font-size: 13px;
  cursor: pointer;
}
.plan-activity-form button:hover { border-color: var(--accent); color: var(--accent); }

.plan-area { margin-bottom: 2rem; }
.plan-area:last-child { margin-bottom: 0; }
.plan-area-title {
  font-size: 21px;
  font-weight: 700;
  margin: 0 0 1rem;
  padding-bottom: 8px;
  border-bottom: 2px solid var(--accent);
}

.plan-group { margin: 0 0 0.6rem; }
.plan-group-label { font-weight: 600; margin: 0.6rem 0 0.4rem; }
.plan-group-depth-2 .plan-group-label,
.plan-group-depth-3 .plan-group-label,
.plan-group-depth-4 .plan-group-label { font-size: 13px; font-weight: 500; color: var(--ink-2); }
.plan-group-children { padding-left: 1rem; border-left: 1px solid var(--line); margin-left: 2px; }

.plan-task-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 6px 0;
}

/* The checklist tick on the Plan page -- distinct from the matrix's
   "selected" checkbox (that puts a task ON the plan; this marks one
   already on it as actually completed). Shared by both the Priority
   Overview <li> rows and the Full Plan by Area task rows, so ticking
   either instance updates both (see plannerSaveDone() in planner.js). A
   custom round, fill-on-check style (vs. the matrix's plain square
   checkbox) so the two -- "on the plan" vs. "actually done" -- read as
   different concepts at a glance, not the same control used twice. */
.plan-priority-list li.plan-done-row { display: flex; align-items: flex-start; gap: 8px; }
.plan-done-checkbox { flex: 0 0 auto; padding-top: 2px; cursor: pointer; }
.plan-done-checkbox input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  margin: 0;
  border: 1.5px solid var(--line);
  border-radius: 50%;
  background: var(--panel);
  cursor: pointer;
  position: relative;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.plan-done-checkbox input[type="checkbox"]:hover { border-color: var(--up); }
.plan-done-checkbox input[type="checkbox"]:checked {
  background: var(--up);
  border-color: var(--up);
}
.plan-done-checkbox input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 5px;
  top: 1px;
  width: 4px;
  height: 8px;
  border: solid var(--panel);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.plan-done .plan-task-label { text-decoration: line-through; color: var(--ink-3); }
.plan-done .plan-priority-badge { text-decoration: line-through; opacity: 0.55; }
body.plan-hide-done .plan-done-row.plan-done { display: none; }

.report table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  margin: 0 0 1.2rem;
}

.report th {
  text-align: left;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 0 10px 8px 0;
  border-bottom: 1px solid var(--line);
}

.report td {
  padding: 9px 10px 9px 0;
  border-top: 1px solid var(--line);
  vertical-align: top;
}

.bar-row-wide {
  grid-template-columns: 190px 1fr 90px 68px 40px;
}

.bar-cap {
  font-family: var(--mono);
  font-size: 11px;
  text-align: right;
  color: var(--accent);
}

.tag {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--line);
  color: var(--ink-2);
  border-radius: 3px;
  padding: 1px 5px;
  margin-left: 5px;
  vertical-align: 1px;
}

/* Flags an event just added by the latest report run, on the Events page —
   same purple used for "worth watching" elsewhere (.chip-flag, .bar-delta
   .is-new), so "new" reads consistently as one color across the app. */
.tag-new {
  background: color-mix(in srgb, var(--new) 18%, var(--panel));
  color: var(--new);
}

/* A genuine all-time high, not just "up from last week" -- the site's own
   accent color rather than the "new" purple, so it reads as an achievement
   rather than a freshness flag. */
.tag-record {
  background: color-mix(in srgb, var(--accent) 18%, var(--panel));
  color: var(--accent);
}

/* A main contributor's "★ main" badge -- same accent-filled treatment as
   .tag-record (an achievement, not just a neutral label) plus bold weight,
   so it reads as clearly as the sphere's own halo ring and enlarged node
   rather than blending into every other plain .tag on the card. */
.tag-main {
  background: color-mix(in srgb, var(--accent) 18%, var(--panel));
  color: var(--accent);
  font-weight: 700;
}

/* Highlights a source configured in taxonomy.SOURCE_WEIGHTS as especially
   reliable (e.g. TFN, Logan T) -- var(--reputable) rather than up/down/new,
   since "trusted/reputable" isn't a state any other part of the UI needs
   to express, but it's still a real theme variable (not a bare hex value)
   so a dark-mode-specific shade only needs to be picked once, in :root. */
.source-reputable { color: var(--reputable) !important; font-weight: 600; }
.source-reputable:hover { color: var(--reputable-dark) !important; }
.tag-reputable {
  background: color-mix(in srgb, var(--reputable) 20%, var(--panel));
  color: var(--reputable-dark);
}

/* A bullet/paragraph in the AI-written narrative (.report) whose own
   inline citation names a reputable source (taxonomy.SOURCE_WEIGHTS) --
   applied in context_world.py's _highlight_reputable_citations(), not
   here; this just makes the whole block stand out, not only the citation
   text at the end of it. Same amber as .tag-reputable/.source-reputable,
   just at low opacity for the fill so body text stays fully readable. */
.report .reputable-block {
  background: color-mix(in srgb, var(--reputable) 7%, transparent);
  border-radius: 4px;
  padding: 2px 10px;
  margin: 0 -10px;
}

.ics-link {
  margin-left: 6px;
  text-decoration: none;
  font-size: 12px;
  opacity: 0.55;
  vertical-align: 1px;
}

/* The result of pressing "Check" on the Suggest a Source page -- rendered
   directly under the check form (not buried below the other sections on
   the page) and visually called out like a banner, so a feed found (or
   not) is impossible to miss rather than something to scroll and hunt
   for. */
.feed-check-result {
  margin: 0 0 1.5rem;
  padding: 14px 18px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--panel);
  /* var(--shadow-sm), not a hardcoded rgba(0,0,0,...) -- a fixed black
     shadow all but disappears against dark mode's already-near-black
     background, leaving the banner looking flat instead of raised. The
     theme variable already carries its own (more visible) dark-mode
     value, same as every other shadow in this file. */
  box-shadow: var(--shadow-sm);
}
.feed-check-result .block-title { margin-top: 0; border-bottom: none; padding-bottom: 0; }
.feed-check-found { border-color: color-mix(in srgb, var(--up) 45%, var(--line)); border-left: 4px solid var(--up); }
.feed-check-none { border-color: color-mix(in srgb, var(--down) 45%, var(--line)); border-left: 4px solid var(--down); }
.feed-check-error {
  border-left: 4px solid var(--down);
  color: var(--down);
  font-weight: 500;
}

.ics-link:hover { opacity: 1; }

/* A pipeline gone quiet (fetch.py / capture_signal.py) shown right on the
   page instead of needing a separate alert channel -- see healthcheck.py. */
.stale-banner {
  background: color-mix(in srgb, var(--down) 12%, var(--panel));
  border-bottom: 1px solid color-mix(in srgb, var(--down) 30%, var(--panel));
  padding: 10px 24px;
}

.stale-banner-row {
  font-size: 13px;
  color: var(--down);
  max-width: 1320px;
  margin: 0 auto;
}

.stale-banner-row + .stale-banner-row { margin-top: 4px; }

/* Something on your watchlist showed up in the latest report -- same
   purple used for "worth watching" elsewhere (.tag-new, .chip-flag) so
   this reads as good news, not a warning like .stale-banner above. */
.watchlist-banner {
  background: color-mix(in srgb, var(--new) 10%, var(--panel));
  border-bottom: 1px solid color-mix(in srgb, var(--new) 28%, var(--panel));
  padding: 10px 24px;
}

.watchlist-banner-row {
  display: block;
  font-size: 13px;
  color: var(--new);
  text-decoration: none;
  max-width: 1320px;
  margin: 0 auto;
}

.watchlist-banner-row:hover { text-decoration: underline; }
.watchlist-banner-row + .watchlist-banner-row { margin-top: 4px; }

/* "This week at a glance" -- a handful of auto-picked highlights (biggest
   raise, most active area, etc.) surfaced above the fold, each linking down
   to the section it came from. Deliberately lighter-weight than .metric
   (no big number, no delta) so it doesn't compete with the real stats. */
.glance-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 1.25rem 0 1.75rem;
}

.glance-card {
  flex: 1 1 200px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s ease, transform 0.15s ease;
  animation: glance-fade-in 0.4s ease both;
}

/* Pure CSS, not JS-driven -- with JS off or slow, a card that depended on a
   script to reveal it would just stay invisible forever. Restrained on
   purpose: opacity only, no slide/bounce, staggered per card so they don't
   all pop at once. */
@keyframes glance-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.glance-card:nth-child(1) { animation-delay: 0.05s; }
.glance-card:nth-child(2) { animation-delay: 0.15s; }
.glance-card:nth-child(3) { animation-delay: 0.25s; }
.glance-card:nth-child(4) { animation-delay: 0.35s; }

.glance-card:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
}

.glance-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 3px;
}

.glance-value {
  font-size: 14px;
  font-weight: 500;
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.glance-sub {
  font-size: 11px;
  color: var(--ink-2);
  margin-top: 2px;
}

.table tr.is-new-row td { background: color-mix(in srgb, var(--new) 6%, var(--panel));
}

/* One continuous world map: a full base layer of every country (so it reads
   as an actual recognisable globe, not just the handful of tracked ones)
   plus a highlight layer redrawing only the tracked countries on top,
   tinted by how much activity they had. A legend list below doubles as the
   click target for filtering, since text labels drawn directly on small
   countries would be illegible at this scale. */
.world-map-svg {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 8px;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-md);
}

.map-ocean { fill: var(--map-ocean); }

/* vector-effect: non-scaling-stroke makes stroke-width mean actual screen
   pixels regardless of the SVG's own coordinate scale -- map_countries.json
   switched from a ~2750-unit viewBox to a ~360-unit (plain degrees) one,
   and a border tuned in the old unit scale would otherwise render roughly
   7x too thick now. This also means stroke width stays sane if the
   coordinate scale ever changes again. */
.map-base-country path {
  fill: var(--map-base-fill);
  stroke: var(--map-base-stroke);
  stroke-width: 0.6;
  vector-effect: non-scaling-stroke;
}

.country-group { cursor: pointer; }

.country-shape path {
  fill: var(--accent-2);
  stroke: var(--panel);
  stroke-width: 0.5;
  vector-effect: non-scaling-stroke;
  transition: fill-opacity 0.15s, fill 0.15s;
}

.country-group:hover .country-shape path { fill-opacity: 1 !important; }
.country-group.active .country-shape path { fill: var(--accent); fill-opacity: 1 !important; }

/* A zero-mention country now has no .country-group at all (see
   _map_macros.html) -- nothing drawn on top of the base layer, no onclick,
   no hover state, genuinely identical to every other untracked country on
   the map. Used to instead render an invisible (fill-opacity:0) shape with
   its own stroke, which painted a second, different-coloured outline over
   the base layer's own border -- exactly the "still looks highlighted"
   that a plain, data-less country shouldn't have. A muted "you clicked an
   empty one" state and a lying hover fill used to live here too; both are
   moot now that there's no element left to click or hover in the first
   place. */

.map-legend-list {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* .map-legend-item: a clickable <a> for a mentioned country, or a plain
   inert <span> for a zero-mention one (see _map_macros.html) -- styled by
   this shared class rather than the element+class combo it used to be, so
   both render identically apart from cursor/hover. */
.map-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: 20px;
  font-size: 12px;
  color: var(--ink-2);
  text-decoration: none;
  cursor: pointer;
  transition: border-color 0.1s, color 0.1s;
}

.map-legend-item:not(.empty):hover { border-color: var(--accent); color: var(--ink); }
.map-legend-item.empty { color: var(--ink-3); cursor: default; }

.map-legend-item.active {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 500;
  background: color-mix(in srgb, var(--accent) 8%, var(--panel));
}

.map-cell-count {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
}

.map-legend-toggle { margin-top: 0.5rem; }

.map-legend-toggle a {
  font-size: 12px;
  color: var(--ink-3);
  text-decoration: underline;
  cursor: pointer;
}

.map-legend-toggle a:hover { color: var(--accent); }

.event-list { list-style: none; margin: 0; padding: 0; }

.event-row {
  display: grid;
  grid-template-columns: 90px 1fr;
  gap: 12px;
  padding: 8px 0;
}

/* Not a border on every row: the first one sitting right under
   .block-title's own border-bottom read as two lines stacked with barely
   any gap between them — only rows after the first need a separator. */
.event-row + .event-row { border-top: 1px solid var(--line); }

.event-date {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--accent);
}

.event-date.unclear { color: var(--ink-3); }

.event-name { font-weight: 500; font-size: 13px; }

.event-name a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dotted var(--ink-3);
}

.event-name a:hover { color: var(--accent); border-bottom-color: var(--accent); }

/* A real gap found while checking dark mode: company/person links inside
   table cells, chips, and bar rows had no color rule at all, so they fell
   back to the browser's default link blue — jarring even in light mode,
   much more so against a dark background. Same treatment as .event-name
   links above, just covering the contexts that were missed. */
.table td a,
.chip a,
.chip-detail-head a,
.bar-name a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dotted var(--ink-3);
}

.table td a:hover,
.chip a:hover,
.chip-detail-head a:hover,
.bar-name a:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.event-note { color: var(--ink-2); font-size: 12px; margin-top: 2px; }

/* The original newsletter text (templates/article.html) -- a real reading
   view (measured line length, generous paragraph spacing) rather than one
   long pre-wrapped block, now that context_world.format_article_body()
   renders actual <p> tags and linkifies URLs instead of leaving raw text
   for the browser to wrap however it likes. */
.article-page {
  max-width: 700px;
  margin: 0 auto;
}

.article-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  row-gap: 2px;
}

.article-sender {
  font-weight: 600;
  color: var(--ink);
}

.article-meta-sep {
  color: var(--line);
}

.article-body {
  font-size: 16px;
  line-height: 1.75;
  color: var(--ink);
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}

.article-body p {
  margin: 0 0 1.25em;
  word-wrap: break-word;
}

.article-body p:last-child {
  margin-bottom: 0;
}

.article-body a {
  word-break: break-word;
}

/* Sourcing caption under a fact -- who said it (real link when one exists),
   plus the fallback search engines when it doesn't. Deliberately quiet
   (small, muted) since it's provenance, not the point of the row. */
.source-line {
  font-size: 11px;
  color: var(--ink-3);
  margin-top: 3px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: baseline;
}

.source-via { font-style: italic; }

.source-line a { color: var(--ink-3); text-decoration: underline; }
.source-line a:hover { color: var(--accent); }

@media (max-width: 860px) {
  /* A real bug found on mobile: .topnav is a nowrap flex row that's wider
     than a phone screen, and nothing scrolls to reveal the overflow — so
     Events, Watchlist, Manage users, and the account/logout links were
     completely unreachable, not just visually cramped. Wrapping is the
     minimal fix that needs no new markup or JS (no hamburger menu). */
  .topnav { padding: 0.75rem 1.25rem; flex-wrap: wrap; row-gap: 0.5rem; }
  .topnav-brand { margin-right: 0; }
  .shell { grid-template-columns: 1fr; }
  .main { padding: 1.75rem 1.25rem; }
  .metrics { grid-template-columns: 1fr 1fr; }
  .split { grid-template-columns: 1fr; gap: 0; }
  .toolbar { flex-direction: column; }
  .week-select { min-width: 0; }
  .bar-row { grid-template-columns: 100px 1fr 70px 38px; }
  .bar-row-wide { grid-template-columns: 110px 1fr 70px 56px 34px; }
  .event-row { grid-template-columns: 70px 1fr; }

  /* Another real mobile bug: .table uses table-layout:auto, so a table
     with several moderately-wide columns (funding, belligerents, ...)
     forces its own intrinsic width well past a phone screen -- and
     because .shell-empty .main centers itself with margin:auto, a grid
     item with auto margins is sized via CSS Grid's fit-content algorithm
     (shrink-wrap to content, up to max-width) instead of stretching to
     the viewport. That's the actual bug: fit-content sizing measures the
     table's own max-content width as an input, so display:block/width:100%/
     overflow-x:auto *on the table* doesn't help -- .main has already grown
     to fit the table before any of those properties get a chance to act,
     and that oversized .main is what drags the whole page wider than the
     screen. The fix has two parts: stop .main from fit-content-sizing
     (drop the auto margin, stretch it to the grid track instead -- with a
     single 1fr column that's just 100% width) so it's capped to the
     viewport, and THEN display:block + overflow-x:auto on .table gives
     any still-too-wide table its own horizontal scrollbar instead of
     overflowing. Desktop is untouched (main is well under 1320px there
     regardless of how it's sized, so this never fires above 860px). */
  .shell-empty .main { margin: 0; width: 100%; }

  .table {
    display: block;
    width: 100%;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* A headerless table (no column labels to lean on) with 3+ columns --
     Belligerents & players, Startups mentioned, the map popup's company
     breakdown -- doesn't get the scroll treatment above; it just shrinks
     each column to fit, which splits one row's cells across the width so
     unevenly (a one-line name next to a five-line note) that they no
     longer read as belonging together. Stacking each row's cells top to
     bottom instead groups them visually, at the cost of the compactness a
     labelled table can afford. Left alone: a 2-column table (Capital by
     stage/region) already reads fine side by side, and a table WITH a
     thead already has its columns identified even once scrolled. */
  .table:not(:has(thead)):has(td:nth-child(3)) tr {
    display: block;
    padding: 10px 0;
    border-bottom: 1px solid var(--line);
  }
  .table:not(:has(thead)):has(td:nth-child(3)) td {
    display: block;
    padding: 2px 0;
    text-align: left;
  }
}

/* Click-to-expand detail panel under the map, shown for whichever region or
   theater the legend/map was last clicked — answers "why was this
   highlighted" (capital + sectors for World, belligerents for DefenceTech)
   without permanently taking up space for every region at once. */
/* .map-wrap is the positioning context a clicked country's detail docks
   to (below) -- established here, not on the map's own <section class="
   block">, so the docked panel's bottom edge lines up with the map itself,
   not the block's padding around it too. */
.map-wrap { position: relative; }

/* Docked to the bottom of the map itself, overlapping it, rather than a
   plain card further down the page a click used to just scroll you to --
   the whole point being that the info shows up right where you clicked,
   immediately, not another block you have to go find. */
.map-details { position: relative; }

.map-detail {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  /* A fixed px cap, not a %, deliberately: .map-wrap has no explicit
     height of its own (it's sized by the SVG's natural content height),
     and a percentage height on an absolutely-positioned child resolves
     against nothing there -- the browser was collapsing this to a sliver
     instead of a real cap. Capped well under the map's own rendered
     height (with height:auto the map itself usually runs ~250-350px) so
     an entry with lots of rows scrolls internally instead of growing
     until the panel covers the entire map. */
  max-height: 200px;
  overflow-y: auto;
  padding: 0.9rem 2.2rem 0.9rem 1rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  box-shadow: var(--shadow-md);
  z-index: 5;
}

.map-detail-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 0.6rem;
  font-size: 14px;
}

.map-detail-close {
  position: absolute;
  top: 0.6rem;
  right: 0.6rem;
  width: 22px;
  height: 22px;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--ink-3);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}
.map-detail-close:hover { background: color-mix(in srgb, var(--ink) 10%, transparent); color: var(--ink); }

.map-detail-capital {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--accent);
}

.map-detail-empty {
  font-size: 13px;
  color: var(--ink-3);
}

/* Capital % change alongside the $ amount in the focus-areas bar chart. */
.bar-cap-delta {
  display: block;
  font-size: 10px;
}

.bar-cap-delta.is-up { color: var(--up); }
.bar-cap-delta.is-down { color: var(--down); }

/* Clicking a focus-area row expands its full-history capital line chart. */
.bar-row-wide.clickable { cursor: pointer; }
.bar-row-wide.clickable:hover .bar-name { color: var(--accent); }

.area-chart {
  margin: 4px 0 12px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  box-shadow: var(--shadow-sm);
}

.area-chart-svg {
  width: 100%;
  height: auto;
  display: block;
}

/* The capital-history line draws itself in on reveal, rather than just
   appearing -- pure CSS (no JS), so it works the same whether the chart is
   visible on page load (Monthly rollup) or only once a detail panel is
   toggled open (the per-area/company charts elsewhere), since a browser
   doesn't advance an animation on a display:none element. 2000 is a fixed
   value comfortably longer than any real chart's path length (all charts
   render at the same 760x260 size), not a per-chart measurement. */
.area-chart-svg polyline {
  stroke-dasharray: 2000;
  stroke-dashoffset: 2000;
  animation: chart-draw-in 900ms ease-out forwards;
}
@keyframes chart-draw-in {
  to { stroke-dashoffset: 0; }
}

.area-chart-caption {
  margin-top: 6px;
  font-size: 11px;
  color: var(--ink-3);
}

.chart-gridline { stroke: var(--line); stroke-width: 1; }

.chart-axis-label {
  font-family: var(--mono);
  font-size: 9px;
  fill: var(--ink-3);
}

.chart-axis-y { dominant-baseline: middle; }

/* Hover tracer on the capital-history line chart: an invisible hit-circle
   per data point reveals its guide line, dot, and a "date — $amount" label
   on hover, all via CSS :hover — no JavaScript needed. */
.chart-tracer-line, .chart-tracer-dot, .chart-tracer-label {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.05s;
}

.chart-tracer-line { stroke: var(--ink-3); stroke-width: 1; stroke-dasharray: 2 2; }
.chart-tracer-dot { fill: var(--accent); }

.chart-tracer-label {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  fill: var(--ink);
  paint-order: stroke;
  stroke: var(--panel);
  stroke-width: 4px;
}

.chart-hover-hit { fill: transparent; cursor: crosshair; }

.chart-hover-target:hover .chart-tracer-line,
.chart-hover-target:hover .chart-tracer-dot,
.chart-hover-target:hover .chart-tracer-label {
  opacity: 1;
}

.map-detail-note {
  margin-top: 0.6rem;
  font-size: 11px;
  color: var(--ink-3);
  font-style: italic;
}

/* Cross-cutting-topic / outside-taxonomy chips that have specific companies
   behind them expand a small detail panel below the chip list on click —
   the same "why was this mentioned" pattern as the map detail panels. */
.chip.clickable { cursor: pointer; }
.chip.clickable:hover { border-color: var(--accent); background-color: var(--bg); }

.chip.active {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, var(--panel));
  font-weight: 500;
}

.chip-detail {
  margin-top: 0.75rem;
  padding: 0.75rem 1rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  box-shadow: var(--shadow-sm);
}

.chip-detail-head {
  font-size: 13px;
  font-weight: 500;
  margin-bottom: 0.5rem;
}

.chip-detail-note {
  font-size: 13px;
  color: var(--ink-2);
}

.bar-row.clickable { cursor: pointer; }
.bar-row.clickable:hover .bar-name { color: var(--accent); }

.bar-row.active .bar-name,
.bar-row-wide.active .bar-name {
  color: var(--accent);
  font-weight: 600;
}

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

.link-button:hover { color: var(--accent); }
.link-button-danger:hover { color: var(--down); }

/* Watchlist page row header (company/area name + priority selector + remove
   button) — .bar-name elsewhere sits next to a progress bar and stays on
   one line via nowrap/ellipsis, which would clip the priority buttons here,
   so this overrides that with a wrapping flex row instead. */
.watchlist-row-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 6px;
  font-weight: 500;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  cursor: pointer;
}

.watchlist-row-head:hover { color: var(--accent); }

/* Color-codes each watchlist row to its taxonomy vertical (icons.area_color)
   -- a quick visual grouping cue on a page that otherwise relies purely on
   section headings to show which area a company belongs to. The color comes
   in as a per-row CSS variable (--row-accent) rather than a hardcoded class
   per area, since the palette lives in Python (icons.py) as the single
   source of truth. */
.area-row-wrap {
  border-left: 3px solid var(--row-accent, transparent);
  padding-left: 10px;
  margin-bottom: 8px;
}

.priority-select { display: inline-flex; gap: 2px; }
.priority-select form { display: inline-flex; }

.priority-btn {
  width: 22px;
  height: 22px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--panel);
  color: var(--ink-3);
  font-family: var(--mono);
  font-size: 11px;
  cursor: pointer;
}

.priority-btn:hover { border-color: var(--accent); color: var(--accent); }

.priority-btn.active {
  background: var(--accent);
  border-color: var(--accent);
  color: white;
  font-weight: 600;
}

.site-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 1.5rem 3rem;
  margin-top: 2rem;
  border-top: 1px solid var(--line);
  font-size: 12px;
  color: var(--ink-3);
}

.site-footer a { color: var(--ink-3); }
.site-footer a:hover { color: var(--accent); }

.star-toggle {
  background: none;
  border: none;
  padding: 0;
  margin-right: 2px;
  font-size: 13px;
  color: var(--ink-3);
  cursor: pointer;
  vertical-align: -1px;
}

.theme-toggle {
  background: none;
  border: none;
  padding: 2px;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  border-radius: 4px;
  transition: background-color 0.15s ease;
}

.theme-toggle:hover { background-color: var(--bg); }

.font-scale-group {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: auto;
}

.font-scale-btn {
  background: none;
  border: 1px solid var(--line);
  color: var(--ink-2);
  width: 22px;
  height: 22px;
  line-height: 1;
  font-family: var(--sans);
  font-size: 12px;
  cursor: pointer;
  border-radius: 4px;
}

.font-scale-btn:hover { border-color: var(--accent); color: var(--accent); }
.font-scale-btn:first-child { font-size: 10px; }
.font-scale-btn:last-child { font-size: 15px; }

.star-toggle:hover { color: var(--new); }

#back-to-top {
  position: fixed;
  right: 24px;
  bottom: 24px;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink-2);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
  transition: opacity 0.15s ease, transform 0.15s ease, color 0.15s ease, border-color 0.15s ease;
  z-index: 50;
}

#back-to-top:hover {
  color: var(--accent);
  border-color: var(--accent);
  transform: translateY(-2px);
}

#back-to-top[hidden] { display: none; }

@media (max-width: 640px) {
  #back-to-top { right: 16px; bottom: 16px; }
}

/* --- 3CSM Planner ---
   Layer 1 (.csm-matrix) is an actual 3x3 grid -- pillar labels down the
   left, one continuous bordered block with hairline grid lines between
   cells (the gap-as-gridline trick: container background shows through a
   1px gap, so no per-edge border bookkeeping). Layers 2/3 (topics, tasks)
   stay the looser .planner-card grid -- they don't have a fixed 3x3 shape
   to reflect, so forcing them into gridlines would be decoration for its
   own sake. Drilling down is a real view swap (plannerShowLayer(), in
   planner.js), not an accordion reveal; .csm-layer-in plays a small
   fade+rise on whichever layer just became visible -- one restrained
   animation, not a slide/bounce showcase. */

@keyframes csm-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes csm-layer-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

#planner-matrix-view,
.planner-detail {
  animation: csm-layer-in 0.25s ease both;
}

.csm-matrix {
  display: flex;
  flex-direction: column;
  gap: 26px;
  margin-bottom: 2.5rem;
}

.csm-matrix-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 1rem;
}

/* Off by default (each editing control is server-rendered `hidden`) so the
   matrix reads as a clean, static grid until an admin actually asks to
   change its shape -- the retire "x" on every cell and the add-row/column
   forms only appear once this is switched on. */
.planner-edit-toggle {
  flex: 0 0 auto;
  padding: 6px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  color: var(--accent);
  font-family: var(--sans);
  font-size: 13px;
  cursor: pointer;
}
.planner-edit-toggle:hover { border-color: var(--accent); }
.planner-edit-toggle.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

/* One row per pillar rather than a fixed N-column grid -- a pillar's own
   cell count is now admin-editable (content.add_cell()/add_pillar()), so
   nothing here can assume exactly 3 across; .csm-pillar-cells wraps
   whatever it's given instead. */
.csm-pillar-row {
  display: flex;
  align-items: flex-start;
  gap: 26px;
}

.csm-matrix-label {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 160px;
  min-width: 0;
  padding: 6px 4px 0;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.csm-pillar-cells {
  flex: 1;
  min-width: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 14px;
}

.csm-cell-wrap { position: relative; }

.csm-cell {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  min-height: 130px;
  padding: 28px 32px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  color: inherit;
  font-family: var(--sans);
  font-size: 19px;
  font-weight: 500;
  text-align: center;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  animation: csm-fade-in 0.3s ease both;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}

.csm-cell-wrap > .planner-remove-form,
.csm-cell-wrap > form {
  position: absolute;
  top: 10px;
  right: 10px;
}

.csm-cell-add-form,
.csm-pillar-add-form {
  display: flex;
  gap: 8px;
}

.csm-cell-add-form {
  align-items: stretch;
  min-height: 130px;
}

.csm-cell-add-form input,
.csm-pillar-add-form input {
  flex: 1;
  min-width: 0;
  padding: 8px 10px;
  border: 1px dashed var(--line);
  border-radius: 10px;
  background: var(--panel);
  color: inherit;
  font-family: var(--sans);
  font-size: 14px;
}

.csm-cell-add-form button,
.csm-pillar-add-form button {
  flex: 0 0 auto;
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  color: var(--accent);
  font-family: var(--sans);
  font-size: 13px;
  cursor: pointer;
}

.csm-pillar-add-form { max-width: 320px; }

.csm-cell-icon {
  width: 34px;
  height: 34px;
  flex: 0 0 auto;
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.85;
}

.csm-cell-badge {
  position: absolute;
  top: 12px;
  right: 12px;
}

/* How many real topics live under this cell -- distinct from
   .csm-cell-badge above (this client's own selected-task count): a sparse
   cell (still mostly "Placeholder topic") and a well-developed one (a
   dozen real topics) used to look identical until you clicked in. Negative
   margin pulls it up against the label, undoing some of .csm-cell's own
   flex gap just for this pair so it reads as one unit, not two stacked
   items with equal weight. */
.csm-cell-topic-count {
  margin-top: -8px;
  font-size: 11px;
  font-weight: 400;
  color: var(--ink-3);
}

.csm-cell:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}
.csm-cell:active { transform: scale(0.98); }

/* A small hand-timed stagger across each pillar row's own cells (not a
   generated/looping delay) -- matches how .glance-card's own fade-in
   above is staggered per nth-child, not computed. Scoped per row (not a
   global count across the whole matrix) since a row's cell count is now
   admin-editable and can't be assumed. */
.csm-pillar-cells > .csm-cell-wrap:nth-of-type(1) .csm-cell { animation-delay: 0.02s; }
.csm-pillar-cells > .csm-cell-wrap:nth-of-type(2) .csm-cell { animation-delay: 0.05s; }
.csm-pillar-cells > .csm-cell-wrap:nth-of-type(3) .csm-cell { animation-delay: 0.08s; }
.csm-pillar-cells > .csm-cell-wrap:nth-of-type(4) .csm-cell { animation-delay: 0.11s; }
.csm-pillar-cells > .csm-cell-wrap:nth-of-type(5) .csm-cell { animation-delay: 0.14s; }
.csm-pillar-cells > .csm-cell-wrap:nth-of-type(6) .csm-cell { animation-delay: 0.17s; }

@media (max-width: 640px) {
  .csm-pillar-row { flex-direction: column; gap: 10px; }
  .csm-matrix-label { flex: 0 0 auto; padding: 0 4px; }
  .csm-pillar-cells { grid-template-columns: 1fr; }
}

.planner-grid {
  display: grid;
  /* auto-fit, not auto-fill: auto-fill reserves a full track for every
     column that WOULD fit even with nothing to put in it, so a handful of
     cards on a wide page (e.g. Planner's client list with just 2-3
     clients) bunched to the left with a wide dead strip of empty grid
     track beside them -- the real "so much empty space" bug, not a page
     margin. auto-fit collapses those empty tracks to 0 and lets the
     actual cards (each 1fr) grow to fill the row instead. */
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px;
  margin-bottom: 1rem;
}

/* Grid items default to min-width:auto, so a card containing an
   unshrinkable child (e.g. the "+ Add (this client only)" button) forces
   its own track -- and the whole page -- wider than the viewport on a
   phone screen with only one column. Letting items shrink below their
   content's natural width is what makes wrapping/overflow rules on the
   content itself (below) actually take effect. */
.planner-grid > * { min-width: 0; }

/* The container-level "+ Add" forms are also direct .planner-grid
   children, which used to size them as a single narrow grid column --
   same width as one topic card -- squeezing the text input down to an
   unusably small typing target. They're not another card among the
   topics, they're a full-width action bar, so they span every column
   instead of sitting in just one. */
.planner-grid > .planner-add-form { grid-column: 1 / -1; }

.planner-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  color: inherit;
  font-family: var(--sans);
  font-size: 14px;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s ease, transform 0.15s ease;
}

.planner-card:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
}

.planner-card:active { transform: scale(0.98); }

.planner-back {
  margin: 0 0 16px;
}

.planner-back-btn {
  background: none;
  border: none;
  padding: 0;
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 500;
  color: var(--accent);
  cursor: pointer;
}

.planner-back-btn:hover { text-decoration: underline; }

.planner-back-sep {
  color: var(--line);
  margin: 0 4px;
}

.btn-primary {
  display: inline-block;
  padding: 10px 18px;
  border: 1px solid var(--accent);
  border-radius: 8px;
  background: var(--accent);
  color: white;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease, transform 0.1s ease;
}

.btn-primary:hover { background: color-mix(in srgb, var(--accent) 85%, black); }
.btn-primary:active { transform: scale(0.98); }

.count-badge {
  flex: 0 0 auto;
  min-width: 20px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--accent);
  color: white;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  text-align: center;
}

.planner-detail {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg);
  padding: 16px;
  margin: -4px 0 1.5rem;
}

.planner-detail-title {
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 10px;
}

/* Text search across a client's whole tree (planner_client_matrix()) --
   the matrix has grown to ~20+ topics across 9 cells, so clicking through
   cell after cell to find one task no longer scales. */
.planner-search-form {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 1.5rem;
}
.planner-search-form input[type="text"] {
  flex: 1;
  max-width: 420px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-family: var(--sans);
  font-size: 14px;
  background: var(--panel);
  color: inherit;
}
.planner-search-form button {
  padding: 8px 16px;
  background: var(--accent);
  color: white;
  border: none;
  border-radius: 6px;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
}
.planner-search-clear {
  font-size: 13px;
  color: var(--ink-3);
  text-decoration: none;
}
.planner-search-clear:hover { color: var(--down); }

.planner-search-list { list-style: none; margin: 0; padding: 0; }
.planner-search-list li { border-bottom: 1px solid var(--line); }
.planner-search-list li:last-child { border-bottom: none; }
.planner-search-list a {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 4px;
  text-decoration: none;
  color: inherit;
}
.planner-search-list a:hover { background: var(--bg); }
.planner-search-label { font-weight: 500; }
.planner-search-path { font-size: 12px; color: var(--ink-3); }

/* Briefly flashed on the task a search result jumped to (planner.js), so
   landing on a layer with several tasks still makes clear which one was
   actually searched for. */
@keyframes planner-highlight-flash {
  0%, 100% { background: transparent; }
  30% { background: color-mix(in srgb, var(--accent) 20%, transparent); }
}
.planner-task-card.planner-highlight { animation: planner-highlight-flash 2s ease-out; }

.planner-task-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  cursor: default;
}

.planner-task-card:hover { transform: none; }

.planner-task-label {
  /* flex-basis 100% (not e.g. 160px) deliberately forces this onto its
     own row, with priority/notes/save-status wrapping together onto the
     next -- some of the longer methodology-sourced task labels run 100+
     characters, and sharing a row with those controls squeezed them into
     a narrow, awkwardly tall wrapped column instead of using the card's
     full width. */
  flex: 1 1 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}

.planner-task-notes {
  flex: 1 1 180px;
  min-width: 0;
  padding: 5px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: inherit;
  font-family: var(--sans);
  font-size: 13px;
}

.planner-save-status {
  flex: 0 0 auto;
  min-width: 3.5rem;
  color: var(--ink-3);
  font-size: 11px;
}

.planner-steps-toggle {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border: none;
  background: none;
  color: var(--ink-3);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  transition: transform 0.15s ease;
}

.planner-steps-toggle:hover { color: var(--accent); }
.planner-steps-toggle.expanded { transform: rotate(90deg); }

.planner-task-steps {
  /* Same fix as .planner-add-child-forms above: the 30px indent has to be
     padding, not margin, on a flex-shrink:0 full-width item, or it pushes
     this box's right edge past the card's own border. */
  flex: 1 0 100%;
  margin-top: 2px;
  padding: 0 0 0 calc(30px + 1.1rem);
  font-size: 13px;
  color: var(--ink-3);
}

.planner-task-steps li { margin: 3px 0; }

.planner-add-child-toggle {
  flex: 0 0 auto;
  padding: 4px 10px;
  border: 1px dashed var(--line);
  border-radius: 999px;
  background: none;
  color: var(--ink-3);
  font-family: var(--sans);
  font-size: 12px;
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
}

.planner-add-child-toggle:hover { border-color: var(--accent); border-style: solid; color: var(--accent); }

/* Holds one or two forms (this-client-only, and permanent unless the row
   itself is already client-scoped) revealed together by the toggle above --
   each inner .planner-add-child-form is just a plain .planner-add-form box,
   stacked rather than side by side so neither one reads as the default. */
.planner-add-child-forms {
  /* flex-shrink is 0 here (this box always wants its own full-width line,
     never squeezed), which means a LEFT MARGIN on it doesn't get absorbed
     the way it would on a shrinkable box -- margin sits outside the
     flex-basis, not inside it, so a 30px margin here pushed this box's
     right edge 30px past its own parent card's border. padding-left does
     the same visual indent but -- with box-sizing: border-box set
     globally -- counts as part of the box's own width instead of being
     added on top of it, so it can never push past the card's edge. */
  flex: 1 0 100%;
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 4px;
  padding-left: 30px;
}

.planner-remove-btn {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: none;
  color: var(--ink-3);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
}

.planner-remove-btn:hover { border-color: var(--down); color: var(--down); }

/* A group card's Remove sits in its own form (never nested inside the
   drill-down <button>, so clicking it can never also trigger the button's
   own onclick) -- absolutely positioned over the card's corner rather than
   squeezed into its flex row, since the card's label + count badge already
   use the full row. */
.planner-card-wrap { position: relative; }
.planner-card-wrap .planner-card { width: 100%; padding-right: 34px; }
.planner-card-wrap .planner-remove-form { position: absolute; top: 10px; right: 10px; }

.planner-add-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border: 1px dashed var(--line);
  border-radius: 8px;
  background: transparent;
}

.planner-add-form input[type="text"] {
  flex: 1 1 140px;
  min-width: 0;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: inherit;
  font-family: var(--sans);
  font-size: 13px;
}

.planner-add-form button {
  flex: 0 0 auto;
  padding: 6px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: var(--accent);
  font-size: 13px;
  cursor: pointer;
}

.planner-add-form button:hover { border-color: var(--accent); }

/* --- Team sphere ---
   Always-on name labels (team_sphere.js positions these every frame by
   projecting each node's 3D position to screen space). pointer-events:none
   so a label never steals a click/drag meant for the canvas underneath it;
   the transition smooths the front/back-face opacity fade rather than
   letting labels pop abruptly as the sphere rotates past the silhouette. */
.team-node-label {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 10px 2px 2px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--panel) 85%, transparent);
  border: 1px solid var(--line);
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
  pointer-events: none;
  transition: opacity 0.15s ease;
}

/* A main contributor's always-on label reads as "featured" too, not just
   their larger, brighter node -- bolder text and an accent border instead
   of the plain neutral one every other label uses. */
.team-node-label-main {
  font-weight: 700;
  border-color: var(--accent);
  background: color-mix(in srgb, var(--panel) 75%, var(--accent) 8%);
}

/* Same "featured" treatment on the plain member-list card and the People
   list under the sphere, so a main contributor reads as one consistently
   across every place they show up, not just the 3D view. */
.team-member-card-main { border-color: var(--accent); }

.team-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  flex: 0 0 auto;
  object-fit: cover;
  background: var(--panel-2, var(--line));
}

.team-avatar-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--accent) 16%, var(--panel));
  color: var(--accent);
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 600;
  text-transform: uppercase;
}

/* Bigger avatar for a bio/detail panel, where a person's photo is the
   whole point of opening it -- the 36px list-card size would be lost
   next to a name in a larger heading. */
.team-avatar-lg {
  width: 56px;
  height: 56px;
}
.team-avatar-lg.team-avatar-placeholder { font-size: 22px; }

/* Consistent rhythm for the bio panel built by memberDetailHtml() in
   team_sphere.js: photo+name, then contact buttons, then one "about"
   paragraph, then the two collapsible details sections, each the same
   distance from the one above instead of ad hoc margins per line. */
.team-bio-head {
  display: flex;
  align-items: center;
  gap: 10px;
}
.team-bio-section { margin-top: 10px; }
.team-bio-section .head-sub + .head-sub { margin-top: 2px; }

/* Small pill buttons for a bio panel's contact links (Signal/Email) --
   plain text links read as throwaway metadata in a list of facts; a
   button makes "get in touch with this person" its own clear action. */
.team-contact-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 12px;
  border: 1px solid var(--accent);
  border-radius: 999px;
  background: var(--accent);
  color: white;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
}
.team-contact-btn:hover { background: color-mix(in srgb, var(--accent) 85%, black); }

/* Collapsed by default: someone covering most/all verticals (Stephan,
   Pia, Noa) turned this into a wall of text that pushed everything else
   in the bio (contact, overlaps) below the fold. One click away instead
   of always-on. */
.team-verticals-details summary {
  cursor: pointer;
  color: var(--ink-3);
  font-size: 12px;
}
.team-verticals-details summary::marker { color: var(--ink-3); }

/* A small avatar wherever a name shows without a full team card around it
   -- the responsible/second-in-command chips on a completed Plan task. */
.plan-person-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ink-2);
}
.plan-person-chip .team-avatar,
.plan-person-chip .team-avatar-placeholder {
  width: 22px;
  height: 22px;
  font-size: 11px;
}

.team-node-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: 0 0 auto;
}

/* The always-on sphere label's avatar -- a real photo where one's on file,
   ringed in the member's own colour so the "which vertical" signal the
   plain dot used to carry isn't lost. box-sizing: border-box so the ring
   doesn't push the image past 22px and throw off the label's padding. */
.team-node-avatar {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  object-fit: cover;
  flex: 0 0 auto;
  box-sizing: border-box;
  border: 2px solid;
  background: var(--panel);
}

.team-node-avatar-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
}

.team-reset-btn {
  position: absolute;
  bottom: 16px;
  left: 16px;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: color-mix(in srgb, var(--panel) 90%, transparent);
  color: var(--ink-3);
  font-family: var(--sans);
  font-size: 12px;
  cursor: pointer;
}

.team-reset-btn:hover { border-color: var(--accent); color: var(--accent); }

.team-legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 3px 8px 3px 4px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: none;
  color: var(--ink-3);
  font-family: var(--sans);
  font-size: 13px;
  cursor: pointer;
}

.team-legend-item:hover { border-color: var(--line); color: var(--ink); }

.team-legend-item.active {
  border-color: var(--accent);
  color: var(--ink);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}

.team-search-input {
  display: block;
  width: 100%;
  max-width: 260px;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  color: inherit;
  font-family: var(--sans);
  font-size: 13px;
}

.team-search-input:focus { outline: none; border-color: var(--accent); }

/* A real popup: fixed to the viewport (not the sphere box), so it stays
   put and visible however far the page is scrolled -- clicking a name
   down in the People list, well below the sphere, still shows their brief
   without jumping back up to the top. Fixed positioning never blocks the
   rest of the page from scrolling (only this panel's own overflow-y
   scrolls once its content outgrows max-height), which is the whole point
   over a page-covering modal. */
.team-detail-panel {
  position: fixed;
  right: 16px;
  bottom: 16px;
  width: 280px;
  max-height: min(70vh, 480px);
  overflow-y: auto;
  z-index: 50;
  padding-right: 28px;
  background: var(--panel);
  box-shadow: var(--shadow-md);
}

.team-detail-close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 22px;
  height: 22px;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--ink-3);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}

.team-detail-close:hover { background: color-mix(in srgb, var(--ink) 10%, transparent); color: var(--ink); }

@media (max-width: 640px) {
  .team-detail-panel {
    left: 8px;
    right: 8px;
    bottom: 8px;
    width: auto;
    max-height: 50vh;
  }
}

/* ============================================================
   Companies index, flags, intro suggestions (feature batch)
   ============================================================ */

.table-scroll { overflow-x: auto; }

.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 12px;
  margin-bottom: 1.25rem;
}
.filter-search,
.filter-select {
  padding: 7px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  color: inherit;
  font-family: var(--sans);
  font-size: 13px;
}
.filter-search { min-width: 220px; flex: 1 1 220px; max-width: 340px; }

.pill-group { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.pill-toggle {
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--ink-2);
  font-family: var(--sans);
  font-size: 12px;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.pill-toggle:hover { border-color: var(--accent); color: var(--ink); }
.pill-toggle.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.tag-new {
  background: color-mix(in srgb, var(--new) 16%, var(--panel));
  color: var(--new);
  border-color: color-mix(in srgb, var(--new) 40%, transparent);
  font-weight: 600;
}
.watched-mark { color: var(--reputable); margin-left: 2px; }

.alias-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 4px 1px 9px;
  margin-right: 4px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 12px;
  background: var(--panel);
}
.alias-undo {
  border: none;
  background: none;
  color: var(--ink-3);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 0 4px;
}
.alias-undo:hover { color: var(--down); }

/* --- flag-as-wrong --- */
.flag-btn {
  margin-left: 6px;
  padding: 0 5px;
  border: 1px solid transparent;
  border-radius: 4px;
  background: none;
  color: var(--ink-3);
  font-size: 12px;
  line-height: 1.5;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
tr:hover .flag-btn,
.event-row:hover .flag-btn,
.flag-btn:focus-visible { opacity: 1; }
.flag-btn:hover { color: var(--down); border-color: var(--line); }
@media (hover: none) { .flag-btn { opacity: 0.7; } }
.flag-done { margin-left: 6px; font-size: 11px; color: var(--down); white-space: nowrap; }

.flag-pop {
  position: absolute;
  z-index: 80;
  width: 280px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  box-shadow: var(--shadow-md);
  font-size: 13px;
}
.flag-pop[hidden] { display: none; }
.flag-pop-title { margin-bottom: 8px; }
.flag-pop-option { display: flex; align-items: center; gap: 6px; padding: 2px 0; cursor: pointer; }
.flag-pop-note {
  width: 100%;
  margin: 8px 0;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  color: inherit;
  font-family: var(--sans);
  font-size: 12px;
}
.flag-pop-actions { display: flex; align-items: center; gap: 12px; }

/* --- intro suggestions --- */
.intro-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 12px;
}
.intro-card {
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
}
.intro-head { display: flex; align-items: center; gap: 10px; }
.intro-reasons { margin: 8px 0; padding-left: 1.1rem; font-size: 12px; color: var(--ink-2); }
.intro-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* --- Ask the archive --- */
.ask-main { max-width: 820px; }
.ask-form textarea,
.ask-form input[type="text"] {
  width: 100%;
  box-sizing: border-box;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  color: inherit;
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  resize: vertical;
  box-shadow: var(--shadow-sm);
}
.ask-form textarea:focus,
.ask-form input[type="text"]:focus { outline: 2px solid color-mix(in srgb, var(--accent) 40%, transparent); border-color: var(--accent); }
.ask-actions { display: flex; align-items: center; gap: 14px; margin: 10px 0; }
.ask-actions .btn-primary:disabled { opacity: 0.6; cursor: wait; }
.ask-examples { display: flex; flex-wrap: wrap; gap: 6px 8px; align-items: center; font-size: 12px; color: var(--ink-3); margin-bottom: 1.5rem; }
.ask-answer { font-size: 15px; line-height: 1.65; }
.ask-answer p { margin: 0 0 0.8em; }
.cite {
  display: inline-block;
  min-width: 1.6em;
  padding: 0 5px;
  margin: 0 1px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 14%, var(--panel));
  color: var(--accent);
  font-family: var(--sans);
  font-size: 0.72em;
  font-weight: 700;
  text-align: center;
  text-decoration: none;
  vertical-align: 0.15em;
}
.cite:hover { background: var(--accent); color: #fff; }
.ask-sources { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.ask-source {
  display: flex;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  scroll-margin-top: 80px;
}
.ask-source:target { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent); }
.ask-source-id {
  flex: 0 0 auto;
  align-self: flex-start;
  min-width: 2.2em;
  padding: 2px 6px;
  border-radius: 6px;
  font-size: 11px;
  font-weight: 700;
  text-align: center;
  color: #fff;
  background: var(--accent);
}
.ask-kind-signal { background: var(--accent-2); }
.ask-kind-fact { background: var(--new); }
.ask-source-title { font-weight: 600; font-size: 13px; }
.ask-source-text { margin-top: 3px; font-size: 13px; color: var(--ink-2); line-height: 1.5; }


/* --- Planner: due dates, links, reminders --- */
.plan-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin-top: 6px; }
.plan-due { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; }
.plan-due input[type="date"] {
  padding: 2px 6px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: inherit;
  font-family: var(--sans);
  font-size: 12px;
}
.due-chip {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  background: color-mix(in srgb, var(--ink-3) 14%, var(--panel));
  color: var(--ink-2);
  white-space: nowrap;
}
.due-overdue { background: color-mix(in srgb, var(--down) 16%, var(--panel)); color: var(--down); }
.due-today, .due-soon { background: color-mix(in srgb, var(--reputable) 18%, var(--panel)); color: var(--reputable-dark); }
.plan-links { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.plan-link-chip {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 1px 4px 1px 9px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  font-size: 12px;
}
.plan-link-chip a { text-decoration: none; }
.plan-link-x { border: none; background: none; color: var(--ink-3); cursor: pointer; font-size: 14px; line-height: 1; padding: 0 4px; }
.plan-link-x:hover { color: var(--down); }
.plan-link-add { position: relative; }
.plan-link-add input {
  width: 210px;
  padding: 2px 8px;
  border: 1px dashed var(--line);
  border-radius: 999px;
  background: transparent;
  color: inherit;
  font-family: var(--sans);
  font-size: 12px;
}
.plan-link-add input:focus { border-style: solid; border-color: var(--accent); outline: none; background: var(--panel); }
.plan-link-results {
  position: absolute;
  z-index: 40;
  top: calc(100% + 4px);
  left: 0;
  min-width: 300px;
  max-width: 420px;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}
.plan-link-results[hidden] { display: none; }
.plan-link-option {
  text-align: left;
  padding: 7px 10px;
  border: none;
  border-bottom: 1px solid var(--line);
  background: none;
  color: inherit;
  font-family: var(--sans);
  font-size: 12px;
  cursor: pointer;
}
.plan-link-option:last-child { border-bottom: none; }
.plan-link-option:hover { background: color-mix(in srgb, var(--accent) 10%, var(--panel)); }
.plan-link-none { padding: 8px 10px; font-size: 12px; color: var(--ink-3); }

/* --- Admin Ops page --- */
.ops-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }
.ops-card { padding: 14px 16px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); box-shadow: var(--shadow-sm); }
.ops-card-title { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 6px; }
.ops-stat { font-size: 24px; font-weight: 600; color: var(--accent); font-variant-numeric: tabular-nums; }
.ops-stat .muted { font-size: 13px; font-weight: 400; }
.ops-meta { font-size: 12px; color: var(--ink-2); margin-top: 4px; line-height: 1.5; }
.ops-bars { display: flex; align-items: flex-end; gap: 3px; height: 64px; margin-top: 12px; }
.ops-bar-col { flex: 1; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; min-width: 0; }
.ops-bar { width: 100%; max-width: 18px; border-radius: 3px 3px 0 0; background: color-mix(in srgb, var(--accent) 70%, var(--panel)); min-height: 2px; }
.ops-bar-col:hover .ops-bar { background: var(--accent); }
.ops-bar-day { font-size: 9px; color: var(--ink-3); margin-top: 3px; }


/* --- Nav v2: spacer, right-aligned popups, user menu, breadcrumbs --- */
.topnav { gap: 1.25rem; }
.topnav-spacer { flex: 1 1 auto; }
.nav-dropdown-popup[hidden] { display: none; }
.nav-dropdown-right { left: auto; right: 0; min-width: 190px; }
.nav-dropdown-right .nav-dropdown-col { width: 100%; }
.nav-user-toggle { font-size: 12px; color: var(--ink-3); }

.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; font-size: 12px; letter-spacing: 0.02em; }
.crumbs a { color: var(--ink-3); text-decoration: none; }
.crumbs a:hover { color: var(--accent); text-decoration: underline; }
.crumbs [aria-current="page"] { color: var(--ink-2); }
.crumb-sep { color: var(--line); }


/* --- Avatars: one component, three sizes, a stable tint per name --- */
.team-avatar.avatar-sm { width: 22px; height: 22px; font-size: 11px; }
.team-avatar.avatar-md { width: 36px; height: 36px; }
.team-avatar.avatar-lg { width: 56px; height: 56px; font-size: 22px; }
.team-avatar { box-shadow: 0 0 0 1px color-mix(in srgb, var(--ink) 8%, transparent); }

/* Placeholder: initial on a soft tint of the name's own hue (the --avatar-h
   custom property is set inline from the name), readable in both themes. */
.team-avatar-placeholder {
  --avatar-h: 150;
  background: hsl(var(--avatar-h) 34% 88%);
  color: hsl(var(--avatar-h) 42% 26%);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .team-avatar-placeholder {
    background: hsl(var(--avatar-h) 26% 26%);
    color: hsl(var(--avatar-h) 55% 82%);
  }
}
:root[data-theme="dark"] .team-avatar-placeholder {
  background: hsl(var(--avatar-h) 26% 26%);
  color: hsl(var(--avatar-h) 55% 82%);
}

.add-photo-nudge {
  font-size: 11px;
  color: var(--ink-3);
  text-decoration: none;
  border-bottom: 1px dotted var(--ink-3);
}
.add-photo-nudge:hover { color: var(--accent); border-bottom-color: var(--accent); }


/* --- Source pills: "via TFN" as a small chip, in captions and in prose --- */
.source-pill,
.via-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0 9px 0 3px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 4%, var(--panel));
  font-style: normal;
  font-size: 0.8em;
  line-height: 1.7;
  white-space: nowrap;
  vertical-align: baseline;
}
/* Prose citations carry no sender-initial dot (their text is the model's
   "(via TFN)" verbatim), so they get plain horizontal padding instead. */
.via-pill { padding: 0 9px; color: var(--ink-2); }
.via-pill a { color: inherit; text-decoration: none; }
.via-pill a:hover { color: var(--accent); text-decoration: underline; }
.source-line a.source-pill { text-decoration: none; color: var(--ink-2); }
.source-line a.source-pill:hover { border-color: var(--accent); color: var(--accent); }
.pill-dot {
  --avatar-h: 150;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.45em;
  height: 1.45em;
  border-radius: 50%;
  font-size: 0.78em;
  font-weight: 700;
  font-style: normal;
  background: hsl(var(--avatar-h) 34% 86%);
  color: hsl(var(--avatar-h) 42% 26%);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pill-dot { background: hsl(var(--avatar-h) 26% 28%); color: hsl(var(--avatar-h) 55% 82%); }
}
:root[data-theme="dark"] .pill-dot { background: hsl(var(--avatar-h) 26% 28%); color: hsl(var(--avatar-h) 55% 82%); }
/* A trusted source keeps its amber identity, now as a tinted pill. */
.source-pill.source-reputable,
.via-pill.source-reputable {
  background: color-mix(in srgb, var(--reputable) 14%, var(--panel));
  border-color: color-mix(in srgb, var(--reputable) 40%, var(--line));
}


/* --- Sparklines on the headline tiles --- */
.metric { position: relative; min-width: 0; }
/* Bottom-right, so a long label ("Funding rounds this week") never runs
   underneath the line, and a fixed size so the tile can't be stretched by it. */
.metric-spark {
  position: absolute;
  top: 2.6rem;
  right: 1.1rem;
  color: var(--accent);
  opacity: 0.85;
  line-height: 0;
  pointer-events: none;
}
.metric:hover .metric-spark { opacity: 1; }
.metric-spark svg { width: 64px; height: 24px; }
.metric:first-child .metric-spark svg { width: 110px; height: 32px; }
.metrics { grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr)); }
.metric-label { overflow-wrap: anywhere; }
@media (max-width: 860px) { .metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Two-up tiles on a phone are too narrow to share a row with the line. */
@media (max-width: 640px) { .metric-spark { display: none; } }
.sparkline { display: block; overflow: visible; }

/* --- Typography: a defined scale, and figures that line up --- */
:root {
  /* Modular steps (about 1.2x) so sizes read as a system rather than a
     scatter of one-off pixel values. New components should pick from here. */
  --fs-2xs: 10px;
  --fs-xs: 11px;
  --fs-sm: 12px;
  --fs-base: 14px;
  --fs-md: 16px;
  --fs-lg: 20px;
  --fs-xl: 24px;
  --fs-2xl: 32px;
  --tracking-caps: 0.06em;   /* uppercase labels */
  --tracking-tight: -0.01em; /* large headings */
}

/* Tabular numerals wherever figures stack in a column or tick up: money in
   tables, counts on chips, dates in lists, headline metrics. Without this a
   proportional "1" is narrower than an "8" and decimal columns ragged. */
.mono,
.metric-value,
.metric-num,
.glance-value,
.table td.right,
.table th.right,
.chip-n,
.bar-num,
.bar-delta,
.event-date,
.count-badge,
.ops-stat,
.map-cell-count,
.due-chip,
.priority-count,
.plan-priority-count {
  font-variant-numeric: tabular-nums lining-nums;
}

/* Cambria's default figures are old-style (text) numerals, which bob up and
   down inside headline numbers -- lining figures look right for data. */
.metric-value, .metric-num, .ops-stat, .glance-value { font-feature-settings: "lnum" 1, "tnum" 1; }

.head h1 { font-size: var(--fs-2xl); letter-spacing: var(--tracking-tight); text-wrap: balance; }
.block-title { letter-spacing: var(--tracking-caps); }
.head-sub, .report p, .report li { text-wrap: pretty; }
.report h2, .report h3 { text-wrap: balance; }


/* --- Map: controls, tooltip, colour scale, entrance --- */
.map-controls {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 4;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.map-controls button {
  width: 28px;
  height: 28px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: color-mix(in srgb, var(--panel) 92%, transparent);
  color: var(--ink-2);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
}
.map-controls button:hover { color: var(--accent); border-color: var(--accent); }

.map-tooltip {
  position: absolute;
  z-index: 6;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 5px 9px;
  border-radius: 6px;
  background: var(--ink);
  color: var(--bg);
  font-size: 12px;
  line-height: 1.35;
  box-shadow: var(--shadow-md);
  max-width: 240px;
}
.map-tooltip[hidden] { display: none; }
.map-tooltip span { opacity: 0.8; font-size: 11px; }

.world-map-svg.is-zoomed { cursor: grab; }
.world-map-svg.is-zoomed:active { cursor: grabbing; }

.map-scale {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  margin: 0.75rem 0 0.25rem;
  font-size: 11px;
  color: var(--ink-3);
}
.map-scale-bar { display: inline-flex; border-radius: 3px; overflow: hidden; border: 1px solid var(--line); }
.map-scale-bar i { display: block; width: 22px; height: 9px; background: var(--accent-2); }
.map-scale-range { color: var(--ink-2); font-variant-numeric: tabular-nums; }
.map-scale-hint { margin-left: auto; }
@media (max-width: 640px) { .map-scale-hint { display: none; } }

@keyframes map-region-in { from { opacity: 0; } to { opacity: 1; } }
.map-highlight-layer .country-group {
  animation: map-region-in 0.6s ease both;
  animation-delay: calc(var(--i, 0) * 45ms + 120ms);
}
@media (prefers-reduced-motion: reduce) {
  .map-highlight-layer .country-group { animation: none; }
}


/* --- Team sphere v2: collision-aware labels, legend counts, featured pulse --- */
.team-node-label { transition: opacity 0.15s ease, padding 0.15s ease; }
.team-node-label.is-compact { padding: 2px; }
.team-node-label.is-compact .team-node-name { display: none; }

.legend-count {
  margin-left: 6px;
  padding: 0 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 8%, transparent);
  color: var(--ink-2);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
}
.team-legend-item.active .legend-count { background: color-mix(in srgb, var(--accent) 22%, transparent); color: var(--accent); }

@keyframes node-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 50%, transparent); }
  70%  { box-shadow: 0 0 0 7px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.team-node-label-main .team-node-avatar { animation: node-pulse 3s ease-out infinite; }
@media (prefers-reduced-motion: reduce) {
  .team-node-label-main .team-node-avatar { animation: none; }
}


/* --- Empty states --- */
.empty-state {
  text-align: center;
  padding: 2.5rem 1rem 2.25rem;
  color: var(--ink-3);
  border: 1px dashed var(--line);
  border-radius: 12px;
  background: color-mix(in srgb, var(--panel) 60%, transparent);
}
.empty-art { display: block; margin: 0 auto 0.85rem; opacity: 0.75; color: var(--accent); }
.empty-state-title { font-size: 15px; font-weight: 600; color: var(--ink-2); margin-bottom: 0.3rem; }
.empty-state-body { max-width: 46ch; margin: 0 auto 1rem; font-size: 13px; line-height: 1.55; }
.empty-state .btn-primary { font-size: 13px; padding: 8px 16px; }

/* --- Phones: bottom sheets and card tables --- */
@media (max-width: 640px) {
  /* The map's detail panel is anchored to the map's own bottom edge, which on
     a phone is a ~150px-tall strip -- far too small for a table of companies.
     As a real bottom sheet it gets the room it needs and stops covering the
     map's own top. */
  .map-detail {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    max-height: 62vh;
    z-index: 70;
    border-radius: 16px 16px 0 0;
    border-bottom: none;
    box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.22);
    padding-top: 1.6rem;
    animation: sheet-up 0.22s ease both;
  }
  .map-detail::before {            /* the grab-handle affordance */
    content: "";
    position: absolute;
    top: 8px; left: 50%;
    width: 38px; height: 4px;
    margin-left: -19px;
    border-radius: 2px;
    background: var(--line);
  }
  .team-detail-panel {
    left: 0; right: 0; bottom: 0;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.22);
    padding-top: 1.4rem;
    max-height: 60vh;
    animation: sheet-up 0.22s ease both;
  }
  .team-detail-panel::before {
    content: "";
    position: absolute;
    top: 8px; left: 50%;
    width: 38px; height: 4px;
    margin-left: -19px;
    border-radius: 2px;
    background: var(--line);
  }

  /* Wide tables become stacked cards: each row a card, each cell "label:
     value". Opt-in per table (class table-cards + data-label on the cells)
     because some tables aren't tabular data at all. */
  .table-cards thead { display: none; }
  .table-cards, .table-cards tbody { display: block; width: 100%; }
  .table-cards tr {
    display: block;
    margin-bottom: 10px;
    padding: 10px 14px;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--panel);
  }
  .table-cards tr[hidden] { display: none; }
  .table-cards td {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 14px;
    padding: 3px 0 !important;
    border: none !important;
    text-align: right;
  }
  .table-cards td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    font-size: 10px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-3);
    text-align: left;
  }
  .table-cards td.strong { display: block; text-align: left; font-size: 15px; padding-bottom: 6px !important; }
  .table-cards td.strong::before { content: none; }
  .table-cards td[colspan] { display: block; text-align: left; }
  .table-cards td[colspan]::before { content: none; }
}
@keyframes sheet-up { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .map-detail, .team-detail-panel { animation: none !important; } }

.ops-card-wide { grid-column: span 2; }
@media (max-width: 640px) { .ops-card-wide { grid-column: auto; } .ops-grid { grid-template-columns: 1fr; } }


/* ============================================================
   Dark-mode pass + small-screen nav
   ============================================================ */

/* Text that sits ON the accent colour. Light mode's accent is a deep green
   (white text reads well); dark mode's accent is a light green, where white
   text drops to ~3:1 -- so there it flips to a near-black green instead. */
:root { --on-accent: #ffffff; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --on-accent: #0E211A; }
}
:root[data-theme="dark"] { --on-accent: #0E211A; }

.btn-primary,
.team-contact-btn,
.pill-toggle.active,
.ask-source-id,
.cite:hover { color: var(--on-accent); }
.btn-primary:hover { color: var(--on-accent); }
.team-contact-btn { color: var(--on-accent); }
.ask-kind-signal, .ask-kind-fact { color: #fff; }

/* Phones: the nav wraps to several rows, and a sticky 3-row header is a
   third of the screen. Let it scroll away (the back-to-top button and the
   brand link are always one tap away). */
@media (max-width: 860px) {
  .topnav { position: static; }
}

/* Plain <button>s with no class of their own (the notes "Add note" button and
   similar) fell back to the browser's bright default in dark mode. */
main button:not([class]) {
  padding: 6px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 13px;
  cursor: pointer;
}
main button:not([class]):hover { border-color: var(--accent); color: var(--accent); }


/* ============================================================
   Newsletter reader (templates/article.html, article_reader.py)
   ============================================================ */

.article-page.nl { max-width: 1120px; margin: 0 auto; }

/* --- header --- */
.nl-title {
  font-size: 30px;
  line-height: 1.2;
  margin: 0.15rem 0 0.5rem;
  text-wrap: balance;
}
.nl-lead { margin-right: 0.15em; }
.nl-topics {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0.4rem 0 0.9rem;
  padding: 0;
}
.nl-topics li {
  padding: 2px 11px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--ink-2);
  font-size: 12px;
}
.nl-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 16px;
  font-size: 13px;
  color: var(--ink-2);
}
.nl-meta a { color: var(--ink-2); }
.nl-sender { font-size: 13px; font-weight: 600; color: var(--ink); }
.nl-pin-form { display: inline; margin: 0; }

/* --- sticky tools bar --- */
.nl-toolbar {
  position: sticky;
  top: 64px;
  z-index: 30;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  margin: 1rem 0 1.75rem;
  padding: 8px 12px 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: color-mix(in srgb, var(--panel) 93%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  box-shadow: var(--shadow-sm);
}
.nl-find { display: flex; align-items: center; gap: 6px; flex: 1 1 280px; min-width: 0; }
.nl-find-input {
  flex: 1;
  min-width: 120px;
  padding: 6px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  color: inherit;
  font-family: var(--sans);
  font-size: 13px;
}
.nl-find-input:focus { outline: 2px solid color-mix(in srgb, var(--accent) 40%, transparent); border-color: var(--accent); }
.nl-find-count { min-width: 5.2em; font-size: 12px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.nl-tool-btn {
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: var(--ink-2);
  font-family: var(--sans);
  font-size: 12px;
  cursor: pointer;
}
.nl-tool-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.nl-tool-btn:disabled { opacity: 0.4; cursor: default; }
.nl-seg { display: inline-flex; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.nl-seg button {
  padding: 5px 12px;
  border: none;
  background: var(--panel);
  color: var(--ink-2);
  font-family: var(--sans);
  font-size: 12px;
  cursor: pointer;
}
.nl-seg button + button { border-left: 1px solid var(--line); }
.nl-seg button.active { background: var(--accent); color: var(--on-accent); }
.nl-progress { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; overflow: hidden; border-radius: 0 0 10px 10px; }
.nl-progress span { display: block; width: 0; height: 100%; background: var(--accent); }

/* --- two columns: text + context panels --- */
.nl-layout { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 2.5rem; align-items: start; }
.nl-main { min-width: 0; max-width: 720px; }
.nl-aside {
  position: sticky;
  top: 142px;
  max-height: calc(100vh - 160px);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 0 4px 1rem 0;
}

/* --- reading typography --- */
.nl-clean, .nl-original { font-size: 17px; line-height: 1.72; color: var(--ink); }
.nl-clean p { margin: 0 0 1.05em; word-break: break-word; text-wrap: pretty; }
.nl-clean ul, .nl-clean ol { margin: 0 0 1.1em; padding-left: 1.3rem; }
.nl-clean li { margin: 0.28em 0; word-break: break-word; }
.nl-clean blockquote {
  margin: 0 0 1.1em;
  padding: 0.15rem 1rem;
  border-left: 3px solid var(--accent);
  color: var(--ink-2);
}
.nl-section { margin-bottom: 1.5rem; scroll-margin-top: 150px; }
.nl-h { font-family: var(--serif); line-height: 1.25; margin: 0 0 0.55rem; letter-spacing: -0.01em; text-wrap: balance; }
.nl-h1, .nl-h2 { font-size: 22px; margin-top: 2.1rem; padding-bottom: 0.35rem; border-bottom: 1px solid var(--line); }
.nl-h3 { font-size: 19px; margin-top: 1.2rem; }
.nl-h a { color: inherit; text-decoration: none; }
.nl-h a:hover { color: var(--accent); text-decoration: underline; }

/* A story (the newsletter's own headline + byline + blurb) reads as a card. */
.nl-story {
  padding: 1rem 1.25rem 0.55rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
  box-shadow: var(--shadow-sm);
}
.nl-story .nl-h { margin-top: 0; padding: 0; border: none; font-size: 19px; }

.nl-byline { font-size: 13px; color: var(--ink-3); margin: -0.15rem 0 0.6rem !important; }
.nl-sub { font-weight: 600; margin: 1.3rem 0 0.35rem !important; }
.nl-sub-5 { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
.nl-sub-4 { font-size: 17px; }
.nl-rule { border: none; border-top: 1px dashed var(--line); margin: 1.4rem 0; }

.nl-clean a, .nl-original-body a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent);
  text-underline-offset: 3px;
}
.nl-clean a:hover, .nl-original-body a:hover { text-decoration-color: var(--accent); }

/* A link with no label -- just where it goes. */
.nl-chip {
  display: inline-block;
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bg);
  color: var(--ink-3) !important;
  font-size: 0.76em;
  line-height: 1.7;
  text-decoration: none !important;
  white-space: nowrap;
  vertical-align: baseline;
}
.nl-chip:hover { border-color: var(--accent); color: var(--accent) !important; }
.nl-chip-tracker { font-style: italic; }

.nl-cta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 15px;
  border: 1px solid var(--accent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent) 8%, var(--panel));
  color: var(--accent) !important;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  text-decoration: none !important;
}
.nl-cta:hover { background: var(--accent); color: var(--on-accent) !important; }

/* A company the analysis tracked, linked to its profile. */
.nl-co {
  padding: 0 2px;
  border-radius: 3px;
  border-bottom: 1.5px dotted var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  color: inherit !important;
  text-decoration: none !important;
}
.nl-co:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }

mark.nl-hit { padding: 0 1px; border-radius: 3px; background: color-mix(in srgb, var(--reputable) 40%, transparent); color: inherit; }
mark.nl-hit.is-current { background: var(--reputable); color: #1a1300; outline: 2px solid var(--reputable-dark); }

/* --- show more / boilerplate --- */
.nl-more > summary, .nl-boiler > summary {
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.nl-more > summary::-webkit-details-marker, .nl-boiler > summary::-webkit-details-marker { display: none; }
.nl-more { margin-top: 0.5rem; }
.nl-more > summary {
  padding: 12px 16px;
  border: 1px dashed var(--line);
  border-radius: 10px;
  text-align: center;
  font-size: 14px;
  color: var(--accent);
  font-weight: 600;
  background: var(--panel);
}
.nl-more > summary:hover { border-color: var(--accent); }
.nl-more[open] > summary { margin-bottom: 1.5rem; }

.nl-boiler { margin-top: 2.25rem; padding-top: 1rem; border-top: 1px solid var(--line); font-size: 13px; color: var(--ink-3); }
.nl-boiler > summary::before { content: "+ "; }
.nl-boiler[open] > summary::before { content: "\2212  "; }
.nl-boiler-note { margin: 0.6rem 0; }
.nl-boiler-group { margin: 0.7rem 0; }
.nl-boiler-label { font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 4px; }
.nl-boiler ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px 10px; }
.nl-boiler li { font-size: 13px; line-height: 1.6; }

/* --- the original-text view --- */
.nl-original-note { margin-bottom: 1rem; padding: 8px 12px; border-radius: 8px; background: var(--panel); border: 1px solid var(--line); font-size: 12px; color: var(--ink-3); }
.nl-original-body p { margin: 0 0 1em; font-size: 14px; line-height: 1.65; color: var(--ink-2); word-break: break-word; }

/* --- previous / next from the same sender --- */
.nl-pager { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 2.75rem; }
.nl-pager-link {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  color: inherit;
  text-decoration: none;
}
.nl-pager-link:hover { border-color: var(--accent); }
.nl-pager-next { text-align: right; grid-column: 2; }
.nl-pager-dir { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); }
.nl-pager-title {
  font-size: 14px; font-weight: 600; line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* --- side panels --- */
.nl-panel { padding: 12px 14px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); font-size: 13px; }
.nl-panel-title { margin: 0 0 8px; font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
summary.nl-panel-title { cursor: pointer; }
.nl-panel-note { margin: 0 0 10px; font-size: 12px; line-height: 1.5; color: var(--ink-3); }
.nl-outline-list { list-style: none; margin: 0; padding: 0; }
.nl-outline-list a {
  display: block;
  padding: 3px 0 3px 10px;
  border-left: 2px solid var(--line);
  color: var(--ink-2);
  font-size: 13px;
  line-height: 1.4;
  text-decoration: none;
}
.nl-outline-list a:hover { color: var(--accent); }
.nl-outline-list a.active { border-left-color: var(--accent); color: var(--accent); font-weight: 600; }
.nl-outline-l3 a { padding-left: 20px; font-size: 12.5px; }
.nl-x-group { margin-bottom: 12px; }
.nl-x-group:last-child { margin-bottom: 0; }
.nl-x-label { margin-bottom: 4px; font-size: 10px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
.nl-panel ul { list-style: none; margin: 0; padding: 0; }
.nl-panel li { padding: 5px 0; border-bottom: 1px solid color-mix(in srgb, var(--line) 60%, transparent); line-height: 1.4; }
.nl-panel li:last-child { border-bottom: none; }
.nl-x-amount { margin-left: 6px; font-variant-numeric: tabular-nums; color: var(--ink-2); font-weight: 600; }
.nl-x-sub { margin-top: 1px; font-size: 12px; color: var(--ink-3); }
.nl-x-group li:hover .flag-btn { opacity: 1; }

/* --- narrower screens: single column, outline first --- */
@media (max-width: 960px) {
  .nl-layout { display: flex; flex-direction: column; gap: 1.25rem; }
  .nl-aside { display: contents; }
  .nl-outline { order: -1; }
  .nl-main { order: 0; max-width: none; }
  .nl-extracted, .nl-related { order: 1; }
  .nl-toolbar { top: 0; }
  .nl-title { font-size: 25px; }
}
@media (max-width: 860px) { .nl-toolbar { position: static; } }
@media (max-width: 640px) {
  .nl-clean, .nl-original { font-size: 16px; }
  .nl-story { padding: 0.85rem 1rem 0.4rem; }
  .nl-pager { grid-template-columns: 1fr; }
  .nl-pager-next { grid-column: auto; text-align: left; }
  .nl-find-count { min-width: 0; }
}

/* The outline can have 15+ entries; keep it compact so the "Extracted from
   this issue" panel below it is visible without scrolling the sidebar. */
.nl-outline-list { max-height: 240px; overflow-y: auto; padding-right: 4px; }

/* --- Labelled form fields (team member editor) --- */
.form-fields { flex-direction: column; align-items: stretch; gap: 12px; margin-bottom: 12px; }
.form-field { display: flex; flex-direction: column; gap: 3px; font-weight: normal; }
.form-field-label {
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* --- Clients section --- */
.client-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
.client-card {
  display: flex; flex-direction: column; gap: 6px;
  padding: 14px 16px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: inherit; text-decoration: none;
  box-shadow: var(--shadow-sm);
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.client-card:hover { border-color: var(--accent); transform: translateY(-1px); }
.client-card-name { font-size: 17px; font-weight: 600; }
.client-card-meta { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 12px; }
.client-card-latest { font-size: 13px; color: var(--ink-2); }
.client-card-counts { display: flex; gap: 12px; font-size: 11.5px; color: var(--ink-3); margin-top: auto; }

.client-links { display: flex; flex-wrap: wrap; gap: 6px 16px; align-items: center; }
.client-tabs {
  display: flex; flex-wrap: wrap; gap: 4px 18px;
  margin: 0 0 1.5rem;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
}
.client-tabs a { color: var(--ink-2); text-decoration: none; padding: 2px 0; }
.client-tabs a:hover { color: var(--accent); }
.client-tabs a span { font-size: 11px; color: var(--ink-3); margin-left: 2px; }

.client-block-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 8px 16px; margin-bottom: 0.5rem; }
.client-block-head form { display: flex; align-items: center; gap: 10px; }
.client-checked { font-size: 12px; }
.btn-secondary {
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: var(--ink);
  font: inherit; font-size: 13px;
  cursor: pointer;
}
.btn-secondary:hover { border-color: var(--accent); color: var(--accent); }

.client-intel { list-style: none; margin: 0 0 0.75rem; padding: 0; }
.client-intel li { padding: 10px 0; border-bottom: 1px solid var(--line); }
.client-intel li:last-child { border-bottom: none; }
.client-intel-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; }
.client-intel-title { font-weight: 600; flex: 1 1 260px; min-width: 0; overflow-wrap: anywhere; }
.client-intel-meta { font-size: 12px; color: var(--ink-3); display: inline-flex; gap: 8px; align-items: center; }
.client-intel-detail { margin-top: 4px; font-size: 13.5px; color: var(--ink-2); white-space: pre-line; overflow-wrap: anywhere; }
.client-intel form { display: inline; }
.client-empty { margin: 0.25rem 0 0.75rem; font-size: 13.5px; }
.client-sub { font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); margin: 1.25rem 0 0.25rem; font-weight: 500; }
.client-debrief { margin: 0.5rem 0 1rem; }

.client-add { margin-top: 0.5rem; }
.client-add > summary { cursor: pointer; font-size: 13px; color: var(--accent); user-select: none; padding: 4px 0; }
.client-add .form-fields { margin-top: 10px; max-width: 560px; }
.client-add-row { display: flex; flex-wrap: wrap; gap: 12px; }
.client-add-row .form-field { flex: 1 1 200px; }
.form-field textarea, .form-field select,
.form-field input[type="text"], .form-field input[type="url"], .form-field input[type="date"],
.form-field input[type="email"] {
  box-sizing: border-box; width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: var(--ink);
  font: inherit; font-size: 13px;
}

/* --- Design switch (Classic / New look) ---
   The new look lives in design_bird.css and only applies when
   <html data-design="bird">. These are the always-on defaults: the switch
   button, and the new-look pieces that must stay hidden in the classic design. */
.design-toggle {
  background: none;
  border: 1px solid var(--line);
  color: var(--ink-2);
  font-family: var(--sans);
  font-size: 12px;
  line-height: 1;
  padding: 5px 10px;
  border-radius: 6px;
  cursor: pointer;
  white-space: nowrap;
}
.design-toggle:hover { border-color: var(--accent); color: var(--ink); }
.csm-cell-icon-bird, .csm-bird { display: none; }

/* The design switch added one more item to the nav; keep every item on one
   line and tighten the spacing slightly so nothing wraps. */
.topnav { gap: 1.1rem; padding-inline: 2rem; }
.topnav a, .topnav-brand, .nav-dropdown-toggle { white-space: nowrap; }
@media (max-width: 1100px) { .topnav { gap: .8rem; padding-inline: 1.25rem; } }

/* ---- Client overview (CRM): done / to do / suggestions ---- */
.crm-bars { display: grid; gap: 6px; margin-bottom: 1.25rem; max-width: 560px; }
.crm-bar-row { display: grid; grid-template-columns: 110px minmax(0, 1fr) 40px; align-items: center; gap: 10px; font-size: 13px; }
.crm-bar-label { color: var(--ink-2); }
.crm-bar { display: block; height: 8px; border-radius: 4px; background: var(--line); overflow: hidden; }
.crm-bar > span { display: block; height: 100%; background: var(--accent); border-radius: 4px; }
.crm-bar-num { color: var(--ink-3); font-variant-numeric: tabular-nums; text-align: right; }
.crm-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; align-items: start; }
.crm-card { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 16px 18px; min-width: 0; }
.crm-card .client-sub { margin-top: 0; }
.crm-card .client-sub + .crm-list, .crm-list + .client-sub { margin-top: 14px; }
.crm-list { list-style: none; margin: 0 0 12px; padding: 0; display: grid; gap: 12px; }
.crm-list li { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 8px; row-gap: 2px; align-items: baseline; position: relative; }
.crm-item-title { font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }
.crm-item-meta { grid-column: 2; font-size: 12px; color: var(--ink-3); overflow-wrap: anywhere; }
.crm-kind { font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; padding: 1px 6px; border-radius: 4px; border: 1px solid var(--line); color: var(--ink-2); white-space: nowrap; }
.crm-level-high, .crm-prio-A { border-color: var(--down); color: var(--down); }
.crm-level-med, .crm-prio-B { border-color: var(--reputable); color: var(--reputable-dark); }
.crm-kind-ai { border-color: var(--new); color: var(--new); }
.crm-due-overdue { color: var(--down); font-weight: 600; }
.crm-due-soon { color: var(--reputable-dark); font-weight: 600; }
.crm-x { position: absolute; top: 0; right: 0; }
@media (max-width: 1000px) { .crm-grid { grid-template-columns: 1fr; } }

/* ---- Ask: tabs, recent questions on top, Ask the team, member profile ---- */
.ask-tabs { display: flex; gap: 6px; margin: 0 0 1.25rem; border-bottom: 1px solid var(--line); }
.ask-tabs a { padding: 8px 16px; border-bottom: 2px solid transparent; margin-bottom: -1px; color: var(--ink-2); text-decoration: none; font-weight: 600; font-size: 14px; }
.ask-tabs a:hover { color: var(--ink); }
.ask-tabs a.active { color: var(--ink); border-bottom-color: var(--accent); }
.ask-recent { margin-bottom: 1.25rem; }
.ask-recent .block-title { font-size: 13px; margin-bottom: .4rem; }
.ask-recent .event-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 2rem; }
@media (max-width: 760px) { .ask-recent .event-list { grid-template-columns: 1fr; } }
.ask-nudge { margin: 1rem 0; padding: 10px 14px; border: 1px dashed var(--line); border-radius: 8px; font-size: 13px; color: var(--ink-2); }
.team-hits { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.team-hit { border: 1px solid var(--line); border-radius: 10px; background: var(--panel); padding: 14px 16px; }
.team-hit-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.team-hit-who { flex: 1 1 200px; min-width: 0; }
.team-hit-name { font-weight: 700; font-size: 16px; }
.team-hit-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.team-evidence { list-style: none; margin: 10px 0 8px; padding: 0; display: grid; gap: 6px; font-size: 14px; }
.team-evidence li { display: flex; gap: 8px; align-items: baseline; }
.team-hit-foot { font-size: 12px; }
.team-fallback { display: flex; gap: 8px; flex-wrap: wrap; margin: 12px 0; }
.member-title { display: flex; align-items: center; gap: 16px; }
.member-title h1 { margin: 0; }
.member-brief { font-size: 17px; line-height: 1.55; max-width: 62ch; margin: 0 0 14px; }
