/* SAF Dashboard base styles.
 *
 * Phase Z: shell chrome + mode namespaces (empty hooks for tab plugins
 * to scope CSS under .saf-dash--admin / --user / --marketing).
 * Bump SAF_DASH_VERSION on every edit (LiteSpeed cache-busts by ?ver=).
 */

:root {
  --saf-dash-brand: #1a1a2e;
  --saf-dash-bg: #ffffff;
  --saf-dash-bg-rail: #f6f7fa;
  --saf-dash-border: #e3e4ea;
  --saf-dash-text: #1a1a2e;
  --saf-dash-text-muted: #5b6072;
  --saf-dash-link: var(--saf-dash-brand);
  --saf-dash-rail-width: 240px;
  --saf-dash-gap: 1.5rem;
  --saf-dash-radius: 8px;
  --saf-dash-shadow: 0 1px 3px rgba(20, 22, 35, 0.06);
}

/* Shell layout */
.saf-dash {
  display: flex;
  gap: var(--saf-dash-gap);
  min-height: 60vh;
  color: var(--saf-dash-text);
  background: var(--saf-dash-bg);
}

.saf-dash__rail {
  width: var(--saf-dash-rail-width);
  flex-shrink: 0;
  background: var(--saf-dash-bg-rail);
  border: 1px solid var(--saf-dash-border);
  border-radius: var(--saf-dash-radius);
  padding: 1rem 0.75rem;
  box-shadow: var(--saf-dash-shadow);
}

.saf-dash__rail-header {
  margin-bottom: 1rem;
  padding: 0 0.25rem;
}

.saf-dash__role-pill {
  display: inline-block;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
  background: var(--saf-dash-brand);
  color: #fff;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
}

.saf-dash__rail-empty {
  color: var(--saf-dash-text-muted);
  font-size: 0.875rem;
  margin: 0.5rem 0.25rem;
}

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

.saf-dash__tab {
  margin: 0.125rem 0;
}

.saf-dash__tab-link,
.saf-dash__subtab-link {
  display: block;
  padding: 0.5rem 0.75rem;
  border-radius: 4px;
  text-decoration: none;
  color: var(--saf-dash-text);
  transition: background-color 120ms ease;
}

.saf-dash__tab-link:hover,
.saf-dash__subtab-link:hover {
  background: rgba(26, 26, 46, 0.06);
}

.saf-dash__tab-link[aria-current="page"] {
  background: var(--saf-dash-brand);
  color: #fff;
  font-weight: 600;
}

.saf-dash__subtablist {
  list-style: none;
  margin: 0.25rem 0 0.5rem 1rem;
  padding: 0;
  border-left: 2px solid var(--saf-dash-border);
}

.saf-dash__subtab-link {
  font-size: 0.875rem;
  color: var(--saf-dash-text-muted);
}

/* Main column */
.saf-dash__main {
  flex: 1;
  min-width: 0;
}

.saf-dash__crumbs {
  font-size: 0.875rem;
  color: var(--saf-dash-text-muted);
  margin-bottom: 1rem;
}

.saf-dash__crumb-sep {
  margin: 0 0.4rem;
  opacity: 0.6;
}

.saf-dash__body {
  border: 1px solid var(--saf-dash-border);
  border-radius: var(--saf-dash-radius);
  padding: 1.5rem;
  background: var(--saf-dash-bg);
  box-shadow: var(--saf-dash-shadow);
  /* Hard horizontal boundary for every tab. Several per-tab SPAs render a
     display:grid root (.saf-events-spa / .saf-peers-spa / etc.) whose single
     column sizes to the min-content width of a bare data table (~685px) —
     on a phone that pushed the whole PAGE into horizontal scroll. overflow-x
     here was not enough alone because grid tracks still expand; pairing it
     with min-width:0 on the SPA grid roots (below) lets the track shrink and
     the table scroll inside its panel. `clip` (not `auto`) avoids creating a
     scroll container that would trap the absolutely-positioned CRUD drawer. */
  overflow-x: clip;
}

