/* ============================================================ *
 * GENERATED FILE — DO NOT EDIT.                                 *
 * Mirror of website/src/components.css                                  *
 * copied here by scripts/sync_design_system.py so the FastAPI-   *
 * served dashboard portal can <link> the canonical v4 design     *
 * system. Edit the SOURCE in website/src/, then re-run the sync. *
 * CI (test_design_system_sync.py) fails the build if this copy   *
 * drifts from its source.                                        *
 * ============================================================ */
/* ═══════════════════════════════════════════════════════════════════
   TREASURYFLOW — COMPONENT LIBRARY v4 · "LEDGER"
   Authored 2026-05-15 by Chief Design Officer.
   Consumes design-tokens.css. The canonical component set for all four
   surfaces — marketing website, adaptive dashboard, Excel taskpane,
   Google Sheets add-on. Every component ships every state:
   rest / hover / focus-visible / active / disabled / loading.

   Naming: BEM-ish. Block `.tf-x`, element `.tf-x__y`, modifier `.tf-x--z`.
   The `tf-` prefix namespaces these so they can be dropped into the
   portal (which has its own legacy classes) without collision.

   Sections:
     A · Primitives — buttons, icon-button, links
     B · Form fields — input, select, textarea, checkbox, radio, toggle, range
     C · Surfaces — card, panel, ink-panel, divider
     D · Data display — KPI tile, sparkline slot, data table, badge/pill,
          delta, trust-band, stat-row
     E · Navigation — top nav, app sidebar, tabs, breadcrumb
     F · Feedback — toast/undo, empty state, skeleton, loading, banner,
          tooltip, progress
     G · Overlay — modal, dropdown menu, command palette
   ═══════════════════════════════════════════════════════════════════ */

@import './design-tokens.css';

/* ── Document-level horizontal-overflow clip ─────────────────────────
   Systemic backstop behind the per-element overflow fixes — every page
   benefits. Uses `overflow-x: clip`, NOT `hidden`: `overflow-x: hidden`
   on the <html>/<body> scroll root forces `overflow-y` to compute to
   `auto`, turning the document root into a degenerate scroll container
   that will not scroll vertically at all. `clip` clips the X axis
   without creating a scroll container, so vertical scrolling is
   genuinely unaffected.
   ──────────────────────────────────────────────────────────────────── */
html { overflow-x: clip; }

/* ════════════════════════════════════════════════════════════════════
   A · PRIMITIVES
   ════════════════════════════════════════════════════════════════════ */

/* ── Button ──────────────────────────────────────────────────────────
   Variants: primary (one per screen — the accent action),
             secondary (bordered, neutral), ghost (chrome action),
             danger (destructive confirm), link (inline text action).
   Sizes: --sm / default / --lg. All >= 44px tall at --lg, default 36px.
   ──────────────────────────────────────────────────────────────────── */
.tf-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  height: var(--control-h);
  padding: 0 var(--space-5);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  line-height: 1;
  letter-spacing: -0.005em;
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition:
    background-color var(--duration-fast) var(--ease-standard),
    border-color var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard),
    transform var(--duration-instant) var(--ease-spring);
}
.tf-btn:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
.tf-btn:active { transform: scale(0.98); }
.tf-btn[disabled],
.tf-btn:disabled,
.tf-btn[aria-disabled="true"] {
  cursor: not-allowed;
  transform: none;
  opacity: 1;             /* don't fade — re-color, so it stays legible */
}
.tf-btn svg { width: 16px; height: 16px; flex-shrink: 0; }

/* Sizes */
.tf-btn--sm { height: var(--control-h-sm); padding: 0 var(--space-4); font-size: var(--text-xs); }
.tf-btn--lg { height: var(--control-h-lg); padding: 0 var(--space-7); font-size: var(--text-base); }
.tf-btn--block { display: flex; width: 100%; }

/* Primary — the ONE accent action. Solid teal. */
.tf-btn--primary {
  background: var(--accent);
  color: var(--accent-contrast);
  box-shadow: var(--shadow-raised);
}
.tf-btn--primary:hover { background: var(--accent-hover); box-shadow: var(--shadow-popover); color: var(--accent-contrast); }
.tf-btn--primary:active { background: var(--accent-active); box-shadow: var(--shadow-raised); }
.tf-btn--primary:focus-visible { box-shadow: var(--shadow-focus); }
.tf-btn--primary:disabled,
.tf-btn--primary[aria-disabled="true"] {
  background: var(--ink-200); color: var(--ink-400); box-shadow: none;
}

/* Secondary — neutral, bordered. The common non-primary action. */
.tf-btn--secondary {
  background: var(--surface-page);
  color: var(--text-primary);
  border-color: var(--border-strong);
}
.tf-btn--secondary:hover { background: var(--surface-sunken); border-color: var(--ink-400); color: var(--text-primary); }
.tf-btn--secondary:active { background: var(--ink-100); }
.tf-btn--secondary:disabled,
.tf-btn--secondary[aria-disabled="true"] {
  background: var(--surface-page); color: var(--text-disabled); border-color: var(--border-subtle);
}

/* Ghost — chrome / tertiary. No border, no fill at rest. */
.tf-btn--ghost {
  background: transparent;
  color: var(--text-secondary);
}
.tf-btn--ghost:hover { background: var(--surface-sunken); color: var(--text-primary); }
.tf-btn--ghost:active { background: var(--ink-100); }
.tf-btn--ghost:disabled,
.tf-btn--ghost[aria-disabled="true"] { color: var(--text-disabled); background: transparent; }

/* Danger — destructive confirm. Red. Used rarely, paired with undo. */
.tf-btn--danger {
  background: var(--cash-down);
  color: #FFFFFF;
}
.tf-btn--danger:hover { background: var(--cash-down-text); color: #FFFFFF; }
.tf-btn--danger:active { background: #991B1B; }
.tf-btn--danger:focus-visible { box-shadow: var(--shadow-focus-danger); }
.tf-btn--danger:disabled,
.tf-btn--danger[aria-disabled="true"] { background: var(--ink-200); color: var(--ink-400); }

/* Link — inline text-action button. */
.tf-btn--link {
  height: auto;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: var(--radius-xs);
  color: var(--text-link);
  font-weight: var(--weight-semibold);
}
.tf-btn--link:hover { color: var(--text-link-hover); text-decoration: underline; text-underline-offset: 3px; }
.tf-btn--link:active { transform: none; }

/* Loading button — shows spinner, locks width, suppresses label */
.tf-btn.is-loading {
  pointer-events: none;
  position: relative;
  color: transparent !important;
}
.tf-btn.is-loading::after {
  content: '';
  position: absolute;
  width: 15px; height: 15px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: var(--radius-pill);
  animation: tf-spin 0.6s linear infinite;
  /* currentColor is transparent on the button; force a visible color */
  color: var(--accent-contrast);
}
.tf-btn--secondary.is-loading::after,
.tf-btn--ghost.is-loading::after { color: var(--accent); }

@keyframes tf-spin { to { transform: rotate(360deg); } }

/* ── Button Character Roll Effect ── */
.tf-btn-roll {
  overflow: hidden;
  position: relative;
}
.tf-btn-roll-inner {
  display: inline-block;
  vertical-align: top;
  pointer-events: none;
}
.tf-btn-roll__char-wrapper {
  display: inline-block;
  overflow: hidden;
  height: 1.3em;
  vertical-align: top;
}
.tf-btn-roll__char-container {
  display: inline-flex;
  flex-direction: column;
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.tf-btn-roll__char-container span {
  display: block;
  height: 1.3em;
  line-height: 1.3em;
}
.tf-btn-roll__space {
  display: inline-block;
  width: 0.28em;
}
.tf-btn-roll:hover .tf-btn-roll__char-container {
  transform: translateY(-50%);
}

/* ── Icon button — square, for toolbars / table-row actions / nav ──── */
.tf-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--control-h);
  height: var(--control-h);
  padding: 0;
  background: transparent;
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard),
              color var(--duration-fast) var(--ease-standard),
              border-color var(--duration-fast) var(--ease-standard);
}
.tf-icon-btn svg { width: 18px; height: 18px; }
.tf-icon-btn:hover { background: var(--surface-sunken); color: var(--text-primary); }
.tf-icon-btn:active { background: var(--ink-100); }
.tf-icon-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.tf-icon-btn[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-strong); }
.tf-icon-btn:disabled { color: var(--text-disabled); background: transparent; cursor: not-allowed; }
/* tap-target hit-area: in dense chrome the visual stays 36px but the
   clickable area extends to 44px via a transparent ::before. */
