/* Plan 24 (2026-09-21) - agent B redesign, per Adnan's brief
   Docs/Plans/briefs/2026-09-21_plan24_agent_B_redesign.md: the Salam app's
   report language (header row / left sidebar / KPI cards / bar panels /
   real tables / Chart.js trend) for the online screen, and a SEPARATE print
   layout built from its own DOM (#sf-print-root), not the screen DOM
   shrunk to fit. Font/class naming stays `sf-` prefixed per this app's own
   convention (matches `hm-` for heatmaps). Tokens not in styles.css are
   added below, light default + dark override via the same
   `[data-theme='dark']` attribute pattern styles.css uses. */

:root {
  --sf-muted: #5f6b68;
  --sf-brand-soft: #e3efec;
  --sf-green-soft: #e4f8ec;
  --sf-orange-soft: #fdf1dc;
  --sf-red-soft: #fbe3e0;
  --sf-blue: #3388ff;
  --sf-page-bg: #f3f5f4;
}

[data-theme='dark'] {
  --sf-muted: #9aa8a4;
  --sf-brand-soft: #163530;
  --sf-green-soft: #163a26;
  --sf-orange-soft: #3a2c10;
  --sf-red-soft: #3a1a16;
  --sf-blue: #4fa3ff;
  --sf-page-bg: #16181a;
}

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

body:has(#sf-app) {
  display: block;
}

body:has(#sf-app) main {
  padding: 0;
  display: block;
}

#sf-app {
  background: var(--sf-page-bg);
  min-height: calc(100vh - 65px);
}

/* ---------- top bar (Salam header-row language) ---------- */
#sf-topbar {
  background: var(--panel-bg);
  border-bottom: 1px solid var(--border);
  padding: 14px 20px;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

#sf-topbar h1 {
  margin: 0;
  font-size: 1.35rem;
  color: var(--brand);
  white-space: nowrap;
}

.sf-topbar-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  color: var(--sf-muted);
  font-size: 0.85rem;
}

.sf-topbar-controls select,
.sf-topbar-controls input[type='date'] {
  font: inherit;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel-bg);
  color: var(--text);
}

.sf-topbar-controls button.sf-arrow {
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel-bg);
  color: var(--text);
  cursor: pointer;
}

.sf-compare-caption {
  white-space: nowrap;
  font-size: 0.82rem;
}

.sf-topbar-spacer {
  flex: 1 1 auto;
}

.sf-topbar-exports {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.sf-topbar-exports button {
  padding: 7px 14px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel-bg);
  color: var(--text);
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
  white-space: nowrap;
}

.sf-topbar-exports button.sf-primary {
  background: var(--brand);
  color: var(--brand-contrast);
  border-color: var(--brand);
}

.sf-mock-banner {
  background: var(--orange);
  color: #1a1a1a;
  font-weight: 600;
  font-size: 0.78rem;
  text-align: center;
  padding: 0.35rem 0.5rem;
}

.sf-freshness-banner {
  background: var(--error);
  color: #fff;
  font-weight: 600;
  font-size: 0.82rem;
  text-align: center;
  padding: 0.4rem 0.6rem;
}

.sf-freshness-banner[hidden] {
  display: none;
}

/* ---------- body: sidebar + content ---------- */
#sf-body {
  display: flex;
  align-items: flex-start;
  min-height: calc(100vh - 130px);
}

#sf-sidebar {
  flex: 0 0 220px;
  padding: 20px 12px;
  position: sticky;
  top: 0;
}

.sf-nav-group {
  margin-bottom: 22px;
}

.sf-nav-group-title {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--sf-muted);
  padding: 0 10px;
  margin-bottom: 6px;
}

.sf-nav-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  text-align: left;
  padding: 8px 10px;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 0.88rem;
  cursor: pointer;
  margin-bottom: 2px;
}

.sf-nav-item:hover {
  background: var(--sf-brand-soft);
}

.sf-nav-item.active {
  background: var(--sf-brand-soft);
  color: var(--brand);
  font-weight: 600;
  box-shadow: inset 3px 0 0 var(--brand);
}

.sf-nav-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: 0 0 auto;
}

.sf-nav-dot.g { background: var(--green); }
.sf-nav-dot.a { background: var(--orange); }
.sf-nav-dot.r { background: var(--red); }