/* Per-tab SPA roots are display:grid/flex; without min-width:0 a wide child
   (data table) blows the track out past the viewport. This generic rule
   covers current (.saf-*-spa) and future SPA panels in one place. */
.saf-dash__body > [class*="-spa"],
.saf-dash__body > [class*="-spa"] > * {
  min-width: 0;
}

.saf-dash__body[aria-hidden="true"] {
  display: none;
}

/* Global overflow containment for ALL dashboard tabs.
 *
 * Text inputs (esp. <input type=search>) default to an intrinsic width of
 * ~20 chars (~450px) and will NOT shrink below it without an explicit cap.
 * Inside a flex/grid toolbar that intrinsic width becomes the track's
 * min-content size, which stretches the whole panel — and on a phone, the
 * whole page — wider than the viewport. This was the root cause of
 * horizontal page-scroll on Events / Peers / Mail / Commerce at 375px.
 *
 * Capping every form control + media element to its container's width
 * (box-sizing already border-box site-wide) lets the panel shrink to fit
 * any viewport. Scoped to .saf-dash__body so it never touches the public
 * site or the drawer's positioned layout. */
.saf-dash__body input,
.saf-dash__body select,
.saf-dash__body textarea,
.saf-dash__body img,
.saf-dash__body table {
  max-width: 100%;
}
.saf-dash__body input[type="search"],
.saf-dash__body input[type="text"],
.saf-dash__body input[type="email"],
.saf-dash__body input[type="url"],
.saf-dash__body input[type="number"] {
  /* Override the UA intrinsic size so these never set the min-content
     width of their flex/grid track. They still grow to fill via flex. */
  min-width: 0;
}

.saf-dash__empty-state h2 {
  margin-top: 0;
}

.saf-dash__tab-error {
  color: #a40000;
  background: #fdecec;
  border: 1px solid #f5b3b3;
  padding: 0.75rem 1rem;
  border-radius: 4px;
}

/* Access denied */
.saf-dash--denied {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 4rem 1rem;
  text-align: center;
  min-height: 40vh;
}

.saf-dash__denied h2 {
  margin: 0 0 0.5rem;
}

.saf-dash__signin-link {
  display: inline-block;
  margin-top: 0.75rem;
  padding: 0.5rem 1.25rem;
  background: var(--saf-dash-brand);
  color: #fff;
  border-radius: 4px;
  text-decoration: none;
}

/* Toasts */
.saf-dash__toasts {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  z-index: 9999;
  pointer-events: none;
}

.saf-dash__toast {
  pointer-events: auto;
  padding: 0.75rem 1rem;
  border-radius: var(--saf-dash-radius);
  background: #1a1a2e;
  color: #fff;
  box-shadow: 0 4px 12px rgba(20, 22, 35, 0.18);
  font-size: 0.875rem;
  max-width: 320px;
}

.saf-dash__toast--success {
  background: #1f7a37;
}
.saf-dash__toast--error {
  background: #a40000;
}
.saf-dash__toast--info {
  background: var(--saf-dash-brand);
}

/* Confirm modal */
.saf-dash__modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 12, 24, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10000;
}

.saf-dash__modal {
  background: #fff;
  border-radius: var(--saf-dash-radius);
  padding: 1.5rem;
  max-width: 420px;
  width: 90%;
  box-shadow: 0 10px 30px rgba(10, 12, 24, 0.3);
}

.saf-dash__modal-msg {
  margin: 0 0 1rem;
  color: var(--saf-dash-text);
}

.saf-dash__modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}

.saf-dash__btn {
  border: 1px solid var(--saf-dash-border);
  background: #fff;
  color: var(--saf-dash-text);
  padding: 0.4rem 0.9rem;
  border-radius: 4px;
  cursor: pointer;
  font-size: 0.875rem;
}

.saf-dash__btn--ghost {
  background: #f6f7fa;
}
.saf-dash__btn--primary {
  background: var(--saf-dash-brand);
  color: #fff;
  border-color: var(--saf-dash-brand);
}