.tf-icon-btn--tap { position: relative; }
.tf-icon-btn--tap::before {
  content: ''; position: absolute;
  inset: calc((var(--tap-min) - var(--control-h)) / -2);
}

/* ════════════════════════════════════════════════════════════════════
   B · FORM FIELDS
   ════════════════════════════════════════════════════════════════════ */

/* ── Field wrapper — label + control + hint/error ──────────────────── */
.tf-field { display: flex; flex-direction: column; gap: var(--space-3); }
.tf-field__label {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.tf-field__label .tf-field__req { color: var(--cash-down-text); font-weight: var(--weight-bold); }
.tf-field__hint { font-size: var(--text-xs); color: var(--text-quiet); line-height: var(--lh-snug); }
.tf-field__error {
  font-size: var(--text-xs);
  color: var(--cash-down-text);
  line-height: var(--lh-snug);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* ── Input / Select / Textarea — shared base ───────────────────────── */
.tf-input,
.tf-select,
.tf-textarea {
  width: 100%;
  height: var(--control-h);
  padding: 0 var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  color: var(--text-primary);
  background: var(--surface-page);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-xs);
  transition: border-color var(--duration-fast) var(--ease-standard),
              box-shadow var(--duration-fast) var(--ease-standard),
              background-color var(--duration-fast) var(--ease-standard);
}
.tf-input::placeholder,
.tf-textarea::placeholder { color: var(--text-quiet); }
.tf-input:hover,
.tf-select:hover,
.tf-textarea:hover { border-color: var(--border-strong); }
.tf-input:focus,
.tf-select:focus,
.tf-textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--shadow-focus);
  background: var(--surface-page);
}
.tf-input:disabled,
.tf-select:disabled,
.tf-textarea:disabled {
  background: var(--surface-disabled);
  color: var(--text-disabled);
  cursor: not-allowed;
  border-color: var(--border-subtle);
}
.tf-input[readonly] { background: var(--surface-sunken); color: var(--text-secondary); }

/* Numeric input — money/figures use mono + tabular, right-aligned */
.tf-input--num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums lining-nums;
  text-align: right;
}

/* Error state — invalid input */
.tf-input.is-error,
.tf-select.is-error,
.tf-textarea.is-error { border-color: var(--cash-down); }
.tf-input.is-error:focus,
.tf-select.is-error:focus,
.tf-textarea.is-error:focus { box-shadow: var(--shadow-focus-danger); }

/* Success state — validated input */
.tf-input.is-valid { border-color: var(--cash-up-border); }

/* Sizes */
.tf-input--sm, .tf-select--sm { height: var(--control-h-sm); font-size: var(--text-sm); }
.tf-input--lg, .tf-select--lg { height: var(--control-h-lg); }

/* Textarea overrides */
.tf-textarea {
  height: auto;
  min-height: 88px;
  padding: var(--space-4);
  line-height: var(--lh-body);
  resize: vertical;
}

/* Select — native, with a chevron affordance */
.tf-select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: var(--space-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%235F5F58' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-4) center;
  cursor: pointer;
}

/* Input with leading affordance (icon / currency symbol) */
.tf-input-group { position: relative; display: flex; align-items: center; }
.tf-input-group__affix {
  position: absolute;
  left: var(--space-4);
  font-size: var(--text-base);
  color: var(--text-quiet);
  pointer-events: none;
  font-family: var(--font-mono);
}
.tf-input-group .tf-input { padding-left: var(--space-8); }
.tf-input-group__affix--trailing { left: auto; right: var(--space-4); }
.tf-input-group:has(.tf-input-group__affix--trailing) .tf-input { padding-left: var(--space-4); padding-right: var(--space-8); }

/* ── Checkbox ──────────────────────────────────────────────────────── */
.tf-checkbox { display: inline-flex; align-items: flex-start; gap: var(--space-3); cursor: pointer; }
.tf-checkbox__box {
  flex-shrink: 0;
  width: 18px; height: 18px;
  margin-top: 1px;
  border: 1.5px solid var(--border-strong);
  border-radius: var(--radius-xs);
  background: var(--surface-page);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background-color var(--duration-fast) var(--ease-standard),
              border-color var(--duration-fast) var(--ease-standard);
}
.tf-checkbox__box svg { width: 12px; height: 12px; color: #FFFFFF; opacity: 0; transition: opacity var(--duration-fast); }
.tf-checkbox input { position: absolute; opacity: 0; width: 0; height: 0; }
.tf-checkbox:hover .tf-checkbox__box { border-color: var(--accent); }
.tf-checkbox input:checked + .tf-checkbox__box {
  background: var(--accent); border-color: var(--accent);
}
.tf-checkbox input:checked + .tf-checkbox__box svg { opacity: 1; }
.tf-checkbox input:focus-visible + .tf-checkbox__box { box-shadow: var(--shadow-focus); }
.tf-checkbox input:disabled + .tf-checkbox__box { background: var(--surface-disabled); border-color: var(--border-default); }
.tf-checkbox__label { font-size: var(--text-base); color: var(--text-primary); line-height: var(--lh-snug); }

/* ── Radio ─────────────────────────────────────────────────────────── */
.tf-radio { display: inline-flex; align-items: flex-start; gap: var(--space-3); cursor: pointer; }
.tf-radio__dot {
  flex-shrink: 0;
  width: 18px; height: 18px;
  margin-top: 1px;
  border: 1.5px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: var(--surface-page);
  position: relative;
  transition: border-color var(--duration-fast) var(--ease-standard);
}
.tf-radio__dot::after {
  content: ''; position: absolute; inset: 3px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  transform: scale(0);
  transition: transform var(--duration-fast) var(--ease-spring);
}
.tf-radio input { position: absolute; opacity: 0; width: 0; height: 0; }
.tf-radio:hover .tf-radio__dot { border-color: var(--accent); }
.tf-radio input:checked + .tf-radio__dot { border-color: var(--accent); }
.tf-radio input:checked + .tf-radio__dot::after { transform: scale(1); }
.tf-radio input:focus-visible + .tf-radio__dot { box-shadow: var(--shadow-focus); }
.tf-radio input:disabled + .tf-radio__dot { background: var(--surface-disabled); border-color: var(--border-default); }
.tf-radio__label { font-size: var(--text-base); color: var(--text-primary); line-height: var(--lh-snug); }

/* ── Toggle / switch ───────────────────────────────────────────────── */
.tf-toggle { display: inline-flex; align-items: center; gap: var(--space-4); cursor: pointer; }
.tf-toggle__track {
  position: relative;
  width: 40px; height: 22px;
  background: var(--ink-200);
  border-radius: var(--radius-pill);
  transition: background-color var(--duration-base) var(--ease-standard);
  flex-shrink: 0;
}
.tf-toggle__track::after {
  content: ''; position: absolute;
  top: 2px; left: 2px;
  width: 18px; height: 18px;
  background: var(--surface-page);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-raised);
  transition: transform var(--duration-base) var(--ease-spring);
}
.tf-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.tf-toggle input:checked + .tf-toggle__track { background: var(--accent); }
.tf-toggle input:checked + .tf-toggle__track::after { transform: translateX(18px); }
.tf-toggle input:focus-visible + .tf-toggle__track { box-shadow: var(--shadow-focus); }
.tf-toggle input:disabled + .tf-toggle__track { background: var(--surface-disabled); }
.tf-toggle__label { font-size: var(--text-base); color: var(--text-primary); }

/* ── Range slider ──────────────────────────────────────────────────── */
.tf-range {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 4px;
  background: var(--ink-150);
  border-radius: var(--radius-pill);
  outline: none;
}
.tf-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 18px; height: 18px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  border: 2px solid var(--surface-page);
  box-shadow: var(--shadow-raised);
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-spring);
}
.tf-range::-webkit-slider-thumb:hover { transform: scale(1.12); }
.tf-range::-moz-range-thumb {
  width: 18px; height: 18px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  border: 2px solid var(--surface-page);
  box-shadow: var(--shadow-raised);
  cursor: pointer;
}
.tf-range:focus-visible::-webkit-slider-thumb { box-shadow: var(--shadow-focus); }