#sf-content {
  flex: 1 1 auto;
  padding: 24px 28px 60px;
  min-width: 0;
}

.sf-section {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

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

.sf-section-title {
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--text);
  margin: 4px 0 -8px;
}

.sf-section-subtitle {
  color: var(--sf-muted);
  font-size: 0.85rem;
  margin-top: -14px;
}

/* ---------- KPI cards ---------- */
.sf-kpi-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px;
}

/* City section's 6-card KPI row only (Summary's 5-card row keeps plain
   .sf-kpi-row's auto-fit - it was never reported broken). 2026-09-21
   (Fable review): auto-fit alone let 6 cards resolve to 5-per-row-plus-a-
   lone-6th at ~1366px (just under 6 x 190px + gaps); force the exact count
   once there is room, auto-fit still handles anything narrower. */
.sf-kpi-row-6 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px;
}

@media (min-width: 1366px) {
  .sf-kpi-row-6 {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

.sf-kpi-card {
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px;
  text-align: center;
}

.sf-kpi-card .l {
  font-size: 0.78rem;
  color: var(--sf-muted);
  margin-bottom: 6px;
}

.sf-kpi-card .v {
  font-size: 1.7rem;
  font-weight: 700;
  color: var(--text);
}

.sf-kpi-card .d {
  margin-top: 4px;
  font-size: 0.82rem;
  font-weight: 600;
}

.sf-kpi-card .d.up { color: #1e7e46; }
.sf-kpi-card .d.down { color: #c0392b; }
.sf-kpi-card .d.flat { color: var(--sf-muted); }

.sf-kpi-card .prev {
  margin-top: 3px;
  font-size: 0.75rem;
  color: var(--sf-muted);
}

/* ---------- city tiles (summary section) ---------- */
.sf-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 14px;
}

/* 2026-09-21 (Fable review): same 4+1-orphan issue as the KPI row above -
   force exactly 5 once there's room for all of them; auto-fit(230px)
   handles narrower widths (3+2, 2+2+1, ...). */
@media (min-width: 1366px) {
  .sf-tiles {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

.sf-tile {
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
}

.sf-tile-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: 700;
  font-size: 1rem;
}

.sf-tile-subs {
  font-size: 1.5rem;
  font-weight: 700;
  margin-top: 6px;
}

.sf-tile-subs small {
  font-size: 0.72rem;
  font-weight: 400;
  color: var(--sf-muted);
}

.sf-tile-util {
  margin-top: 4px;
}

.sf-tile-util .peak {
  font-size: 1.05rem;
  font-weight: 700;
}

.sf-tile-util .caption {
  display: block;
  font-size: 0.72rem;
  color: var(--sf-muted);
}

.sf-tile-band {
  display: flex;
  height: 8px;
  border-radius: 4px;
  overflow: hidden;
  margin: 10px 0 8px;
  background: var(--border);
}

.sf-tile-band i { display: block; height: 100%; }
.sf-tile-band .g { background: var(--green); }
.sf-tile-band .a { background: var(--orange); }
.sf-tile-band .r { background: var(--red); }
.sf-tile-band .n { background: var(--neutral); opacity: 0.5; }

.sf-tile-chips {
  display: flex;
  gap: 6px;
  margin-bottom: 10px;
}

.sf-tile-chips .sf-chip {
  flex: 1 1 0;
  text-align: center;
}

.sf-tile-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 8px;
  font-size: 0.78rem;
}

.sf-tile-facts span:nth-child(odd) { color: var(--sf-muted); white-space: nowrap; }
.sf-tile-facts span:nth-child(even) { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }

.sf-pill {
  font-size: 0.68rem;
  padding: 2px 9px;
  border-radius: 10px;
  font-weight: 700;
  color: #fff;
  white-space: nowrap;
}

.sf-pill.g { background: #27ae60; }
.sf-pill.a { background: #d68910; }
.sf-pill.r { background: #c0392b; }

.sf-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 5px;
  font-size: 0.75rem;
  font-weight: 600;
}

.sf-chip.g { background: var(--sf-green-soft); color: #1e7e46; }
.sf-chip.a { background: var(--sf-orange-soft); color: #8a5a00; }
.sf-chip.r { background: var(--sf-red-soft); color: #a3261a; }
.sf-chip.n { background: var(--sf-brand-soft); color: var(--sf-muted); }

/* ---------- panels (bar panels + table panels + generic) ---------- */
.sf-panel {
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 18px 20px;
}

.sf-panel h2,
.sf-panel h3 {
  margin: 0 0 14px;
  font-size: 1rem;
  color: var(--text);
}

.sf-panel .sf-note {
  font-size: 0.78rem;
  color: var(--sf-muted);
  margin-top: 10px;
}

.sf-row-2col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

@media (max-width: 1199px) {
  .sf-row-2col {
    grid-template-columns: 1fr;
  }
}

/* ---------- bar panel rows (Salam "Top Utilized Links" language) ------- */
.sf-bar-row {
  display: grid;
  grid-template-columns: minmax(140px, 220px) 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid var(--border);
}

/* "Where to sell" panel only - adds a leading rank number column. */
.sf-bar-row-ranked {
  grid-template-columns: 20px minmax(140px, 220px) 1fr auto;
}

.sf-bar-rank {
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--sf-muted);
  text-align: right;
}

.sf-bar-row:last-child { border-bottom: none; }

.sf-bar-label {
  font-size: 0.85rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sf-bar-label .cap {
  display: block;
  font-size: 0.72rem;
  color: var(--sf-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sf-bar-track {
  position: relative;
  height: 18px;
  background: var(--bg);
  border-radius: 4px;
  overflow: hidden;
}

.sf-bar-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  border-radius: 4px;
}

.sf-bar-fill.g { background: var(--green); }
.sf-bar-fill.a { background: var(--orange); }
.sf-bar-fill.r { background: var(--red); }
.sf-bar-fill.brand { background: var(--brand); }

.sf-bar-threshold {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 0;
  border-left: 1px dashed var(--sf-muted);
  opacity: 0.6;
}

.sf-bar-value {
  font-size: 0.85rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-align: right;
  min-width: 70px;
}

/* ---------- real tables (screen) ---------- */
.sf-table-wrap {
  overflow-x: auto;
}

.sf-table-scroll {
  max-height: 560px; /* ~15 data rows + header, per the brief */
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
}

table.sf-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
}

table.sf-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--sf-brand-soft);
  color: var(--brand);
  text-align: left;
  padding: 8px 10px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
}

/* Movement table only: city columns hold this file's own long-form
   GROUP_LABEL (DDK = "DDK (Dammam - Khobar)") - the plain rule above
   forces nowrap on every header by default, which is right for sortable
   data tables but wrong here (2026-09-21, Fable review: DDK is allowed to
   wrap, just not mid-word). .sf-nowrap on the "Change" column still wins
   (one more class = higher specificity) so that column stays on one line. */
table.sf-table-movement thead th {
  white-space: normal;
}

table.sf-table thead th.sf-no-sort {
  cursor: default;
}

table.sf-table thead th .sf-sort-arrow {
  font-size: 0.7em;
  color: var(--sf-muted);
  margin-left: 3px;
}

table.sf-table tbody td {
  padding: 7px 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
  /* styles.css's global `table td { white-space: nowrap }` (shared by every
     plain table in this app - admin users, batch results, etc.) would
     otherwise silently un-wrap every cell here unless it happens to carry
     .sf-wrap; flip the default back to normal so wrapping is opt-OUT
     (.sf-nowrap) for ID/number/chip columns, not opt-IN for every free-text
     cell (a missed .sf-wrap on one row silently truncated the "Five
     cities" totals row's guidance text - 2026-09-21). */
  white-space: normal;
}

table.sf-table tbody tr:nth-child(even) {
  background: var(--sf-page-bg);
}

table.sf-table td.sf-num,
table.sf-table th.sf-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Columns holding IDs/numbers/chips must never wrap (screen or print) -
   only the designated free-text column (capacity action / focus /
   definition) should. */
table.sf-table td.sf-nowrap,
table.sf-table th.sf-nowrap {
  white-space: nowrap;
}

table.sf-table td.sf-wrap {
  white-space: normal;
  min-width: 220px;
}

/* ---------- map (city section) ---------- */
.sf-map-panel {
  position: relative;
}

.sf-map {
  width: 100%;
  height: 440px;
  border-radius: 8px;
  background: var(--bg);
}

.sf-map-legend {
  position: absolute;
  right: 26px;
  bottom: 26px;
  background: var(--panel-bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 12px;
  font-size: 0.78rem;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  z-index: 400;
}

.sf-map-legend .row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 2px 0;
}

.sf-map-legend .dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  display: inline-block;
}

/* ---------- trend chart row ---------- */
.sf-trend-row {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 16px;
}

@media (max-width: 1199px) {
  .sf-trend-row {
    grid-template-columns: 1fr;
  }
}

.sf-trend-canvas-wrap {
  position: relative;
  height: 280px;
}

/* 2026-09-21 (Fable review): .sf-landing-bars's `height: 100%` claimed the
   full grid-stretched panel height (matching the taller trend panel
   alongside it), but its .sf-note sibling below it then rendered outside
   the panel's visual box at 1366px - a plain block child after a
   height:100% sibling doesn't get "pushed inside" a shorter box the way a
   flex layout would. Making the .sf-panel itself a flex column fixes this
   properly: h3 (auto), .sf-landing-bars (flex:1, vertically centers its
   rows in whatever space is actually left), .sf-note (auto, always the
   last visible line, never outside the border). */
.sf-panel-flex {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.sf-panel-flex .sf-landing-bars {
  flex: 1 1 auto;
}

.sf-panel-flex .sf-note {
  flex: 0 0 auto;
}

.sf-landing-bars {
  display: flex;
  flex-direction: column;
  gap: 10px;
  justify-content: center;
}

.sf-landing-row .l {
  display: flex;
  justify-content: space-between;
  font-size: 0.82rem;
  margin-bottom: 4px;
}

.sf-landing-track {
  height: 10px;
  border-radius: 5px;
  background: var(--bg);
  overflow: hidden;
}

.sf-landing-fill { height: 100%; }

/* ---------- definitions (two-column list panel) ---------- */
.sf-def-list {
  display: grid;
  grid-template-columns: minmax(140px, 220px) 1fr;
  gap: 10px 18px;
}

.sf-def-term {
  font-weight: 700;
  font-size: 0.85rem;
}

.sf-def-body {
  font-size: 0.85rem;
}

.sf-def-source {
  display: block;
  font-size: 0.72rem;
  color: var(--sf-muted);
  margin-top: 2px;
}

@media (max-width: 700px) {
  .sf-def-list {
    grid-template-columns: 1fr;
  }
}

/* ---------- loading / error / skeletons ---------- */
.sf-loading,
.sf-error {
  padding: 3rem 1rem;
  text-align: center;
  color: var(--sf-muted);
}

.sf-error { color: var(--error); }

.sf-skeleton {
  background: linear-gradient(90deg, var(--border) 25%, var(--sf-page-bg) 37%, var(--border) 63%);
  background-size: 400% 100%;
  animation: sf-skeleton-shine 1.4s ease infinite;
  border-radius: 8px;
}

@keyframes sf-skeleton-shine {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}

/* ---------- sidebar collapses to a top tab strip under 900px ---------- */
@media (max-width: 899px) {
  #sf-body {
    flex-direction: column;
  }

  #sf-sidebar {
    position: static;
    width: 100%;
    display: flex;
    overflow-x: auto;
    gap: 6px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border);
  }

  .sf-nav-group {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-bottom: 0;
    flex: 0 0 auto;
  }

  .sf-nav-group-title {
    padding: 0 4px 0 10px;
    margin-bottom: 0;
    white-space: nowrap;
  }

  .sf-nav-item {
    white-space: nowrap;
  }

  #sf-content {
    padding: 16px;
  }

  .sf-kpi-row,
  .sf-tiles {
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  }
}

/* Schedules modal (unchanged from the previous build) */
.sf-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 4vh 1rem;
  z-index: 2000;
  overflow-y: auto;
}

.sf-modal-backdrop[hidden] { display: none; }

.sf-modal {
  background: var(--panel-bg);
  color: var(--text);
  border-radius: 8px;
  width: 100%;
  max-width: 720px;
  padding: 1rem 1.25rem 1.25rem;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35);
}