/* Mode namespaces (empty in Phase Z; tab plugins populate) */
.saf-dash--admin {
}
.saf-dash--user {
}
.saf-dash--marketing {
}

/* Sidebar group labels (N-6): a thin section header + divider that breaks
   the flat ~40-item rail into scannable clusters. Order-banded in shell.php;
   aria-hidden so screen readers still hear one continuous tablist. */
.saf-dash__tab-group {
  margin: 0.75rem 0.25rem 0.25rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--saf-dash-border);
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--saf-dash-text-muted);
}
/* First group gets no top divider/space — it sits right under the header. */
.saf-dash__tablist > .saf-dash__tab-group:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

/* Mobile rail toggle + drawer backdrop (B-2). Both are injected into the
   DOM by saf-dashboard.js unconditionally, so they need an explicit base
   display:none to stay hidden on desktop; the <=768px media block below is
   the ONLY place they become visible.
   The selector is scoped under .saf-dash on purpose: both controls are
   <button> elements, and the active theme ships a later-loading
   `[type="button"]{display:inline-block}` rule of EQUAL (0,1,0) specificity
   that would otherwise win on source order and leave the toggle + a
   full-screen backdrop overlay painted on desktop. `.saf-dash .x` is
   (0,2,0), so it wins the cascade without !important. */
.saf-dash .saf-dash__rail-toggle,
.saf-dash .saf-dash__rail-backdrop {
  display: none;
}