/* Segmented control — for view-switchers (Day / Week / Month) */
.tf-segmented {
  display: inline-flex;
  padding: 3px;
  background: var(--surface-sunken);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-sm);
  gap: 2px;
}
.tf-segmented__option {
  padding: 0 var(--space-5);
  height: 28px;
  display: inline-flex;
  align-items: center;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  background: transparent;
  border: none;
  border-radius: var(--radius-xs);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard),
              color var(--duration-fast) var(--ease-standard),
              box-shadow var(--duration-fast) var(--ease-standard);
}
.tf-segmented__option:hover { color: var(--text-primary); }
.tf-segmented__option[aria-selected="true"],
.tf-segmented__option.is-active {
  background: var(--surface-page);
  color: var(--text-primary);
  font-weight: var(--weight-semibold);
  box-shadow: var(--shadow-raised);
}
.tf-segmented__option:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }

/* ════════════════════════════════════════════════════════════════════
   C · SURFACES
   ════════════════════════════════════════════════════════════════════ */

/* ── Card — white, defined by a hairline border. NO shadow at rest. ── */
.tf-card {
  background: var(--surface-raised);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  padding: var(--space-6);
}
.tf-card--glass {
  background: rgba(255, 255, 255, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.4);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 8px 32px 0 rgba(11, 16, 32, 0.02);
}
.glow-bg {
  position: relative;
  z-index: 1;
}
.glow-bg::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--radial-glow-1), var(--radial-glow-2);
  pointer-events: none;
  opacity: 0.85;
}
.tf-card--lg { border-radius: var(--radius-lg); padding: var(--space-7); }
.tf-card--flush { padding: 0; }     /* for cards wrapping a table edge-to-edge */
.tf-card--sunken { background: var(--surface-sunken); }

/* Interactive card — hover lifts with a soft shadow, not a color change */
.tf-card--interactive { cursor: pointer; transition: box-shadow var(--duration-base) var(--ease-out),
                                                       border-color var(--duration-base) var(--ease-out),
                                                       transform var(--duration-base) var(--ease-out); }
.tf-card--interactive:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-raised);
  transform: translateY(-2px);
}
.tf-card--interactive:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* Card header / body / footer slots */
.tf-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-bottom: var(--space-5);
  margin-bottom: var(--space-5);
  border-bottom: var(--border-width) solid var(--border-subtle);
}
.tf-card__title {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  letter-spacing: var(--tracking-snug);
}
.tf-card__footer {
  padding-top: var(--space-5);
  margin-top: var(--space-5);
  border-top: var(--border-width) solid var(--border-subtle);
}

/* ── Panel — a card with an accent left-rule (sections, callouts) ──── */
.tf-panel {
  background: var(--surface-raised);
  border: var(--border-width) solid var(--border-default);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-md);
  padding: var(--space-6);
}
.tf-panel--up    { border-left-color: var(--cash-up); }
.tf-panel--down  { border-left-color: var(--cash-down); }
.tf-panel--warn  { border-left-color: var(--warn); }

/* ── Ink panel — the ONE dark surface. Final CTA only. ─────────────── */
.tf-ink-panel {
  background: var(--surface-ink);
  color: var(--text-on-ink);
  border-radius: var(--radius-xl);
  padding: var(--space-11) var(--space-8);
  text-align: center;
}
.tf-ink-panel h2, .tf-ink-panel .tf-h2 { color: var(--text-on-ink); }
.tf-ink-panel p { color: var(--text-on-ink-soft); }
.tf-ink-panel a:not(.tf-btn) { color: #5EEAD4; }    /* light teal on ink — 9.0:1 */
.tf-ink-panel .tf-btn--secondary {
  background: rgba(255,255,255,0.08);
  color: var(--text-on-ink);
  border-color: rgba(255,255,255,0.20);
}
.tf-ink-panel .tf-btn--secondary:hover { background: rgba(255,255,255,0.14); border-color: rgba(255,255,255,0.34); color: var(--text-on-noir); }

/* ── Divider ───────────────────────────────────────────────────────── */
.tf-divider { height: var(--border-width); background: var(--border-subtle); border: none; margin: var(--space-6) 0; }
.tf-divider--strong { background: var(--border-default); }
.tf-divider--labeled {
  display: flex; align-items: center; gap: var(--space-4);
  color: var(--text-quiet); font-size: var(--text-xs);
  text-transform: uppercase; letter-spacing: var(--tracking-wide);
  background: none; height: auto; margin: var(--space-6) 0;
}
.tf-divider--labeled::before,
.tf-divider--labeled::after { content: ''; flex: 1; height: var(--border-width); background: var(--border-subtle); }

/* ── Stepper — segmented step-progress ──────────────────────────────
   A horizontal run of segments showing position in a short linear flow
   (onboarding: Connect → Sync → View). One segment per step. State is
   carried by a modifier on each segment: --done (filled accent),
   --active (filled accent, wider — the "you are here" emphasis), and
   the base/upcoming state (faint track). Promoted from the onboarding
   reference's hand-rolled `.ob-track` (onboarding plan §6) so the
   portal first-run flow and any future linear wizard share one part.

   Markup contract:
     .tf-stepper                         — the segment row (flex)
       .tf-stepper__seg                  — one segment (upcoming)
         .tf-stepper__seg--done          — a completed step
         .tf-stepper__seg--active        — the current step (wider)        */
.tf-stepper {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.tf-stepper__seg {
  width: 36px;
  height: 4px;
  border-radius: var(--radius-pill);
  background: var(--ink-150);
  transition: width var(--duration-base) var(--ease-out),
              background-color var(--duration-base) var(--ease-out);
}
.tf-stepper__seg--done   { background: var(--accent); }
.tf-stepper__seg--active { background: var(--accent); width: 48px; }
@media (prefers-reduced-motion: reduce) {
  .tf-stepper__seg { transition: none; }
}

/* ── Bank logo chip — a square monogram tile for a bank ─────────────
   A small rounded square holding a bank's 2–4 letter monogram, set on
   the bank's brand colour. Used in the onboarding bank picker and the
   consolidation strip (how the total is built). The brand colour is set
   inline per bank (`style="background:#1A4FA0"`) since it is data, not a
   token. --lg is the picker size; the base size suits inline rows.
   Promoted from the reference's `.ob-bank__logo` / `.ob-bankrow__logo`.

   Markup contract:
     .tf-bank-logo                       — the chip (inline-flex)
       .tf-bank-logo--lg                 — larger variant (bank picker)    */
.tf-bank-logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-sm);
  background: var(--ink-500);
  color: #FFFFFF;
  font-size: 10px;
  font-weight: var(--weight-bold);
  letter-spacing: -0.01em;
  line-height: 1;
}
.tf-bank-logo--lg {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  font-size: var(--text-xs);
}

/* ── Permission list — the can / cannot trust ledger ────────────────
   A two-column "what we CAN do / what we CANNOT do" card. The trust
   surface a finance buyer reads before granting bank access — the
   boundary is legible in one glance. Used by the pre-Plaid trust modal
   and the onboarding connect-a-bank step. Promoted out of the
   hand-rolled `.ob-perm` in page-onboarding.css (dashboard-migration
   I6 + onboarding plan §6) so both surfaces share one component.

   Markup contract:
     .tf-permission-list                 — the grid (2 col, 1 col ≤560px)
       .tf-permission                    — one column
         .tf-permission--can             — affirmative (green hairline)
         .tf-permission--cannot          — boundary (neutral hairline)
         .tf-permission__head            — icon + label row
         .tf-permission__list (<ul>)     — the claims (<li>s)              */
.tf-permission-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-5);
}
@media (max-width: 560px) { .tf-permission-list { grid-template-columns: 1fr; } }
.tf-permission {
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  background: var(--surface-page);
}
.tf-permission--can    { border-color: var(--cash-up-border); background: var(--cash-up-soft); }
.tf-permission--cannot { border-color: var(--border-default); background: var(--surface-sunken); }
.tf-permission__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  margin-bottom: var(--space-4);
}
.tf-permission__head svg { width: 16px; height: 16px; flex-shrink: 0; }
.tf-permission--can .tf-permission__head svg    { color: var(--cash-up-text); }
.tf-permission--cannot .tf-permission__head svg { color: var(--text-quiet); }
.tf-permission__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.tf-permission__list li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  font-size: var(--text-sm);
  line-height: var(--lh-snug);
  color: var(--text-secondary);
}
.tf-permission__list li::before {
  content: '';
  flex-shrink: 0;
  width: 5px; height: 5px;
  margin-top: 7px;
  border-radius: var(--radius-pill);
  background: var(--ink-300);
}
.tf-permission--can .tf-permission__list li::before { background: var(--cash-up); }