.sf-modal h2 {
  margin-top: 0;
  color: var(--brand);
  font-size: 1.1rem;
}

.sf-modal-close {
  float: right;
}

.sf-sched-table {
  width: 100%;
  border-collapse: collapse;
  margin: 0.75rem 0;
  font-size: 0.85rem;
}

.sf-sched-table th,
.sf-sched-table td {
  border-bottom: 1px solid var(--border);
  padding: 0.35rem 0.5rem;
  text-align: left;
}

.sf-sched-status {
  font-size: 0.75rem;
  padding: 1px 6px;
  border-radius: 4px;
}

.sf-sched-status.ok { background: var(--sf-green-soft); color: #1e7e46; }
.sf-sched-status.fail { background: var(--sf-red-soft); color: #a3261a; }
.sf-sched-status.pending { background: var(--sf-brand-soft); color: var(--sf-muted); }

#sf-schedule-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 0.6rem;
  margin-top: 0.75rem;
  border-top: 1px solid var(--border);
  padding-top: 0.75rem;
}

#sf-schedule-form label {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: 0.82rem;
}

#sf-schedule-form .sf-span2 { grid-column: 1 / -1; }

#sf-schedule-message {
  grid-column: 1 / -1;
  font-size: 0.85rem;
}

/* ---------- admin capacity notes / city groups page (unchanged classes) */
.sf-admin-search {
  margin: 0.75rem 0;
}