/* Responsive */
@media (max-width: 768px) {
  /* Stack, and put the CONTENT first so a phone user lands on the active
     panel — not a wall of ~40 nav links. The rail becomes a collapsible
     drawer toggled by the hamburger button (default closed). */
  .saf-dash {
    flex-direction: column;
  }
  /* The toggle is the ONLY way to reach the nav on mobile, so it sticks to
     the top of the viewport — a user who has scrolled deep into a tab can
     still open Sections without scrolling back up. order:1 keeps it first.
     Scoped under .saf-dash (0,2,0) to beat the theme's later (0,1,0)
     [type="button"] reset, same as the base hide rule above. */
  .saf-dash .saf-dash__rail-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    order: 1;
    align-self: flex-start;
    position: sticky;
    top: 0.5rem;
    z-index: 30;
    padding: 0.6rem 1rem;
    margin-bottom: 0.5rem;
    background: var(--saf-dash-brand);
    color: #fff;
    border: 0;
    border-radius: var(--saf-dash-radius);
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    box-shadow: 0 2px 6px rgba(20, 22, 35, 0.18);
  }
  /* Hamburger glyph: a centered middle bar with two pseudo-element bars
     above/below. The span is sized to the full 16x12 icon box (not a 2px
     line) so the three bars sit centered in the button instead of clipping
     to the top-left corner. */
  .saf-dash__rail-toggle-bars {
    display: block;
    position: relative;
    width: 16px;
    height: 12px;
  }
  .saf-dash__rail-toggle-bars::before,
  .saf-dash__rail-toggle-bars::after,
  .saf-dash__rail-toggle-bars > i {
    content: "";
  }
  .saf-dash__rail-toggle-bars::before,
  .saf-dash__rail-toggle-bars::after {
    display: block;
    position: absolute;
    left: 0;
    width: 16px;
    height: 2px;
    background: #fff;
    border-radius: 1px;
  }
  .saf-dash__rail-toggle-bars::before {
    top: 0;
  }
  .saf-dash__rail-toggle-bars::after {
    bottom: 0;
  }
  /* Middle bar (the span's own background, vertically centered). */
  .saf-dash__rail-toggle-bars {
    background: linear-gradient(#fff, #fff) left center / 16px 2px no-repeat;
  }
  /* Content panel renders BEFORE the rail on mobile. */
  .saf-dash__main {
    order: 2;
  }
  /* The rail is a slide-out OVERLAY drawer, not an inline block. Inline
     placement appended the ~2000px nav at the bottom of the page, so tapping
     "Sections" opened a drawer ~1600px below the fold — the user never saw it
     appear. As a fixed left-anchored panel it slides into the viewport over
     the content, is independently scrollable, and is dismissed by the toggle,
     a tab tap, Escape, or the backdrop. */
  .saf-dash__rail {
    order: 3;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: min(82vw, 320px);
    max-width: 320px;
    margin: 0;
    border-radius: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    z-index: 50;
    transform: translateX(-105%);
    transition: transform 200ms ease;
    box-shadow: 0 0 24px rgba(20, 22, 35, 0.28);
  }
  .saf-dash--rail-open .saf-dash__rail {
    transform: translateX(0);
  }
  /* Dimmed backdrop behind the open drawer. Injected by saf-dashboard.js as
     the last child of .saf-dash; clicking it closes the drawer (JS). Hidden
     by the (0,2,0) base rule above; only the .saf-dash--rail-open rule below
     (also (0,2,0)) reveals it. */
  .saf-dash__rail-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(10, 12, 24, 0.5);
    z-index: 40;
    border: 0;
    padding: 0;
    margin: 0;
    cursor: pointer;
  }
  .saf-dash--rail-open .saf-dash__rail-backdrop {
    display: block;
  }
  @media (prefers-reduced-motion: reduce) {
    .saf-dash__rail {
      transition: none;
    }
  }
  /* Filter/toolbar rows stack vertically so the 'All statuses' dropdown
     and Filter button are full-width and never clip to a chevron. */
  .saf-dash__body .saf-events-toolbar,
  .saf-dash__body .saf-mail-toolbar,
  .saf-dash__body .saf-dash-toolbar {
    flex-direction: column;
    align-items: stretch;
  }
  .saf-dash__body .saf-events-toolbar > *,
  .saf-dash__body .saf-mail-toolbar > *,
  .saf-dash__body .saf-dash-toolbar > * {
    width: 100%;
    margin-left: 0;
  }
  /* Shell-level backstop: no tab's content may push the whole page wider
     than the viewport (caused horizontal page-scroll on Events/Peers/Mail
     at 375). The base .saf-dash-table carries min-width:480px for column
     legibility; on a phone that floor exceeds the screen. Tabs that wrap
     their table in .saf-dash-table-wrap already scroll it; for bare tables
     (mail recent-campaigns, events list, peers applications) relax the
     floor so the table reflows to fit instead of stretching the document.
     A wrapped table keeps its scroll behaviour and is unaffected. */
  .saf-dash__body .saf-dash-table:not(.saf-dash-table-wrap .saf-dash-table) {
    min-width: 0;
  }
  /* Header/lede/toolbars are flex/grid tracks that inherit the wide
     table's intrinsic width; let them shrink and wrap on narrow screens. */
  .saf-dash__body .saf-dash-section-header {
    flex-wrap: wrap;
  }
  .saf-dash__body .saf-dash-lede {
    min-width: 0;
  }
}

/* ============================================================
   Phase AA: shared tab-content primitives
   Used by Events / Metrics / Peers / Settings tab render_callbacks.
   ============================================================ */

/*
 * Break out of the theme's .saf-container--narrow (800px max-width) so
 * the dashboard has room to breathe. The theme's page.php wraps content
 * in a narrow container by default; widen to the standard 1200px when
 * the dashboard shell is present on the page.
 */
.saf-container--narrow:has(.saf-dash) {
  max-width: var(--saf-container, 1200px);
}
/* The theme caps .saf-content (prose) to ~620px; widen for the dashboard. */
.saf-content:has(.saf-dash) {
  max-width: none;
}
article:has(.saf-dash) {
  width: 100%;
}

.saf-dash-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-block: 0 1rem;
  flex-wrap: wrap;
}
.saf-dash-section-header h2 {
  margin: 0;
  font-size: 1.5rem;
  line-height: 1.2;
}
.saf-dash-subhead {
  margin-block: 1.5rem 0.5rem;
  font-size: 1.05rem;
  color: #444;
  font-weight: 600;
}
.saf-dash-lede {
  margin-block: 0 1rem;
  color: #555;
}