/* ════════════════════════════════════════════════════════════════════
   D · DATA DISPLAY  — the heart of a treasury product
   ════════════════════════════════════════════════════════════════════ */

/* ── KPI / metric tile ───────────────────────────────────────────────
   Anatomy: overline label · the number (mono, tabular) · a delta/verdict
   line · a sparkline slot. The one tile that carries the screen's hero
   number gets --hero (the number renders in accent teal). Every other
   tile is monochrome — the white-dominant rule.
   ──────────────────────────────────────────────────────────────────── */
.tf-kpi {
  background: var(--surface-raised);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
}
.tf-kpi__label {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--text-quiet);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.tf-kpi__value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums lining-nums;
  font-size: var(--num-md);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.02em;
  color: var(--text-primary);
  line-height: 1.1;
}
.tf-kpi__verdict {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
/* Sparkline slot — host an inline SVG sparkline here (28-40px tall) */
.tf-kpi__spark {
  margin-top: auto;
  height: 36px;
  display: flex;
  align-items: flex-end;
}
.tf-kpi__spark svg { width: 100%; height: 100%; display: block; overflow: visible; }

/* Hero KPI — the single most important number on the screen. The number
   is the only place accent teal appears on the dashboard read view. */
.tf-kpi--hero {
  border-color: var(--accent-border);
  background: var(--accent-softer);
}
.tf-kpi--hero .tf-kpi__value { font-size: var(--num-lg); color: var(--accent-strong); }
.tf-kpi--hero .tf-kpi__label { color: var(--accent-strong); }

/* Compact KPI — for dense multi-account rollups */
.tf-kpi--compact { padding: var(--space-5); gap: var(--space-2); }
.tf-kpi--compact .tf-kpi__value { font-size: var(--num-sm); }

/* KPI loading state */
.tf-kpi.is-loading .tf-kpi__value,
.tf-kpi.is-loading .tf-kpi__verdict { visibility: hidden; }
.tf-kpi.is-loading { position: relative; }

/* ── Delta — the up/down/flat indicator. Reused in KPI, table, hero. ──
   The signature finance micro-component. Triangle glyph + tabular number.
   ──────────────────────────────────────────────────────────────────── */
.tf-delta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums lining-nums;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}
.tf-delta::before { font-size: 0.85em; line-height: 1; }
.tf-delta--up   { color: var(--cash-up-text); }
.tf-delta--up::before   { content: '\25B2'; }   /* ▲ */
.tf-delta--down { color: var(--cash-down-text); }
.tf-delta--down::before { content: '\25BC'; }   /* ▼ */
.tf-delta--flat { color: var(--cash-flat-text); }
.tf-delta--flat::before { content: '\2013'; }   /* – */
/* Pill variant — delta in a soft-fill chip */
.tf-delta--pill {
  padding: 3px var(--space-3);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
}
.tf-delta--pill.tf-delta--up   { background: var(--cash-up-soft); }
.tf-delta--pill.tf-delta--down { background: var(--cash-down-soft); }
.tf-delta--pill.tf-delta--flat { background: var(--cash-flat-soft); }

/* ── Badge / pill / status dot ─────────────────────────────────────── */
.tf-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  line-height: 1;
  padding: 4px var(--space-3);
  border-radius: var(--radius-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
}
.tf-badge--neutral { background: var(--ink-100); color: var(--text-secondary); }
.tf-badge--accent  { background: var(--accent-soft); color: var(--accent-strong); }
.tf-badge--up      { background: var(--cash-up-soft); color: var(--cash-up-text); }
.tf-badge--down    { background: var(--cash-down-soft); color: var(--cash-down-text); }
.tf-badge--warn    { background: var(--warn-soft); color: var(--warn-text); }
.tf-badge--outline { background: transparent; color: var(--text-secondary); border: var(--border-width) solid var(--border-default); }
/* Hero eyebrow exception — the marketing hero reuses .tf-badge for a long
   descriptive eyebrow sentence (e.g. "For Construction & Manufacturing CFOs
   · Multi-bank, bank-agnostic"). A status pill stays nowrap; a sentence-
   length eyebrow MUST wrap or it floors the page width on a 375px phone.
   The base .tf-badge is inline-flex, which sizes to the text's max-content
   width even with white-space:normal — so we also cap it to the column
   width. text-wrap:balance keeps the wrapped lines visually even. */
.tf-badge.hero__eyebrow {
  white-space: normal;
  line-height: var(--lh-snug);
  text-align: center;
  max-width: 100%;
  text-wrap: balance;
}
/* Status dot — a leading dot for live/synced/error states */
.tf-dot {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: var(--radius-pill);
  flex-shrink: 0;
}
.tf-dot--live  { background: var(--cash-up); }
.tf-dot--warn  { background: var(--warn); }
.tf-dot--error { background: var(--cash-down); }
.tf-dot--idle  { background: var(--ink-300); }
/* Pulsing live dot (synced/connected). Reduced-motion safe. */
.tf-dot--pulse { position: relative; }
.tf-dot--pulse::after {
  content: ''; position: absolute; inset: -3px;
  border-radius: var(--radius-pill);
  border: 1.5px solid currentColor;
  color: var(--cash-up);
  opacity: 0;
  animation: tf-pulse 2.4s var(--ease-out) infinite;
}
@keyframes tf-pulse {
  0%   { transform: scale(0.7); opacity: 0.6; }
  70%  { transform: scale(1.6); opacity: 0; }
  100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .tf-dot--pulse::after { animation: none; display: none; }
}

/* ── Pill — bank/account/category chip (selectable, removable) ─────── */
.tf-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 26px;
  padding: 0 var(--space-3);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  background: var(--surface-sunken);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-pill);
}
.tf-pill--selected { background: var(--accent-soft); border-color: var(--accent-border); color: var(--accent-strong); }
.tf-pill__remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px;
  border: none; background: none; cursor: pointer;
  color: var(--text-quiet); border-radius: var(--radius-pill);
}
.tf-pill__remove:hover { color: var(--text-primary); background: var(--ink-150); }

/* ── DATA TABLE — the spreadsheet-grade table. The core component. ───
   Built like an Excel grid: hairline rules on every row, a tinted header
   band, a sticky header, tabular-figure numeric columns right-aligned,
   quiet zebra + hover, a selected-row state, and a clickable row that
   IS the drill-down affordance (click any number → see transactions).
   ──────────────────────────────────────────────────────────────────── */
.tf-table-wrap {
  width: 100%;
  /* max-width + min-width:0 are load-bearing: a .tf-table carries a
     min-width (560px on mobile), and without these the table's intrinsic
     width propagates up through the wrap and stretches its parent —
     overflow-x never engages and the whole page floors wide. Capping the
     wrap at 100% of its container forces the table to scroll INSIDE the
     box instead. */
  max-width: 100%;
  min-width: 0;
  overflow-x: auto;
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  background: var(--surface-page);
}
.tf-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
/* Header — tinted band, sticky, uppercase micro-label */
.tf-table thead th {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: var(--surface-sunken);
  padding: var(--table-cell-pad-y) var(--table-cell-pad-x);
  text-align: left;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--text-quiet);
  border-bottom: var(--border-width) solid var(--gridline-strong);
  white-space: nowrap;
}
/* Sortable header */
.tf-table th.tf-th--sortable { cursor: pointer; user-select: none; }
.tf-table th.tf-th--sortable:hover { color: var(--text-primary); }
.tf-table th.tf-th--sortable::after {
  content: '\2195'; margin-left: var(--space-2); opacity: 0.4; font-weight: 400;
}
.tf-table th[aria-sort="ascending"]::after  { content: '\2191'; opacity: 1; color: var(--accent); }
.tf-table th[aria-sort="descending"]::after { content: '\2193'; opacity: 1; color: var(--accent); }