.sf-planned-release-col,
.sf-note-col {
  min-width: 160px;
}

.sf-inline-edit {
  width: 100%;
  font: inherit;
}

.sf-city-groups-editor {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-width: 640px;
}

.sf-city-group-row {
  display: grid;
  grid-template-columns: 140px minmax(0, 1fr) auto;
  gap: 0.5rem;
  align-items: center;
}

/* ================================================================
   PRINT LAYOUT - separate DOM (#sf-print-root), built only for ?print=1.
   Adnan's amendment (2026-09-21 08:50): page counts are NOT fixed anymore
   (drop the old 3/7 target) - normal font sizes (>=11pt body, >=10pt
   tables), comfortable row heights, one panel/table per page section with
   breathing room, break before a table that would split badly, IDs/numbers
   NEVER wrapped, no shrink-to-fit. Screen styles above are irrelevant here;
   this is its own layout, not the screen DOM reused. On screen (no print),
   #sf-print-root stays empty/hidden.
   ================================================================ */
#sf-print-root {
  display: none;
}

body.sf-print-mode #sf-app {
  display: none;
}

body.sf-print-mode #sf-print-root {
  display: block;
}

.sf-p-page {
  padding: 14mm 14mm 16mm;
}

.sf-p-page + .sf-p-page {
  break-before: page;
  page-break-before: always;
}