.saf-dash-button {
  display: inline-block;
  padding: 0.45rem 0.9rem;
  background: var(--saf-dash-brand);
  color: #fff;
  border-radius: 4px;
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
  border: 1px solid var(--saf-dash-brand);
  cursor: pointer;
  white-space: nowrap;
}
/* Re-assert the primary text color on ANCHOR buttons. The Elementor global kit
 * emits `.elementor-kit-4213 a { color: #bd2727 }` (specificity 0-1-1) which
 * loads AFTER this file and ties/beats a plain `a.saf-dash-button` (also
 * 0-1-1) -> a resting-state <a class="saf-dash-button"> rendered dark red on
 * the red base bg (WCAG fail). :hover/:focus already re-asserted #fff, so only
 * the resting state was broken. Scope with the dashboard container class to
 * reach 0-2-1 and out-specify the kit. Discovered s26 on the admin Metrics
 * Export CSV buttons (latent since #495); this fixes every bare (primary)
 * anchor-button, not just those. `body.saf-dash-active` is on every dashboard
 * page and lifts this above the kit. The :not() guards EXCLUDE the white/
 * transparent --secondary and --ghost variants (which are meant to keep their
 * brand-red text) so this rule never overrides them. */
body.saf-dash-active
  a.saf-dash-button:not(.saf-dash-button--secondary):not(.saf-dash-button--ghost) {
  color: #fff;
}
.saf-dash-button:hover,
.saf-dash-button:focus {
  filter: brightness(0.92);
  text-decoration: none;
  color: #fff;
}

.saf-dash-empty {
  margin: 0.5rem 0 1rem;
  color: #777;
  font-style: italic;
}

.saf-dash__tab-denied {
  padding: 1rem;
  border: 1px solid #f0c0c0;
  background: #fdecec;
  border-radius: 4px;
  color: #7a1414;
}

/*
 * Tables: scroll horizontally on narrow containers instead of letting cells
 * wrap to 6+ lines. Wrap the table in a div with class .saf-dash-table-wrap
 * if you want explicit overflow control; otherwise the table itself gets
 * the scroll behavior on the surrounding flex/grid context.
 */
.saf-dash-table-wrap {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.saf-dash-table {
  width: 100%;
  min-width: 480px;
  border-collapse: collapse;
  margin-block: 0.5rem 1rem;
  font-size: 0.95rem;
}
.saf-dash-table th,
.saf-dash-table td {
  text-align: left;
  padding: 0.55rem 0.75rem;
  border-bottom: 1px solid #ececef;
  vertical-align: middle;
}
.saf-dash-table thead th {
  font-weight: 600;
  font-size: 0.78rem;
  color: #555;
  letter-spacing: 0.03em;
  border-bottom: 2px solid #d8d8dc;
  background: #f9f9fb;
}
.saf-dash-table tbody tr:hover {
  background: #f6f7fa;
}
.saf-dash-table td:last-child {
  text-align: right;
  white-space: nowrap;
}
/* First column (title/name) gets more room and can wrap; date columns stay one line. */
.saf-dash-table td:first-child {
  font-weight: 500;
}
.saf-dash-table td:nth-child(2),
.saf-dash-table td:nth-child(3) {
  white-space: nowrap;
}

/*
 * Cards: container-driven auto-fit grid. Cards stay >= 150px wide so labels
 * like "Pending applications" don't truncate. Drops columns automatically
 * as the container narrows, regardless of viewport width.
 */
.saf-dash-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.75rem;
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
}
.saf-dash-card {
  padding: 0.9rem 1rem;
  background: #fff;
  border: 1px solid #e3e3e8;
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}
.saf-dash-card__value {
  font-size: 1.6rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: #1a1a1f;
  line-height: 1.1;
}
.saf-dash-card__label {
  font-size: 0.78rem;
  color: #666;
  letter-spacing: 0.02em;
  /* No uppercase: long labels like "With consent to follow up" stay legible. */
  text-transform: none;
  font-weight: 500;
}