/* Body rows — hairline rule under each (the Excel gridline) */
.tf-table tbody td {
  padding: var(--table-cell-pad-y) var(--table-cell-pad-x);
  border-bottom: var(--border-width) solid var(--gridline);
  color: var(--text-primary);
  height: var(--row-h);
  vertical-align: middle;
}
.tf-table tbody tr:last-child td { border-bottom: none; }
/* Zebra — barely-there, off by default; opt in with --zebra */
.tf-table--zebra tbody tr:nth-child(even) td { background: var(--ink-25); }
/* Row hover */
.tf-table tbody tr { transition: background-color var(--duration-fast) var(--ease-standard); }
.tf-table tbody tr:hover td { background: var(--surface-hover); }
/* Selected row */
.tf-table tbody tr[aria-selected="true"] td,
.tf-table tbody tr.is-selected td { background: var(--surface-selected); }
/* Clickable row — the drill-down affordance */
.tf-table--drill tbody tr { cursor: pointer; }
.tf-table--drill tbody tr:hover td { background: var(--surface-selected); }
.tf-table tbody tr:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }

/* Numeric column — right-aligned, tabular. Data cells use mono; headers
   use the base font (Inter) so they match the rest of the header band. */
.tf-table .tf-th--num {
  text-align: right;
  white-space: nowrap;
}
.tf-table .tf-td--num {
  text-align: right;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums lining-nums;
  white-space: nowrap;
}
.tf-table .tf-td--num { color: var(--text-primary); font-weight: var(--weight-medium); }
/* Directional numbers in a cell */
.tf-table .tf-td--up   { color: var(--cash-up-text); }
.tf-table .tf-td--down { color: var(--cash-down-text); }
/* Muted / secondary cell text */
.tf-table .tf-td--muted { color: var(--text-quiet); }
/* Compact density mode */
.tf-table--compact tbody td { height: var(--row-h-compact); padding: var(--space-3) var(--table-cell-pad-x); }
/* A totals / footer row — heavier rule, semibold */
.tf-table tfoot td {
  padding: var(--table-cell-pad-y) var(--table-cell-pad-x);
  border-top: 2px solid var(--gridline-strong);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  background: var(--surface-sunken);
}
.tf-table tfoot .tf-td--num { font-family: var(--font-mono); }
/* Drill-down affordance icon — appears on row hover */
.tf-table__drill-icon { opacity: 0; color: var(--text-quiet); transition: opacity var(--duration-fast); }
.tf-table--drill tbody tr:hover .tf-table__drill-icon { opacity: 1; }

/* Cell-embedded sparkline (a column of trend shapes) */
.tf-table__cell-spark { display: inline-block; width: 64px; height: 20px; vertical-align: middle; }
.tf-table__cell-spark svg { width: 100%; height: 100%; }

/* ── Stat row — label / value pairs (account list, breakdown) ──────── */
.tf-stat-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: var(--border-width) solid var(--gridline);
}
.tf-stat-row:last-child { border-bottom: none; }
.tf-stat-row__label { display: flex; align-items: center; gap: var(--space-3); font-size: var(--text-sm); color: var(--text-secondary); }
.tf-stat-row__value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums lining-nums;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}
.tf-stat-row--clickable { cursor: pointer; margin: 0 calc(var(--space-4) * -1); padding-left: var(--space-4); padding-right: var(--space-4); border-radius: var(--radius-xs); transition: background-color var(--duration-fast); }
.tf-stat-row--clickable:hover { background: var(--surface-hover); }

/* ── Entity tag — a quiet account-ownership label inside a table cell ─
   Promoted from page-dashboard.css in dashboard-migration I3: the portal's
   Cash Position "By Bank Account" rows and any multi-entity table need it,
   so it graduates from the dashboard page layer into the shared component
   library. A quiet, square, monochrome label — deliberately NOT a colored
   category chip (the design system's anti-pattern). Sits inside a <td>. */
.tf-entity-tag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 20px;
  padding: 0 var(--space-3);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--text-quiet);
  background: var(--surface-sunken);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-xs);
  white-space: nowrap;
}
.tf-entity-tag__dot {
  width: 6px; height: 6px;
  border-radius: var(--radius-pill);
  background: var(--ink-300);
  flex-shrink: 0;
}

/* ── Method note — a quiet provenance sentence under a number ─────────
   Promoted from page-dashboard.css in dashboard-migration I3: a forecast or
   a derived metric must always state its method (the hero KPI's runway
   line, a forecast panel). Graduates into the shared library because the
   portal's Cash Position hero KPI uses it. */
.tf-method-note {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  font-size: var(--text-xs);
  color: var(--text-quiet);
  line-height: var(--lh-snug);
}
.tf-method-note svg { width: 14px; height: 14px; flex-shrink: 0; margin-top: 1px; }

/* ── Trust band — the canonical security signal ──────────────────────
   Per repo memory: the trust band after the hero is the ONE place
   security claims live. A quiet hairline-bordered strip, monochrome,
   each item a check glyph + a fact. Not a badge wall.
   ──────────────────────────────────────────────────────────────────── */
.tf-trust-band {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-6) var(--space-8);
  padding: var(--space-6) var(--space-7);
  background: var(--surface-page);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
}
.tf-trust-band__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-secondary);
  white-space: nowrap;
}
.tf-trust-band__item strong { color: var(--text-primary); font-weight: var(--weight-semibold); }
.tf-trust-band__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px; height: 20px;
  flex-shrink: 0;
  color: var(--accent);
}
.tf-trust-band__sep { width: var(--border-width); height: 20px; background: var(--border-default); }
/* Mobile — a single trust fact ("Plaid-secured — same infrastructure as
   Wealthfront, Venmo & Chime") is wider than a 375px phone. On a wide row
   each fact stays on one line (the desktop look is unchanged); on a narrow
   viewport the item and its text MUST be allowed to wrap, and the vertical
   hairline separator is dropped since the items now stack. */
@media (max-width: 640px) {
  .tf-trust-band__item {
    white-space: normal;
    max-width: 100%;
    align-items: flex-start;
    text-align: left;
  }
  .tf-trust-band__item > span { min-width: 0; }
  .tf-trust-band__sep { display: none; }
}
/* Sunken variant — for inside the dashboard (e.g. above bank connect) */
.tf-trust-band--sunken { background: var(--surface-sunken); border-color: var(--border-subtle); }

/* ── Verified mark — small "data verified / reconciled" trust chip ───
   The audit found a customer who distrusts exported data. This chip
   makes correctness visible: a number can be tagged "verified".
   ──────────────────────────────────────────────────────────────────── */
.tf-verified {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--cash-up-text);
}
.tf-verified svg { width: 13px; height: 13px; }
.tf-verified--pending { color: var(--warn-text); }
.tf-verified--source {
  color: var(--text-quiet);
  font-family: var(--font-mono);
  text-transform: none;
  letter-spacing: 0;
}

/* ════════════════════════════════════════════════════════════════════
   E · NAVIGATION
   ════════════════════════════════════════════════════════════════════ */

/* ── Top nav — marketing site + dashboard top bar ──────────────────── */
.tf-nav {
  position: sticky;
  top: 0;
  z-index: var(--z-nav);
  background: rgba(255,255,255,0.86);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  backdrop-filter: saturate(160%) blur(14px);
  border-bottom: var(--border-width) solid var(--border-subtle);
  transition: box-shadow var(--duration-base) var(--ease-standard),
              border-color var(--duration-base) var(--ease-standard);
}
.tf-nav--scrolled { box-shadow: var(--shadow-raised); border-color: var(--border-default); }
.tf-nav__inner {
  max-width: var(--container-wide);
  margin: 0 auto;
  height: var(--topbar-h);
  padding: 0 var(--space-6);
  display: flex;
  align-items: center;
  gap: var(--space-7);
}
.tf-nav__links { display: flex; align-items: center; gap: var(--space-6); flex: 1; }
.tf-nav__link {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  transition: color var(--duration-fast) var(--ease-standard);
}
.tf-nav__link:hover { color: var(--text-primary); }
.tf-nav__link[aria-current="page"] { color: var(--text-primary); font-weight: var(--weight-semibold); }
.tf-nav__actions { display: flex; align-items: center; gap: var(--space-4); }