.sf-p-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  border-bottom: 2pt solid var(--brand);
  padding-bottom: 6pt;
  margin-bottom: 14pt;
}

/* Page 1 only: "FWA Sales Focus - Five Major Cities" is long enough at
   20pt that sharing a flex row with the meta block (which the shorter
   per-city h2 titles don't need to) wrapped it to two lines - 2026-09-21
   (Fable review). Give the title its own full-width line, meta below it
   as one line instead of fighting it for horizontal room. */
.sf-p-head-wide {
  flex-direction: column;
  align-items: flex-start;
  gap: 3pt;
}

.sf-p-head-wide .meta {
  text-align: left;
}

.sf-p-head h1,
.sf-p-head h2 {
  margin: 0;
  font-size: 20pt;
  color: var(--brand);
}

.sf-p-head h2 { font-size: 16pt; }

.sf-p-head .sub { color: var(--sf-muted); font-size: 11pt; margin-top: 2pt; }

.sf-p-head .meta {
  text-align: right;
  color: var(--sf-muted);
  font-size: 9.5pt;
  line-height: 1.4;
}

.sf-p-section {
  margin-bottom: 18pt;
  break-inside: avoid;
  page-break-inside: avoid;
}

/* Tables are explicitly allowed to break across pages (Adnan: let the STOP
   table run to a second/third page rather than shrink) - only the section
   HEADING stays glued to at least its table's header row. */
.sf-p-section.sf-p-table-section {
  break-inside: auto;
  page-break-inside: auto;
}

.sf-p-h3 {
  font-size: 13pt;
  color: var(--brand);
  text-transform: uppercase;
  letter-spacing: 0.3pt;
  margin: 0 0 8pt;
}