.saf-dash-links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* ============================================================
   N-1 backstop: keep the public site chrome out of the admin shell.
   Primary suppression is server-side (sober-af-jtc-bridge.php disables
   the JTC header/footer locations on dashboard pages). This CSS is a
   defensive net for any path that still emits the public header/footer
   inside a dashboard page (body.saf-dash-active). The WP admin bar
   (#wpadminbar) is intentionally NOT hidden.
   ============================================================ */
body.saf-dash-active .saf-header,
body.saf-dash-active .site-header,
body.saf-dash-active > .jet-theme-core-header,
body.saf-dash-active [data-elementor-type="header"],
body.saf-dash-active .elementor-location-header {
  display: none !important;
}
body.saf-dash-active .saf-footer,
body.saf-dash-active .site-footer,
body.saf-dash-active [data-elementor-type="footer"],
body.saf-dash-active .elementor-location-footer {
  display: none !important;
}

/* Wide metric tables: horizontal scroll so the 16-metric grid never overflows
   the page (funder reporting tables). Keeps the rest of the SPA full-width. */
.saf-dash-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin-block: 0 1rem;
}
.saf-dash-table-scroll .saf-dash-table {
  min-width: max-content;
}
/* A subhead row that pairs a heading with an action (Export CSV) on the right. */
.saf-dash-subhead-row {
  margin-block: 1.5rem 0.5rem;
}
.saf-dash-subhead-row .saf-dash-subhead {
  margin-block: 0;
}
/* Live row-filter input on the metrics toolbar. */
.saf-dash-toolbar__filter input[type="search"] {
  min-width: 16rem;
  max-width: 100%;
  padding: 0.45rem 0.7rem;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 0.95rem;
}
/* Sortable metric-table headers + grand-total footer row. */
.saf-dash-table thead th[role="columnheader"] {
  user-select: none;
  white-space: nowrap;
}
.saf-dash-table thead th[aria-sort="ascending"]::after {
  content: " \2191";
}
.saf-dash-table thead th[aria-sort="descending"]::after {
  content: " \2193";
}
.saf-dash-table thead th[role="columnheader"]:hover {
  background: rgba(0, 0, 0, 0.04);
}
.saf-dash-table tfoot th,
.saf-dash-table tfoot td {
  font-weight: 700;
  border-top: 2px solid #999;
  background: #f3f3f3;
}
/* Inline edit drawer (Programs / Program Years admin tab). */
.saf-dash-inline-edit {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: flex-end;
  padding: 0.75rem;
  background: #f7f7f9;
  border: 1px solid #e0e0e0;
  border-radius: 6px;
}
.saf-dash-inline-edit__field {
  display: flex;
  flex-direction: column;
  font-size: 0.85rem;
  gap: 0.25rem;
}
.saf-dash-inline-edit__field input,
.saf-dash-inline-edit__field select {
  padding: 0.4rem 0.6rem;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 0.95rem;
  min-width: 12rem;
}
.saf-dash-inline-edit__hint {
  font-size: 0.78rem;
  color: #595959; /* AA on the panel bg. */
  font-style: italic;
}
.saf-dash-button--ghost {
  background: transparent;
  color: var(--saf-dash-brand);
}

/* Secondary variant: referenced by 10+ call sites (board/awards/sponsors
 * Export CSV, replies, commerce, auctions) but was never DEFINED -- <a>
 * usages fell through to the theme link color on the red base bg (dark red
 * on red, WCAG fail; s25 deep-verify). Compound selector so it also beats
 * global-kit `a { color }` rules on anchors. */
.saf-dash-button.saf-dash-button--secondary {
  background: #fff;
  color: var(--saf-dash-brand);
  border-color: var(--saf-dash-brand);
}