/* ── App sidebar — the adaptive dashboard navigation rail ────────────
   Dimmed chrome (Linear: "don't compete for attention you haven't
   earned"). Quiet at rest; the active item gets a teal left-rule + a
   faint teal wash. Collapsible to a 64px icon rail. Works for both
   single-company and multi-client modes — see the workspace switcher.
   ──────────────────────────────────────────────────────────────────── */
.tf-sidebar {
  width: var(--sidebar-w);
  background: var(--surface-page);
  border-right: var(--border-width) solid var(--border-default);
  display: flex;
  flex-direction: column;
  transition: width var(--duration-slow) var(--ease-out);
}
.tf-sidebar--collapsed { width: var(--sidebar-w-collapsed); }

/* Workspace switcher — top of sidebar. In single-company mode it shows
   the company; in fractional-firm mode it's a client picker. */
.tf-workspace {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: var(--topbar-h);
  padding: 0 var(--space-5);
  border-bottom: var(--border-width) solid var(--border-subtle);
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tf-workspace:hover { background: var(--surface-hover); }
.tf-workspace__mark {
  width: 28px; height: 28px;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent-strong);
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: var(--weight-bold);
  font-size: var(--text-sm);
  flex-shrink: 0;
}
.tf-workspace__text { display: flex; flex-direction: column; min-width: 0; }
.tf-workspace__name {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tf-workspace__meta { font-size: var(--text-xs); color: var(--text-quiet); }
.tf-workspace__chevron { margin-left: auto; color: var(--text-quiet); flex-shrink: 0; }
.tf-sidebar--collapsed .tf-workspace__text,
.tf-sidebar--collapsed .tf-workspace__chevron { display: none; }

/* Nav group + items */
.tf-sidebar__nav { flex: 1; padding: var(--space-5) var(--space-4); overflow-y: auto; display: flex; flex-direction: column; gap: var(--space-1); }
.tf-sidebar__group-label {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--text-quiet);
  padding: var(--space-5) var(--space-3) var(--space-2);
}
.tf-sidebar--collapsed .tf-sidebar__group-label { opacity: 0; height: var(--space-5); }
.tf-nav-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: 38px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  border-left: 2px solid transparent;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard),
              color var(--duration-fast) var(--ease-standard);
}
.tf-nav-item svg { width: 18px; height: 18px; flex-shrink: 0; color: var(--text-quiet); transition: color var(--duration-fast); }
.tf-nav-item:hover { background: var(--surface-hover); color: var(--text-primary); }
.tf-nav-item:hover svg { color: var(--text-secondary); }
.tf-nav-item:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.tf-nav-item[aria-current="page"],
.tf-nav-item.is-active {
  background: var(--accent-soft);
  color: var(--accent-strong);
  font-weight: var(--weight-semibold);
  border-left-color: var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.tf-nav-item.is-active svg { color: var(--accent); }
.tf-nav-item__badge { margin-left: auto; }
.tf-sidebar--collapsed .tf-nav-item__label,
.tf-sidebar--collapsed .tf-nav-item__badge { display: none; }
.tf-sidebar--collapsed .tf-nav-item { justify-content: center; padding: 0; }

/* Sidebar footer — collapse toggle / account */
.tf-sidebar__footer { padding: var(--space-4); border-top: var(--border-width) solid var(--border-subtle); }

/* ── Tabs — in-content section switcher ────────────────────────────── */
.tf-tabs {
  display: flex;
  gap: var(--space-6);
  border-bottom: var(--border-width) solid var(--border-default);
}
.tf-tab {
  position: relative;
  padding: var(--space-4) 0;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  background: none;
  border: none;
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-standard);
}
.tf-tab:hover { color: var(--text-primary); }
.tf-tab:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; border-radius: var(--radius-xs); }
.tf-tab[aria-selected="true"],
.tf-tab.is-active { color: var(--text-primary); font-weight: var(--weight-semibold); }
.tf-tab[aria-selected="true"]::after,
.tf-tab.is-active::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--accent);
  border-radius: var(--radius-pill) var(--radius-pill) 0 0;
}

/* ── Breadcrumb ────────────────────────────────────────────────────── */
.tf-breadcrumb { display: flex; align-items: center; gap: var(--space-3); font-size: var(--text-sm); }
.tf-breadcrumb a { color: var(--text-quiet); }
.tf-breadcrumb a:hover { color: var(--text-primary); }
.tf-breadcrumb__sep { color: var(--ink-300); }
.tf-breadcrumb__current { color: var(--text-primary); font-weight: var(--weight-medium); }

/* ════════════════════════════════════════════════════════════════════
   F · FEEDBACK
   ════════════════════════════════════════════════════════════════════ */

/* ── Toast + undo — optimistic-UI safety net ─────────────────────────
   Every user action applies instantly; a toast confirms it and offers a
   5-second undo (the Superhuman pattern). Toasts stack bottom-left.
   ──────────────────────────────────────────────────────────────────── */
.tf-toast-rack {
  position: fixed;
  bottom: var(--space-6);
  left: var(--space-6);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: 380px;
}
.tf-toast {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  background: var(--surface-ink);
  color: var(--text-on-ink);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-toast);
  font-size: var(--text-sm);
  animation: tf-toast-in var(--duration-slow) var(--ease-out);
}
@keyframes tf-toast-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.tf-toast.is-leaving { animation: tf-toast-out var(--duration-base) var(--ease-in) forwards; }
@keyframes tf-toast-out {
  to { opacity: 0; transform: translateY(8px); }
}
.tf-toast__icon { display: inline-flex; flex-shrink: 0; }
.tf-toast__icon--up   { color: #5EEAD4; }
.tf-toast__icon--warn { color: #FCD34D; }
.tf-toast__icon--down { color: #FCA5A5; }
.tf-toast__body { flex: 1; min-width: 0; }
.tf-toast__title { font-weight: var(--weight-semibold); }
.tf-toast__msg { color: var(--text-on-ink-soft); }
/* Undo action — the affordance that makes optimistic UI safe */
.tf-toast__undo {
  flex-shrink: 0;
  padding: var(--space-2) var(--space-3);
  background: rgba(255,255,255,0.10);
  color: #5EEAD4;
  border: none;
  border-radius: var(--radius-xs);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  cursor: pointer;
  transition: background-color var(--duration-fast);
}
.tf-toast__undo:hover { background: rgba(255,255,255,0.18); }
.tf-toast__undo:focus-visible { outline: 2px solid #5EEAD4; outline-offset: 1px; }
/* Undo timer ring — a thin progress bar counting down the 5s window */
.tf-toast__timer {
  position: absolute;
  left: 0; bottom: 0;
  height: 2px;
  background: #5EEAD4;
  border-radius: var(--radius-pill);
  animation: tf-toast-timer 5s linear forwards;
}
.tf-toast { position: relative; overflow: hidden; }
@keyframes tf-toast-timer { from { width: 100%; } to { width: 0%; } }
@media (prefers-reduced-motion: reduce) {
  .tf-toast, .tf-toast.is-leaving { animation: none; }
}

/* ── Empty state — teaches the next action, never a blank screen ───── */
.tf-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-5);
  padding: var(--space-10) var(--space-7);
  background: var(--surface-page);
  border: 1.5px dashed var(--border-strong);
  border-radius: var(--radius-lg);
}
.tf-empty__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px; height: 52px;
  border-radius: var(--radius-md);
  background: var(--accent-soft);
  color: var(--accent);
}
.tf-empty__title {
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  letter-spacing: var(--tracking-snug);
}
.tf-empty__text {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  max-width: 420px;
  line-height: var(--lh-body);
}
.tf-empty__actions { display: flex; gap: var(--space-3); flex-wrap: wrap; justify-content: center; margin-top: var(--space-2); }

/* ── Skeleton — animated placeholder mirroring real layout ─────────── */
.tf-skeleton {
  background: linear-gradient(
    100deg,
    var(--ink-100) 30%,
    var(--ink-50) 50%,
    var(--ink-100) 70%
  );
  background-size: 220% 100%;
  border-radius: var(--radius-xs);
  animation: tf-shimmer 1.4s ease-in-out infinite;
}
@keyframes tf-shimmer {
  from { background-position: 180% 0; }
  to   { background-position: -20% 0; }
}
.tf-skeleton--text   { height: 12px; }
.tf-skeleton--text-lg{ height: 18px; }
.tf-skeleton--title  { height: 26px; width: 60%; }
.tf-skeleton--num    { height: 34px; width: 45%; }
.tf-skeleton--block  { height: 100%; }
.tf-skeleton--circle { border-radius: var(--radius-pill); }
.tf-skeleton--line   { width: 100%; }
.tf-skeleton--w-50   { width: 50%; }
.tf-skeleton--w-75   { width: 75%; }
@media (prefers-reduced-motion: reduce) {
  .tf-skeleton { animation: none; background: var(--ink-100); }
}

/* ── Inline loading — spinner for content regions ──────────────────── */
.tf-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-9);
  color: var(--text-quiet);
  font-size: var(--text-sm);
}
.tf-spinner {
  width: 24px; height: 24px;
  border: 2.5px solid var(--ink-150);
  border-top-color: var(--accent);
  border-radius: var(--radius-pill);
  animation: tf-spin 0.7s linear infinite;
}
.tf-spinner--sm { width: 16px; height: 16px; border-width: 2px; }
.tf-spinner--lg { width: 36px; height: 36px; border-width: 3px; }