.sf-p-h3 small {
  text-transform: none;
  letter-spacing: 0;
  color: var(--sf-muted);
  font-weight: 400;
  font-size: 10pt;
}

.sf-p-page p,
.sf-p-page body {
  font-size: 11pt;
  line-height: 1.5;
}

.sf-p-lead {
  font-size: 11pt;
  line-height: 1.55;
  margin: 0 0 14pt;
}

/* 2026-09-21 (Adnan 08:50 amendment: page count no longer fixed, "one panel
   per page section with breathing room", no shrink-to-fit) - 5 cards in one
   row at A4 width left ~55pt per card, too narrow for values like
   "+161 (+11.6%)" or "187 / 1,364" at a normal (not shrunk) font size
   without either wrapping numbers mid-token or overflowing the card edge.
   3 per row (2 rows: 3 + 2) roughly doubles each card's width instead. */
.sf-p-cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8pt;
  margin-bottom: 10pt;
}

.sf-p-card {
  border: 1pt solid var(--border);
  border-radius: 6pt;
  padding: 9pt 11pt;
  box-sizing: border-box;
  min-width: 0;
}

.sf-p-card * { box-sizing: border-box; }

.sf-p-city {
  font-weight: 700;
  font-size: 11pt;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 4pt;
  min-width: 0;
}

/* The pill badge (GROW/WATCH/STOP) must never shrink or wrap; the label
   next to it normally won't either (live city labels are always short
   single words), but if one ever were longer than the card can hold,
   ellipsis here keeps it inside the card instead of overflowing into the
   next one - safer than a bare white-space:nowrap on the whole row. */
.sf-p-city-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.sf-p-city .sf-p-chip {
  flex: 0 0 auto;
}

.sf-p-big { font-size: 16pt; font-weight: 700; margin-top: 4pt; }
.sf-p-big small { font-size: 9pt; font-weight: 400; color: var(--sf-muted); }

.sf-p-util-peak { font-size: 13pt; font-weight: 700; margin-top: 2pt; }
.sf-p-util-caption { display: block; font-size: 8.5pt; color: var(--sf-muted); line-height: 1.35; }

.sf-p-kv {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2pt 8pt;
  font-size: 9.5pt;
  margin-top: 6pt;
}

.sf-p-kv span:nth-child(odd) { color: var(--sf-muted); white-space: nowrap; }
.sf-p-kv span:nth-child(even) { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }

.sf-p-actions {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4pt;
}

.sf-p-actions div {
  text-align: center;
  border-radius: 4pt;
  padding: 3pt 0;
  font-size: 8.5pt;
  font-weight: 600;
  white-space: nowrap;
}