/* Kit `button` cascade leak on BUTTON elements (s28, same class as the s26
 * anchor fix above): the Elementor global kit (post-4213.css, loads AFTER
 * this file) paints every bare <button> at 0-1-1 -- background #be2727,
 * "Helvetica Neue" 600, radius 6px -- and button:hover/:focus at 0-2-1 with
 * #7b181a. Both beat the single-class variants above on <button> call sites
 * (anchors were fixed in s25/s26), so ghost buttons rendered as filled
 * primary clones (Reorder / Import CSV looked identical to Add). Re-assert
 * the dashboard design under body.saf-dash-active to out-specify the kit
 * without !important. The compound --ghost/--secondary groups (0-3-1, with
 * :hover/:focus at 0-4-1) also out-specify the generic
 * `.saf-dash-button:hover { color: #fff }` rule, which was turning ghost
 * ANCHOR text white-on-white on hover. */
/* Re-assert ONLY the properties another global rule contests: the kit sets
 * background-color/color/font-family/font-weight/border-radius; the theme's
 * bare `button` reset (0-1-1) contests font-size. Uncontested properties
 * (border, padding) stay on the 0-1-0 rules above. NOTE for new variants:
 * any future .saf-dash-button--X that changes a contested property must be
 * defined at >= 0-3-1 (compound selector under body.saf-dash-active, like
 * --ghost/--secondary/--danger/--small below) or this rule will paint it
 * primary. */
body.saf-dash-active button.saf-dash-button {
  background: var(--saf-dash-brand);
  color: #fff;
  border-radius: 4px;
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 500;
}
body.saf-dash-active button.saf-dash-button:hover,
body.saf-dash-active button.saf-dash-button:focus {
  background: var(--saf-dash-brand);
  color: #fff;
}
body.saf-dash-active .saf-dash-button.saf-dash-button--ghost {
  background: transparent;
  color: var(--saf-dash-brand);
}
body.saf-dash-active .saf-dash-button.saf-dash-button--secondary {
  background: #fff;
  color: var(--saf-dash-brand);
}
/* Ghost/secondary hover affordance (s30 polish): a subtle brand tint on
 * hover/focus so these low-emphasis buttons give feedback like the primary.
 * Selector is 0-3-1 (under body.saf-dash-active) like the base rules above,
 * so the Elementor kit button leak can't repaint it; the :hover/:focus pseudo
 * adds a class-level tiebreak (0-3-2), so it wins over the base on hover only.
 * :not([disabled]) so a disabled button shows no false affordance. color-mix
 * degrades gracefully (unsupported browsers keep the base transparent/#fff). */