/* ── Banner — page-level notice (info / warn / down / up) ──────────── */
.tf-banner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-md);
  border: var(--border-width) solid;
  font-size: var(--text-sm);
}
.tf-banner__icon { flex-shrink: 0; margin-top: 1px; }
.tf-banner__body { flex: 1; color: var(--text-secondary); }
.tf-banner__body strong { color: var(--text-primary); font-weight: var(--weight-semibold); }
.tf-banner__close { flex-shrink: 0; }
.tf-banner--info { background: var(--info-soft); border-color: var(--info-border); }
.tf-banner--info .tf-banner__icon { color: var(--info-text); }
.tf-banner--warn { background: var(--warn-soft); border-color: var(--warn-border); }
.tf-banner--warn .tf-banner__icon { color: var(--warn-text); }
.tf-banner--down { background: var(--cash-down-soft); border-color: var(--cash-down-border); }
.tf-banner--down .tf-banner__icon { color: var(--cash-down-text); }
.tf-banner--up { background: var(--cash-up-soft); border-color: var(--cash-up-border); }
.tf-banner--up .tf-banner__icon { color: var(--cash-up-text); }

/* ── Tooltip — quiet, dark, fast ───────────────────────────────────── */
.tf-tooltip {
  position: relative;
  display: inline-flex;
}
.tf-tooltip__bubble {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  padding: var(--space-2) var(--space-3);
  background: var(--surface-ink);
  color: var(--text-on-ink);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  white-space: nowrap;
  border-radius: var(--radius-xs);
  box-shadow: var(--shadow-popover);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-fast) var(--ease-standard),
              transform var(--duration-fast) var(--ease-standard);
  z-index: var(--z-dropdown);
}
.tf-tooltip:hover .tf-tooltip__bubble,
.tf-tooltip:focus-within .tf-tooltip__bubble {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ── Progress bar ──────────────────────────────────────────────────── */
.tf-progress {
  height: 6px;
  background: var(--ink-150);
  border-radius: var(--radius-pill);
  overflow: hidden;
}
.tf-progress__fill {
  height: 100%;
  background: var(--accent);
  border-radius: var(--radius-pill);
  transition: width var(--duration-slow) var(--ease-out);
}
.tf-progress__fill--up   { background: var(--cash-up); }
.tf-progress__fill--warn { background: var(--warn); }
.tf-progress__fill--down { background: var(--cash-down); }

/* ════════════════════════════════════════════════════════════════════
   G · OVERLAY
   ════════════════════════════════════════════════════════════════════ */

/* ── Modal dialog ──────────────────────────────────────────────────── */
.tf-modal-scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--surface-overlay);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6);
  animation: tf-fade-in var(--duration-base) var(--ease-standard);
}
@keyframes tf-fade-in { from { opacity: 0; } to { opacity: 1; } }
.tf-modal {
  position: relative;
  z-index: var(--z-modal);
  width: 100%;
  max-width: 520px;
  max-height: 86vh;
  overflow-y: auto;
  background: var(--surface-page);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-modal);
  animation: tf-modal-in var(--duration-slow) var(--ease-out);
}
@keyframes tf-modal-in {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.tf-modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-6);
  border-bottom: var(--border-width) solid var(--border-subtle);
}
.tf-modal__title { font-size: var(--text-md); font-weight: var(--weight-semibold); color: var(--text-primary); }
.tf-modal__body { padding: var(--space-6); }
.tf-modal__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-6);
  border-top: var(--border-width) solid var(--border-subtle);
  background: var(--surface-sunken);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}
.tf-modal--sm { max-width: 400px; }
.tf-modal--lg { max-width: 720px; }
@media (prefers-reduced-motion: reduce) {
  .tf-modal-scrim, .tf-modal { animation: none; }
}

/* ── Dropdown menu ─────────────────────────────────────────────────── */
.tf-menu {
  min-width: 200px;
  padding: var(--space-3);
  background: var(--surface-page);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-popover);
  z-index: var(--z-dropdown);
}
.tf-menu__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-xs);
  font-size: var(--text-sm);
  color: var(--text-primary);
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  transition: background-color var(--duration-fast) var(--ease-standard);
}
.tf-menu__item svg { width: 16px; height: 16px; color: var(--text-quiet); }
.tf-menu__item:hover { background: var(--surface-hover); }
.tf-menu__item:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.tf-menu__item--danger { color: var(--cash-down-text); }
.tf-menu__item--danger svg { color: var(--cash-down-text); }
.tf-menu__item--danger:hover { background: var(--cash-down-soft); }
.tf-menu__item[aria-disabled="true"] { color: var(--text-disabled); pointer-events: none; }
.tf-menu__sep { height: var(--border-width); background: var(--border-subtle); margin: var(--space-3) 0; }
.tf-menu__label {
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--text-quiet);
}
.tf-menu__shortcut { margin-left: auto; font-size: var(--text-xs); color: var(--text-quiet); font-family: var(--font-mono); }

/* ── Command palette (⌘K) — power-tool signal, teaches its shortcuts ── */
.tf-command-scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-command);
  background: var(--surface-overlay);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  display: flex;
  justify-content: center;
  padding-top: 12vh;
  animation: tf-fade-in var(--duration-fast) var(--ease-standard);
}
.tf-command {
  width: 100%;
  max-width: 580px;
  height: fit-content;
  max-height: 60vh;
  background: var(--surface-page);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-modal);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  animation: tf-modal-in var(--duration-base) var(--ease-out);
}
.tf-command__search {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-6);
  border-bottom: var(--border-width) solid var(--border-subtle);
}
.tf-command__search svg { color: var(--text-quiet); flex-shrink: 0; }
.tf-command__input {
  flex: 1;
  border: none;
  outline: none;
  font-size: var(--text-md);
  color: var(--text-primary);
  background: transparent;
}
.tf-command__input::placeholder { color: var(--text-quiet); }
.tf-command__kbd {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-quiet);
  padding: 2px var(--space-2);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-xs);
  background: var(--surface-sunken);
}
.tf-command__list { overflow-y: auto; padding: var(--space-3); }
.tf-command__group-label {
  padding: var(--space-4) var(--space-3) var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--text-quiet);
}
.tf-command__item {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  width: 100%;
  padding: var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--text-primary);
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
}
.tf-command__item svg { width: 17px; height: 17px; color: var(--text-quiet); flex-shrink: 0; }
/* Selected item — keyboard navigation highlight */
.tf-command__item[aria-selected="true"],
.tf-command__item:hover {
  background: var(--accent-soft);
  color: var(--accent-strong);
}
.tf-command__item[aria-selected="true"] svg { color: var(--accent); }
.tf-command__item-shortcut { margin-left: auto; }
@media (prefers-reduced-motion: reduce) {
  .tf-command-scrim, .tf-command { animation: none; }
}

/* ════════════════════════════════════════════════════════════════════
   TYPOGRAPHY UTILITIES — the type scale as classes
   ════════════════════════════════════════════════════════════════════ */