.sf-p-actions .g { background: var(--sf-green-soft); color: #1e7e46; }
.sf-p-actions .a { background: var(--sf-orange-soft); color: #8a5a00; }
.sf-p-actions .r { background: var(--sf-red-soft); color: #a3261a; }
.sf-p-actions b { display: block; font-size: 11pt; white-space: nowrap; }

.sf-p-legend {
  display: flex;
  gap: 12pt;
  font-size: 9.5pt;
  margin: 8pt 0;
  flex-wrap: wrap;
  color: var(--sf-muted);
}

.sf-p-dot { display: inline-block; width: 8pt; height: 8pt; border-radius: 50%; margin-right: 3pt; }
.sf-p-dot.g { background: var(--green); }
.sf-p-dot.a { background: var(--orange); }
.sf-p-dot.r { background: var(--red); }
.sf-p-dot.n { background: var(--neutral); }

/* print tables - real tables, allowed to paginate; thead repeats per page */
table.sf-p-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 10pt;
}

table.sf-p-table thead {
  display: table-header-group;
}

table.sf-p-table tr {
  break-inside: avoid;
  page-break-inside: avoid;
}

table.sf-p-table th {
  background: var(--sf-brand-soft);
  color: var(--brand);
  text-align: left;
  padding: 6pt 8pt;
  font-weight: 600;
  font-size: 9.5pt;
  white-space: nowrap;
}

table.sf-p-table td {
  padding: 6pt 8pt;
  border-bottom: 0.5pt solid var(--border);
  vertical-align: top;
  font-size: 10pt;
  /* Same styles.css global-nowrap issue as table.sf-table above (this page
     still loads styles.css in print mode too) - default to wrapping,
     .sf-p-nowrap opts specific ID/number/chip columns back out. */
  white-space: normal;
}

table.sf-p-table tbody tr:nth-child(even) { background: var(--sf-page-bg); }

table.sf-p-table td.sf-num,
table.sf-p-table th.sf-num { text-align: right; font-variant-numeric: tabular-nums; }

/* IDs/numbers/chips: never wrap. Only the one designated free-text column
   per table (capacity action / focus / definition) gets sf-p-wrap. */
table.sf-p-table td.sf-p-nowrap,
table.sf-p-table th.sf-p-nowrap {
  white-space: nowrap;
}

table.sf-p-table td.sf-p-wrap {
  white-space: normal;
  min-width: 55mm;
}

.sf-p-chip {
  display: inline-block;
  padding: 1.5pt 6pt;
  border-radius: 4pt;
  font-size: 9pt;
  font-weight: 600;
  white-space: nowrap;
}

.sf-p-chip.g { background: var(--sf-green-soft); color: #1e7e46; }
.sf-p-chip.a { background: var(--sf-orange-soft); color: #8a5a00; }
.sf-p-chip.r { background: var(--sf-red-soft); color: #a3261a; }

.sf-p-panel {
  border: 1pt solid var(--border);
  border-radius: 6pt;
  padding: 10pt 12pt;
  box-sizing: border-box;
}

.sf-p-panel h4 {
  margin: 0 0 8pt;
  font-size: 11pt;
  color: var(--brand);
}

.sf-p-map {
  width: 100%;
  height: 100mm;
  border-radius: 6pt;
  background: var(--bg);
  display: block;
}

.sf-p-map-legend {
  display: flex;
  gap: 12pt;
  font-size: 9pt;
  color: var(--sf-muted);
  margin-top: 6pt;
  flex-wrap: wrap;
}

.sf-p-note {
  font-size: 9pt;
  color: var(--sf-muted);
  margin-top: 6pt;
  line-height: 1.4;
}

/* .sf-p-foot (the old per-section footer div) is gone - see the @page
   margin-box footer in @media print below, which replaced it. */

@media print {
  /* 2026-09-21 (Fable review): the old per-section .sf-p-foot <div> was
     wrong on two counts - it hardcoded a single word ("City"/"Actions"/
     "Summary") where a page number belonged, and since it's ordinary DOM
     content it can only ever appear once per *logical* section, not once
     per *physical* page, so any city/STOP-cells table long enough to spill
     onto a second or third physical page had no footer at all on those
     continuation pages. Verified this Chromium build actually implements
     CSS Paged Media's @page margin boxes with real counter(page)/
     counter(pages) (a quick pagetest.html + page.pdf() round-trip, not
     assumed) - that renders correctly on every physical page regardless of
     how the DOM is split, which a hand-written footer div fundamentally
     can't. (string-set/content:string() for a per-page running city name
     was NOT supported in the same test, so the left side is a fixed
     string rather than the current city's name - a small, known trade-off
     for a footer that is actually correct everywhere.) */
  @page {
    size: A4 portrait;
    margin: 12mm 12mm 18mm 12mm;
    @bottom-left {
      content: "FWA Sales Focus \00b7 confidential";
      font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
      font-size: 8.5pt;
      color: #5f6b68;
    }
    @bottom-right {
      content: "Page " counter(page) " of " counter(pages);
      font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
      font-size: 8.5pt;
      color: #5f6b68;
    }
  }

  body { background: #fff; }

  header,
  #sf-app,
  #sf-schedule-modal,
  .sf-loading {
    display: none !important;
  }
}

/* 2026-09-21 - there used to be an `@media screen { #sf-print-root {
   display: none !important; } }` "safety net" here. It was actively wrong:
   Playwright's page.pdf() (used by the live PDF export) renders print CSS
   internally as a separate pass, but all the JS that builds this DOM and
   initialises Leaflet/Chart.js runs earlier, in the ordinary screen
   rendering pass - `!important` beat body.sf-print-mode's `display: block`
   the whole time JS ran, so Leaflet always measured a 0x0 container and
   every print-mode map rendered blank. The plain `#sf-print-root { display:
   none; }` rule above (no @media, no !important) already keeps it hidden
   outside print mode - body.sf-print-mode's own rule is the only thing
   that needs to win, and only it should. */