body.saf-dash-active .saf-dash-button.saf-dash-button--ghost:hover:not([disabled]),
body.saf-dash-active .saf-dash-button.saf-dash-button--ghost:focus:not([disabled]) {
  background: color-mix(in srgb, var(--saf-dash-brand) 8%, transparent);
  color: var(--saf-dash-brand);
}
body.saf-dash-active .saf-dash-button.saf-dash-button--secondary:hover:not([disabled]),
body.saf-dash-active .saf-dash-button.saf-dash-button--secondary:focus:not([disabled]) {
  background: color-mix(in srgb, var(--saf-dash-brand) 8%, #fff);
  color: var(--saf-dash-brand);
}

/* Danger variant: referenced by resources (Decline) + surveys (remove
 * question) <button>s but never defined -- those call sites LOOKED
 * danger-red only because the kit leak painted every bare button #be2727.
 * Define it explicitly (s25 --secondary precedent) so the button
 * re-assertion above doesn't turn destructive actions brand-primary. */
.saf-dash-button--danger,
body.saf-dash-active .saf-dash-button.saf-dash-button--danger,
body.saf-dash-active .saf-dash-button.saf-dash-button--danger:hover,
body.saf-dash-active .saf-dash-button.saf-dash-button--danger:focus {
  background: var(--saf-danger, #9a3c2c);
  border-color: var(--saf-danger, #9a3c2c);
  color: #fff;
}

/* ── Grant Targets subpanel (metrics tab) ───────────────────────────────── */
.saf-dash-toolbar__field {
  display: inline-flex;
  flex-direction: column;
  font-size: 0.8rem;
  gap: 0.2rem;
  margin-right: 0.75rem;
}
.saf-dash-toolbar__field select,
.saf-dash-toolbar__field input {
  padding: 0.35rem 0.55rem;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 0.9rem;
}
.saf-dash-targets__list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
  gap: 1rem;
  margin-top: 1rem;
}
.saf-targets-card {
  border: 1px solid #e2e2e6;
  border-radius: 8px;
  padding: 1rem 1.1rem;
  background: #fff;
}
.saf-targets-card__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
}
.saf-targets-card__title {
  margin: 0;
  font-size: 1rem;
}
.saf-targets-card__period {
  font-size: 0.75rem;
  color: #555;
  white-space: nowrap;
}
.saf-targets-card__meta {
  margin: 0.35rem 0 0;
  font-size: 0.8rem;
  color: #555;
}
.saf-targets-card__objectives {
  margin: 0.5rem 0 0;
  font-size: 0.85rem;
}
.saf-targets-card__goals {
  margin-top: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.saf-targets-card__empty {
  margin: 0.75rem 0 0;
  font-size: 0.85rem;
  color: #777;
  font-style: italic;
}
.saf-targets-goal__head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.82rem;
}
.saf-targets-goal__label {
  font-weight: 600;
}
.saf-targets-goal__nums {
  margin-left: auto;
  color: #444;
  font-variant-numeric: tabular-nums;
}
.saf-targets-bar {
  margin-top: 0.3rem;
  height: 0.55rem;
  border-radius: 4px;
  background: #ececed;
  overflow: hidden;
}
.saf-targets-bar__fill {
  height: 100%;
  background: var(--saf-dash-brand, #b23a2e);
  transition: width 0.2s ease;
}
.saf-targets-bar__fill.is-full {
  background: #1f7a45;
}
.saf-targets-pill {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
}
.saf-targets-pill--ok {
  background: #def3e4;
  color: #1f7a45;
}
.saf-targets-pill--behind {
  background: #fbe3e0;
  color: #b23a2e;
}
.saf-targets-pill--na {
  background: #ececef;
  color: #777;
}

/* Grant Targets — per-card funder-link actions */
.saf-targets-card__actions {
  margin-top: 0.9rem;
  padding-top: 0.75rem;
  border-top: 1px solid #ececef;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}
.saf-targets-action {
  font-size: 0.78rem;
  padding: 0.3rem 0.6rem;
}
/* Scoped under body.saf-dash-active (0-3-1) so it out-specifies the s28
 * kit-leak re-assertion `body.saf-dash-active button.saf-dash-button`
 * (0-2-2) above -- otherwise Revoke would render as a filled primary. */
.saf-dash-button.saf-targets-action--danger,
body.saf-dash-active .saf-dash-button.saf-targets-action--danger {
  background: transparent;
  color: #b23a2e;
  border: 1px solid #e3b4ae;
}
.saf-targets-card__action-msg {
  font-size: 0.78rem;
  color: #1f7a45;
  margin-left: auto;
}
.saf-targets-card__action-msg.is-error {
  color: #b23a2e;
}

/* System health card (audit tab) — WP-cron heartbeat at a glance. */
.saf-dash-health-card {
  border: 1px solid #e2e2e6;
  border-radius: 8px;
  padding: 0.9rem 1.1rem;
  margin-bottom: 1.25rem;
  background: #fafafa;
}
.saf-dash-health-card__title {
  font-size: 1rem;
  margin: 0 0 0.5rem;
}
.saf-dash-health-card__row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0;
  flex-wrap: wrap;
}
.saf-dash-health-card__row + .saf-dash-health-card__row {
  margin-top: 0.5rem;
}
.saf-dash-health-card__badge {
  font-size: 0.78rem;
  font-weight: 600;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  white-space: nowrap;
}
.saf-dash-health-card__badge--ok {
  background: #e3f3ea;
  color: #1f7a45; /* AA on the light-green chip. */
}
.saf-dash-health-card__badge--stale,
.saf-dash-health-card__badge--unknown {
  background: #f7e7e4;
  color: #9a2f24; /* AA on the light-brick chip. */
}
.saf-dash-health-card__detail {
  font-size: 0.85rem;
  color: #444;
}