.tf-display {
  font-family: var(--font-display);
  font-size: clamp(var(--text-4xl), 8vw, var(--text-5xl));
  font-weight: var(--weight-display);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-display);
  color: var(--text-primary);
}
/* Hero headline weight — SHARED across every marketing page. The hero H1
   uses .tf-display, which sits at the light display weight (300) — right
   for a section heading, too tentative for the single most important
   promise on a page. .hero__title steps it up to semibold: the confident,
   authoritative register Stripe / Linear / Mercury use for a hero. This
   lives in the shared library (not on .tf-display, which non-hero display
   headings also use, and not in each page's CSS where it kept getting
   forgotten) so every page's hero matches the homepage. Tracking eases in
   a touch — semibold at display size needs less negative tracking than
   300 did. Per-page CSS still owns hero margin + responsive size. */
.hero__title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.028em;
  /* Evenly distribute the headline across lines so no single word orphans on a
     narrow phone column (the old hard <br> stranded "number"). Graceful no-op
     on engines without support. */
  text-wrap: balance;
}
/* Hero accent word — canonical gradient wordmark across EVERY page.
   Was inconsistent: 6 pages used solid var(--accent-strong) (per-page
   override in page-*.css), 5 used the gradient. Designer audit 2026-05-28
   flagged the split; this rule + removal of the per-page overrides
   unifies on the canonical teal→navy ramp. style.css carried the same
   rule but only forecast-builder.html loaded it; components.css is the
   right home (every page-*.css @imports it). */
.hero__title-accent {
  background: var(--gradient-wordmark);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  /* Fallback when background-clip:text is unsupported: deepest teal
     for AA contrast (9.7:1 on white). Same fallback as style.css. */
  color: var(--accent-strong);
}
.tf-h1 {
  font-family: var(--font-display);
  font-size: clamp(var(--text-3xl), 5.5vw, var(--text-4xl));
  font-weight: var(--weight-bold);
  line-height: var(--lh-heading);
  letter-spacing: var(--tracking-display);
  color: var(--text-primary);
}
.tf-h2 {
  font-family: var(--font-display);
  font-size: clamp(var(--text-2xl), 3.5vw, var(--text-3xl));
  font-weight: var(--weight-bold);
  line-height: var(--lh-heading);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}
.tf-h3 {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  line-height: var(--lh-heading);
  letter-spacing: var(--tracking-snug);
  color: var(--text-primary);
}
.tf-h4 {
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  line-height: var(--lh-snug);
  color: var(--text-primary);
}
.tf-lead {
  font-size: var(--text-lg);
  font-weight: var(--weight-normal);
  line-height: var(--lh-snug);
  color: var(--text-secondary);
}
.tf-body { font-size: var(--text-base); line-height: var(--lh-body); color: var(--text-secondary); }
.tf-small { font-size: var(--text-sm); line-height: var(--lh-body); color: var(--text-secondary); }
.tf-caption { font-size: var(--text-xs); line-height: var(--lh-snug); color: var(--text-quiet); }
.tf-overline {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-widest);
  color: var(--accent);
}
.tf-serif { font-family: var(--font-serif); font-weight: var(--weight-normal); }
.tf-mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums lining-nums; }
.tf-num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: 0;
}

/* ════════════════════════════════════════════════════════════════════
   ADAPTIVE DASHBOARD SHELL — the layout primitive
   One shell, two default layouts. The shell is identical; the data-mode
   attribute reconfigures the default widget grid:
     [data-mode="company"] → in-house CFO: one company, hero = total cash
     [data-mode="firm"]    → fractional firm: many clients, hero = client grid
   ════════════════════════════════════════════════════════════════════ */
.tf-app {
  display: grid;
  grid-template-columns: auto 1fr;
  min-height: 100vh;
  background: var(--surface-sunken);
}
.tf-app__main { display: flex; flex-direction: column; min-width: 0; }
.tf-app__topbar {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  height: var(--topbar-h);
  padding: 0 var(--dash-pad);
  background: var(--surface-page);
  border-bottom: var(--border-width) solid var(--border-default);
}
.tf-app__title { font-size: var(--text-md); font-weight: var(--weight-semibold); color: var(--text-primary); }
.tf-app__topbar-actions { margin-left: auto; display: flex; align-items: center; gap: var(--space-3); }
.tf-app__content {
  flex: 1;
  padding: var(--dash-pad);
  overflow-y: auto;
  max-width: var(--container-app);
  width: 100%;
}
/* The adaptive widget grid */
.tf-dash-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--dash-gutter);
}
/* Column spans — widgets declare how many of 12 columns they take */
.tf-col-3  { grid-column: span 3; }
.tf-col-4  { grid-column: span 4; }
.tf-col-6  { grid-column: span 6; }
.tf-col-8  { grid-column: span 8; }
.tf-col-12 { grid-column: span 12; }

/* Company mode: KPI tiles default to 4-up across the top */
.tf-app[data-mode="company"] .tf-dash-grid > .tf-kpi { grid-column: span 3; }
/* Firm mode: the client-rollup grid leads; KPI tiles compress to a strip */
.tf-app[data-mode="firm"] .tf-dash-grid > .tf-kpi { grid-column: span 4; }

/* ── FAQ Item (details/summary accordion) baseline style ── */
.faq__item {
  transition: border-color var(--duration-base);
}
.faq__item[open]:not(.is-closing) {
  border-color: var(--accent-primary-border);
}
.faq__item summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-4);
}
.faq__item summary::-webkit-details-marker {
  display: none;
}
.faq__item summary::after {
  content: '+';
  font-size: 24px;
  color: var(--accent-primary);
  font-weight: var(--weight-normal);
  transition: transform var(--duration-base) var(--ease-emphasized);
  flex-shrink: 0;
}
.faq__item[open]:not(.is-closing) summary::after {
  transform: rotate(45deg);
}

/* ════════════════════════════════════════════════════════════════════
   RESPONSIVE — iPhone 17 Pro (402px) baseline
   ════════════════════════════════════════════════════════════════════ */
@media (max-width: 1024px) {
  .tf-app { grid-template-columns: 1fr; }
  .tf-sidebar {
    position: fixed;
    left: 0; top: 0; bottom: 0;
    z-index: var(--z-sidebar);
    transform: translateX(-100%);
    transition: transform var(--duration-slow) var(--ease-out);
    box-shadow: var(--shadow-modal);
  }
  .tf-sidebar.is-open { transform: translateX(0); }
  .tf-col-3, .tf-col-4, .tf-col-6, .tf-col-8 { grid-column: span 6; }
  .tf-app[data-mode="company"] .tf-dash-grid > .tf-kpi,
  .tf-app[data-mode="firm"] .tf-dash-grid > .tf-kpi { grid-column: span 6; }
  /* Nav collapses to a drawer at 1024px — the SAME breakpoint every
     page-*.css re-authors .tf-nav__links into its off-canvas panel.
     Kept in lock-step with that page-level drawer breakpoint so a future
     page can't render a horizontal nav row between 641–1024px. */
  .tf-nav__links { display: none; }

  /* Mobile menu backdrop scrim — overlay when nav is open */
  body::after {
    content: "";
    position: fixed;
    top: var(--topbar-h);
    left: 0;
    right: 0;
    bottom: 0;
    background: #0f172a;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity var(--duration-base) var(--ease-standard),
                visibility var(--duration-base);
    z-index: 40; /* stays behind sticky nav (50) but above content */
  }
  body:has(.tf-nav.is-open)::after {
    opacity: 0.45;
    visibility: visible;
    pointer-events: auto;
  }
}

@media (max-width: 640px) {
  .tf-col-3, .tf-col-4, .tf-col-6, .tf-col-8, .tf-col-12 { grid-column: span 12; }
  .tf-app[data-mode="company"] .tf-dash-grid > .tf-kpi,
  .tf-app[data-mode="firm"] .tf-dash-grid > .tf-kpi { grid-column: span 12; }
  .tf-app__content { padding: var(--space-5); }
  .tf-card, .tf-kpi { padding: var(--space-5); }
  .tf-toast-rack { left: var(--space-4); right: var(--space-4); bottom: var(--space-4); max-width: none; }
  .tf-modal { max-width: none; }
  /* Tap targets: every interactive control honors 44px on touch */
  .tf-btn { height: var(--control-h-lg); }
  .tf-icon-btn { width: var(--tap-min); height: var(--tap-min); }
  .tf-nav-item { height: var(--tap-min); }
  /* Tables scroll horizontally rather than crush columns */
  .tf-table { min-width: 560px; }
}
