/* ============================================================
   FieldForce Web Console — design-token system + component classes.
   Source of truth: design/design_handoff_fieldforce_web (README Design Tokens).
   Fluid layout: sidebar fixed 250px, content fills. Figtree everywhere.
   ============================================================ */
:root {
  /* Brand accent — PICASSO BLUE, after the palette of Picasso's Blue Period (ultramarine, Prussian,
     cobalt), aligned to the mobile app (#2A5DA8 / #1F4E93). It replaced coral (#F27166) in Sep 2026.
     Token names kept (--ff-teal*) so the whole console retints with no .razor edits.
     Contrast with white text: #2A5DA8 6.5:1, #1F4E93 8.2:1, #173B6E 11:1 — all AA. */
  --ff-teal: #2A5DA8;         /* brand accent — Picasso Blue */
  --ff-teal-deep: #1F4E93;    /* brand deep — Ultramarine: button fills / tab text */
  --ff-brand-strong: #173B6E; /* brand text — Prussian: wordmarks / .ff-tag */
  --ff-ink: #0F2A33;          /* primary text ink (shared with the app) */
  --ff-hero: #2A5DA8;         /* hero banner start (gradient → --ff-teal-deep) */
  --ff-cta-from: #2A5DA8;     /* CTA gradient start */
  --ff-cta-to: #1F4E93;       /* CTA gradient end */
  --ff-cta: #1F4E93;          /* solid CTA */
  --ff-canvas: #F4F7FB;       /* cool off-white (matches the app's background) */
  --ff-card: #FFFFFF;
  --ff-border: #DCE4EF;       /* cool border */
  --ff-hairline: #E9EEF5;
  --ff-thead: #F2F5FA;        /* cool table header */

  /* Text */
  --ff-text: #0F2A33;
  --ff-text-2: #5B7078;
  --ff-muted: #7A8F96;
  --ff-faint: #93A6AC;
  --ff-sidebar-muted: #A9BEC5;

  /* Status */
  --ff-success: #16A34A;   --ff-success-bg: #E7F6EC; --ff-success-tx: #15803D;
  --ff-warn: #F59E0B;      --ff-warn-bg: #FEF6E7;    --ff-warn-tx: #B45309;
  --ff-error: #DC2626;     --ff-error-bg: #FCE9E9;   --ff-error-tx: #B91C1C;
  /* Info — and travel — is teal, not blue: a blue here would read as the brand. Each theme keeps it
     apart from its own brand (see the theme blocks below; Ocean Teal turns it blue). */
  --ff-info: #0E7490;      --ff-info-bg: #E0F1F5;    --ff-info-tx: #155E75;
  --ff-purple: #7C3AED;    --ff-purple-bg: #F0EBFA;  --ff-purple-tx: #5B21B6;

  /* Accent tint tiles. --ff-tint-teal is the BRAND tint (Blue Wash) — pair it with the brand colour;
     --ff-tint-orange is a warm tile for warning and alert icons, never for the brand. */
  --ff-tint-teal: #E7EEF8;
  --ff-tint-green: #E7F6EC;
  --ff-tint-orange: #FDECE9;
  --ff-tint-purple: #F0EBFA;
  --ff-tint-amber: #FEF6E7;

  /* Radii / shadow */
  --ff-r-pill: 999px;
  --ff-r-card: 14px;
  --ff-r-input: 10px;
  --ff-r-tile: 10px;
  --ff-shadow-float: 0 6px 18px rgba(0,0,0,.14);
  --ff-shadow-toast: 0 8px 22px rgba(0,0,0,.3);
}

/* ---- Console-scoped base (does not touch login / MudBlazor pages) ---- */
.ff-console, .ff-console * { box-sizing: border-box; font-family: Figtree, system-ui, sans-serif; }
.ff-console { display: flex; height: 100vh; overflow: hidden; background: var(--ff-canvas); color: var(--ff-text); }

/* ---- Sidebar (grouped accordion, light) ---- */
:root {
  /* Light sidebar on the cool console; Picasso Blue accent. */
  --ff-nav-surface: #FFFFFF;   --ff-nav-hover: #EEF3FA;   --ff-nav-elevated: #E9EFF8;
  --ff-nav-accent: #2A5DA8;    --ff-nav-accent-tint: rgba(42,93,168,.12);
  --ff-nav-badge: #F59E0B;     --ff-nav-badge-soft: rgba(245,158,11,.16);
  --ff-nav-idle: #6E7E86;      --ff-nav-group: #0F2A33;   --ff-nav-section: #8FA0B8;
  --ff-nav-line: #E9EEF5;      --ff-nav-border: #DCE4EF;
  --ff-nav-input: #F4F7FB;     --ff-nav-input-line: #DCE4EF;
  --ff-nav-thumb: #D5DDE8;     --ff-nav-thumb-hover: #BCC8D8;
}

/* ---- Colour themes a user may choose (Settings → Appearance) ----
   The blocks above ARE Picasso Blue, the default. Each theme below redefines only the brand and the
   neutrals tuned to it; status colours never change, and info/travel stays apart from every brand.
   The server stamps data-ff-theme on <html> from the user's choice, so the page never flashes.

   The rule each theme keeps (pinned by ThemeCatalogTests, alongside UiThemes on the server and the
   app's theme.dart): white text on --ff-teal, --ff-teal-deep and --ff-cta reads at 4.5:1 or better,
   and the brand is at least 20° of hue from every status colour — except Coral Classic against error
   red, which the company chose knowing they sit close (errors always carry an icon and words too). */
:root[data-ff-theme="coral-classic"] {
  --ff-teal: #C54B2C;          --ff-teal-deep: #A63D22;   --ff-brand-strong: #82301B;
  --ff-hero: #C54B2C;          --ff-cta-from: #C54B2C;    --ff-cta-to: #A63D22;       --ff-cta: #A63D22;
  --ff-canvas: #FBF6F4;        --ff-border: #ECE2DE;      --ff-hairline: #F3EBE8;     --ff-thead: #FBF4F1;
  --ff-tint-teal: #FBEAE4;
  --ff-nav-hover: #F7EEEA;     --ff-nav-elevated: #F4E8E3;
  --ff-nav-accent: #C54B2C;    --ff-nav-accent-tint: rgba(197,75,44,.12);
  --ff-nav-section: #A08E88;   --ff-nav-line: #F0E8E5;    --ff-nav-border: #ECE2DE;
  --ff-nav-input: #FBF6F4;     --ff-nav-input-line: #ECE2DE;
  --ff-nav-thumb: #E3D6D1;     --ff-nav-thumb-hover: #CDBDB7;
}
:root[data-ff-theme="graphite"] {
  --ff-teal: #475569;          --ff-teal-deep: #334155;   --ff-brand-strong: #1E293B;
  --ff-hero: #475569;          --ff-cta-from: #475569;    --ff-cta-to: #334155;       --ff-cta: #334155;
  --ff-canvas: #F5F6F8;        --ff-border: #DDE1E6;      --ff-hairline: #EBEEF1;     --ff-thead: #F3F4F6;
  --ff-tint-teal: #E8EBEF;
  --ff-nav-hover: #EFF1F4;     --ff-nav-elevated: #E9ECF0;
  --ff-nav-accent: #475569;    --ff-nav-accent-tint: rgba(71,85,105,.12);
  --ff-nav-section: #949DA8;   --ff-nav-line: #EBEEF1;    --ff-nav-border: #DDE1E6;
  --ff-nav-input: #F5F6F8;     --ff-nav-input-line: #DDE1E6;
  --ff-nav-thumb: #D6DAE0;     --ff-nav-thumb-hover: #BEC4CC;
}
:root[data-ff-theme="plum"] {
  --ff-teal: #8E3A7C;          --ff-teal-deep: #742F65;   --ff-brand-strong: #58244D;
  --ff-hero: #8E3A7C;          --ff-cta-from: #8E3A7C;    --ff-cta-to: #742F65;       --ff-cta: #742F65;
  --ff-canvas: #F9F5F8;        --ff-border: #E9DFE6;      --ff-hairline: #F2EBF0;     --ff-thead: #F8F3F6;
  --ff-tint-teal: #F4E6F0;
  --ff-nav-hover: #F5EEF3;     --ff-nav-elevated: #F1E7EE;
  --ff-nav-accent: #8E3A7C;    --ff-nav-accent-tint: rgba(142,58,124,.12);
  --ff-nav-section: #A08C9A;   --ff-nav-line: #F2EBF0;    --ff-nav-border: #E9DFE6;
  --ff-nav-input: #F9F5F8;     --ff-nav-input-line: #E9DFE6;
  --ff-nav-thumb: #E4D7E0;     --ff-nav-thumb-hover: #CFBFCA;
}
:root[data-ff-theme="ocean-teal"] {
  --ff-teal: #0E7490;          --ff-teal-deep: #155E75;   --ff-brand-strong: #164E63;
  --ff-hero: #0E7490;          --ff-cta-from: #0E7490;    --ff-cta-to: #155E75;       --ff-cta: #155E75;
  --ff-canvas: #F3F8F9;        --ff-border: #D9E7EA;      --ff-hairline: #E8F1F3;     --ff-thead: #F1F7F8;
  --ff-tint-teal: #E0F1F5;
  /* Teal is the brand here, so info and travel turn blue. */
  --ff-info: #2563EB;          --ff-info-bg: #E5EDFB;     --ff-info-tx: #1D4ED8;
  --ff-nav-hover: #EBF5F7;     --ff-nav-elevated: #E3F0F3;
  --ff-nav-accent: #0E7490;    --ff-nav-accent-tint: rgba(14,116,144,.12);
  --ff-nav-section: #88A5AD;   --ff-nav-line: #E8F1F3;    --ff-nav-border: #D9E7EA;
  --ff-nav-input: #F3F8F9;     --ff-nav-input-line: #D9E7EA;
  --ff-nav-thumb: #D0E2E6;     --ff-nav-thumb-hover: #B6CFD5;
}
/* Shared, used OUTSIDE the sidebar too (topbar / profile / user lists / Messages) —
   keep the original look; the sidebar overrides these under .ff-sidebar below. */
.ff-avatar { width: 34px; height: 34px; border-radius: 50%; background: var(--ff-teal); color: #fff; display: flex; align-items: center; justify-content: center; font: 700 13px Figtree, sans-serif; flex: none; }
.ff-nav-badge { background: var(--ff-cta-from); color: #fff; font: 700 10px Figtree, sans-serif; border-radius: var(--ff-r-pill); padding: 2px 7px; }

.ff-sidebar, .ff-sidebar * { font-family: 'Hanken Grotesk', system-ui, sans-serif; }
/* position: relative so the rail's drawer can hang off it. HERE, above the drawer rule in the
   max-width: 1024px block below, which needs position: fixed to win — a media query adds no
   specificity, so the later of two equal rules is the one that applies. */
.ff-sidebar { width: 288px; flex: none; background: var(--ff-nav-surface); color: #0F2A33;
  display: flex; flex-direction: column; border-right: 1px solid var(--ff-nav-border);
  position: relative; transition: width .28s cubic-bezier(.4,0,.2,1); }
.ff-sidebar.is-rail { width: 70px; }

.ff-side-head { display: flex; align-items: center; gap: 11px; padding: 16px 14px 12px; }
.ff-side-logo { width: 34px; height: 34px; flex: none; border-radius: 9px; overflow: hidden;
  background: #fff; display: grid; place-items: center;
  box-shadow: 0 6px 16px -6px color-mix(in srgb, var(--ff-teal) 60%, transparent); }
/* The logo's shape (an alpha mask cut from logo.png) filled with the theme's brand, so it changes with the theme. */
.ff-logo-mark { display: block; width: 100%; height: 100%; background-color: var(--ff-teal);
  -webkit-mask: url(img/theme/logo-mask.png) center / 100% 100% no-repeat;
  mask: url(img/theme/logo-mask.png) center / 100% 100% no-repeat; }
.ff-side-brand { flex: 1; min-width: 0; }
.ff-side-brand-row { display: flex; align-items: center; gap: 7px; font: 700 15px 'Hanken Grotesk'; color: var(--ff-teal-deep); }
.ff-side-tag { font: 700 9.5px 'Hanken Grotesk'; letter-spacing: .08em; color: var(--ff-teal-deep);
  background: var(--ff-nav-accent-tint); padding: 2px 6px; border-radius: 5px; }
.ff-side-brand-sub { font: 500 11px 'Hanken Grotesk'; color: #7A8F96; margin-top: 1px; }
.ff-side-collapse { width: 30px; height: 30px; flex: none; border: 0; background: transparent;
  color: #7A8F96; border-radius: 8px; cursor: pointer; display: grid; place-items: center; }
.ff-side-collapse:hover { background: var(--ff-nav-hover); color: #0F2A33; }
.ff-sidebar.is-rail .ff-side-head { flex-direction: column; gap: 8px; padding: 16px 0 10px; }

.ff-side-search { display: flex; align-items: center; gap: 8px; margin: 0 14px 10px; padding: 0 10px;
  height: 38px; background: var(--ff-nav-input); border: 1px solid var(--ff-nav-input-line); border-radius: 10px; color: #7A8F96; }
.ff-side-search:focus-within { border-color: var(--ff-teal-deep); }
.ff-side-search input { flex: 1; min-width: 0; border: 0; background: transparent; outline: none;
  color: #0F2A33; font: 500 13px 'Hanken Grotesk'; }
.ff-side-search-clear { border: 0; background: transparent; color: #7A8F96; cursor: pointer; display: grid; place-items: center; padding: 0; }

.ff-nav { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 2px 10px 12px; display: flex; flex-direction: column; }
/* Thin, subtle scrollbar that blends into the light nav surface. */
.ff-sidebar .ff-nav { scrollbar-width: thin; scrollbar-color: var(--ff-nav-thumb) transparent; }
.ff-sidebar .ff-nav::-webkit-scrollbar { width: 8px; }
.ff-sidebar .ff-nav::-webkit-scrollbar-track { background: transparent; }
.ff-sidebar .ff-nav::-webkit-scrollbar-thumb { background: var(--ff-nav-thumb); border-radius: 99px; border: 2px solid transparent; background-clip: content-box; }
.ff-sidebar .ff-nav::-webkit-scrollbar-thumb:hover { background: var(--ff-nav-thumb-hover); background-clip: content-box; }
.ff-sidebar.is-rail .ff-nav { align-items: center; padding: 2px 0 12px; gap: 3px; }
.ff-nav-section { font: 700 10.5px 'Hanken Grotesk'; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ff-nav-section); padding: 12px 8px 4px; }

/* group header (accordion parent) + direct link */
.ff-nav-group { display: flex; align-items: center; gap: 10px; width: 100%; border: 0; cursor: pointer;
  background: transparent; text-align: left; color: var(--ff-nav-group); font: 600 12.5px 'Hanken Grotesk';
  padding: 7px 8px; border-radius: 9px; text-decoration: none; margin-bottom: 1px; }
.ff-nav-group:hover { background: var(--ff-nav-elevated); }
.ff-nav-group.has-active, .ff-nav-group--link.active { color: var(--ff-teal-deep); }
.ff-nav-gicon { width: 27px; height: 27px; flex: none; display: grid; place-items: center; border-radius: 8px;
  color: #7A8F96; padding: 4px; }
.ff-nav-group.has-active .ff-nav-gicon, .ff-nav-group--link.active .ff-nav-gicon {
  color: var(--ff-nav-accent); background: var(--ff-nav-accent-tint); }
.ff-nav-group .ff-nav-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ff-chev { width: 15px; height: 15px; flex: none; color: var(--ff-nav-section); transform: rotate(-90deg); transition: transform .24s; display: grid; place-items: center; }
.ff-chev.is-open { transform: rotate(0deg); }

/* animated children wrapper */
.ff-nav-children { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .26s cubic-bezier(.4,0,.2,1); }
.ff-nav-children.is-open { grid-template-rows: 1fr; }
.ff-nav-children-inner { min-height: 0; overflow: hidden; }

/* child link */
.ff-nav-item { position: relative; display: flex; align-items: center; gap: 8px; padding: 6px 10px 6px 30px;
  border-radius: 8px; color: var(--ff-nav-idle); font: 500 12.5px 'Hanken Grotesk'; text-decoration: none; cursor: pointer; }
.ff-nav-item:hover { background: var(--ff-nav-hover); color: #0F2A33; }
.ff-nav-item.active { background: var(--ff-nav-accent-tint); color: var(--ff-teal-deep); font-weight: 600; box-shadow: inset 2px 0 0 var(--ff-nav-accent); }
.ff-nav-dot { position: absolute; left: 15px; top: 50%; transform: translateY(-50%); width: 5px; height: 5px; border-radius: 50%; background: var(--ff-nav-thumb-hover); }
.ff-nav-item.active .ff-nav-dot { background: var(--ff-nav-accent); }
.ff-nav-item .ff-nav-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* badges (scoped to the sidebar so the shared .ff-nav-badge keeps its global look elsewhere) */
.ff-sidebar .ff-nav-badge { flex: none; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px;
  background: var(--ff-nav-badge); color: #231704; font: 700 11px 'Hanken Grotesk'; display: inline-grid; place-items: center; font-variant-numeric: tabular-nums; }
.ff-sidebar .ff-nav-badge--soft { background: var(--ff-nav-badge-soft); color: #B45309; }

/* collapsed icon rail */
.ff-rail-btn { position: relative; width: 46px; height: 42px; flex: none; display: grid; place-items: center;
  border: 0; background: transparent; color: #7A8F96; border-radius: 11px; cursor: pointer; }
.ff-rail-btn:hover { background: var(--ff-nav-hover); color: #0F2A33; }
.ff-rail-btn.active { background: var(--ff-nav-accent-tint); color: var(--ff-teal-deep); box-shadow: inset 2px 0 0 var(--ff-nav-accent); }
.ff-rail-badge { position: absolute; top: 4px; right: 5px; min-width: 15px; height: 15px; padding: 0 3px; border-radius: 999px;
  background: var(--ff-nav-badge); color: #231704; font: 700 9.5px 'Hanken Grotesk'; display: grid; place-items: center; border: 1.5px solid var(--ff-nav-surface); font-variant-numeric: tabular-nums; }

/* footer */
.ff-side-foot { border-top: 1px solid var(--ff-nav-line); padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; }
.ff-sidebar.is-rail .ff-side-foot { align-items: center; padding: 10px 0; }
.ff-side-user { display: flex; align-items: center; gap: 10px; }
.ff-sidebar .ff-avatar { width: 32px; height: 32px; border-radius: 9px;
  background: linear-gradient(150deg, var(--ff-teal), var(--ff-teal-deep)); font: 700 12px 'Hanken Grotesk'; }
.ff-side-user-meta { flex: 1; min-width: 0; }
.ff-sidebar .ff-user-name { font: 600 13px 'Hanken Grotesk'; color: #0F2A33; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ff-sidebar .ff-user-role { font: 500 11px 'Hanken Grotesk'; color: #7A8F96; }
.ff-side-bell { position: relative; width: 32px; height: 32px; flex: none; color: #7A8F96; border-radius: 8px; display: grid; place-items: center; }
.ff-side-bell-dot { position: absolute; top: 5px; right: 6px; width: 7px; height: 7px; border-radius: 50%; background: var(--ff-nav-badge); border: 1.5px solid var(--ff-nav-surface); }
.ff-sidebar-foot { font: 500 10.5px 'Hanken Grotesk'; color: #93A6AC; padding-left: 2px; }

@media (prefers-reduced-motion: reduce) {
  .ff-sidebar, .ff-nav-children, .ff-chev { transition: none; }
}

/* ---- Topbar ---- */
.ff-main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.ff-topbar { height: 64px; flex: none; background: #fff; border-bottom: 1px solid var(--ff-border); display: flex; align-items: center; gap: 16px; padding: 0 24px; }
.ff-title-block { flex: 0 1 auto; min-width: 0; overflow: hidden; }
.ff-title { font: 800 18px Figtree, sans-serif; color: var(--ff-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ff-crumb { font: 500 11.5px Figtree, sans-serif; color: var(--ff-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ff-search { flex: 1 1 130px; min-width: 0; display: flex; align-items: center; gap: 8px; background: var(--ff-canvas); border: 1px solid var(--ff-border); border-radius: var(--ff-r-input); padding: 8px 12px; }
.ff-search input { border: none; outline: none; background: transparent; font: 500 13px Figtree, sans-serif; width: 100%; color: var(--ff-text); }
.ff-topbar-ctl { flex: none; display: flex; align-items: center; gap: 6px; }
.ff-bell { position: relative; width: 38px; height: 38px; border-radius: var(--ff-r-input); display: flex; align-items: center; justify-content: center; color: var(--ff-text-2); cursor: pointer; }
.ff-bell-count { position: absolute; top: 2px; right: 2px; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px; background: var(--ff-error); color: #fff; font: 700 9.5px Figtree, sans-serif; display: flex; align-items: center; justify-content: center; border: 2px solid #fff; }

/* ---- Topbar: hamburger, search results, profile menu ---- */
/* The nav toggle only exists on mobile, where the sidebar is an off-canvas drawer;
   desktop keeps the sidebar as a static column with its own rail collapse. */
.ff-nav-toggle { display: none; }
.ff-iconbtn { width: 38px; height: 38px; flex: none; border: none; background: none; border-radius: var(--ff-r-input); display: flex; align-items: center; justify-content: center; color: var(--ff-text-2); cursor: pointer; }
.ff-iconbtn:hover { background: var(--ff-canvas); }
.ff-search-results { position: absolute; top: calc(100% + 6px); left: 0; right: 0; background: #fff; border: 1px solid var(--ff-border); border-radius: 12px; box-shadow: var(--ff-shadow-float); z-index: 80; max-height: 380px; overflow-y: auto; padding: 6px; }
.ff-search-group { font: 700 10px Figtree, sans-serif; letter-spacing: .06em; text-transform: uppercase; color: var(--ff-muted); padding: 8px 10px 4px; }
.ff-search-hit { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 8px; cursor: pointer; }
.ff-search-hit:hover, .ff-search-hit.is-active { background: var(--ff-canvas); }
.ff-search-hit b { font: 600 12.5px Figtree, sans-serif; color: var(--ff-ink); }
.ff-search-hit span { font: 500 11.5px Figtree, sans-serif; color: var(--ff-muted); }
.ff-search-hit-ic { display: flex; flex: none; color: var(--ff-muted); }
.ff-hl { background: transparent; color: var(--ff-teal); font-weight: 800; }

/* Searchable select (combobox) */
.ff-ss { position: relative; }
.ff-ss-btn { display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%; text-align: left; cursor: pointer; }
.ff-ss-btn:disabled { opacity: .55; cursor: not-allowed; }
.ff-ss-ph { color: var(--ff-muted); }
.ff-ss-chev { flex: none; color: var(--ff-muted); display: flex; }
.ff-ss-panel { padding: 6px; }
.ff-ss-input { width: 100%; border: 1px solid var(--ff-border); border-radius: 8px; outline: none; font: 500 13px Figtree, sans-serif; color: var(--ff-text); padding: 8px 10px; margin-bottom: 4px; }
.ff-ss-input:focus { border-color: var(--ff-teal); }
/* 340, not 300: a two-line row is ~12px taller, and the taller list keeps about as many of them in
   view as the one-line row used to show. */
.ff-ss-list { max-height: 340px; overflow-y: auto; }

/* Keep a floating panel's own scroll inside it. Without this, wheeling past the last option chains
   the remainder to .ff-modal underneath, which is a genuine OUTER scroll — so ffDropdown dismisses
   the panel exactly as somebody reaches the option they were scrolling for. Both of the panel's
   scrollers: the root is one and .ff-ss-list inside it is the other.

   Scoped to .ff-ss-float, NOT to .ff-search-results, which the topbar omnisearch also wears. That
   one is position:absolute, closes on blur, and has no dismiss-on-scroll to protect. */
.ff-ss-float, .ff-ss-list { overscroll-behavior: contain; }
/* A combobox row is two lines: the name, and under it whatever tells it apart from the name above.
   One line could only ever wrap. The panel is as wide as the field it hangs under — 280px on a
   filter column — so "MOHAMMAD LATIF PAMPORI [RSM] · Emp-150" broke at the bracket AND split the
   code after its hyphen, because nothing said Emp-150 was one token.

   Both lines are declared outright rather than left to `.ff-search-hit span`, which paints every
   span in a row the same muted 11.5px: the name is the thing being read and has to look like it.
   The selectors carry .ff-search-hit so they outrank that rule, which is earlier in this file. */
.ff-search-hit .ff-ss-txt { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 1px; }
.ff-search-hit .ff-ss-name { font: 600 12.5px Figtree, sans-serif; color: var(--ff-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* nowrap on the detail line as well: it is short, and "Emp-" over "150" is the failure this fixes. */
.ff-search-hit .ff-ss-sub { font: 500 11.5px Figtree, sans-serif; color: var(--ff-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ff-ss-sub { color: var(--ff-muted); font: 500 11.5px Figtree, sans-serif; }
/* The closed control has ONE line and no second one to overflow into, so a long choice is cut
   rather than allowed to wrap and make the field two rows tall. The chevron is already flex:none. */
.ff-ss-btn > span:first-child { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ff-ss-empty { cursor: default; }
.ff-ss-add { width: 100%; margin-top: 4px; border: 0; border-top: 1px solid var(--ff-hairline); background: none; text-align: left; font: 600 12.5px Figtree, sans-serif; color: var(--ff-brand-strong); }
/* Combobox panels only. ffDropdown supplies top/left/width/max-height once the trigger has been
   measured; fixed is what gets the panel out of .ff-table-wrap, .ff-card-scroll and .ff-modal, each
   of which is a scroll container that clips it. The PANEL's z-index clears .ff-modal-scrim (1100)
   and stays under .ff-toast (1200) — its scrim is a separate rule below, and used not to. The
   topbar omnisearch and profile menu keep plain .ff-search-results — they are anchored at the top
   of the screen and can never run out of room. */
/* border-box is load-bearing, not tidiness: the panel has 6px padding and a 1px border, and this
   sheet sets no global box-sizing, so under content-box a max-height of N renders N+14 and the
   panel overhangs the very edge it was measured to fit inside. */
/* A negative money cell: a sales return that outweighed the sales in that month. Colour AND the
   minus sign, never colour alone — the figure has to read correctly in a printed or exported grid
   and to anyone who cannot distinguish the hue. */
.ff-neg { color: var(--ff-error-tx, #B03A24); }

/* A drill-down on a grid cell.

   This used to be `color: inherit; text-decoration: none` with nothing at rest, on the reasoning
   that keeping the ink colour made it "discoverable without hovering every cell". That was exactly
   backwards: keeping the ink colour and dropping the underline made a clickable amount render
   pixel-identical to a plain number, and a screen of them read as an ordinary read-only grid.

   So: a dotted rule at rest — present enough to say "this does something", quiet enough that a
   column of them is not a wall of underlines — going solid on hover.

   The rest colour is deliberately NEUTRAL, not the brand. A brand-blue rule under every figure in
   a money column turns the grid into a wall of links, and colour already has one meaning here: a
   negative amount is red (#B91C1C), a sales return. Grey says "interactive" and says nothing else.
   The figure keeps its own ink throughout, so a negative stays red and its minus sign still carries
   the meaning for anyone who cannot separate the hues. */
.ff-row-link { color: inherit; text-decoration: none; cursor: pointer;
               border-bottom: 1px dotted var(--ff-muted); }
.ff-row-link:hover { color: var(--ff-brand-strong); border-bottom: 1px solid var(--ff-brand-strong); }
/* A negative keeps its own red on hover: turning it brand blue would drop the "this is a return" cue
   at the very moment the reader is looking at that figure. */
.ff-neg .ff-row-link:hover { color: var(--ff-error-tx); border-bottom-color: var(--ff-error-tx); }

/* An inline action inside a sentence — "Use it" beside the period a file states. A button, not a
   link, because it changes a value on this page rather than navigating anywhere. */
.ff-link-btn { border: 0; background: none; padding: 0 0 0 4px; cursor: pointer;
               font: 700 12px Figtree, sans-serif; color: var(--ff-brand-strong); text-decoration: underline; }

.ff-ss-float { position: fixed; z-index: 1150; box-sizing: border-box; }

/* The floating panel's outside-click catcher, one below the panel it belongs to.

   COMPOUND, not `.ff-scrim-float` alone, and that is the whole point of this rule. The element
   wears `ff-scrim-transparent ff-scrim-float`, and `.ff-scrim-transparent { z-index: 70 }` sits
   further down this file at equal specificity (0,0,1,0) — so the single-class version lost on
   source order and the scrim resolved to 70, not 1149. Verified in a browser: getComputedStyle
   read 70. Two classes make it (0,0,2,0), which wins wherever either rule is moved to.

   70 is right for the OTHER user of that class — the topbar profile menu's scrim, which pairs with
   .ff-menu at 80 and must sit under it. So the base value stays and this narrows it. */
.ff-scrim-transparent.ff-scrim-float { z-index: 1149; }
.ff-kbd { flex: none; font: 700 10px Figtree, sans-serif; color: var(--ff-muted); background: #fff; border: 1px solid var(--ff-border); border-radius: 6px; padding: 2px 6px; letter-spacing: .03em; white-space: nowrap; }
.ff-menu { position: absolute; top: calc(100% + 8px); right: 0; width: 220px; background: #fff; border: 1px solid var(--ff-border); border-radius: 12px; box-shadow: var(--ff-shadow-float); z-index: 80; overflow: hidden; }
.ff-menu-head { padding: 12px 14px; border-bottom: 1px solid var(--ff-hairline); }
.ff-menu-item { display: flex; align-items: center; gap: 10px; padding: 11px 14px; font: 600 13px Figtree, sans-serif; color: var(--ff-text); text-decoration: none; cursor: pointer; width: 100%; border: none; background: none; text-align: left; }
.ff-menu-item:hover { background: var(--ff-canvas); }
.ff-menu-item.danger { color: var(--ff-error); border-top: 1px solid var(--ff-hairline); }

/* FieldMasterRightsCard: who may add which master record, as a grid of master × field role. */
.ff-rights { display: flex; flex-direction: column; gap: 12px; }
.ff-rights-table .ff-rights-col { text-align: center; width: 72px; }
.ff-rights-table input[type="checkbox"] { width: 17px; height: 17px; accent-color: var(--ff-teal); cursor: pointer; }
.ff-rights-table input[type="checkbox"]:disabled { cursor: default; }
.ff-rights-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }

/* DateRangePill: two dates in one pill, on one line at a header button's height, with quick ranges.
   Each date is a native date input laid invisibly over the words; its picker indicator is stretched
   over the whole input so a click anywhere in the date opens the browser's own calendar. */
.ff-range-group { display: flex; align-items: center; gap: 8px; flex: none; }
.ff-range-label { font: 600 12px Figtree, sans-serif; color: var(--ff-muted); white-space: nowrap; }
.ff-range { display: inline-flex; align-items: center; gap: 2px; height: 36px; padding: 0 4px 0 11px;
  background: #fff; border: 1px solid var(--ff-border); border-radius: 999px; white-space: nowrap;
  transition: border-color .15s, box-shadow .15s; }
.ff-range:hover { border-color: color-mix(in srgb, var(--ff-teal) 35%, var(--ff-border)); }
.ff-range:focus-within { border-color: var(--ff-teal); box-shadow: 0 0 0 3px var(--ff-nav-accent-tint); }
.ff-range.is-set { border-color: color-mix(in srgb, var(--ff-teal) 55%, var(--ff-border)); background: var(--ff-canvas); }
.ff-range-icon { display: inline-flex; color: var(--ff-muted); margin-right: 3px; }
.ff-range.is-set .ff-range-icon { color: var(--ff-teal); }
.ff-range-seg { position: relative; display: inline-flex; align-items: center; height: 28px; padding: 0 8px;
  border-radius: 8px; font: 600 13px Figtree, sans-serif; color: var(--ff-ink); cursor: pointer; }
.ff-range-seg:hover { background: var(--ff-tint-teal); }
.ff-range-seg.is-empty { color: var(--ff-muted); font-weight: 500; }
.ff-range-input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0;
  border: 0; opacity: 0; cursor: pointer; font-size: 16px; }
.ff-range-input::-webkit-calendar-picker-indicator { position: absolute; inset: 0; width: auto; height: auto;
  margin: 0; padding: 0; cursor: pointer; }
.ff-range-arrow { display: inline-flex; color: var(--ff-faint); }
.ff-range-clear { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px;
  margin-left: 2px; border: 0; border-radius: 50%; background: var(--ff-tint-teal); color: var(--ff-teal-deep); cursor: pointer; }
.ff-range-clear:hover { background: var(--ff-teal); color: #fff; }
.ff-range-quick { position: relative; }
.ff-range-quick-btn { display: inline-flex; align-items: center; gap: 6px; height: 36px; padding: 0 12px;
  border: 1px solid var(--ff-border); border-radius: 999px; background: #fff; cursor: pointer;
  font: 600 13px Figtree, sans-serif; color: var(--ff-text-2); white-space: nowrap; }
.ff-range-quick-btn:hover, .ff-range-quick-btn.is-open { border-color: var(--ff-teal); color: var(--ff-teal-deep); }
.ff-range, .ff-range-quick-btn { box-sizing: border-box; }
.ff-range-menu { width: 320px; }
.ff-range-menu .ff-menu-item { white-space: nowrap; gap: 16px; }
.ff-range-menu .ff-menu-item.is-on { background: var(--ff-tint-teal); color: var(--ff-teal-deep); }
.ff-range-menu-dates { font: 500 12px Figtree, sans-serif; color: var(--ff-muted); }
@media (max-width: 720px) {
  .ff-range-group { flex: 1 1 100%; flex-wrap: wrap; }
  .ff-range-label { flex: 1 1 100%; }
  .ff-range { flex: 1 1 auto; justify-content: space-between; }
}
.ff-scrim-transparent { position: fixed; inset: 0; z-index: 70; }

/* ---- Content ---- */
/* The top padding is a BLOCK rather than padding, so a sticky table heading pins flush under
   the application header instead of 24px below it with rows showing through the gap. Sticky
   top: 0 resolves against the scrollport, and the scrollport starts inside the padding. The two
   render identically; see .ff-table--sticky. */
.ff-content { flex: 1; overflow-y: auto; padding: 0 24px 24px; }
.ff-content::before { content: ""; display: block; height: 24px; }
/* The same 24px, named, because a frozen column has to add it back. scrollWidth on an overflowing
   box leaves the right padding out, so the scroll stops a gutter short of the content and a column
   pinned to right:0 is still sitting on the column before it at the end of the travel. Keep this in
   step with the padding above and with the 640px override. See .ff-table--pin-end. */
:root { --ff-gutter: 24px; }
.ff-grid { display: grid; gap: 16px; }
.ff-grid-4 { grid-template-columns: repeat(4, 1fr); }
.ff-grid-3 { grid-template-columns: repeat(3, 1fr); }
.ff-grid-2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 1100px) { .ff-grid-4 { grid-template-columns: repeat(2, 1fr); } .ff-grid-3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 680px)  { .ff-grid-4, .ff-grid-3, .ff-grid-2 { grid-template-columns: 1fr; } }
/* Masonry-style packing for uneven-height cards (e.g. Configuration) — cards flow
   and fill vertically instead of a grid row taking the tallest card's height. */
.ff-config-grid { column-count: 2; column-gap: 16px; }
.ff-config-grid > .ff-card { break-inside: avoid; margin-bottom: 16px; }
@media (max-width: 680px) { .ff-config-grid { column-count: 1; } }

/* ---- Card ---- */
.ff-card { background: var(--ff-card); border: 1px solid var(--ff-border); border-radius: var(--ff-r-card); }
.ff-card-pad { padding: 18px; }
.ff-card-head { display: flex; align-items: center; gap: 12px; padding: 16px 18px; border-bottom: 1px solid var(--ff-hairline); }
.ff-card-title { font: 700 14px Figtree, sans-serif; color: var(--ff-ink); }
.ff-card-sub { font: 500 12px Figtree, sans-serif; color: var(--ff-muted); }
.ff-card-foot { padding: 12px 18px; border-top: 1px solid var(--ff-hairline); display: flex; align-items: center; gap: 8px; font: 500 11.5px Figtree, sans-serif; color: var(--ff-muted); }

/* ---- Stat card ---- */
.ff-stat { background: var(--ff-card); border: 1px solid var(--ff-border); border-radius: var(--ff-r-card); padding: 16px; }
.ff-stat-top { display: flex; justify-content: space-between; align-items: flex-start; }
.ff-stat-label { font: 600 12px Figtree, sans-serif; color: var(--ff-muted); }
.ff-stat-icon { width: 30px; height: 30px; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex: none; }
.ff-stat-value { display: block; font: 800 28px Figtree, sans-serif; color: var(--ff-ink); margin-top: 8px; }
.ff-stat-sub { font: 500 11.5px Figtree, sans-serif; margin-top: 2px; }

/* ---- Table ---- */
.ff-table { width: 100%; border-collapse: collapse; }
.ff-table thead tr { background: var(--ff-thead); }
.ff-table th { text-align: left; font: 700 10.5px Figtree, sans-serif; letter-spacing: .05em; color: var(--ff-muted); padding: 11px 18px; text-transform: uppercase; }
.ff-table td { padding: 13px 18px; font: 600 12.5px Figtree, sans-serif; color: var(--ff-ink); border-top: 1px solid var(--ff-hairline); vertical-align: middle; }
.ff-cell-muted { color: var(--ff-text-2); font-weight: 500; }
.ff-name-cell { display: flex; align-items: center; gap: 10px; }

/* ---- Pills / badges ---- */
.ff-pill { display: inline-flex; align-items: center; gap: 5px; font: 600 11px Figtree, sans-serif; border-radius: var(--ff-r-pill); padding: 4px 9px; }
.ff-pill .dot { width: 6px; height: 6px; border-radius: 50%; }
.ff-pill--success { color: var(--ff-success-tx); background: var(--ff-success-bg); } .ff-pill--success .dot { background: var(--ff-success); }
.ff-pill--warn    { color: var(--ff-warn-tx);    background: var(--ff-warn-bg); }    .ff-pill--warn .dot { background: var(--ff-warn); }
.ff-pill--error   { color: var(--ff-error-tx);   background: var(--ff-error-bg); }   .ff-pill--error .dot { background: var(--ff-error); }
.ff-pill--info    { color: var(--ff-info-tx);    background: var(--ff-info-bg); }    .ff-pill--info .dot { background: var(--ff-info); }
.ff-pill--purple  { color: var(--ff-purple-tx);  background: var(--ff-purple-bg); }  .ff-pill--purple .dot { background: var(--ff-purple); }
.ff-pill--muted   { color: var(--ff-text-2);     background: var(--ff-hairline); }   .ff-pill--muted .dot { background: var(--ff-faint); }
.ff-tag { font: 700 10px Figtree, sans-serif; border-radius: 6px; padding: 3px 9px; color: var(--ff-brand-strong); background: var(--ff-tint-teal); }

/* ---- Inline error message ----
   .ff-error was used on ~30 console pages and 53 call sites without ever being defined, so
   every server error rendered as unstyled body text — the same weight and colour as the form
   label above it. The message an admin most needs to notice was the one hardest to see.

   Uses the existing error triple and no border, so it reads as the same family as
   .ff-pill--error — the status colours here are triples (base/bg/tx) and adding a fourth
   border token for one rule would break that pattern for everything else.

   overflow-wrap matters more than it looks: these carry server text, and an unbroken file
   name or GUID would otherwise push the whole card sideways. */
.ff-error { padding: 10px 12px; border-radius: 9px; background: var(--ff-error-bg); color: var(--ff-error-tx); font: 600 12.5px Figtree, sans-serif; overflow-wrap: anywhere; }

/* ---- Inline warning message ----
   Exactly the same story as .ff-error above, one screen over: .ff-warn was used on the sales-import
   and import-profile screens and defined nowhere, so "Totals check overruled" — a banner whose
   whole job is to be noticed months later by whoever opens the batch — rendered as plain body text.
   Found while adding a second banner beside it, which would have inherited the same fate.

   Same shape as .ff-error, on the warn triple, so the two read as one family. */
.ff-warn { padding: 10px 12px; border-radius: 9px; background: var(--ff-warn-bg); color: var(--ff-warn-tx); font: 600 12.5px Figtree, sans-serif; overflow-wrap: anywhere; }

/* ---- Buttons ---- */
.ff-btn { display: inline-flex; align-items: center; gap: 7px; font: 700 12.5px Figtree, sans-serif; border-radius: 9px; padding: 9px 16px; border: 1px solid transparent; cursor: pointer; text-decoration: none; }
.ff-btn--cta { color: #fff; background: linear-gradient(90deg, var(--ff-cta-from), var(--ff-cta-to)); }
.ff-btn--primary { color: #fff; background: var(--ff-teal); }
.ff-btn--success { color: #fff; background: var(--ff-success); }
.ff-btn--danger-o { color: var(--ff-error); border-color: var(--ff-error); background: #fff; }
.ff-btn--ghost { color: var(--ff-text-2); border-color: var(--ff-border); background: #fff; }
.ff-btn:disabled { opacity: .5; cursor: not-allowed; }

/* ---- Chips ---- */
.ff-chips { display: flex; gap: 8px; flex-wrap: wrap; }
/* The budget filter's area chips. A patch runs to 145 areas on the live tenant, so the row is
   bounded and scrolls rather than pushing the rest of the form off the screen. */
.ff-cbr-areas { max-height: 150px; overflow-y: auto; align-content: flex-start; padding: 2px; }
.ff-chip { font: 600 12.5px Figtree, sans-serif; color: #33565F; background: #fff; border: 1px solid var(--ff-border); border-radius: var(--ff-r-pill); padding: 8px 15px; cursor: pointer; }
.ff-chip.active { color: #fff; background: var(--ff-teal); border-color: var(--ff-teal); font-weight: 700; }
/* Selected items as removable chips in a single horizontally-scrollable row. */
.ff-chip-row { display: flex; gap: 8px; flex-wrap: nowrap; overflow-x: auto; padding-bottom: 4px; -webkit-overflow-scrolling: touch; }
.ff-chip-row .ff-chip { flex: 0 0 auto; white-space: nowrap; cursor: default; display: inline-flex; align-items: center; }
.ff-chip-x { border: 0; background: transparent; color: inherit; font: inherit; font-size: 15px; line-height: 1; margin-left: 7px; padding: 0; cursor: pointer; opacity: .8; }
.ff-chip-x:hover { opacity: 1; }

/* ---- Toggle ---- */
.ff-toggle { width: 48px; height: 28px; border-radius: 14px; background: #C6D2D6; display: inline-flex; align-items: center; padding: 3px; cursor: pointer; transition: background .15s; justify-content: flex-start; }
.ff-toggle.on { background: var(--ff-success); justify-content: flex-end; }
.ff-toggle .knob { width: 22px; height: 22px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.25); }

/* ---- Qty stepper ---- */
.ff-stepper { display: inline-flex; align-items: center; gap: 10px; }
.ff-stepper button { width: 26px; height: 26px; border-radius: 7px; border: 1px solid var(--ff-border); background: #fff; color: var(--ff-text-2); cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 16px; line-height: 1; }
.ff-stepper .val { font: 600 13px Figtree, sans-serif; color: var(--ff-ink); min-width: 18px; text-align: center; }

/* ---- Progress ---- */
.ff-progress { height: 8px; border-radius: 4px; background: var(--ff-hairline); overflow: hidden; }
.ff-progress > i { display: block; height: 100%; border-radius: 4px; background: var(--ff-teal); }

/* ---- Ring gauge ---- */
.ff-ring { position: relative; width: 120px; height: 120px; flex: none; }
.ff-ring-face { width: 120px; height: 120px; border-radius: 50%; }
.ff-ring-hole { position: absolute; inset: 12px; border-radius: 50%; background: #fff; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.ff-ring-val { font: 800 26px Figtree, sans-serif; color: var(--ff-ink); }
.ff-ring-cap { font: 500 10px Figtree, sans-serif; color: var(--ff-muted); }

/* ---- Approval row ---- */
.ff-approval { display: flex; align-items: center; gap: 16px; padding: 16px 18px; }
.ff-approval-icon { width: 42px; height: 42px; border-radius: 11px; display: flex; align-items: center; justify-content: center; flex: none; }
.ff-approval-body { flex: 1; min-width: 0; }
.ff-approval-title { display: flex; align-items: center; gap: 8px; font: 700 14px Figtree, sans-serif; color: var(--ff-ink); }
.ff-approval-detail { font: 500 12px Figtree, sans-serif; color: var(--ff-text-2); margin-top: 2px; }
.ff-approval-actions { display: flex; align-items: center; gap: 10px; flex: none; }

/* ---- Icon tile (reports) ---- */
.ff-tile { cursor: pointer; }
.ff-tile-head { display: flex; align-items: center; gap: 10px; }
.ff-tile-icon { width: 38px; height: 38px; border-radius: var(--ff-r-tile); display: flex; align-items: center; justify-content: center; flex: none; }
.ff-tile-title { flex: 1; font: 700 13.5px Figtree, sans-serif; color: var(--ff-ink); }
.ff-tile-desc { display: block; font: 500 11.5px Figtree, sans-serif; color: var(--ff-muted); margin-top: 9px; }

/* ---- Map canvas ---- */
.ff-map { background: #E9F1EC; border-radius: var(--ff-r-card); position: relative; min-height: 560px; overflow: hidden; }
.ff-map-pin { position: absolute; width: 40px; height: 40px; border-radius: 50%; border: 3px solid #fff; box-shadow: 0 2px 10px rgba(0,0,0,.28); display: flex; align-items: center; justify-content: center; color: #fff; font: 800 12px Figtree, sans-serif; }
.ff-pulse { animation: ffpulseg 2.2s infinite; }

/* ---- Toast ---- */
.ff-toast { position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%); background: var(--ff-ink); color: #fff; font: 600 13px Figtree, sans-serif; border-radius: var(--ff-r-pill); padding: 12px 20px; box-shadow: var(--ff-shadow-toast); display: flex; align-items: center; gap: 9px; z-index: 1200; animation: fftoast .25s ease; }
.ff-toast-check { width: 19px; height: 19px; border-radius: 50%; background: var(--ff-success); display: flex; align-items: center; justify-content: center; flex: none; color: #fff; }

/* ---- Modal ---- */
.ff-modal-scrim { position: fixed; inset: 0; background: rgba(15,42,51,.4); display: flex; align-items: center; justify-content: center; z-index: 1100; padding: 24px; }
.ff-modal { background: #fff; border-radius: var(--ff-r-card); width: 100%; max-width: 480px; max-height: 90vh; overflow-y: auto; box-shadow: 0 20px 60px rgba(15,42,51,.22); }
.ff-modal--wide { max-width: 920px; }

/* A form wide enough for two columns.

   The user form asks twenty-three questions. At the default 480px every one of them was a
   full-width box stacked in a column half a screen tall, so the eye travelled the whole way down
   to find anything and the three-across rows inside it came out 150px each. min() rather than a
   flat 1180: on a 1280 laptop a fixed one would run edge to edge and the scrim - which is what
   says "this is a dialog" - would disappear. */
.ff-modal--xl { max-width: min(1180px, 92vw); }

/* The first heading in a body needs no rule above it: the modal header is already the line. */
.ff-modal-body > .ff-form-rule:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
/* space-between, so the close control sits in the CORNER. Modal.razor gets there anyway
   because .ff-modal-title carries flex:1, but a dialog that lays out its own header (a title
   over a subtitle, say) has no such child - and its X ended up tucked against the title text
   instead of the top right. The gap keeps the two apart when the title is long. */
.ff-modal-head { display: flex; align-items: center; justify-content: space-between; gap: 12px;
                 padding: 18px; border-bottom: 1px solid var(--ff-hairline); }
.ff-modal-title { font: 700 15px Figtree, sans-serif; color: var(--ff-ink); flex: 1; }
.ff-modal-body { padding: 18px; display: flex; flex-direction: column; gap: 14px; }
.ff-modal-foot { padding: 14px 18px; border-top: 1px solid var(--ff-hairline); display: flex; justify-content: flex-end; gap: 10px; }

/* ---- Form fields ---- */
/* min-width: 0 because a grid track is minmax(auto, 1fr), and "auto" is the content's MIN-content
   size — so one field holding something that cannot wrap pushes its column past its share and
   squeezes its neighbours. Costs nothing when the content fits. */
.ff-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.ff-label { font: 600 12px Figtree, sans-serif; color: var(--ff-text-2); }
/* Explanatory line under a field. Was repeated as an inline style in several places. */
.ff-hint { font: 500 12px Figtree, sans-serif; color: var(--ff-muted); }
/* A tickable row in a long pick list (products under a brand, visuals in a batch). */
.ff-check-row { display: flex; align-items: center; gap: 9px; padding: 7px 4px; cursor: pointer;
                border-bottom: 1px solid var(--ff-hairline); font: 500 13px Figtree, sans-serif; }
.ff-check-row:last-child { border-bottom: 0; }
.ff-check-row:hover { background: var(--ff-thead); }
/* The two company banner slots, side by side above the brand list. */
.ff-banner-slots { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; }
.ff-banner-slot { display: flex; flex-direction: column; gap: 7px; align-items: flex-start;
                  padding: 12px; border: 1px solid var(--ff-border); border-radius: 10px; }
.ff-banner-have { font: 600 13px Figtree, sans-serif; }
.ff-input, .ff-select { box-sizing: border-box; width: 100%; padding: 9px 11px; border: 1px solid var(--ff-border); border-radius: var(--ff-r-input); font: 500 13px Figtree, sans-serif; color: var(--ff-text); background: #fff; outline: none; }
.ff-input:focus, .ff-select:focus { border-color: var(--ff-teal); }
/* A disabled input had only the browser's 0.7 opacity to distinguish it — the same white fill and
   the same border, so it read as clickable. First noticed on the CBR territory strip, where three
   of the four selects are disabled until the level above them is chosen. */
.ff-input:disabled, .ff-select:disabled, textarea.ff-input:disabled { background: var(--ff-hairline); color: var(--ff-faint); cursor: not-allowed; }
/* Narrow numeric cell — the running-order box in the visuals table. MUST come after
   .ff-input: same specificity, so source order is all that makes it win. Declared above
   it, the base rule's width:100% and 11px side padding took over and left a box with
   room for the number spinner and nothing else. */
.ff-input--tiny { width: 76px; padding-left: 10px; padding-right: 6px; text-align: center; }
/* A running-order box whose number differs from what is saved — nothing is written until
   Re-order is clicked, so the admin needs to see which rows are still pending. */
.ff-input--staged { border-color: var(--ff-warn); background: var(--ff-warn-bg); font-weight: 700; }
.ff-input--bad { border-color: var(--ff-error); background: var(--ff-error-bg); }   /* a rung the price ladder refuses */

/* ---- misc ---- */
.ff-section-label { font: 700 11px Figtree, sans-serif; letter-spacing: .06em; color: var(--ff-muted); text-transform: uppercase; }
.ff-feed-item { display: flex; align-items: flex-start; gap: 10px; padding: 9px 0; }
.ff-feed-dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 5px; flex: none; }
.ff-empty { text-align: center; color: var(--ff-muted); font: 500 13px Figtree, sans-serif; padding: 48px 16px; }
.ff-spinner { border: 3px solid var(--ff-hairline); border-top-color: var(--ff-teal); border-radius: 50%; width: 26px; height: 26px; animation: ffspin .7s linear infinite; margin: 40px auto; }

/* In-button spinner. currentColor so it works on every button variant, and it sits in the space
   the icon vacates so the button does not jump width when the label changes. */
.ff-btn-spin { display: inline-block; width: 13px; height: 13px; flex: none; border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%; opacity: .7; animation: ffspin .6s linear infinite; }

/* ---- inline add-line row ---- */
.ff-add-line { display: flex; gap: 8px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--ff-hairline); flex-wrap: wrap; align-items: center; }
.ff-add-line .ff-input, .ff-add-line .ff-select { width: auto; flex: 1; min-width: 120px; }

/* ---- master list + visit rows (DCR history) ---- */
.ff-list { display: flex; flex-direction: column; }
.ff-list-row { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-bottom: 1px solid var(--ff-hairline); cursor: pointer; font: 500 13px Figtree, sans-serif; }
.ff-list-row:last-child { border-bottom: none; }
.ff-list-row:hover { background: var(--ff-canvas); }
.ff-list-row.active { background: var(--ff-info-bg); }
.ff-visit-row { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border: 1px solid var(--ff-border); border-radius: var(--ff-r-tile); }

/* ---- tabs (visit editor) ---- */
.ff-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--ff-hairline); margin-bottom: 14px; flex-wrap: wrap; }
.ff-tab { padding: 8px 14px; font: 600 13px Figtree, sans-serif; color: var(--ff-muted); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.ff-tab:hover { color: var(--ff-text); }
.ff-tab.active { color: var(--ff-teal-deep); border-bottom-color: var(--ff-teal); }
.ff-editor-actions { display: flex; justify-content: space-between; gap: 10px; margin-top: 12px; flex-wrap: wrap; }

/* ---- photo grid ---- */
.ff-photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; }
.ff-photo-tile { border: 1px solid var(--ff-border); border-radius: var(--ff-r-tile); overflow: hidden; background: var(--ff-canvas); }
.ff-photo-tile img { width: 100%; height: 120px; object-fit: cover; display: block; }
.ff-photo-meta { display: flex; align-items: center; justify-content: space-between; gap: 6px; padding: 6px 8px; font: 600 11px Figtree, sans-serif; color: var(--ff-text-2); }

/* ---- notification row ---- */
.ff-noti-ico { width: 34px; height: 34px; border-radius: 10px; display: flex; align-items: center; justify-content: center; flex: none; }
.ff-noti-ico--unread { background: var(--ff-info-bg); color: var(--ff-info); }
.ff-noti-ico--read { background: var(--ff-canvas); color: var(--ff-muted); }

/* ---- table helpers ---- */
.ff-sub-key { font: 500 11px Figtree, sans-serif; color: var(--ff-muted); margin-top: 1px; }
.ff-td-muted { color: var(--ff-muted); }

/* ---- Pager ---- */
.ff-pager { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 4px 2px; flex-wrap: wrap; }
.ff-pager-info { font: 500 12px Figtree, sans-serif; color: var(--ff-muted); }
.ff-pager-status { display: inline-flex; align-items: center; gap: 8px; }
/* The small spinner beside the range while the next page loads; see Pager's Busy. */
.ff-pager-busy { display: inline-block; width: 12px; height: 12px; flex: none; border: 2px solid var(--ff-hairline); border-top-color: var(--ff-teal); border-radius: 50%; animation: ffspin .7s linear infinite; }
/* The rows of a page that is being replaced: kept on screen, so the page does not collapse under a
   spinner and the pager keeps its focus, but dimmed and not clickable, so nobody acts on a row that
   is about to go. */
.ff-refreshing { opacity: .5; pointer-events: none; transition: opacity .15s; }
.ff-pager-btns { display: flex; gap: 8px; }
.ff-pager-btns .ff-btn { display: inline-flex; align-items: center; gap: 4px; }
.ff-pager-btns .ff-btn:disabled { opacity: .45; cursor: default; }

/* ---- Audit / history timeline ---- */
.ff-timeline { display: flex; flex-direction: column; }
.ff-tl-row { display: flex; gap: 12px; padding: 2px 0; }
.ff-tl-marker { position: relative; display: flex; justify-content: center; width: 14px; }
.ff-tl-marker::before { content: ''; position: absolute; top: 0; bottom: 0; width: 2px; background: var(--ff-hairline); }
.ff-tl-row:first-child .ff-tl-marker::before { top: 8px; }
.ff-tl-row:last-child .ff-tl-marker::before { bottom: calc(100% - 8px); }
.ff-tl-dot { position: relative; width: 9px; height: 9px; border-radius: 50%; margin-top: 4px; background: var(--ff-info); box-shadow: 0 0 0 3px var(--ff-card); }
.ff-tl-dot--info { background: var(--ff-info); }
.ff-tl-dot--success { background: var(--ff-success); }
.ff-tl-dot--amber { background: var(--ff-warn); }
.ff-tl-dot--red { background: var(--ff-error); }
.ff-tl-dot--muted { background: var(--ff-muted); }
.ff-tl-body { flex: 1; min-width: 0; padding-bottom: 14px; }
.ff-tl-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.ff-tl-action { font: 700 13px Figtree, sans-serif; color: var(--ff-ink); }
.ff-tl-entity { font: 600 12px Figtree, sans-serif; color: var(--ff-text-2); }
.ff-tl-when { font: 500 11px Figtree, sans-serif; color: var(--ff-muted); margin-left: auto; }
.ff-tl-meta { font: 500 12px Figtree, sans-serif; color: var(--ff-muted); margin-top: 2px; }
.ff-tl-actor { color: var(--ff-text-2); }

/* ---- File upload ---- */
.ff-upload { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ff-upload-btn { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.ff-upload-hint { font: 500 12px Figtree, sans-serif; color: var(--ff-muted); }

@keyframes ffpulseg { 0% { box-shadow: 0 0 0 0 rgba(22,163,74,.45); } 70% { box-shadow: 0 0 0 10px rgba(22,163,74,0); } 100% { box-shadow: 0 0 0 0 rgba(22,163,74,0); } }
@keyframes fftoast { 0% { opacity: 0; transform: translate(-50%, 10px); } 100% { opacity: 1; transform: translate(-50%, 0); } }
@keyframes ffspin { to { transform: rotate(360deg); } }

/* ==================================================================
   Responsive — mobile + tablet. All rules below are additive and
   ordered last so they win by source order. Two breakpoints:
   tablet ≤1024px, phone ≤640px. Desktop (≥1025px) is unchanged.
   ================================================================== */

/* Shared toolbar row (filter chips + search + primary button). Wraps; on
   desktop the search+button group is pushed right (replaces old spacer div). */
.ff-toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
.ff-toolbar .ff-input { max-width: 240px; margin-left: auto; }
/* The client lists' place strip: a label over each picker, so the button and the loading note sit
   on the pickers' line rather than midway up their labels. */
.ff-geo-strip { align-items: flex-end; gap: 10px; }
.ff-geo-field { gap: 4px; }
.ff-geo-loading { display: inline-flex; align-items: center; gap: 6px; font: 500 12px Figtree, sans-serif; color: var(--ff-muted); padding-bottom: 10px; }

/* Card headers (search/CTA live here via the Actions slot) may wrap. */
.ff-card-head { flex-wrap: wrap; }

/* Wide tables/content sit in a non-padded Card; let them scroll sideways
   instead of forcing page overflow. No-op when content already fits. */
.ff-card-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.ff-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* Sidebar drawer scrim — hidden except when the drawer is open on small screens. */
.ff-nav-scrim { display: none; }

@media (max-width: 1024px) {
    .ff-topbar { padding: 0 14px; gap: 10px; }

    /* The only way into the drawer on mobile — desktop hides it (see above). */
    .ff-nav-toggle { display: flex; }

    /* Sidebar becomes an off-canvas overlay drawer. */
    .ff-sidebar {
        position: fixed; top: 0; left: 0; height: 100vh; z-index: 60;
        transform: translateX(-100%); transition: transform .22s ease;
        box-shadow: var(--ff-shadow-float);
    }
    .ff-console.is-nav-open .ff-sidebar { transform: none; }
    .ff-nav-scrim { display: block; position: fixed; inset: 0; background: rgba(15,42,51,.45); z-index: 55; }
}

@media (min-width: 1025px) {
    /* Desktop keeps the hamburger "reclaim space" collapse. */
    .ff-console.is-nav-closed .ff-sidebar { display: none; }
}

@media (max-width: 640px) {
    /* Same split as the full-size rule: the top inset stays a BLOCK so a sticky table heading
       keeps pinning flush. A plain `padding: 14px` here would put the gap back on a phone. */
    .ff-content { padding: 0 14px 14px; }
    .ff-content::before { height: 14px; }
    :root { --ff-gutter: 14px; }
    .ff-company-chip { display: none; }

    /* Toolbar + card-head controls go full width so nothing collides. */
    .ff-toolbar .ff-input,
    .ff-card-head .ff-input { max-width: none; margin-left: 0; flex: 1 1 100%; }
    .ff-toolbar .ff-btn,
    .ff-card-head .ff-btn { flex: 1 1 100%; justify-content: center; }

    /* 16px avoids the iOS focus-zoom; trim heavy table cell padding.
       .ff-ss-input is the combobox panel's own search box and matches none of the other three, so
       it used to zoom the moment the panel opened — shrinking the visual viewport at exactly the
       moment the panel needs vertical room. */
    .ff-input, .ff-select, textarea.ff-input, .ff-ss-input { font-size: 16px; }
    .ff-table th, .ff-table td { padding: 10px 12px; }

    /* Tabs scroll horizontally rather than wrapping into tall stacks. */
    .ff-tabs { flex-wrap: nowrap; overflow-x: auto; }
    .ff-tab { white-space: nowrap; }

    /* A dialog on a phone should use the screen rather than sit in a letterbox. 8px keeps
       the card visibly a card; 94vh leaves room for the browser chrome. --wide is a
       desktop-only idea, so its 920px cap is dropped here. */
    .ff-modal-scrim { padding: 8px; align-items: flex-start; }
    .ff-modal, .ff-modal--wide, .ff-modal--xl { max-width: none; max-height: 94vh; }
    .ff-modal-head, .ff-modal-body { padding: 14px; }
    .ff-modal-foot { padding: 12px 14px; }
    /* Footer buttons go full width — side by side they end up too small to hit. */
    .ff-modal-foot { flex-wrap: wrap; }
    .ff-modal-foot .ff-btn { flex: 1 1 140px; justify-content: center; }

    /* Approval cards: buttons drop full-width below the text instead of
       crushing the title/detail into a narrow column. */
    .ff-approval { flex-wrap: wrap; gap: 12px; }
    .ff-approval-actions { flex: 1 1 100%; }
    .ff-approval-actions .ff-btn { flex: 1; justify-content: center; }
}

/* ---- TP calendar (Month / Week / Agenda) ---- */
.tp-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.tp-legend { display: flex; flex-wrap: wrap; gap: 6px 12px; }
.tp-legend-item { display: inline-flex; align-items: center; gap: 5px; font: 500 11.5px Figtree, sans-serif; color: var(--ff-text-2); }
.tp-swatch { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }

.tp-month { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.tp-dow { text-align: center; font: 700 11px Figtree, sans-serif; color: var(--ff-faint); padding-bottom: 2px; }
.tp-cell { min-height: 62px; border: 1.5px solid transparent; border-radius: 10px; padding: 6px 4px; display: flex; flex-direction: column; align-items: center; gap: 3px; }
.tp-cell--empty { border-color: var(--ff-hairline); }
.tp-cell--tap { cursor: pointer; }
.tp-cell--tap:hover { filter: brightness(0.97); }
.tp-date { font: 700 13px Figtree, sans-serif; color: var(--ff-ink); width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; }
.tp-cell--empty .tp-date { color: var(--ff-faint); font-weight: 500; }
.tp-date--today { background: var(--ff-ink); color: #fff; border-radius: 50%; }
.tp-cell-label { font: 700 11px Figtree, sans-serif; }

.tp-week-nav { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.tp-week-nav span { font: 700 13px Figtree, sans-serif; color: var(--ff-ink); }
.ff-icon-btn { background: none; border: 1px solid var(--ff-border); border-radius: 8px; padding: 5px 8px; cursor: pointer; color: var(--ff-text-2); display: inline-flex; }
.ff-icon-btn:disabled { opacity: .4; cursor: default; }
.tp-week { display: flex; flex-direction: column; gap: 7px; }
.tp-week-row { display: flex; align-items: center; gap: 12px; border-left: 4px solid var(--ff-hairline); border-radius: 0 10px 10px 0; padding: 9px 12px; }
.tp-week-row--empty { background: var(--ff-thead); }
.tp-week-date { width: 42px; text-align: center; flex: none; }
.tp-week-dow { display: block; font: 500 11px Figtree, sans-serif; color: var(--ff-muted); }
.tp-week-num { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; font: 700 16px Figtree, sans-serif; color: var(--ff-ink); }
.tp-week-body { display: flex; flex-direction: column; }
.tp-week-act { font: 700 13px Figtree, sans-serif; }
.tp-week-areas, .tp-week-note { font: 500 12px Figtree, sans-serif; color: var(--ff-text-2); }
.tp-week-note { color: var(--ff-muted); }
.tp-week-clients { font: 400 11.5px Figtree, sans-serif; color: var(--ff-text-2); margin-top: 3px; line-height: 1.5; }
.tp-week-clients span { color: var(--ff-ink); }

.tp-agenda { display: flex; flex-direction: column; gap: 8px; }
.tp-agenda-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; border: 1px solid var(--ff-hairline); border-left: 4px solid var(--ff-faint); border-radius: 0 10px 10px 0; padding: 11px 14px; }
.tp-agenda-dates { font: 700 13px Figtree, sans-serif; color: var(--ff-ink); }
.tp-agenda-sub { font: 500 12px Figtree, sans-serif; color: var(--ff-text-2); margin-top: 2px; }
.tp-agenda-pill { font: 700 11.5px Figtree, sans-serif; padding: 4px 11px; border-radius: var(--ff-r-pill); white-space: nowrap; }

@media (max-width: 640px) {
    .tp-cell { min-height: 52px; }
    .tp-cell-label { font-size: 10px; }
}

/* ---- Bulk import wizard (AdminImport) ---- */
.ffi-steps { display:flex; gap:8px; margin-bottom:16px; flex-wrap:wrap; }
.ffi-step { display:flex; align-items:center; gap:8px; padding:6px 14px 6px 6px; border-radius:var(--ff-r-pill); background:var(--ff-card); border:1px solid var(--ff-border); }
.ffi-step-dot { width:24px; height:24px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; font-size:12px; font-weight:700; background:var(--ff-canvas); color:var(--ff-muted); }
.ffi-step-label { font-size:13px; font-weight:600; color:var(--ff-muted); }
.ffi-step--active { border-color:var(--ff-teal); }
.ffi-step--active .ffi-step-dot { background:var(--ff-teal); color:#fff; }
.ffi-step--active .ffi-step-label { color:var(--ff-text); }
.ffi-step--done .ffi-step-dot { background:var(--ff-success); color:#fff; }
.ffi-step--done .ffi-step-label { color:var(--ff-text-2); }
.ffi-grid { display:flex; gap:12px; flex-wrap:wrap; margin-bottom:12px; }
.ffi-tile { display:flex; align-items:center; gap:10px; padding:14px 18px; min-width:150px; border-radius:var(--ff-r-tile); border:1.5px solid var(--ff-border); background:var(--ff-card); cursor:pointer; font-weight:600; color:var(--ff-text); transition:border-color .12s, background .12s; }
.ffi-tile:hover { border-color:var(--ff-teal); }
.ffi-tile.is-selected { border-color:var(--ff-teal); background:var(--ff-tint-teal); }
.ffi-actions { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-top:14px; }
.ffi-stat { display:flex; flex-direction:column; align-items:center; gap:2px; padding:16px 26px; border-radius:var(--ff-r-tile); background:var(--ff-canvas); border:1px solid var(--ff-border); }
.ffi-stat-num { font-size:26px; font-weight:800; line-height:1; }

/* ---- Map location picker (MapPicker) ---- */
.ffi-map-search { display:flex; align-items:center; gap:8px; margin-bottom:10px; }
.ffi-map-search .ff-input { flex:1; }
.ffi-mapbox { width:100%; height:420px; border-radius:var(--ff-r-input); overflow:hidden; border:1px solid var(--ff-border); background:var(--ff-canvas); }
.ffi-map-readout { margin-top:10px; font:600 13px Figtree, sans-serif; color:var(--ff-text); }
.ffi-latlng-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:6px; }
.ff-btn--sm { padding:5px 10px; font-size:12px; }
/* Google Places autocomplete dropdown must float above the modal scrim (z-index 1100). */
.pac-container { z-index: 2000 !important; }

/* ---- Team Analytics: comparison bar chart + active leaderboard row ---- */
.ff-bars { display:flex; flex-direction:column; gap:9px; }
.ff-bar-row { display:flex; align-items:center; gap:10px; }
.ff-bar-label { flex:0 0 132px; width:132px; font:600 12px Figtree, sans-serif; color:var(--ff-text-2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ff-bar-track { flex:1; height:14px; background:var(--ff-hairline); border-radius:7px; overflow:hidden; }
.ff-bar-track > i { display:block; height:100%; border-radius:7px; min-width:2px; transition:width .25s ease; }
.ff-bar-val { flex:0 0 58px; width:58px; text-align:right; font:700 12px Figtree, sans-serif; color:var(--ff-ink); }
.ff-table tbody tr.ff-row-active { background:var(--ff-tint-teal); }

/* ---- Remote screen-share viewer (AdminScreenShare) ---- */
.ff-ss-stage { display:flex; align-items:center; justify-content:center; min-height:70vh; background:var(--ff-canvas); padding:12px; border-radius:0 0 var(--ff-r-card) var(--ff-r-card); }
/* Scale the shared phone frame UP to fill the stage height (a phone screenshot is a
   small portrait image; max-* alone would only cap it, leaving it tiny on desktop).
   width:auto + max-width keep the aspect ratio and cap the rare landscape frame. */
.ff-ss-frame { height:70vh; width:auto; max-width:100%; object-fit:contain; border-radius:10px; box-shadow:var(--ff-shadow-float); }

/* Billing grace/expiry banner (persistent, admin pages). */
.ff-billing-banner { display:flex; align-items:center; gap:10px; padding:9px 16px; font:600 12.5px Figtree; }
.ff-billing-banner-x { background:transparent; border:0; color:inherit; opacity:.8; cursor:pointer; font-size:13px; line-height:1; padding:2px 4px; }
.ff-billing-banner-x:hover { opacity:1; }

/* Session banner (SessionKeeper): the session has ended, and the page waits, untouched, for the user
   to sign in again in another tab.

   In the flow of .ff-main above the top bar, never laid over the page: it pushes everything down
   rather than covering any of it, the page's Save buttons included. A dialog is the one thing that
   would still cover the BANNER, and a dialog is exactly where unsaved work tends to be — so while
   the banner is up a dialog opens below it instead, and gives up the same height, so its own Save
   stays on screen. --ff-session-h is the banner's floor. Should it wrap taller, the lift above the
   scrim keeps its controls clickable at the cost of a few pixels of the dialog's title bar. Without
   :has() a dialog opens as it always has, and the banner is still reachable by keyboard. */
.ff-console { --ff-session-h: 44px; }
.ff-session-banner { flex: none; display: flex; align-items: center; flex-wrap: wrap; gap: 6px 14px;
                     min-height: var(--ff-session-h); padding: 7px 16px;
                     background: var(--ff-ink); color: #fff; font: 600 12.5px Figtree, sans-serif; }
.ff-session-banner-text { flex: 1 1 260px; min-width: 0; }
.ff-session-banner-note { display: block; font-weight: 500; opacity: .85; }
.ff-session-banner-actions { display: flex; gap: 8px; flex: none; }
.ff-session-banner .ff-btn { background: #fff; color: var(--ff-ink); }
.ff-session-banner .ff-btn--ghost { background: transparent; color: #fff; border-color: rgba(255,255,255,.55); }
.ff-session-banner .ff-btn[aria-disabled="true"] { opacity: .6; cursor: progress; }
.ff-session-banner .ff-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.ff-console:has(.ff-session-banner) .ff-modal-scrim { top: var(--ff-session-h); }
.ff-console:has(.ff-session-banner) .ff-modal { max-height: calc(90vh - var(--ff-session-h)); }
.ff-console:has(.ff-modal-scrim) .ff-session-banner { position: relative; z-index: 1101; }
@media (max-width: 640px) {
    /* Two rows on a phone: the words, then the buttons. */
    .ff-console { --ff-session-h: 84px; }
    .ff-console:has(.ff-session-banner) .ff-modal { max-height: calc(94vh - var(--ff-session-h)); }
}

/* Read out, not shown: "(opens a new tab)" after a link that does. */
.ff-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
              clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ── Multi-select (RemoteMultiSelect) ──────────────────────────────────────────
   A tick column rather than a checkbox input: the whole row is the click target, and a real
   checkbox would take the click and the focus away from the search box the user is still typing
   in. Fixed width so the labels line up whether or not a row is chosen. */
.ff-ms-tick { display: inline-block; width: 14px; flex: none; font-weight: 800;
              color: var(--ff-brand-strong); }

/* Pinned under the results. "Done" is not strictly needed — clicking away closes it — but a
   multi-select with no visible way to finish reads as stuck. */
.ff-ms-foot { display: flex; align-items: center; gap: 12px; padding: 8px 12px;
              border-top: 1px solid var(--ff-hairline); font: 600 12px Figtree, sans-serif;
              color: var(--ff-muted); }
.ff-ms-foot .ff-link-btn { margin-left: auto; }
.ff-ms-foot .ff-link-btn + .ff-link-btn { margin-left: 0; }

/* Chips live OUTSIDE the panel, so what has been chosen stays readable once it is closed — the
   whole point of a multi-select is that the answer is several things and you can see them all.

   WRAPPING, unlike the shared .ff-chip-row, which is a horizontal scroller by design. Twelve
   products chosen for a requisition are all equally the answer, and hiding two thirds of them
   behind a sideways scroll in a form the user is still filling in reads as a truncated list. */
.ff-ms-chips { margin-top: 8px; flex-wrap: wrap; overflow-x: visible; }

/* An excluded line on the CBR grid. Dimmed, not hidden: a reviewer needs to see what they turned
   off, and a row that vanished would read as a bug rather than a decision. */
.ff-row-off { opacity: .45; }
.ff-row-off td { text-decoration: line-through; }
.ff-row-off td:first-child { text-decoration: none; }

/* ---- Retailer Wise Sales -------------------------------------------
   The console's first multi-row <thead>. `.ff-table th` carries no border rule at all, so stacked
   header rows read as one grey block and the month grouping is invisible — hence the band
   separators below. They are what make 52 near-identical figures parseable.

   Padding is tightened on THIS table only. At the default 13px/18px the grid is ~5,300px wide
   against roughly 1,140px of content area on a 1440px screen; 8px/10px takes about 23% off it. */
.ff-rws th, .ff-rws td { padding: 8px 10px; }

/* The first column of each month band — now every FOURTH cell, not every second. The class is
   emitted per cell from RetailerCell.OpensBand, so this rule follows the model rather than
   restating its arithmetic. */
.ff-rws th.ff-rws-band, .ff-rws td.ff-rws-band { border-left: 1px solid var(--ff-border); }

/* The bottom of the header block. Without it the header and the first data row run together. */
.ff-rws thead tr:last-child th { border-bottom: 1px solid var(--ff-border); }

/* Units against money, on the CELLS and not only the header. The header is some 4,000px wide and
   only its first screen is ever visible — by the time the reader has scrolled to January there is
   nothing left on screen saying which column is which, and a unit count and a rupee figure are
   otherwise indistinguishable. Money keeps the default ink; units step back. */
.ff-rws .ff-rws-units { color: var(--ff-text-2); }
.ff-rws thead .ff-rws-units, .ff-rws thead .ff-rws-money { font-weight: 700; }

/* The frozen identity strip: SL and Retailer, so the shop's name stays put across 4,000px of
   scrolling. .ff-table-wrap is the overflow-x scrollport, so that is what `left` resolves against.

   Two mechanics that bite otherwise. `.ff-table` is border-collapse: collapse and a collapsed
   border belongs to the table rather than the cell, so a sticky cell loses it — hence box-shadow
   for the strip's right edge. And a sticky cell needs an OPAQUE background or the figures scroll
   underneath it; subtotal and total rows already sit on --ff-canvas, so they repeat it here. */
.ff-rws th:nth-child(1), .ff-rws th:nth-child(2),
.ff-rws td:nth-child(1), .ff-rws td:nth-child(2) {
  position: sticky; background: var(--ff-card); z-index: 1;
}
.ff-rws th:nth-child(1), .ff-rws td:nth-child(1) { left: 0; }
.ff-rws th:nth-child(2), .ff-rws td:nth-child(2) { left: 34px; }
.ff-rws th:nth-child(2), .ff-rws td:nth-child(2) { box-shadow: 1px 0 0 var(--ff-border); }

/* The header's own strip has to sit above the body's, or the body scrolls over it. */
.ff-rws thead th:nth-child(1), .ff-rws thead th:nth-child(2) { z-index: 3; background: var(--ff-canvas); }
.ff-rws-sub td:nth-child(1), .ff-rws-sub td:nth-child(2) { background: var(--ff-canvas); }
.ff-rws tfoot td:nth-child(1), .ff-rws tfoot td:nth-child(2) { background: var(--ff-canvas); z-index: 2; }

/* A retailer's subtotal. Tinted, never coloured: colour in a money grid means "these figures are
   different", which is the one thing a subtotal must not imply. */
.ff-rws-sub td { font-weight: 800; background: var(--ff-canvas); }

/* The explanatory lines above the grid: the value legend, the data range, the unmatched count. */
.ff-rws-note {
  padding: 8px 16px; font: 500 12.5px Figtree, sans-serif; color: var(--ff-text-2);
  border-bottom: 1px solid var(--ff-hairline);
}
.ff-rws-warn {
  padding: 8px 16px; font: 600 12.5px Figtree, sans-serif; color: var(--ff-text-2);
  background: var(--ff-warn-bg); border-bottom: 1px solid var(--ff-hairline);
}

/* With 59 columns the browser distributes width evenly and squeezes the identity block until
   "A A M MEDICAL AGENCY BATMALLO - [KASHMIR OPEN MARKET]" wraps over six lines. These floors keep
   the names readable; the grid already scrolls inside .ff-table-wrap, so the extra width costs
   nothing the layout was not already handling. */
/* Width only. NOT text-align: the first cell of a subtotal row is its LABEL, spanning the frozen
   columns, and right-aligning it pushes "Party Total" away from the rows it belongs to. The SL
   cell carries its own alignment inline. */
.ff-rws th:nth-child(1) { min-width: 34px; }
.ff-rws th:nth-child(2) { min-width: 190px; }   /* Retailer */
.ff-rws th:nth-child(3) { min-width: 110px; }   /* Mapped Client   — blank until CBR is populated */
.ff-rws th:nth-child(4) { min-width: 96px;  }   /* Last 3 Investment */
.ff-rws th:nth-child(5) { min-width: 150px; }   /* Item */
.ff-rws th:nth-child(6) { min-width: 120px; }   /* Area */
.ff-rws th:nth-child(7) { min-width: 68px;  }   /* the rate */
/* Two floors, by measure rather than by position: a unit count is narrower than a rupee figure,
   and at 52 cells the difference is worth about 350px of scrolling. Class-based because the body
   cells are offset by the seven identity columns, so an nth-child rule would need a second copy
   that has to agree with the first. */
.ff-rws .ff-rws-units { min-width: 54px; }
.ff-rws .ff-rws-money { min-width: 68px; }

/* ---- Retailer Sale Yearly / FY -------------------------------------
   Its own class rather than .ff-rws, whose frozen strip and column floors are positional and
   written for SL | Retailer | Mapped Client | ... — on this grid column 1 is the Retailer, so those
   rules would pin the wrong cells at the wrong offsets. Same mechanics, one frozen column. */
.ff-rsy th, .ff-rsy td { padding: 8px 10px; }
.ff-rsy th.ff-rsy-band, .ff-rsy td.ff-rsy-band { border-left: 1px solid var(--ff-border); }
.ff-rsy thead tr:last-child th { border-bottom: 1px solid var(--ff-border); }
.ff-rsy thead th { font-weight: 700; }
.ff-rsy .ff-rsy-units { color: var(--ff-text-2); min-width: 54px; }
.ff-rsy .ff-rsy-money { min-width: 84px; }

/* The Retailer column stays put while a year of pairs scrolls past. Opaque, and a box-shadow for
   its edge, for the reasons given for .ff-rws above. */
.ff-rsy th:nth-child(1), .ff-rsy td:nth-child(1) {
  position: sticky; left: 0; background: var(--ff-card); z-index: 1; box-shadow: 1px 0 0 var(--ff-border);
}
.ff-rsy thead tr:first-child th:nth-child(1) { z-index: 3; background: var(--ff-canvas); min-width: 200px; }
.ff-rsy tfoot td:nth-child(1) { background: var(--ff-canvas); z-index: 2; }

/* Every row names its retailer, as the sheet does; a rule above each retailer's first row is what
   still lets the eye find where one shop's block ends. */
.ff-rsy tr.ff-rsy-first td { border-top: 1px solid var(--ff-border); }

/* ---- Sales Drill-down ------------------------------------------------------------------------ */

/* The breadcrumb between the filters and the grid: every step but the last goes back up to it. */
.ff-drill-crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 16px 2px 0; font: 600 13px Figtree, sans-serif; }
.ff-drill-crumbs a { color: var(--ff-teal); text-decoration: none; }
.ff-drill-crumbs a:hover { text-decoration: underline; }
.ff-drill-sep { color: var(--ff-faint); }
.ff-drill-here { color: var(--ff-text); font-weight: 800; }

/* The coverage headline: what nobody owns, before any figure that leaves it out. */
.ff-drill-coverage {
  margin-top: 12px; padding: 10px 14px; border: 1px solid var(--ff-hairline); border-radius: var(--ff-r-card);
  background: var(--ff-info-bg); font: 500 13px Figtree, sans-serif; color: var(--ff-text-2);
  display: flex; flex-direction: column; gap: 3px;
}
.ff-drill-coverage a { color: var(--ff-teal); font-weight: 700; }

.ff-drill-switch { display: flex; gap: 6px; flex-wrap: wrap; }
.ff-drill-search { display: flex; gap: 8px; align-items: center; padding: 10px 16px; border-bottom: 1px solid var(--ff-hairline); }
.ff-drill-search .ff-input { max-width: 360px; }

.ff-drill th:first-child { min-width: 220px; }
.ff-drill .ff-drill-num { text-align: right; white-space: nowrap; }
/* The meter column on the doctor list, where money columns now sit beside it. The bar reads
   as a shape, not a figure — Budget and Sales carry the numbers — so it is pinned narrow
   instead of soaking up whatever width the table has spare. The 150px floor on the meter
   itself is lifted inside this cell only: the team table above and the big meter on the
   doctor page still want theirs. */
.ff-drill th.ff-drill-meter, .ff-drill td.ff-drill-meter { width: 150px; }
.ff-drill td.ff-drill-meter .ff-bd-meter { min-width: 0; }
.ff-drill tbody tr:hover td { background: var(--ff-canvas); }
/* Blue at rest, not only on hover: a drill name that looks like body text gives a
   mouse user a hover to discover and a touch user nothing at all. The weight stays 700,
   which is what already separates a link from the plain span.ff-drill-name beside it. */
.ff-drill a.ff-drill-name { color: var(--ff-teal); font-weight: 700; text-decoration: none; }
.ff-drill a.ff-drill-name:hover { color: var(--ff-teal-deep); text-decoration: underline; }
.ff-drill span.ff-drill-name { font-weight: 600; }
.ff-drill .ff-drill-go { width: 28px; text-align: center; }
.ff-drill .ff-drill-go a { color: var(--ff-muted); font-size: 18px; line-height: 1; text-decoration: none; padding: 2px 6px; }
.ff-drill .ff-drill-go a:hover { color: var(--ff-teal); }
/* Unassigned sits apart from the people above it: it is a gap in the org chart, not a member of it. */
.ff-drill tr.ff-drill-unassigned td { border-top: 1px solid var(--ff-border); font-style: italic; }
.ff-drill tr.ff-drill-unassigned td.ff-drill-num { font-style: normal; }
.ff-drill tfoot td { font-weight: 800; background: var(--ff-canvas); border-top: 1px solid var(--ff-border); }

/* ---- Budget Drill-down ---------------------------------------------------------------------- */

/* A band colours a meter's fill, a number, or a doctor row's left edge: green on track, amber watch,
   red at risk, grey when there is nothing to judge. */
.ff-bd--ok { --ff-bd-tone: var(--ff-success); }
.ff-bd--watch { --ff-bd-tone: var(--ff-warn); }
.ff-bd--risk { --ff-bd-tone: var(--ff-error); color: var(--ff-error-tx); }
.ff-bd--none { --ff-bd-tone: var(--ff-faint); }
.ff-table td.ff-bd--risk { color: var(--ff-error-tx); font-weight: 800; }

.ff-bd-meter { display: flex; align-items: center; gap: 8px; min-width: 150px; color: inherit; }
.ff-bd-track { flex: 1; height: 6px; border-radius: 3px; background: var(--ff-hairline); overflow: hidden; }
.ff-bd-fill { display: block; height: 100%; border-radius: 3px; background: var(--ff-bd-tone, var(--ff-faint)); }
.ff-bd-pct { width: 64px; text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ff-text); }
.ff-bd-meter--big .ff-bd-track { height: 10px; border-radius: 5px; }

.ff-drill tr.ff-bd-row td:first-child { box-shadow: inset 3px 0 0 var(--ff-bd-tone, var(--ff-faint)); }
.ff-drill tr.ff-bd-row { color: inherit; }

.ff-bd-tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--ff-hairline); }
.ff-bd-tile .k { font: 500 12px Figtree, sans-serif; color: var(--ff-muted); margin-bottom: 4px; }
.ff-bd-tile .v { font: 800 20px Figtree, sans-serif; color: var(--ff-text); }
.ff-bd-tile .v.ff-bd--risk { color: var(--ff-error-tx); }

.ff-bd-doc { padding: 16px; display: flex; flex-direction: column; gap: 18px; }
.ff-bd-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
.ff-bd-who { display: flex; gap: 12px; align-items: center; min-width: 0; }
.ff-bd-avatar {
  width: 44px; height: 44px; border-radius: 50%; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  background: var(--ff-tint-teal); color: var(--ff-teal-deep); font: 800 14px Figtree, sans-serif;
}
.ff-bd-name { font: 800 17px Figtree, sans-serif; color: var(--ff-text); }
.ff-bd-section { display: flex; flex-direction: column; gap: 8px; }
.ff-bd-big { font: 800 44px/1 Figtree, sans-serif; color: var(--ff-text); margin-right: 8px; }
.ff-bd-big.ff-bd--risk { color: var(--ff-error-tx); }
.ff-bd-pair { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px; flex-wrap: wrap; }
.ff-bd-kpi { font: 800 22px Figtree, sans-serif; color: var(--ff-text); }
.ff-bd-spark { width: 140px; color: var(--ff-muted); }
.ff-bd-trend--growing { color: var(--ff-success); }
.ff-bd-trend--flat { color: var(--ff-warn); }
.ff-bd-trend--declining { color: var(--ff-error); }
.ff-bd-flag { background: var(--ff-error-bg); color: var(--ff-error-tx); font: 600 13px Figtree, sans-serif; padding: 8px 12px; border-radius: 8px; }
.ff-bd-reasons { margin: 0; padding-left: 18px; color: var(--ff-text-2); font: 500 13px Figtree, sans-serif; }
.ff-bd-notes { padding: 4px 0 8px; }

@media (max-width: 720px) {
  .ff-bd-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ff-bd-meter { min-width: 110px; }
  /* Later in the file than the rule above, which is the only reason it wins: a media query
     adds no specificity of its own. */
  .ff-drill th.ff-drill-meter, .ff-drill td.ff-drill-meter { width: 110px; }
  .ff-bd-big { font-size: 36px; }
}

/* ---- Doctor & Chemist 360 (Shared/Customer360Drilldown.razor) ----
   Reuses the Budget Drill-down's meters, row edges and band tones (.ff-bd-*); adds the list tabs, the
   metric cards and the three trend bars of the customer's mockup. */
.ff-360-tabs { display: flex; gap: 8px; flex-wrap: wrap; padding: 12px 16px 0; }
.ff-360-tabs .ff-chip { text-decoration: none; display: inline-flex; align-items: center; }
.ff-360-back { font: 600 12.5px Figtree, sans-serif; color: var(--ff-teal); text-decoration: none; }
.ff-360-metrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.ff-360-metrics--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.ff-360-metric { background: var(--ff-canvas); border: 1px solid var(--ff-hairline); border-radius: var(--ff-r-tile); padding: 10px 12px; min-width: 0; }
.ff-360-metric .k { font: 500 11.5px Figtree, sans-serif; color: var(--ff-muted); margin-bottom: 4px; }
.ff-360-metric .v { font: 800 18px Figtree, sans-serif; color: var(--ff-text); overflow-wrap: anywhere; }
.ff-360-metric .v.ff-bd--risk { color: var(--ff-error-tx); }
.ff-360-metric .s { font: 500 11.5px Figtree, sans-serif; color: var(--ff-muted); margin-top: 2px; }
.ff-360-bars { display: flex; gap: 18px; align-items: flex-end; min-height: 72px; margin: 6px 0 2px; }
.ff-360-bar { display: flex; flex-direction: column; align-items: center; gap: 4px; font: 500 11px Figtree, sans-serif; color: var(--ff-muted); font-variant-numeric: tabular-nums; }
.ff-360-bar i { display: block; width: 28px; border-radius: 3px; background: var(--ff-360-tone, var(--ff-faint)); }
.ff-360-trend--growing { --ff-360-tone: var(--ff-success); }
.ff-360-trend--flat { --ff-360-tone: var(--ff-warn); }
.ff-360-trend--declining { --ff-360-tone: var(--ff-error); }
.ff-360-trend--notenoughdata { --ff-360-tone: var(--ff-faint); }
.ff-360-foot { font: 500 12.5px Figtree, sans-serif; color: var(--ff-muted); }

@media (max-width: 720px) {
  .ff-360-metrics, .ff-360-metrics--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---- Colour-theme swatches (Settings -> Appearance, Configuration -> Company theme) ----
   Each swatch is a tiny console in that theme: its bar, a button and a tint on its own ground. The
   colours are inline, from UiThemeCatalog, because a swatch must show ITS theme, not the page's. */
.ff-theme-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: 10px; }
.ff-theme-card {
  display: flex; flex-direction: column; gap: 6px; padding: 8px; border-radius: 12px; cursor: pointer; text-align: left;
  border: 1.5px solid var(--ff-border); background: var(--ff-card); font: inherit; color: var(--ff-text);
}
.ff-theme-card:hover { border-color: var(--ff-teal); }
.ff-theme-card:focus-visible { outline: 3px solid var(--ff-teal); outline-offset: 2px; }
.ff-theme-card.is-on { border-color: var(--ff-teal); box-shadow: 0 0 0 2px var(--ff-nav-accent-tint); }
.ff-theme-card:disabled { cursor: progress; opacity: .7; }
.ff-theme-preview { display: flex; flex-direction: column; gap: 7px; height: 58px; border-radius: 8px; overflow: hidden; border: 1px solid rgba(0,0,0,.06); }
.ff-theme-bar { height: 14px; flex: none; }
.ff-theme-row { display: flex; align-items: center; gap: 6px; padding: 0 8px; }
.ff-theme-btn { width: 38px; height: 14px; border-radius: 999px; }
.ff-theme-chip { width: 26px; height: 14px; border-radius: 999px; border: 1.5px solid; }
.ff-theme-name { font: 700 12.5px Figtree, sans-serif; }
.ff-theme-sub { font: 500 11px Figtree, sans-serif; color: var(--ff-muted); margin-top: -4px; }
.ff-theme-card.is-on .ff-theme-name::after { content: " ✓"; color: var(--ff-teal); }

/* ---- Company Health (/admin) ----
   Status colours come from the shared success/warn/error tokens, so every theme reads the same way:
   green is healthy, amber is watch, red is poor, grey is "no data yet" — never a score of 100. */
.ff-health-bar { padding: 14px 16px; margin-bottom: 16px; }
.ff-health-bar-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 18px; }
.ff-health-bar-row .ff-field { margin: 0; }
/* The two period selects sit side by side, not stacked.

   .ff-select is width:100% everywhere else in the console, which is right for a field in a column
   and wrong for two of them in a row: each one asks for the whole container, the pair overflows it,
   and flex-wrap put the second under the first. They were 266px each inside a 266px box on a
   1378px row. flex:1 lets them share instead of each demanding all of it, and the field is given a
   basis wide enough that sharing leaves both readable. */
.ff-health-period { display: flex; flex-wrap: nowrap; gap: 12px; }
.ff-health-period .ff-select { flex: 1 1 0; min-width: 0; }

/* Wide enough for a period label to read, capped so it does not swallow the whole row on a big
   screen and leave Valued at stranded at the far end. */
.ff-health-period-field { flex: 1 1 560px; max-width: 820px; }
.ff-policy-edit { display: flex; align-items: center; gap: 6px; }
.ff-policy-edit .ff-input { max-width: 140px; }
/* The policy finder: a search box over the category chips, with the count it narrowed to. */
/* The find box: an input with one clear cross and a count beside it. Was .ff-policy-search, which
   was generic in everything but its name - the approvals register needed the same thing and a
   second copy under a second name is how two search boxes start drifting apart. */
.ff-find { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 12px; }
/* The box itself only has to position the clear cross. Its WIDTH belongs to the row it sits in,
   so the basis is scoped to that row - unscoped, `flex: 0 1 380px` followed a .ff-find-box into a
   .ff-field, which is a COLUMN flex, where a 380px basis is 380px of height rather than width and
   opened a hole down the middle of the approvals filter card. */
.ff-find-box { position: relative; }
.ff-find > .ff-find-box { flex: 0 1 380px; min-width: 200px; }
.ff-find-box .ff-input { padding-right: 32px; }
/* The browser draws its own clear cross on type=search, in its own place and only on some
   engines. One cross, ours, so it sits where the padding above makes room for it. */
.ff-find-box input[type="search"]::-webkit-search-cancel-button { display: none; }
.ff-find-clear {
  position: absolute; top: 50%; right: 5px; transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center; width: 22px; height: 22px;
  padding: 0; border: 0; border-radius: 50%; background: transparent; cursor: pointer;
  font: 500 17px/1 Figtree, sans-serif; color: var(--ff-muted);
}
.ff-find-clear:hover { background: var(--ff-hairline); color: var(--ff-text); }
.ff-find-count { font: 500 12.5px Figtree, sans-serif; color: var(--ff-muted); }
/* Superseded by the flex sharing above: a min-width of 180 on one of two selects that are each
   trying to be 100% wide is what made the pair overflow and wrap in the first place. */
.ff-health-fresh { margin-left: auto; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font: 500 12.5px Figtree, sans-serif; color: var(--ff-muted); }
.ff-health-divisions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }

/* The bar is two rows: the period and what it is valued at on the first, then the divisions on the
   left of the second with Refresh and Thresholds on its right. Centre rather than flex-end, because
   this row is chips and buttons of one height rather than fields sitting on a baseline. The spacing
   moves to the row so the chips are not also carrying a margin of their own. */
.ff-health-bar-row--split { align-items: center; margin-top: 12px; }
.ff-health-bar-row--split .ff-health-divisions { margin-top: 0; }
.ff-health-notice { margin: 0 0 12px; padding: 10px 14px; border-radius: var(--ff-r-tile); background: var(--ff-info-bg); color: var(--ff-info-tx); font: 600 13px Figtree, sans-serif; }
.ff-health-section-title { font: 800 16px Figtree, sans-serif; color: var(--ff-text); margin: 4px 2px 10px; }
.ff-health-section-title span { font-weight: 500; font-size: 13px; color: var(--ff-muted); }
.ff-health-gap { margin-top: 16px; }

.ff-health-good { color: var(--ff-success-tx); }
.ff-health-bad { color: var(--ff-error-tx); }
.ff-health-flat { color: var(--ff-muted); }

.ff-health-pillars { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; margin-bottom: 12px; }
.ff-health-pillar {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; text-align: left; cursor: pointer;
  padding: 12px 14px 10px; border-radius: var(--ff-r-card); border: 1px solid var(--ff-border); border-top: 4px solid var(--ff-faint);
  background: var(--ff-card); font: inherit; color: var(--ff-text); min-width: 0;
}
.ff-health-pillar:hover { border-color: var(--ff-teal); }
.ff-health-pillar:focus-visible { outline: 3px solid var(--ff-teal); outline-offset: 2px; }
.ff-health-pillar.is-on { box-shadow: 0 0 0 2px var(--ff-nav-accent-tint); border-color: var(--ff-teal); }
.ff-health-pillar-name { font: 700 12.5px Figtree, sans-serif; color: var(--ff-text-2); }
.ff-health-pillar-score { font: 800 28px Figtree, sans-serif; line-height: 1.1; }
.ff-health-pillar-status { font: 700 12px Figtree, sans-serif; }
.ff-health-pillar-reason { font: 500 12px Figtree, sans-serif; color: var(--ff-muted); min-height: 32px; overflow-wrap: anywhere; }
.ff-health-pillar .ff-health-spark { color: var(--ff-faint); margin-top: 4px; }
.ff-health--healthy { border-top-color: var(--ff-success); }
.ff-health--healthy .ff-health-pillar-status, .ff-health--healthy .ff-health-pillar-score { color: var(--ff-success-tx); }
.ff-health--watch { border-top-color: var(--ff-warn); }
.ff-health--watch .ff-health-pillar-status, .ff-health--watch .ff-health-pillar-score { color: var(--ff-warn-tx); }
.ff-health--poor { border-top-color: var(--ff-error); }
.ff-health--poor .ff-health-pillar-status, .ff-health--poor .ff-health-pillar-score { color: var(--ff-error-tx); }
.ff-health--none .ff-health-pillar-status, .ff-health--none .ff-health-pillar-score { color: var(--ff-muted); }

.ff-health-kpis { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }
.ff-health-kpi { padding: 12px 14px 8px; min-width: 0; }
.ff-health-kpi-label { font: 600 12px Figtree, sans-serif; color: var(--ff-text-2); }
.ff-health-kpi-value { font: 800 22px Figtree, sans-serif; color: var(--ff-text); margin: 2px 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ff-health-kpi-delta { display: flex; flex-wrap: wrap; gap: 4px 8px; font: 600 12px Figtree, sans-serif; min-height: 16px; }
.ff-health-kpi .ff-health-spark { margin-top: 6px; display: block; }

.ff-health-trend svg { display: block; max-width: 100%; height: auto; }
.ff-health-grid { stroke: var(--ff-hairline); stroke-width: 1; }
.ff-health-axis { font: 500 11px Figtree, sans-serif; fill: var(--ff-muted); }
.ff-health-axis--here { font-weight: 800; fill: var(--ff-text); }
.ff-health-here { fill: var(--ff-tint-teal); }
.ff-health-bar-net { fill: var(--ff-teal); background: var(--ff-teal); }
.ff-health-bar-ret { fill: var(--ff-warn); background: var(--ff-warn); }
.ff-health-line { stroke: var(--ff-error); stroke-width: 2; }
.ff-health-dot { fill: var(--ff-error); }
.ff-health-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 8px; font: 500 12px Figtree, sans-serif; color: var(--ff-text-2); }
.ff-health-key { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 6px; vertical-align: -1px; }
.ff-health-key--line { height: 3px; border-radius: 2px; background: var(--ff-error); vertical-align: 2px; }

.ff-health-filter { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 12px 16px; border-bottom: 1px solid var(--ff-hairline); }
.ff-health-toggle { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; font: 500 12.5px Figtree, sans-serif; color: var(--ff-text-2); cursor: pointer; }
.ff-health-list { list-style: none; margin: 0; padding: 0; }
.ff-health-row { border-bottom: 1px solid var(--ff-hairline); border-left: 4px solid var(--ff-faint); }
.ff-health-row:last-child { border-bottom: 0; }
.ff-health-row-main { display: grid; grid-template-columns: 96px minmax(0, 1fr) auto auto; align-items: start; gap: 12px; padding: 12px 16px 12px 12px; }
.ff-health-sev { font: 800 11px Figtree, sans-serif; text-transform: uppercase; letter-spacing: .04em; padding-top: 2px; }
.ff-health-what { min-width: 0; }
.ff-health-title { font: 700 13.5px Figtree, sans-serif; color: var(--ff-text); background: none; border: 0; padding: 0; text-align: left; cursor: default; }
button.ff-health-title { cursor: pointer; }
button.ff-health-title:hover { color: var(--ff-teal); }
.ff-health-caret { color: var(--ff-muted); font-size: 11px; }
.ff-health-detail { font: 500 12.5px Figtree, sans-serif; color: var(--ff-text-2); margin-top: 2px; }
.ff-health-meta { display: flex; flex-wrap: wrap; gap: 4px 12px; font: 600 11.5px Figtree, sans-serif; color: var(--ff-muted); margin-top: 4px; }
.ff-health-impact { font: 800 14px Figtree, sans-serif; color: var(--ff-text); white-space: nowrap; padding-top: 1px; }
.ff-health-fix { white-space: nowrap; }
.ff-health-offenders { margin: 0 16px 12px 120px; padding-left: 18px; font: 500 12.5px Figtree, sans-serif; color: var(--ff-text-2); }
.ff-health-offenders li { margin: 2px 0; overflow-wrap: anywhere; }
.ff-health-sev--critical { border-left-color: var(--ff-error); }
.ff-health-sev--critical .ff-health-sev { color: var(--ff-error-tx); }
.ff-health-sev--warning { border-left-color: var(--ff-warn); }
.ff-health-sev--warning .ff-health-sev { color: var(--ff-warn-tx); }
.ff-health-sev--info { border-left-color: var(--ff-info); }
.ff-health-sev--info .ff-health-sev { color: var(--ff-info-tx); }
.ff-health-sev--none .ff-health-sev { color: var(--ff-muted); }

.ff-health-h { font: 700 12.5px Figtree, sans-serif; color: var(--ff-text-2); margin-bottom: 6px; }
.ff-health-drivers { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px 24px; }
.ff-health-movers { min-width: 0; }
.ff-health-mover { display: flex; justify-content: space-between; gap: 10px; padding: 3px 0; font: 500 13px Figtree, sans-serif; }
.ff-health-mover-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ff-health-mover span:last-child { font-weight: 700; white-space: nowrap; }
.ff-health-split { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 16px 24px; margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--ff-hairline); }
.ff-health-mix { display: flex; height: 14px; border-radius: 7px; overflow: hidden; background: var(--ff-hairline); }
.ff-health-mix-seg { display: block; min-width: 2px; }
.ff-health-mix-keys { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 8px; font: 500 12px Figtree, sans-serif; color: var(--ff-text-2); }
.ff-health-mix-keys i { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: 5px; }
.ff-health-mix-0 { background: var(--ff-teal); }
.ff-health-mix-1 { background: var(--ff-info); }
.ff-health-mix-2 { background: var(--ff-purple); }
.ff-health-mix-3 { background: var(--ff-warn); }
.ff-health-mix-4 { background: var(--ff-success); }
.ff-health-mix-5 { background: var(--ff-faint); }
.ff-health-pair { display: flex; gap: 24px; font: 500 12px Figtree, sans-serif; }
.ff-health-big { font: 800 22px Figtree, sans-serif; }

.ff-health-teams th:first-child { min-width: 200px; }
.ff-health-teams a.ff-drill-name { color: var(--ff-teal); font-weight: 700; text-decoration: none; }
.ff-health-teams a.ff-drill-name:hover { color: var(--ff-teal-deep); text-decoration: underline; }
.ff-health-teams .ff-drill-num { text-align: right; white-space: nowrap; }
.ff-health-teams tr.ff-drill-unassigned td { border-top: 1px solid var(--ff-border); font-style: italic; }
.ff-health-teams td.ff-health-good { color: var(--ff-success-tx); font-weight: 700; }
.ff-health-teams td.ff-health-bad { color: var(--ff-error-tx); font-weight: 700; }

.ff-health-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.ff-health-stat { padding: 10px 12px; border-radius: var(--ff-r-tile); background: var(--ff-canvas); font: 500 12px Figtree, sans-serif; min-width: 0; }
.ff-health-stat-v { font: 800 18px Figtree, sans-serif; color: var(--ff-text); }
.ff-health-waiting { padding: 12px 14px; border-radius: var(--ff-r-tile); background: var(--ff-canvas); font: 500 13px Figtree, sans-serif; color: var(--ff-text-2); }
.ff-health-waiting a { color: var(--ff-teal); font-weight: 700; }
.ff-health-mini { list-style: none; margin: 12px 0 0; padding: 0; }
.ff-health-mini li { display: flex; justify-content: space-between; gap: 10px; padding: 6px 0 6px 10px; border-left: 3px solid var(--ff-faint); font: 600 12.5px Figtree, sans-serif; }
.ff-health-mini li + li { margin-top: 4px; }
.ff-health-mini a { color: var(--ff-teal); white-space: nowrap; }
.ff-health-mini li.ff-health-sev--critical { border-left-color: var(--ff-error); }
.ff-health-mini li.ff-health-sev--warning { border-left-color: var(--ff-warn); }
.ff-health-mini li.ff-health-sev--info { border-left-color: var(--ff-info); }

@media (max-width: 1200px) {
  .ff-health-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 1024px) {
  .ff-health-pillars { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ff-health-drivers { grid-template-columns: 1fr; }
  .ff-health-split { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .ff-health-pillars, .ff-health-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ff-health-fresh { margin-left: 0; }
  .ff-health-row-main { grid-template-columns: minmax(0, 1fr) auto; }
  .ff-health-sev { grid-column: 1 / -1; }
  .ff-health-fix { grid-column: 1 / -1; justify-self: start; }
  .ff-health-offenders { margin-left: 16px; }
  .ff-health-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ff-health-toggle { margin-left: 0; }
}

/* ---- Daily Call Report ------------------------------------------------------------------------
   The league table, the person × day grid and the day panel. Scoped names (.ff-dcr-*) because the
   grid is unlike any other table here: fixed-width day cells, a sticky person column and a legend.
   .ff-num is deliberately generic — a right-aligned, tabular-figure cell is wanted everywhere a
   number is printed, and every report that adds one by hand gets it slightly different. */
.ff-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ff-table th.ff-num { text-align: right; }

.ff-dcr-strong { font-weight: 800; color: var(--ff-ink); }
.ff-dcr-sub { display: block; font: 600 11px Figtree, sans-serif; color: var(--ff-muted); margin-top: 2px; }
.ff-dcr-wrap { white-space: normal; max-width: 280px; }
.ff-dcr-linkbtn { border: 0; background: none; padding: 0; font: 800 12.5px Figtree, sans-serif; color: var(--ff-teal); cursor: pointer; }
.ff-dcr-linkbtn:hover { text-decoration: underline; }

.ff-dcr-tiles { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 12px; margin-top: 14px; }
.ff-dcr-tile { padding: 13px 15px; }
.ff-dcr-lab { font: 700 10.5px Figtree, sans-serif; letter-spacing: .07em; text-transform: uppercase; color: var(--ff-muted); }
.ff-dcr-val { font: 800 25px Figtree, sans-serif; letter-spacing: -.02em; margin-top: 5px; font-variant-numeric: tabular-nums; color: var(--ff-ink); }
.ff-dcr-of { font: 700 13px Figtree, sans-serif; color: var(--ff-muted); }
.ff-dcr-sub2, .ff-dcr-tile .ff-dcr-sub { display: block; font: 600 11.5px Figtree, sans-serif; color: var(--ff-muted); margin-top: 3px; }
.ff-dcr-warn { background: #FFFBF5; }

.ff-dcr-tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--ff-border); margin: 20px 0 0; }
.ff-dcr-tabs a { padding: 10px 16px; font: 700 12.5px Figtree, sans-serif; color: var(--ff-muted); border-bottom: 2px solid transparent; border-radius: 8px 8px 0 0; text-decoration: none; }
.ff-dcr-tabs a:hover { background: var(--ff-tint-teal); }
.ff-dcr-tabs a.active { color: var(--ff-teal); border-bottom-color: var(--ff-teal); background: #fff; }

.ff-dcr-table th { padding-left: 10px; padding-right: 10px; }
.ff-dcr-table td { padding-left: 10px; padding-right: 10px; }
.ff-dcr-band th { font-size: 10px; color: var(--ff-muted); text-align: center; padding-bottom: 2px; }

.ff-dcr-mini { display: inline-block; width: 42px; height: 4px; border-radius: 2px; background: var(--ff-hairline); overflow: hidden; vertical-align: middle; margin-left: 7px; }
.ff-dcr-mini i { display: block; height: 100%; }

/* The grid. Day cells are fixed so a month of them lines up, and the person column stays put while
   the days scroll — a row of blocks with no name against it says nothing. */
.ff-dcr-cal th, .ff-dcr-cal td { padding: 3px; }
.ff-dcr-cal-who { position: sticky; left: 0; background: #fff; z-index: 1; min-width: 210px; text-align: left; padding: 7px 12px !important; }
.ff-dcr-cal thead .ff-dcr-cal-who { background: var(--ff-thead); }
.ff-dcr-cal th { text-align: center; font-size: 10.5px; line-height: 1.25; }
.ff-dcr-cal th small { display: block; font: 600 9.5px Figtree, sans-serif; color: var(--ff-muted); letter-spacing: .04em; }
.ff-dcr-cal-cell { text-align: center; }
.ff-dcr-off { background: var(--ff-thead); }
.ff-dcr-blk { width: 34px; height: 30px; border-radius: 6px; display: inline-flex; align-items: center; justify-content: center; font: 800 11.5px Figtree, sans-serif; border: 1px solid transparent; padding: 0; }
button.ff-dcr-blk { cursor: pointer; }
button.ff-dcr-blk:hover { outline: 2px solid var(--ff-teal); outline-offset: 1px; }

.ff-dcr-key { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; padding: 12px 16px; border-top: 1px solid var(--ff-hairline); font: 600 12px Figtree, sans-serif; color: var(--ff-muted); }
.ff-dcr-k { display: inline-flex; align-items: center; gap: 6px; }
.ff-dcr-sw { width: 18px; height: 18px; border-radius: 5px; display: inline-block; border: 1px solid transparent; }

.ff-dcr-decide { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; justify-content: space-between; background: #FFFBF5; border: 1px solid #E6C9A8; border-radius: 10px; padding: 12px 14px; font: 600 12.5px Figtree, sans-serif; color: #5C3A05; }
.ff-dcr-day-head { display: flex; flex-wrap: wrap; gap: 26px; align-items: flex-start; margin-top: 12px; }
.ff-dcr-day-head > div { display: flex; flex-direction: column; gap: 3px; }

@media (max-width: 1100px) {
  .ff-dcr-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 680px) {
  .ff-dcr-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ff-dcr-cal-who { min-width: 150px; }
}

/* The Daily Call Report's filter chips, tile bars and the Team toolbar. */
.ff-dcr-chips { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; margin-top: 14px; }
.ff-dcr-chip { display: inline-flex; align-items: center; gap: 6px; background: var(--ff-tint-teal); color: var(--ff-brand-strong); border-radius: var(--ff-r-pill); padding: 4px 11px; font: 700 11.5px Figtree, sans-serif; }
.ff-dcr-bar { height: 5px; border-radius: 3px; background: var(--ff-hairline); overflow: hidden; margin-top: 9px; }
.ff-dcr-bar i { display: block; height: 100%; border-radius: 3px; }
.ff-dcr-toolbar { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid var(--ff-hairline); }
.ff-seg { display: inline-flex; border: 1px solid var(--ff-border); border-radius: 9px; overflow: hidden; background: #fff; }
.ff-seg button { border: 0; background: #fff; font: 600 12.5px Figtree, sans-serif; padding: 8px 13px; cursor: pointer; color: var(--ff-text-2); border-right: 1px solid var(--ff-hairline); }
.ff-seg button:last-child { border-right: 0; }
.ff-seg button[aria-pressed="true"] { background: var(--ff-teal); color: #fff; font-weight: 800; }

/* A name that opens something is a link and looks like one; a grouped row's name opens nothing
   and must not. The one visual difference between "you can click this" and "you cannot". */
.ff-dcr-link { font: 800 12.5px Figtree, sans-serif; color: var(--ff-teal); text-decoration: none; }
.ff-dcr-link:hover { text-decoration: underline; }

/* The report's own page head: the sentence that says what the screen is for, and the two actions
   that belong to the whole report rather than to one table. */
.ff-dcr-head { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-end; justify-content: space-between; margin-bottom: 4px; }
.ff-dcr-lede { font: 500 13px Figtree, sans-serif; color: var(--ff-muted); margin-top: 3px; max-width: 760px; }
.ff-dcr-acts { display: flex; gap: 9px; align-items: center; }

/* The filter row: labels above their control, wrapping, the person picker taking the slack —
   not a rigid three-column grid, which stacked a date input beside a wide select. */
.ff-dcr-filters { display: flex; flex-wrap: wrap; gap: 13px; align-items: flex-end; }
.ff-dcr-filters .ff-field { flex: 0 0 auto; }
.ff-dcr-filters .ff-field--wide { flex: 1 1 260px; min-width: 220px; }

/* ============================================================
   Business Review (/admin/reports/business-review)
   ============================================================
   The owner's one-glance screen. Its own prefix so nothing here can reach Company Health or the
   Command Center, which keep their own looks and their own questions.

   Colours are the status -tx variants, never the raw --ff-success / --ff-error: the raw ones are
   fills, and at 13px on white they sit around 3:1. Up and down also differ in weight and carry an
   arrow, so the two are told apart without relying on hue. */

.ff-br-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: 14px; margin: 2px 0 14px; }
.ff-br-h { margin: 0; font: 800 21px Figtree, sans-serif; letter-spacing: -.02em; color: var(--ff-brand-strong); }
.ff-br-lede { margin-top: 4px; font-size: 13px; color: var(--ff-text-2); }
.ff-br-acts { display: flex; gap: 8px; }
.ff-br-filters { display: flex; flex-wrap: wrap; gap: 12px; }
.ff-br-filters .ff-field { min-width: 170px; }

.ff-br-text { margin: 0; font-size: 13.5px; line-height: 1.6; color: var(--ff-text-2); }
.ff-br-empty { margin: 4px 0; font-size: 13px; color: var(--ff-muted); }
.ff-br-notice { margin: 12px 0; padding: 10px 14px; border-radius: 10px; background: var(--ff-warn-bg);
  color: var(--ff-warn-tx); font-size: 12.5px; font-weight: 600; }
.ff-br-eyebrow { font-size: 11px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ff-text-2); }

/* ---- the verdict ---- */
.ff-br-verdict { display: flex; gap: 18px; margin: 14px 0; padding: 20px 22px; background: var(--ff-card);
  border: 1px solid var(--ff-border); border-radius: var(--ff-r-card); }
.ff-br-rule { flex: none; width: 5px; border-radius: 999px; background: var(--ff-teal); }
.ff-br-verdict-body { min-width: 0; }
.ff-br-headline { margin: 8px 0 0; font-size: 20px; line-height: 1.45; font-weight: 600;
  letter-spacing: -.01em; color: var(--ff-text); }
.ff-br-detail { margin: 9px 0 0; font-size: 13.5px; line-height: 1.6; color: var(--ff-text-2); }

/* ---- tiles ---- */
.ff-br-kpis { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; margin-bottom: 14px; }
.ff-br-kpi { background: var(--ff-card); border: 1px solid var(--ff-border); border-radius: var(--ff-r-card);
  padding: 14px 16px; display: flex; flex-direction: column; gap: 5px; color: var(--ff-teal); }
.ff-br-kpi-label { font-size: 11.5px; font-weight: 700; color: var(--ff-text-2); }
.ff-br-kpi-value { font: 800 25px Figtree, sans-serif; letter-spacing: -.02em; color: var(--ff-text);
  font-variant-numeric: tabular-nums; }
.ff-br-kpi-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.ff-br-kpi-note { font-size: 11.5px; color: var(--ff-text-2); }
.ff-br-spark { flex: none; }
.ff-br-pill { font-size: 12px; font-weight: 700; border-radius: var(--ff-r-pill); padding: 2px 9px;
  font-variant-numeric: tabular-nums; }

.ff-br-up { color: var(--ff-success-tx); }
.ff-br-down { color: var(--ff-error-tx); }
.ff-br-flat { color: var(--ff-text-2); }
.ff-br-pill.ff-br-up { background: var(--ff-success-bg); }
.ff-br-pill.ff-br-down { background: var(--ff-error-bg); }
.ff-br-pill.ff-br-flat { background: var(--ff-thead); }

/* ---- the bridge ----
   Each bar is positioned from the BOTTOM of its plot as a percentage, so a change hangs between the
   running totals either side of it and the chart keeps its shape at any width. */
.ff-br-bridge { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 16px; align-items: end;
  margin-top: 6px; }
.ff-br-col { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.ff-br-plot { position: relative; height: 210px; }
.ff-br-bar { position: absolute; left: 0; right: 0; border-radius: 6px; min-height: 3px; }
.ff-br-bar--total { background: var(--ff-brand-strong); border-radius: 6px 6px 0 0; }
.ff-br-bar--up { background: var(--ff-success-tx); }
.ff-br-bar--down { background: var(--ff-error-tx); }
.ff-br-bar-value { font: 800 15px Figtree, sans-serif; color: var(--ff-text); font-variant-numeric: tabular-nums; }
.ff-br-bar-label { font-size: 12px; font-weight: 600; color: var(--ff-text-2); line-height: 1.4; }

.ff-br-callout { margin-top: 16px; padding: 12px 16px; border-radius: 10px; font-size: 13.5px;
  line-height: 1.55; color: var(--ff-text); }
.ff-br-callout--bad { background: var(--ff-error-bg); }
.ff-br-callout--good { background: var(--ff-success-bg); }

.ff-br-foot { margin-top: 10px; font-size: 12px; line-height: 1.5; color: var(--ff-text-2); }

/* A branch view's figures do not add up to the company's. Said once, at the top, in the info tone
   rather than the warning one: it is a fact about the view, not a problem with it. */
.ff-br-covers { margin: 12px 0; padding: 11px 15px; border-radius: 10px; background: var(--ff-info-bg);
  color: var(--ff-text); font-size: 12.5px; line-height: 1.55; }
.ff-br-covers strong { color: var(--ff-info-tx); }

/* ---- panels ---- */
.ff-br-three { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.ff-br-four { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }

.ff-br-slice { margin-bottom: 13px; }
.ff-br-slice-top { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.ff-br-slice-name { font-size: 13.5px; font-weight: 700; color: var(--ff-text); }
.ff-br-slice-val { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
.ff-br-slice-sub { margin-top: 4px; font-size: 11.5px; color: var(--ff-text-2); }
.ff-br-track { margin-top: 6px; height: 9px; border-radius: 999px; background: var(--ff-hairline); overflow: hidden; }
.ff-br-fill { height: 100%; background: var(--ff-teal); }
.ff-br-fill--warn { background: var(--ff-warn-tx); }

.ff-br-table { width: 100%; }
.ff-br-person { font-weight: 600; color: var(--ff-text); }
.ff-br-person-code { font-size: 11.5px; color: var(--ff-text-2); }
.ff-br-gap td { text-align: center; color: var(--ff-muted); font-size: 11.5px; padding: 4px 0; }
.ff-br-warn { margin-top: 12px; padding: 10px 12px; border-radius: 10px; background: var(--ff-warn-bg);
  color: var(--ff-text); font-size: 12px; line-height: 1.5; }
.ff-br-move { display: flex; justify-content: space-between; gap: 8px; font-size: 13px; padding: 4px 0;
  font-variant-numeric: tabular-nums; }
.ff-br-move span:first-child { font-weight: 600; color: var(--ff-text); }

/* ---- tiles inside a card ---- */
.ff-br-tile { border: 1px solid var(--ff-hairline); border-radius: 12px; padding: 14px 16px; }
.ff-br-tile--warn { border-color: var(--ff-warn-tx); background: var(--ff-warn-bg); }
.ff-br-tile-label { font-size: 12px; font-weight: 700; color: var(--ff-text-2); }
.ff-br-tile-value { margin-top: 5px; font: 800 23px Figtree, sans-serif; letter-spacing: -.02em;
  color: var(--ff-text); font-variant-numeric: tabular-nums; }
.ff-br-tile-sub { margin-top: 2px; font-size: 13px; color: var(--ff-text); }
.ff-br-tile-note { margin-top: 8px; font-size: 11.5px; line-height: 1.5; color: var(--ff-text-2); }
.ff-br-split { margin-top: 10px; display: flex; gap: 4px; height: 9px; }
.ff-br-split-in { border-radius: 999px; background: var(--ff-success-tx); }
.ff-br-split-out { border-radius: 999px; background: var(--ff-error-tx); }

/* ---- decisions ---- */
.ff-br-decide { margin: 14px 0; padding: 22px 24px; border-radius: var(--ff-r-card); background: var(--ff-brand-strong); }
.ff-br-decide-h { margin: 0; font: 700 17px Figtree, sans-serif; color: #fff; }
.ff-br-decide-sub { margin: 4px 0 16px; font-size: 13px; color: #BBD0EA; }
.ff-br-decision { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; background: var(--ff-card);
  border-radius: 12px; padding: 14px 16px; margin-bottom: 9px; }
.ff-br-decision:last-child { margin-bottom: 0; }
.ff-br-decision-n { flex: none; width: 46px; height: 46px; border-radius: 12px; background: var(--ff-tint-teal);
  color: var(--ff-teal-deep); font: 800 18px Figtree, sans-serif; display: flex; align-items: center;
  justify-content: center; }
.ff-br-decision-body { flex: 1 1 420px; min-width: 0; }
.ff-br-decision-t { font-size: 14.5px; font-weight: 700; color: var(--ff-text); }
.ff-br-decision-d { margin-top: 3px; font-size: 12.5px; line-height: 1.5; color: var(--ff-text-2); }

/* ---- blind spots ---- */
.ff-br-spot { border-left: 3px solid var(--ff-hairline); padding-left: 12px; }
.ff-br-spot-label { font-size: 12.5px; font-weight: 700; color: var(--ff-text); }
.ff-br-spot-detail { margin-top: 3px; font-size: 12px; line-height: 1.5; color: var(--ff-text-2); }

/* Narrow screens: the five-across and four-across bands stack rather than squeeze, and the bridge
   keeps its six columns because a bridge with a wrapped column is not a bridge. */
@media (max-width: 1200px) {
  .ff-br-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ff-br-three, .ff-br-four { grid-template-columns: minmax(0, 1fr); }
  .ff-br-bridge { gap: 8px; }
  .ff-br-bar-label { font-size: 11px; }
}

/* ============================================================
   Celebrations (/admin/celebrations, /manager/celebrations, /exec/celebrations)
   ============================================================
   Who to wish today, and who is going to do it. Its own prefix, because nothing here is a figure
   and none of the report blocks fit a list of people.

   Two things the layout has to carry. A row whose customer is assigned to NOBODY is marked, since
   a birthday nobody owns reminds nobody and that is the finding, not an edge case. And the
   coverage bar sits ABOVE the list, because an empty list is almost always explained by the bar
   rather than by the week. */

.ff-cel-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: 14px; margin: 2px 0 14px; }
.ff-cel-h { margin: 0; font: 800 21px Figtree, sans-serif; letter-spacing: -.02em; color: var(--ff-brand-strong); }
.ff-cel-lede { margin-top: 4px; font-size: 13px; color: var(--ff-text-2); }
.ff-cel-acts { display: flex; gap: 8px; }

.ff-cel-windows { margin-bottom: 14px; }
.ff-cel-filters { display: flex; flex-wrap: wrap; gap: 12px; }
.ff-cel-filters .ff-field { min-width: 190px; }
.ff-cel-filters .ff-cel-person { flex: 1 1 260px; min-width: 240px; }

.ff-cel-text { margin: 0; font-size: 13.5px; line-height: 1.6; color: var(--ff-text-2); }

/* ---- coverage ---- */
.ff-cel-cover { margin: 14px 0; padding: 14px 18px; background: var(--ff-card);
  border: 1px solid var(--ff-border); border-radius: var(--ff-r-card); }
.ff-cel-cover-top { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 9px; }
.ff-cel-cover-line { font-size: 12.5px; font-weight: 600; color: var(--ff-text-2); }
.ff-cel-cover-pct { font: 800 14px Figtree, sans-serif; color: var(--ff-teal-deep); }
.ff-cel-bar { height: 8px; border-radius: 999px; background: var(--ff-hairline); overflow: hidden; }
.ff-cel-bar-fill { height: 100%; border-radius: 999px; background: var(--ff-teal); min-width: 2px; }

.ff-cel-notice { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 12px 0;
  padding: 12px 16px; border-radius: 10px; background: var(--ff-warn-bg); color: var(--ff-warn-tx);
  font-size: 12.5px; font-weight: 600; line-height: 1.55; }
.ff-cel-notice-a { margin-left: auto; white-space: nowrap; }

.ff-cel-count { margin: 16px 0 8px; font-size: 11px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ff-text-2); }

/* ---- a day ---- */
.ff-cel-day { margin-bottom: 16px; }
.ff-cel-dayhead { display: flex; align-items: center; gap: 10px; margin: 0 0 7px; }
.ff-cel-dayname { font: 700 13px Figtree, sans-serif; color: var(--ff-text); }
.ff-cel-dayname--now { color: var(--ff-teal-deep); }
.ff-cel-daycount { font: 700 11px Figtree, sans-serif; color: var(--ff-text-2);
  background: var(--ff-hairline); border-radius: 999px; padding: 2px 8px; }

/* ---- a row ---- */
.ff-cel-row { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-bottom: 8px;
  padding: 12px 16px; background: var(--ff-card); border: 1px solid var(--ff-border);
  border-left: 3px solid transparent; border-radius: var(--ff-r-card); }
.ff-cel-row:last-child { margin-bottom: 0; }
/* Nobody holds this customer, so nobody is reminded. Marked by a bar AND by the words in the
   owner column, never by colour alone. */
.ff-cel-row--orphan { border-left-color: var(--ff-warn); background: var(--ff-warn-bg); }

.ff-cel-mark { flex: none; width: 48px; height: 48px; border-radius: 12px; display: flex;
  flex-direction: column; align-items: center; justify-content: center; line-height: 1.1; }
.ff-cel-mark--b { background: var(--ff-tint-teal); color: var(--ff-teal-deep); }
.ff-cel-mark--a { background: var(--ff-tint-purple); color: var(--ff-purple-tx); }
.ff-cel-mark-d { font: 800 17px Figtree, sans-serif; }
.ff-cel-mark-m { font: 700 9.5px Figtree, sans-serif; letter-spacing: .07em; text-transform: uppercase; }

.ff-cel-who { flex: 1 1 320px; min-width: 0; }
.ff-cel-name { font-size: 14px; font-weight: 700; color: var(--ff-text); }
.ff-cel-code { margin-left: 8px; font: 600 11px Figtree, sans-serif; color: var(--ff-muted); }
.ff-cel-meta { margin-top: 3px; font-size: 12.5px; line-height: 1.5; color: var(--ff-text-2); }

.ff-cel-owner { flex: 0 1 220px; min-width: 150px; }
.ff-cel-owner-label { display: block; font-size: 10.5px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ff-muted); }
.ff-cel-owner-who { display: block; margin-top: 2px; font-size: 12.5px; font-weight: 600; color: var(--ff-text); }
.ff-cel-owner-who--none { color: var(--ff-warn-tx); }

.ff-cel-call { flex: none; margin-left: auto; }

/* Narrow screens: the date tile and the name stay on the first line, the owner and the call drop
   under them rather than squeezing the name to three characters. */
@media (max-width: 900px) {
  .ff-cel-owner { flex: 1 1 100%; margin-left: 62px; }
  .ff-cel-call { margin-left: 62px; }
}

/* ============================================================
   Console navigation - one search, shortcuts, rail flyout
   ============================================================
   The menu holds 68 entries. Nothing below makes it shorter; what they do is put the six a person
   actually opens above the sixty-eight, and make the one search good enough that the tree is for
   browsing rather than for hunting.

   Colours are the --ff-nav-* tokens the five themes already redefine, so this retints with them. */

/* ---- the one search, in the menu ---- */
.ff-side-search-wrap { padding: 0 12px 10px; }

.ff-omni { position: relative; display: flex; align-items: center; gap: 8px; height: 38px;
  padding: 0 10px; border-radius: 10px; background: var(--ff-nav-input);
  box-shadow: inset 0 0 0 1px var(--ff-nav-input-line); }
.ff-omni:focus-within { background: var(--ff-nav-surface);
  box-shadow: 0 0 0 2px var(--ff-nav-accent-tint), inset 0 0 0 1px var(--ff-nav-accent); }
.ff-omni-ic { display: flex; color: var(--ff-muted); flex: none; }
.ff-omni:focus-within .ff-omni-ic { color: var(--ff-nav-accent); }
.ff-omni input { flex: 1; min-width: 0; border: 0; background: transparent; outline: none;
  font: 500 12.5px Figtree, sans-serif; color: var(--ff-text); }
.ff-omni input::placeholder { color: var(--ff-muted); }
.ff-omni-x { flex: none; width: 20px; height: 20px; border: 0; border-radius: 6px; cursor: pointer;
  background: var(--ff-nav-hover); color: var(--ff-text-2); display: flex; align-items: center;
  justify-content: center; }

/* The results hang over the page, so they clear the menu's own scroll area. */
.ff-omni .ff-search-results { position: absolute; top: calc(100% + 7px); left: 0; width: 320px;
  max-height: 460px; overflow: auto; z-index: 1200; background: var(--ff-card);
  border: 1px solid var(--ff-border); border-radius: 13px; box-shadow: var(--ff-shadow-float);
  padding: 7px; }
.ff-omni.is-compact .ff-search-results { width: 316px; }

.ff-search-group { display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  padding: 7px 11px 5px; font: 700 9.5px Figtree, sans-serif; letter-spacing: .11em;
  text-transform: uppercase; color: var(--ff-nav-section); }
.ff-search-count { font-size: 9.5px; letter-spacing: 0; text-transform: none; color: var(--ff-faint); }

.ff-search-hit { display: flex; align-items: center; gap: 10px; padding: 7px 11px; border-radius: 9px;
  cursor: pointer; color: var(--ff-text); }
.ff-search-hit.is-active, .ff-search-hit:hover { background: var(--ff-nav-hover); }
.ff-search-hit-ic { display: flex; flex: none; color: var(--ff-nav-accent); }
.ff-search-hit-txt { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ff-search-hit-txt b { font: 600 12.5px Figtree, sans-serif; }
.ff-search-hit-sub { font-size: 10.5px; color: var(--ff-text-2); }
.ff-hl { background: #FEF0C7; color: var(--ff-text); border-radius: 3px; padding: 0 1px; }
.ff-ss-empty { color: var(--ff-text-2); font-size: 12px; }

.ff-omni-keys { display: flex; gap: 13px; padding: 9px 11px 4px; margin-top: 3px;
  border-top: 1px solid var(--ff-nav-line); font-size: 10px; color: var(--ff-faint); }
.ff-omni-keys b { color: var(--ff-text-2); }

.ff-sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; }

/* ---- pinned and recent ---- */
.ff-nav-section--quick { display: flex; align-items: center; justify-content: space-between; }

.ff-quick { position: relative; display: flex; align-items: center; }
.ff-quick-link { flex: 1; min-width: 0; display: flex; align-items: center; gap: 11px;
  padding: 8px 12px; border-radius: 9px; font-size: 13px; color: var(--ff-text);
  text-decoration: none; }
.ff-quick-link:hover { background: var(--ff-nav-hover); }
.ff-quick-link.active { background: var(--ff-nav-accent-tint); color: var(--ff-teal-deep); font-weight: 700; }

/* Every menu row can be pinned, which is why .ff-nav-row exists: the link keeps the whole width
   it had, and the button sits over its right edge. Pinning only from Pinned and Recent — where it
   started — meant a screen had to be visited before it could be pinned, and somebody with neither
   saw no pin button at all. */
.ff-nav-row { position: relative; display: flex; align-items: center; }
.ff-nav-row > .ff-nav-item,
.ff-nav-row > .ff-nav-group--link { flex: 1; min-width: 0; }
.ff-nav-row > .ff-nav-item .ff-nav-badge,
.ff-nav-row > .ff-nav-group--link .ff-nav-badge { margin-right: 20px; }

/* Only on hover or focus: a column of pins down the menu is noise, and the one that is already
   pinned has to stay visible or unpinning becomes a guess. */
.ff-quick-pin { position: absolute; right: 7px; width: 24px; height: 24px; border: 0; cursor: pointer;
  border-radius: 7px; background: transparent; color: var(--ff-faint); opacity: 0;
  display: flex; align-items: center; justify-content: center; }
.ff-quick:hover .ff-quick-pin, .ff-nav-row:hover .ff-quick-pin,
.ff-quick-pin:focus-visible { opacity: 1; }
.ff-quick-pin:hover { background: var(--ff-nav-elevated); color: var(--ff-text-2); }
.ff-quick-pin.is-on { opacity: 1; color: var(--ff-nav-badge); }

/* Why a pin did not take. Shown where the stars are, because that is where the click was. */
.ff-quick-err { margin: 4px 12px 0; font-size: 11px; line-height: 1.45; color: var(--ff-warn-tx); }

.ff-nav-rule { height: 1px; background: var(--ff-nav-line); margin: 11px 12px 8px; }

/* ---- the rail drawer ----
   Twelve icons and no labels is a memory test, so a click on the rail opens that group's items
   beside it. The panel is a SIBLING of .ff-nav and never a child: .ff-nav is overflow-x: hidden so
   that it can scroll, and anything positioned inside it is clipped at the rail's 70px — the panel
   would simply not be there, with nothing on screen to say why.

   The position: relative it hangs from is on the BASE .ff-sidebar rule further up this file, NOT
   here. Setting it here blanked the whole menu on any screen under 1024px: the drawer rule in that
   media query is `position: fixed; transform: translateX(-100%)`, a media query adds no
   specificity, and a later rule of equal specificity wins — so the sidebar came back into the flex
   flow at its full 288px while its contents stayed translated off the left edge. An empty white
   column where the menu should be, and the page shoved sideways by it. */
.ff-rail-drawer { position: absolute; left: 100%; top: 0; bottom: 0; width: 226px; z-index: 1300;
  background: var(--ff-card); border-right: 1px solid var(--ff-border);
  box-shadow: var(--ff-shadow-float); padding: 12px 8px; overflow-y: auto;
  animation: ff-rail-drawer-in .15s cubic-bezier(.2,.8,.3,1) both; }

@keyframes ff-rail-drawer-in { from { opacity: 0; transform: translateX(-6px); } }

.ff-rail-drawer-h { display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 2px 10px 9px; font: 700 9.5px Figtree, sans-serif; letter-spacing: .11em;
  text-transform: uppercase; color: var(--ff-nav-section); }
.ff-rail-drawer-x { width: 22px; height: 22px; flex: none; border: 0; border-radius: 6px; cursor: pointer;
  background: transparent; color: var(--ff-faint); display: flex; align-items: center; justify-content: center; }
.ff-rail-drawer-x:hover { background: var(--ff-nav-hover); color: var(--ff-text-2); }

.ff-rail-drawer-i { display: block; padding: 8px 12px; border-radius: 8px; font-size: 12.5px;
  color: var(--ff-text-2); text-decoration: none; }
.ff-rail-drawer-i:hover { background: var(--ff-nav-hover); color: var(--ff-text); }
.ff-rail-drawer-i.active { background: var(--ff-nav-accent-tint); color: var(--ff-teal-deep); font-weight: 600; }

/* ---- the header, now that the search has left it ----
   The page's title takes the room. The gap is what keeps the controls on the right rather than
   letting a short title drag them into the middle of the bar. */
.ff-topbar-gap { flex: 1; min-width: 12px; }

/* A phone has no room for a 272px menu, so the shortcuts and the flyout go with it. */
@media (max-width: 900px) {
  .ff-omni .ff-search-results { width: min(320px, calc(100vw - 48px)); }
  .ff-rail-drawer { width: min(226px, calc(100vw - 86px)); }
}

/* Orders (/admin/orders) — the register of what the field placed, and the file the invoicing
   system is handed. */
.ff-ord-filters { display: flex; flex-wrap: wrap; gap: 12px; }
.ff-ord-filters .ff-field { min-width: 165px; }
.ff-ord-filters .ff-ord-person { flex: 1 1 240px; min-width: 220px; }
.ff-ord-code { margin-left: 8px; font: 600 11px Figtree, sans-serif; color: var(--ff-muted); }
.ff-ord-foot { padding: 10px 18px; font-size: 11.5px; color: var(--ff-text-2);
  border-top: 1px solid var(--ff-hairline); }

/* The requisition’s note when the budget type expects nothing back: the form stops asking for
   three fields, and a form that quietly stops asking reads as a form that has gone wrong. */
.ff-cbr-note { margin: 0 0 12px; padding: 9px 13px; border-radius: 10px; background: var(--ff-info-bg);
  color: var(--ff-info-tx); font-size: 12.5px; line-height: 1.55; }

/* ---- Customer Movement: the shops behind the Business Review's bridge ---- */
/* The count beside a tab's name. Muted and smaller, because the word is what is being chosen and
   the number is what it is worth looking at. */
.ff-tab-count { margin-left: 6px; font-size: 11.5px; font-weight: 600; color: var(--ff-muted); }
.ff-tab.active .ff-tab-count { color: var(--ff-teal-deep); }
/* A bridge column that leads somewhere says so. The two period totals are not buckets and keep the
   plain label, so the difference between a door and a caption is visible before it is clicked. */
.ff-br-bar-link { display: block; color: var(--ff-teal-deep); text-decoration: none; cursor: pointer; }
.ff-br-bar-link:hover { text-decoration: underline; }

/* ---------------------------------------------------------------- Product Wise Sales
   A dozen numeric columns beside a product name. Scoped .razor.css is never served in this project,
   so this lives here with everything else. */
.ff-pws .ff-pws-sl { width: 44px; text-align: right; color: var(--ff-muted); }
.ff-pws .ff-pws-num, .ff-pws th.ff-pws-num { text-align: right; white-space: nowrap; }
.ff-pws .ff-pws-total { font-weight: 700; }

/* The division band. A heading inside the grid rather than another product row: a subtotal that
   looks like a row gets added to the rows beneath it by eye. */
.ff-pws tr.ff-pws-group > td {
    background: var(--ff-canvas);
    font-weight: 700;
    border-top: 2px solid var(--ff-border);
}

/* A count that opens what is behind it, in a column of counts.

   Blue is the whole affordance. A bordered button here reads as an editable box, and its padding
   pushed the number off the right edge the plain rows sit on - so a column of 0, 7, 0, 35 came out
   with the clickable ones out of line. Inherits the cell's font so the only difference from the
   number beside it is that this one can be pressed. */
.ff-num-link { border: 0; background: none; padding: 0; cursor: pointer;
               font: inherit; font-weight: 600; color: var(--ff-brand-strong); }
.ff-num-link:hover { text-decoration: underline; }

/* A heading inside a long form.

   The user modal asks twenty-three questions. A flat list of twenty-three is a form people give
   up on, so the groups are named and the rule is what separates them - quieter than a card, which
   would make a modal of boxes inside a box. */
.ff-form-rule { display: flex; align-items: baseline; gap: 10px; margin: 18px 0 2px;
                padding-top: 14px; border-top: 1px solid var(--ff-hairline);
                font: 700 11px Figtree, sans-serif; letter-spacing: .4px;
                text-transform: uppercase; color: var(--ff-text-2); }
.ff-form-rule__note { font: 400 11.5px Figtree, sans-serif; letter-spacing: 0;
                      text-transform: none; color: var(--ff-warn-tx); }

/* Why THIS box is wrong, under this box. One message at the foot of a twenty-three question form
   is a hunt; the error belongs against the field that caused it. */
.ff-field-error { margin-top: 4px; font: 500 11.5px Figtree, sans-serif; line-height: 1.4;
                  color: var(--ff-error-tx); }

/* A PAN, an IFSC, an account number: strings where one wrong character matters and the eye has to
   compare them. Monospaced and spaced out, so a transposition is visible. */
.ff-input--mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
                  letter-spacing: 1px; text-transform: uppercase; }

/* A section of a form folded away, showing what is in it.

   On the Edit user form the first two sections are settled facts, and somebody who opened it to
   set a joining date should not scroll past six boxes to reach one. A real <button>, not a div
   with a click on it: a fold that Tab cannot reach is a section a keyboard cannot open. */
.ff-fold { display: flex; align-items: center; gap: 10px; width: 100%; box-sizing: border-box;
           margin: 4px 0; padding: 11px 14px; text-align: left; cursor: pointer;
           background: var(--ff-thead); border: 1px solid var(--ff-hairline);
           border-radius: 10px; color: var(--ff-success-tx); font: inherit; }
.ff-fold:hover { border-color: var(--ff-border); background: var(--ff-canvas); }

.ff-fold__name { flex: none; font: 600 13px Figtree, sans-serif; color: var(--ff-ink); }

/* The values, and they are allowed to run out rather than wrap: a fold is one line, and a second
   line of it would cost more height than the fields it is hiding. */
.ff-fold__sum { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
                white-space: nowrap; font: 400 12px Figtree, sans-serif; color: var(--ff-text-2); }

.ff-fold__act { flex: none; font: 500 12px Figtree, sans-serif; color: var(--ff-teal-deep); }

/* Hide, on an open section's heading. Pushed to the right end of the rule it sits in. */
.ff-fold-act { margin-left: auto; padding: 0; border: 0; background: none; cursor: pointer;
               font: 500 11.5px Figtree, sans-serif; letter-spacing: 0; text-transform: none;
               color: var(--ff-teal-deep); }
.ff-fold-act:hover { text-decoration: underline; }

/* The day behind an approval row.

   Four numbers across the top, because an approver's question is "what is this day" and four
   figures answer it faster than eight rows do. Hairline-separated rather than boxed: they are one
   reading of one day, not four cards. */
.ff-dcr-tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
                gap: 1px; background: var(--ff-hairline);
                border: 1px solid var(--ff-hairline); border-radius: 10px; overflow: hidden; }
.ff-dcr-tile { padding: 13px 18px; background: var(--ff-card); }
.ff-dcr-tile__v { font: 700 22px Figtree, sans-serif; letter-spacing: -0.5px;
                  color: var(--ff-ink); font-variant-numeric: tabular-nums; }
.ff-dcr-tile__l { font-size: 11.5px; color: var(--ff-text-2); margin-top: 1px; }

.ff-dcr-calls { border: 1px solid var(--ff-border); border-radius: 10px; overflow: hidden; }
.ff-dcr-call { display: flex; align-items: flex-start; gap: 14px;
               padding: 10px 14px; border-bottom: 1px solid var(--ff-hairline); }
.ff-dcr-call:last-child { border-bottom: 0; }
.ff-dcr-call:nth-child(even) { background: var(--ff-thead); }

/* The time is the spine of the list: fixed width and tabular, so eight check-ins read as a
   column somebody can scan for a gap rather than eight ragged starts. */
.ff-dcr-call__t { flex: none; width: 46px; padding-top: 1px;
                  font: 600 12.5px Figtree, sans-serif; color: var(--ff-text-2);
                  font-variant-numeric: tabular-nums; }

@media (max-width: 680px) {
    .ff-dcr-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* What a call promoted, by name.

   Capped and ellipsised on one line: three names fit comfortably at the dialog's width, and a
   second line on every row would cost more height than the names are worth. The row's title
   carries the full list for the calls that detailed more. */
.ff-dcr-call__p { flex: none; max-width: 300px; overflow: hidden; text-overflow: ellipsis;
                  white-space: nowrap; text-align: right;
                  font: 600 12px Figtree, sans-serif; color: var(--ff-ink); }

/* ---- Missed Customers (Admin / Manager / MR) ------------------------------------------------
   Who was not called on between two dates. The band, the honesty note, the promised/not-promised
   split, the owner strip and the table. */
.ff-mc-filters { padding: 14px 16px; margin-bottom: 14px; }
.ff-mc-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; }
.ff-mc-lbl { display: block; font: 500 11.5px Figtree, sans-serif; color: var(--ff-muted); margin-bottom: 4px; }
.ff-mc-presets { display: flex; gap: 7px; flex-wrap: wrap; padding-bottom: 1px; }

.ff-mc-tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--ff-border); margin: 0 0 2px; }
.ff-mc-tab {
  padding: 11px 18px; border: 0; background: none; cursor: pointer; font: 700 14px Figtree, sans-serif;
  color: var(--ff-muted); border-bottom: 3px solid transparent; margin-bottom: -1px;
  display: flex; align-items: center; gap: 8px;
}
.ff-mc-tab:hover { color: var(--ff-text); }
.ff-mc-tab.active { color: var(--ff-teal-deep); border-bottom-color: var(--ff-teal-deep); }
.ff-mc-tab .n { background: var(--ff-hairline); color: var(--ff-text-2); border-radius: 999px; padding: 2px 8px; font: 700 11.5px Figtree, sans-serif; }
.ff-mc-tab.active .n { background: var(--ff-teal-deep); color: #fff; }

.ff-mc-band { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin: 16px 0 0; }
.ff-mc-stat {
  background: var(--ff-card); border: 1px solid var(--ff-border); border-top: 4px solid var(--ff-faint);
  border-radius: var(--ff-r-card); padding: 14px 16px;
}
.ff-mc-stat.bad { border-top-color: var(--ff-error); }
.ff-mc-stat.warn { border-top-color: var(--ff-warn); }
.ff-mc-stat.brand { border-top-color: var(--ff-teal); }
.ff-mc-stat .k { font: 600 11.5px Figtree, sans-serif; color: var(--ff-muted); text-transform: uppercase; letter-spacing: .4px; }
.ff-mc-stat .v { font: 800 26px Figtree, sans-serif; margin: 5px 0 1px; line-height: 1.12; }
.ff-mc-stat .v small { font: 700 14px Figtree, sans-serif; color: var(--ff-muted); }
.ff-mc-stat .s { font: 500 12px Figtree, sans-serif; color: var(--ff-text-2); }
.ff-mc-link { border: 0; background: none; padding: 0; cursor: pointer; font: 600 12px Figtree, sans-serif; color: var(--ff-teal-deep); }
.ff-mc-link:hover { text-decoration: underline; }

/* The line that stops the report doing harm when the range outruns the visit history. */
.ff-mc-note {
  margin: 14px 0 0; padding: 11px 14px; border-radius: var(--ff-r-tile);
  background: var(--ff-info-bg); color: var(--ff-info-tx);
  font: 600 12.5px Figtree, sans-serif; display: flex; gap: 9px; align-items: flex-start;
}
.ff-mc-note .i { font-weight: 800; }

.ff-mc-split { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 16px 0 4px; }
.ff-mc-split .lbl { font: 600 12px Figtree, sans-serif; color: var(--ff-muted); text-transform: uppercase; letter-spacing: .4px; margin-right: 2px; }
.ff-mc-split .ff-chip b { font-weight: 800; margin-left: 4px; }

.ff-mc-ownhead { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: baseline; margin: 18px 2px 8px; }
.ff-mc-ownhead h4 { margin: 0; font: 700 12px Figtree, sans-serif; color: var(--ff-muted); text-transform: uppercase; letter-spacing: .4px; }
.ff-mc-ownhead span { font: 500 12px Figtree, sans-serif; color: var(--ff-faint); }

.ff-mc-strip { display: flex; gap: 10px; overflow-x: auto; padding: 2px 2px 8px; }
.ff-mc-own {
  min-width: 172px; text-align: left; background: var(--ff-card); border: 1px solid var(--ff-border);
  border-radius: var(--ff-r-tile); padding: 10px 13px 11px; cursor: pointer; display: block;
}
.ff-mc-own:hover { border-color: var(--ff-teal); box-shadow: 0 2px 8px rgba(42, 93, 168, .12); }
.ff-mc-own.on { border-color: var(--ff-teal-deep); box-shadow: 0 0 0 2px var(--ff-nav-accent-tint); }
.ff-mc-own .nm { display: block; font: 700 13px Figtree, sans-serif; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ff-mc-own .cd { display: block; font: 500 11px Figtree, sans-serif; color: var(--ff-muted); margin-bottom: 6px; }
.ff-mc-own .pct { display: block; font: 800 19px Figtree, sans-serif; }
.ff-mc-own .pct.bad { color: var(--ff-error-tx); }
.ff-mc-own .pct.mid { color: var(--ff-warn-tx); }
.ff-mc-own .pct.ok { color: var(--ff-success-tx); }
.ff-mc-own .of { display: block; font: 500 11.5px Figtree, sans-serif; color: var(--ff-text-2); }
.ff-mc-own .meter { display: block; height: 5px; border-radius: 3px; background: var(--ff-hairline); margin-top: 7px; overflow: hidden; }
.ff-mc-own .meter i { display: block; height: 100%; background: var(--ff-error); }
.ff-mc-own .meter i.mid { background: var(--ff-warn); }
.ff-mc-own .meter i.ok { background: var(--ff-success); }

.ff-mc-sechead { padding: 13px 16px; border-bottom: 1px solid var(--ff-border); display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
.ff-mc-sechead h3 { margin: 0; font: 700 14.5px Figtree, sans-serif; }
.ff-mc-sechead .c { font: 500 12px Figtree, sans-serif; color: var(--ff-muted); }

/* A row that costs money is tinted, and only that one. Two thousand red rows say nothing about
   which to open first, which is the only question the colour is there to answer. */
.ff-table tbody tr.hot { background: #FFF8F8; }
.ff-table tbody tr.hot:hover { background: #FEF0F0; }
/* .ff-table td sets a colour and is one element more specific than a lone class, so a bare
   .ff-mc-money lost and the money column rendered in ordinary ink. Qualified to out-specify it. */
.ff-table td.ff-mc-money { font-weight: 700; color: var(--ff-error-tx); }
.ff-mc-said { font: 500 11.5px Figtree, sans-serif; color: var(--ff-text-2); font-style: italic; margin-top: 5px; max-width: 260px; }

@media (max-width: 1100px) { .ff-mc-band { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---- Missed Customers: the panel behind a row --------------------------------------------- */
.ff-mc-tr { cursor: pointer; }

.ff-mcp-scrim {
  position: fixed; inset: 0; background: rgba(15, 42, 51, .42); z-index: 60;
  opacity: 0; visibility: hidden; transition: opacity .18s ease, visibility .18s ease;
}
.ff-mcp-scrim.on { opacity: 1; visibility: visible; }

.ff-mcp {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(620px, 96vw); z-index: 61;
  background: var(--ff-card); display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform .22s ease;
  box-shadow: -8px 0 28px rgba(15, 42, 51, .14);
}
.ff-mcp.on { transform: none; }

.ff-mcp-head { padding: 18px 20px; border-bottom: 1px solid var(--ff-border); display: flex; justify-content: space-between; gap: 12px; }
.ff-mcp-head h2 { margin: 0; font: 800 18px Figtree, sans-serif; }
.ff-mcp-head .sub { font: 500 12.5px Figtree, sans-serif; color: var(--ff-muted); margin-top: 3px; }
.ff-mcp-x { border: 0; background: none; font-size: 22px; line-height: 1; color: var(--ff-muted); cursor: pointer; padding: 0 2px; }
.ff-mcp-x:hover { color: var(--ff-text); }

.ff-mcp-body { padding: 18px 20px; flex: 1; overflow-y: auto; }
.ff-mcp-foot { padding: 14px 20px; border-top: 1px solid var(--ff-border); display: flex; gap: 9px; flex-wrap: wrap; }

/* The paragraph the panel opens with. Red when the miss costs money, amber otherwise. */
.ff-mcp-why { border-radius: var(--ff-r-tile); padding: 13px 15px; margin-bottom: 18px; border: 1px solid; }
.ff-mcp-why.bad { border-color: var(--ff-error); background: var(--ff-error-bg); }
.ff-mcp-why.bad h4, .ff-mcp-why.bad p { color: var(--ff-error-tx); }
.ff-mcp-why.warn { border-color: var(--ff-warn); background: var(--ff-warn-bg); }
.ff-mcp-why.warn h4, .ff-mcp-why.warn p { color: var(--ff-warn-tx); }
.ff-mcp-why h4 { margin: 0 0 6px; font: 800 13px Figtree, sans-serif; }
.ff-mcp-why p { margin: 0; font: 500 12.5px Figtree, sans-serif; line-height: 1.55; }

.ff-mcp-mini { font: 700 12px Figtree, sans-serif; color: var(--ff-muted); text-transform: uppercase; letter-spacing: .4px; margin: 0 0 9px; }

.ff-mcp-kv { display: grid; grid-template-columns: 148px 1fr; gap: 9px 14px; font: 500 13px Figtree, sans-serif; margin: 0 0 20px; }
.ff-mcp-kv dt { color: var(--ff-muted); }
.ff-mcp-kv dd { margin: 0; font-weight: 600; }

/* The six-month chart. Grey is "no history", red is "history, no call", brand is calls made:
   the two zeroes mean opposite things and must never look alike. */
.ff-mcp-spark { display: flex; align-items: flex-end; gap: 5px; height: 52px; }
.ff-mcp-bar { flex: 1; border-radius: 3px 3px 0 0; background: var(--ff-hairline); }
.ff-mcp-bar.none { background: var(--ff-hairline); }
.ff-mcp-bar.miss { background: var(--ff-error); }
.ff-mcp-bar.some { background: var(--ff-teal); }
.ff-mcp-sparkx { display: flex; gap: 5px; margin-top: 5px; }
.ff-mcp-sparkx span { flex: 1; text-align: center; font: 500 10.5px Figtree, sans-serif; color: var(--ff-faint); }
.ff-mcp-note { font: 500 11.5px Figtree, sans-serif; color: var(--ff-muted); margin: 10px 0 0; line-height: 1.5; }

/* ---- A table's headings stay on screen while its rows scroll -------------------------------
   The column headings scrolled away on every long report, so the eighth column became a number
   with no name over it. They now pin directly under the application header.

   THREE MECHANICS, and each one of them breaks it on its own:

   1. position: sticky pins to the NEAREST SCROLLING ANCESTOR. `.ff-table-wrap` carries
      overflow-x: auto for wide tables, and CSS computes the other axis to auto with it - so the
      wrap IS a scroll container, and a sticky heading inside it pins to the wrap, which never
      scrolls vertically. The heading therefore never moves and scrolls away with the page. The
      modifier below removes that scroller so the heading pins to `.ff-content` instead.

   2. THE PRICE of removing it: a table wider than the window now scrolls the whole content area
      sideways rather than just the card. That is the trade and it cannot be avoided - the
      heading can only pin if nothing between it and the page scrolls. The headings travel with
      the columns, which is what you want; the filter bar travels too, which you may not.

   3. `.ff-content` carries 24px of padding and sticky top: 0 pins to the PADDING box, which left
      a 24px strip above the pinned headings with the rows passing visibly through it. Painting
      over the strip does not work: `.ff-table` is border-collapse: collapse and cell shadows are
      clipped. So the padding stops being padding - see .ff-content below.

   NOT APPLIED to the three tables that freeze a first column (.ff-rws, .ff-rsy, .ff-dcr-cal):
   those pin with `left: 0`, which needs the wrap to stay a horizontal scroller. Taking it away
   would trade a sticky heading for a broken frozen column. StickyTableHeaderTests holds them out.
   Nor to tables inside a modal, where the dialog scrolls rather than the page. */
/* THE MARKER GOES ON THE TABLE, not on a wrapper. Most tables in this console have no
   .ff-table-wrap at all - the Attendance report puts its table straight inside the card - so a
   wrapper-based modifier could only ever reach a third of them, and reached the wrong third.

   Then clear EVERY scroll container between the heading and the page, because a sticky heading is
   only as good as the least clear ancestor. There are two: .ff-table-wrap, and the .ff-card-scroll
   that Card renders for an unpadded body. Clearing one and not the other just moves which element
   the heading uselessly pins to - which shipped once and changed nothing on screen. */
.ff-table-wrap:has(> .ff-table--sticky),
.ff-card-scroll:has(.ff-table--sticky) { overflow: visible; }

/* The whole THEAD sticks, not each TH. Two tables carry a second header row, and two rows of th
   pinned to top: 0 land on top of each other; a sticky thead stacks them as one block. */
.ff-table--sticky > thead {
  position: sticky;
  top: 0;
  /* Above the rows passing underneath, and above a frozen column's z-index: 1. */
  z-index: 3;
}

/* A sticky heading MUST be opaque or the rows show straight through it. --ff-thead is what
   .ff-table th already paints; it is repeated because this rule has to win on its own. And a
   collapsed border belongs to the TABLE rather than the cell, so it does not travel with a stuck
   row - the same reason .ff-rws draws its edge with a shadow. */
.ff-table--sticky > thead > tr > th {
  background: var(--ff-thead);
  box-shadow: inset 0 -1px 0 var(--ff-border);
}

/* ---- A grid that freezes a column AND pins its headings ------------------------------------
   Retailer Wise Sales, Retailer Sale Yearly and the DCR calendar pin a first column with
   `left: 0`, which NEEDS their wrap to stay a horizontal scroller - so .ff-table--sticky cannot
   be used on them: clearing that scroller to let the heading reach the page would unstick the
   column, and a heading cannot pin to the page while anything between scrolls. The two are
   mutually exclusive, and the column is worth more than the page-level pin.

   So these pin BOTH to the wrap instead. The wrap scrolls in both directions and takes a height,
   the column holds at left: 0 and the headings at top: 0, and a grid of months against retailers
   keeps its row labels and its column labels at the same time. It costs the grid its own
   scrollbar, which on a table this wide is what you want anyway. */
.ff-table-wrap--grid {
  overflow: auto;
  /* The topbar, this screen's own filters and the card's head, give or take. Capped at a share of
     the window rather than a fixed figure so it still works on a short laptop screen. */
  max-height: min(68vh, calc(100vh - 300px));
}

.ff-table-wrap--grid > .ff-table > thead {
  position: sticky;
  top: 0;
  /* Above the frozen column's body cells, which sit at 1. The corner cell - frozen AND a heading -
     keeps its own 3 inside this stacking context, so it still paints over its header siblings. */
  z-index: 4;
}

.ff-table-wrap--grid > .ff-table > thead > tr > th {
  background: var(--ff-thead);
  box-shadow: inset 0 -1px 0 var(--ff-border);
}

/* The Activity Doctor tab's own note reads as money rather than as information, because that is
   what it is about: budget already approved against doctors nobody called on. */
.ff-mc-note--money { background: var(--ff-warn-bg); color: var(--ff-warn-tx); }

/* ---------------------------------------------------------------------------
   Row actions: one decision on the row, the rest behind a kebab.

   A register row used to carry every action it allowed at the same weight. On a pending
   requisition that was seven controls, three of them red, with Reject a few pixels from Approve.
   Nothing led the eye, and a colour spent on Reject AND Cancel AND Delete stops reading as danger.
   Now the decision stays out and everything else is one click away. See RowActions.razor.
   --------------------------------------------------------------------------- */

/* Fixed width, so a pending row and an approved row line up instead of zigzagging down the page. */
.ff-row-actions { display: flex; align-items: center; justify-content: flex-end; gap: 6px; }

/* The refusal is a word, not a red slab: no border until the pointer reaches it, and only then
   does it turn red. Easy to find, never easy to hit by accident. */
.ff-btn--refuse { color: var(--ff-text-2); border-color: transparent; background: transparent; }
.ff-btn--refuse:hover { color: var(--ff-error-tx); background: var(--ff-error-bg); }

.ff-rowmenu { display: inline-flex; }

.ff-rowmenu-trigger {
  width: 30px; height: 28px; padding: 0; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid transparent; border-radius: 8px;
  background: transparent; color: var(--ff-muted); cursor: pointer;
}
.ff-rowmenu-trigger:hover,
.ff-rowmenu-trigger[aria-expanded="true"] {
  background: #EEF3FA; color: var(--ff-text); border-color: var(--ff-border);
}
.ff-rowmenu-trigger:disabled { opacity: .45; cursor: not-allowed; }
.ff-rowmenu-trigger svg { display: block; }

/* position and max-height are written by ffDropdown; everything here is only how it looks.

   1150 to match .ff-ss-float, which is the console's other fixed floating panel and picked that
   number for the same reason: it has to clear the modal scrim at 1100. The first draft of this
   used 60, which happens to be the phone sidebar AND the rail drawer scrim, and would have put the
   menu underneath both. Its own scrim is .ff-scrim-float at 1149, one below. */
.ff-rowmenu-panel {
  position: fixed; z-index: 1150; min-width: 194px;
  background: var(--ff-card); border: 1px solid var(--ff-border); border-radius: 11px;
  padding: 5px; overflow: auto; overscroll-behavior: contain;
  box-shadow: 0 12px 30px rgba(15, 42, 51, .14), 0 2px 6px rgba(15, 42, 51, .07);
}

.ff-rowmenu-item {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
  font: 600 12.5px Figtree, sans-serif; color: var(--ff-text);
  background: none; border: 0; padding: 8px 10px; border-radius: 7px; cursor: pointer;
}
.ff-rowmenu-item:hover { background: #F2F6FC; }
.ff-rowmenu-item:disabled { opacity: .45; cursor: not-allowed; background: none; }

/* Cancel, Write off and Delete. Red lettering inside a menu rather than three red buttons on the
   row: still unmistakable, no longer shouting over the decision. */
.ff-rowmenu-item--danger { color: var(--ff-error-tx); }
.ff-rowmenu-item--danger:hover { background: var(--ff-error-bg); }

.ff-rowmenu-sep { border: 0; border-top: 1px solid var(--ff-hairline); margin: 5px 7px; }

.ff-rowmenu-label {
  font: 800 10px Figtree, sans-serif; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ff-faint); padding: 7px 10px 4px;
}

/* ---------------------------------------------------------------------------
   A last column that stays reachable however far the table scrolls sideways.

   The Activity Approvals register carries thirteen columns. With the sidebar open the content area
   loses about 340px, the table no longer fits, and the column that goes out of view first is the
   last one - which is the one holding Approve and Reject. The decision became something you had to
   go looking for, and on a narrow laptop it looked like the buttons had fallen off the page.

   Mirror image of the frozen FIRST columns on .ff-rws and .ff-rsy, with one difference worth
   knowing: those tables scroll inside their own .ff-table-wrap, and this one does not. A table
   marked .ff-table--sticky has its wrap set to overflow:visible a few rules above, so the heading
   can pin to .ff-content rather than uselessly to the wrap. Sticky pins to the nearest SCROLLING
   ancestor, so right:0 here pins to .ff-content - the same scrollport the heading uses, which is
   why the two agree instead of fighting.

   Opaque, or the rows slide visibly underneath it. Shadow on the LEFT edge, because that is the
   side content passes on.
   --------------------------------------------------------------------------- */
.ff-table--pin-end > thead > tr > th:last-child,
.ff-table--pin-end > tbody > tr > td:last-child {
  position: sticky;
  right: 0;
  background: var(--ff-card);
  box-shadow: -1px 0 0 var(--ff-border);
  transition: box-shadow .16s ease;
}

/* Give the scroll a gutter's worth of extra travel, or the last column before the pinned one never
   fully clears it.

   Reported as "after scrolling right, part of Status is still underneath". It was, by 24px, and the
   24 is not a coincidence: scrollWidth on an overflowing box does not count the right padding, so
   .ff-content's own gutter is missing from the scroll range. At what the browser calls the end of
   the travel, the table has 24px still to go, and a column pinned to right:0 is therefore still
   sitting a gutter's width over its neighbour.

   Padding on the column BEFORE the pinned one is what lengthens the table, and the table is what
   lengthens the scroll. Measured: 127px of travel becomes 151, and the clipped pill goes from 13px
   to nothing. A trailing margin on the table or the card does neither - scrollWidth ignores those
   too, which is the same bug wearing a different hat.

   The 11px is .ff-table--dense's own cell padding, which is the only pairing in use; the gutter is
   added on top of it rather than replacing it. */
.ff-table--pin-end > thead > tr > th:nth-last-child(2),
.ff-table--pin-end > tbody > tr > td:nth-last-child(2) {
  padding-right: calc(11px + var(--ff-gutter, 24px));
}

/* The edge lifts only while something is actually passing underneath, and lies flat when nothing
   is. That is the whole answer to "why is it covering my data": a frozen column that looks frozen
   reads as frozen, and a one-pixel line with no heading above it reads as a rendering fault.
   Scrolled fully right the column sits where it would anyway, covers nothing, and the shadow goes.
   ffPinEdge in console-interop.js is what adds and removes the class. */
.ff-table--pin-end.is-pin-lifted > thead > tr > th:last-child,
.ff-table--pin-end.is-pin-lifted > tbody > tr > td:last-child {
  box-shadow: -1px 0 0 var(--ff-border), -10px 0 12px -8px rgba(15, 42, 51, .26);
}

/* NO z-index on the body cell, and that is the whole point of this comment.

   position:sticky with a numeric z-index creates a STACKING CONTEXT. The row menu is a fixed panel
   living inside this very cell, so a z-index here traps it: its own 1150 stops meaning "above the
   page" and starts meaning "above things inside this cell". The panel then paints under the pinned
   cells of every row below it, which are later in the DOM at the same level - and the menu opened
   as a white box with its items hidden behind the Top up buttons underneath.

   z-index:auto leaves no stacking context, and a sticky cell still paints above the ordinary
   non-positioned cells it slides over, which is all this column needs. The thead keeps its z-index
   because no panel lives in the heading. */

/* And the heading's own corner above BOTH: the sticky thead is z-index 3, so the one cell that is
   pinned on both axes has to clear it or the other headings scroll over the top of it. */
.ff-table--pin-end > thead > tr > th:last-child {
  z-index: 5;
  background: var(--ff-thead);
}

/* A register wide enough that its own padding is what pushes it off the screen.

   Activity Approvals carries thirteen columns. Measured at 18px each side, that is 468px of
   padding in a table overflowing its content area by 476px - the padding IS the overflow. Dropping
   to 11px gives back about 180px, which is the difference between fitting and not on a 1600px
   laptop with the sidebar open.

   Not applied to .ff-table generally. Most tables in this console have five or six columns and
   room to spare, and 18px is what makes them readable. */
.ff-table--dense > thead > tr > th,
.ff-table--dense > tbody > tr > td { padding-left: 11px; padding-right: 11px; }

/* ---------------------------------------------------------------------------
   Activity Reports: a filter's own Clear, the "On now" strip, and the three totals.
   --------------------------------------------------------------------------- */

/* A control and the button that clears just that one. */
.ff-filter-one { display: flex; align-items: stretch; gap: 8px; }
.ff-filter-one > :first-child { flex: 1; min-width: 0; }
.ff-filter-one .ff-btn { flex: none; }


/* What is ACTUALLY narrowing the report. Five selects on sensible defaults do not say which of
   them are doing anything, and the one most often missed is a person: the report looks small
   rather than looks filtered. */
.ff-onnow {
  display: flex; flex-wrap: wrap; align-items: center; gap: 9px;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--ff-hairline);
}
.ff-onnow-lead {
  font: 700 11px Figtree, sans-serif; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ff-faint);
}
.ff-onnow-clear {
  background: none; border: 0; color: var(--ff-teal); font: 700 12.5px Figtree, sans-serif;
  cursor: pointer; text-decoration: underline; text-underline-offset: 3px; padding: 4px;
}
.ff-onnow-clear:hover { color: var(--ff-teal-deep); }

.ff-fchip {
  display: inline-flex; align-items: center; gap: 7px;
  background: #EDF3FB; color: var(--ff-teal-deep); border: 1px solid #D7E3F4;
  border-radius: 999px; padding: 5px 7px 5px 12px; font: 600 12.5px Figtree, sans-serif;
}
.ff-fchip b { font-weight: 800; }
.ff-fchip--none { background: #F4F6F9; color: var(--ff-muted); border-color: var(--ff-hairline); padding: 5px 12px; }
.ff-fchip-x {
  width: 18px; height: 18px; flex: none; border: 0; border-radius: 50%; background: transparent;
  color: var(--ff-teal-deep); cursor: pointer; font: 700 13px Figtree, sans-serif; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
}
.ff-fchip-x:hover { background: #D7E3F4; }

/* The three figures. One accent each, down the left edge and on the dot, so they read as three
   different things at a glance rather than three of the same thing. */
.ff-totals { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; margin: 0 0 16px; }
@media (max-width: 880px) { .ff-totals { grid-template-columns: 1fr; } }

.ff-tot {
  background: var(--ff-card); border: 1px solid var(--ff-border); border-radius: var(--ff-r-card);
  padding: 16px 18px; position: relative; overflow: hidden;
}
.ff-tot::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--ff-tot-accent); }
.ff-tot-k {
  font: 800 10.5px Figtree, sans-serif; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ff-muted); display: flex; align-items: center; gap: 7px;
}
.ff-tot-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ff-tot-accent); flex: none; }
.ff-tot-v {
  font: 800 30px/1.15 Figtree, sans-serif; color: var(--ff-ink); margin: 9px 0 2px;
  letter-spacing: -.5px; font-variant-numeric: tabular-nums;
}
.ff-tot-sub { font: 500 12.5px Figtree, sans-serif; color: var(--ff-text-2); }
.ff-tot-sub b { color: var(--ff-text); font-weight: 700; }
.ff-tot-bar { height: 6px; border-radius: 999px; background: var(--ff-hairline); margin-top: 12px; overflow: hidden; }
.ff-tot-bar i { display: block; height: 100%; border-radius: 999px; background: var(--ff-tot-accent); }

.ff-tot--cost { --ff-tot-accent: var(--ff-teal); }
.ff-tot--expected { --ff-tot-accent: var(--ff-purple); }
.ff-tot--measured { --ff-tot-accent: var(--ff-success); }

/* A limit that has been passed, or an issue the code does not allow at all. Red because both
   are wrong, and a compliance screen that tints a breach the same as a total is not reporting. */
.ff-tot--breach { --ff-tot-accent: var(--ff-error); }

/* Four figures where three is the norm. Two limits and two counts do not fold into three
   without one of them hiding inside another. */
.ff-totals--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1180px) { .ff-totals--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 880px) { .ff-totals--4 { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------------------
   The team register: a collapsible team band over its own entries.
   --------------------------------------------------------------------------- */

.ff-team-head {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  background: var(--ff-thead); border: 0; border-bottom: 1px solid var(--ff-border);
  padding: 12px 16px; cursor: pointer; font: inherit; color: var(--ff-text);
}
.ff-team-head:hover { background: #EAF0F8; }
.ff-team-caret { color: var(--ff-muted); flex: none; font-size: 12px; }
.ff-team-name { font: 800 14px Figtree, sans-serif; flex: 1; min-width: 0; }
.ff-team-name small { display: block; font: 500 11.5px Figtree, sans-serif; color: var(--ff-muted); }

/* Right-aligned and tabular, so the money lines up between one team band and the next. */
.ff-team-figs { display: flex; gap: 20px; flex-wrap: wrap; justify-content: flex-end; }
.ff-team-figs > span {
  font: 800 13.5px Figtree, sans-serif; text-align: right; font-variant-numeric: tabular-nums;
}
.ff-team-figs small {
  display: block; font: 700 9.5px Figtree, sans-serif; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ff-muted);
}

/* An OPEN window is grey, never red or green. A budget on day 40 of 250 has not failed, and a red
   bar against a rep who still has seven months is the report saying something untrue about them. */
.ff-band-met   { color: var(--ff-success-tx); font-weight: 700; }
.ff-band-near  { color: var(--ff-warn-tx);    font-weight: 700; }
.ff-band-short { color: var(--ff-error-tx);   font-weight: 700; }
.ff-band-run   { color: var(--ff-text-2);     font-weight: 600; }
.ff-band-none  { color: var(--ff-faint); }

.ff-band-fill-met   { background: var(--ff-success); }
.ff-band-fill-near  { background: var(--ff-warn); }
.ff-band-fill-short { background: var(--ff-error); }
.ff-band-fill-run   { background: var(--ff-muted); }
.ff-band-fill-none  { background: var(--ff-hairline); }

@media (max-width: 760px) {
  .ff-team-head { flex-wrap: wrap; }
  .ff-team-figs { gap: 14px; }
}

/* The register's own six-figure strip, team band and type pill. */
.ff-reg-kpi {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px; margin: 0 0 14px;
}
.ff-k {
  background: var(--ff-card); border: 1px solid var(--ff-border); border-radius: 10px; padding: 12px 14px;
}
.ff-k small {
  display: block; font: 700 10.5px Figtree, sans-serif; letter-spacing: .05em;
  text-transform: uppercase; color: var(--ff-muted);
}
.ff-k b {
  display: block; margin-top: 3px; font: 800 21px Figtree, sans-serif;
  color: var(--ff-ink); font-variant-numeric: tabular-nums;
}

/* The team band lives INSIDE the table, so its money sits in the same columns as the rows under
   it. A band in a card of its own looks tidier and lines up with nothing. */
.ff-table tbody tr.ff-reg-team > td {
  background: var(--ff-thead); font-weight: 700; cursor: pointer;
  border-top: 1px solid var(--ff-border);
}
.ff-table tbody tr.ff-reg-team:hover > td { background: #EAF0F8; }
.ff-reg-team small { font-weight: 500; color: var(--ff-muted); margin-left: 6px; }
.ff-reg-caret { color: var(--ff-muted); margin-right: 7px; font-size: 11px; }

.ff-tp {
  display: inline-block; font: 700 11px Figtree, sans-serif; padding: 2px 9px; border-radius: 999px;
  white-space: nowrap;
}
.ff-tp--cost  { background: var(--ff-tint-teal);   color: var(--ff-teal-deep); }
.ff-tp--gift  { background: var(--ff-tint-amber);  color: var(--ff-warn-tx); }
.ff-tp--topup { background: var(--ff-tint-purple); color: var(--ff-purple-tx); }
/* The other two budget-only types. Kept near Gift in colour because they are the same kind of
   money - spent with nothing expected back - and apart from Cost, which is measured. */
.ff-tp--sponsorship { background: var(--ff-info-bg);    color: var(--ff-info-tx); }
.ff-tp--other       { background: var(--ff-tint-green); color: var(--ff-success-tx); }

/* The Type chips.

   Their own class rather than .ff-chip-row, which the tour-programme editor and the multi-select
   also use for chips that only DISPLAY a choice - that row sets cursor:default, which is right
   there and wrong here. These are buttons.

   16px off the Filters card above, the same gap the health bar and the totals strip leave, so the
   chips read as a thing in their own right rather than as the bottom of the card. */
.ff-reg-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 16px 0 14px; }
.ff-reg-chips .ff-chip { cursor: pointer; }

/* The count on a chip, so one with nothing behind it says so before it is pressed. */
.ff-chip-n { opacity: .65; font-weight: 700; margin-left: 5px; }
.ff-reg-chips .ff-chip:disabled { opacity: .4; cursor: not-allowed; }

/* ---------------------------------------------------------------------------
   A drawer: a panel that comes in from the right over the screen behind it.

   Generic on purpose. The console's first one was .ff-mcp, named for the single
   screen that had it, and a second screen borrowing those classes would have left two
   features sharing a name that describes only one. The geometry here is that panel's,
   so .ff-mcp can move onto this later without anything changing on screen.

   z-index: a drawer sits over the page and under a modal. The console's floating panels are
   at 1149/1150 and the modal scrim at 1100, so 1090/1091 keeps a drawer below a dialog opened
   from inside it - which is the order somebody expects when a drawer offers an action.
   --------------------------------------------------------------------------- */
.ff-drawer-scrim {
  position: fixed; inset: 0; background: rgba(15, 42, 51, .42); z-index: 1090;
  opacity: 0; visibility: hidden; transition: opacity .18s ease, visibility .18s ease;
}
.ff-drawer-scrim.on { opacity: 1; visibility: visible; }

.ff-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(620px, 96vw); z-index: 1091;
  background: var(--ff-card); display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform .22s ease;
  box-shadow: -8px 0 28px rgba(15, 42, 51, .14);
}
.ff-drawer.on { transform: none; }

/* Nothing slides for somebody who asked the browser to stop animating. It still opens and
   closes; it simply stops moving to do it. */
@media (prefers-reduced-motion: reduce) {
  .ff-drawer, .ff-drawer-scrim { transition: none; }
}

.ff-drawer-head {
  padding: 18px 20px; border-bottom: 1px solid var(--ff-border);
  display: flex; justify-content: space-between; gap: 12px; align-items: flex-start;
}
.ff-drawer-head h2 { margin: 0; font: 800 18px Figtree, sans-serif; color: var(--ff-brand-strong); }
.ff-drawer-head .sub { font: 500 12.5px Figtree, sans-serif; color: var(--ff-muted); margin-top: 3px; }
.ff-drawer-x {
  border: 1px solid var(--ff-border); background: #fff; border-radius: 8px; flex: none;
  width: 30px; height: 30px; font-size: 19px; line-height: 1; color: var(--ff-text-2); cursor: pointer;
}
.ff-drawer-x:hover { background: #F6F9FD; color: var(--ff-text); }
.ff-drawer-body { padding: 18px 20px 28px; flex: 1; overflow-y: auto; }

/* ---- what the client drawer puts in one ---- */

.ff-cd-kv { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 0 0 18px; }
.ff-cd-kv > div {
  background: var(--ff-canvas); border: 1px solid var(--ff-hairline); border-radius: 10px; padding: 10px 12px;
}
.ff-cd-kv small {
  display: block; font: 700 10px Figtree, sans-serif; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ff-muted);
}
.ff-cd-kv b {
  display: block; margin-top: 2px; font: 800 17px Figtree, sans-serif; color: var(--ff-ink);
  font-variant-numeric: tabular-nums;
}
.ff-cd-kv span { font-size: 11.5px; color: var(--ff-text-2); }

.ff-cd-h3 {
  font: 800 11px Figtree, sans-serif; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ff-muted); margin: 0 0 9px; padding-top: 4px;
}
.ff-cd-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }
.ff-cd-item { border: 1px solid var(--ff-border); border-radius: 11px; padding: 11px 13px; }
.ff-cd-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ff-cd-code { font: 700 12px Figtree, sans-serif; color: var(--ff-text); }
.ff-cd-when { font-size: 11.5px; color: var(--ff-muted); margin-left: auto; }
.ff-cd-line { font-size: 12px; color: var(--ff-text-2); margin-top: 5px; }
.ff-cd-figs { display: flex; gap: 16px; margin-top: 8px; flex-wrap: wrap; }
.ff-cd-figs > span { font: 800 13px Figtree, sans-serif; color: var(--ff-ink); font-variant-numeric: tabular-nums; }
.ff-cd-figs small {
  display: block; font: 700 9.5px Figtree, sans-serif; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ff-muted);
}

/* A customer's name wherever it opens a drawer: a link, because it goes somewhere.
   Weight 800 and not 700 because the names it replaced were <strong>, which the browser
   renders at 900; 700 read visibly lighter than the screen it landed on. */
.ff-client-link {
  color: var(--ff-teal); font: inherit; font-weight: 800; background: none; border: 0;
  padding: 0; cursor: pointer; text-align: left; border-radius: 4px;
}
.ff-client-link:hover { color: var(--ff-teal-deep); text-decoration: underline; text-underline-offset: 2px; }
.ff-client-link:focus-visible { outline: 2px solid var(--ff-teal); outline-offset: 2px; }

/* ---------------------------------------------------------------------------
   Declaration evidence: the nine provisions, before anyone downloads the pack.

   The readiness strip is one segment per provision, in the order the rows are
   shown, so a reader who takes in nothing else sees how much of the strip is
   red. A provision with nothing on file is left grey rather than tinted
   neutral-positive: a signature covers the unrecorded provisions exactly as
   much as the recorded ones.
   --------------------------------------------------------------------------- */

.ff-ev-ready { margin: 0 0 16px; }
.ff-ev-count { font: 800 24px Figtree, sans-serif; color: var(--ff-ink); margin: 6px 0 0; letter-spacing: -.3px; }
.ff-ev-bar { display: flex; gap: 4px; margin-top: 9px; }
.ff-ev-bar i { height: 7px; border-radius: 999px; flex: 1; background: var(--ff-hairline); }
.ff-ev-bar i.ok { background: var(--ff-success); }
.ff-ev-bar i.part { background: var(--ff-warn); }
.ff-ev-bar i.no { background: var(--ff-error); }
.ff-ev-lead { font: 500 12.5px Figtree, sans-serif; color: var(--ff-text-2); margin-top: 9px; }
.ff-ev-bad { color: var(--ff-error); font-weight: 600; }

.ff-ev-sheets { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
@media (max-width: 760px) { .ff-ev-sheets { grid-template-columns: 1fr; } }
.ff-ev-sheets > div { border: 1px solid var(--ff-border); border-radius: 10px; padding: 10px 13px; }
.ff-ev-sheets b { font: 700 13px Figtree, sans-serif; display: block; }
.ff-ev-sheets span { font: 500 11.5px Figtree, sans-serif; color: var(--ff-text-2); }

/* Pushes the evidence button and its conflict count to the far end of the chip row. */
.ff-reg-chips-end { margin-left: auto; display: flex; align-items: center; gap: 9px; }

/* ---------------------------------------------------------------------------
   How old an unanswered alert is.

   Quiet while it is new, amber once it has passed the chase wait, red when it
   has been ignored for a fortnight. Only an OPEN alert ages: colouring an
   answered one red would tell somebody off for work they already did.
   --------------------------------------------------------------------------- */

.ff-age { font: 700 13px Figtree, sans-serif; color: var(--ff-text); }
.ff-age--warn { color: var(--ff-warn); }
.ff-age--error { color: var(--ff-error); }

/* The consequence loop: last cycle's verdict beside this cycle's list. */
.ff-loop-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 18px; flex-wrap: wrap; }
.ff-loop-line { font: 700 15px Figtree, sans-serif; color: var(--ff-ink); margin-top: 5px; }

/* ---------------------------------------------------------------------------
   Setup readiness: what each person is missing, against what their role needs.

   "not for a manager" is deliberately quiet rather than a tick or a blank. A
   blank reads as an oversight and a tick claims something was set up that was
   not; the words say the rule instead.
   --------------------------------------------------------------------------- */

.ff-tot-of { font: 700 17px Figtree, sans-serif; color: var(--ff-muted); letter-spacing: 0; }
.ff-setup-na { color: var(--ff-faint); font-size: 12px; }
.ff-setup-fix { font: 600 12px Figtree, sans-serif; color: var(--ff-teal); text-decoration: none; margin-left: 7px; }
.ff-setup-fix:hover { color: var(--ff-teal-deep); text-decoration: underline; }

.ff-setup-co { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
@media (max-width: 880px) { .ff-setup-co { grid-template-columns: 1fr; } }
.ff-setup-co > div { border: 1px solid var(--ff-border); border-radius: 10px; padding: 11px 13px; }
.ff-setup-co b { font: 700 13px Figtree, sans-serif; display: block; }
.ff-setup-co span { font: 500 11.5px Figtree, sans-serif; color: var(--ff-text-2); }

/* ---- Expense review -------------------------------------------------------------------------
   The claim seen line by line. Its own prefix throughout: .ff-chip here is already a clickable
   FILTER chip and .ff-timeline already has a different DOM shape, so reusing either would have
   drawn inline labels as buttons and the history as nothing. */
.ff-rvw-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; margin-bottom: 12px; }
.ff-rvw-who { font: 700 19px Figtree, sans-serif; color: var(--ff-text); margin-top: 4px; }
.ff-rvw-sub { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; font: 500 12.5px Figtree, sans-serif; color: var(--ff-text-2); margin-top: 3px; }
.ff-rvw-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

/* An inline LABEL, not a control: no pointer, no padding of a tap target. */
.ff-rvw-tag { display: inline-flex; align-items: center; gap: 5px; font: 600 11.5px Figtree, sans-serif; color: var(--ff-text-2); background: var(--ff-faint); border: 1px solid var(--ff-hairline); border-radius: var(--ff-r-pill); padding: 2px 9px; white-space: nowrap; }
.ff-rvw-tag--warn { color: var(--ff-warn); background: var(--ff-tint-amber); border-color: var(--ff-hairline); }
.ff-rvw-tag--danger { color: var(--ff-error); background: var(--ff-tint-orange); border-color: var(--ff-hairline); }

.ff-rvw-badge { display: inline-flex; min-width: 18px; height: 18px; padding: 0 5px; margin-left: 6px; align-items: center; justify-content: center; font: 700 11px Figtree, sans-serif; color: #fff; background: rgba(0,0,0,.25); border-radius: var(--ff-r-pill); }

.ff-rvw-totals { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 10px 0 8px; }
.ff-rvw-total { display: flex; flex-direction: column; }
.ff-rvw-total-k { font: 600 11px Figtree, sans-serif; color: var(--ff-text-2); text-transform: uppercase; letter-spacing: .04em; }
.ff-rvw-total-v { font: 700 17px Figtree, sans-serif; color: var(--ff-text); }
.ff-rvw-arrow { color: var(--ff-text-2); font-size: 18px; }
.ff-rvw-delta { font: 700 12.5px Figtree, sans-serif; color: var(--ff-error); }

.ff-rvw-note { border: 1px solid var(--ff-border); background: var(--ff-faint); border-radius: 10px; padding: 10px 12px; margin: 10px 0; font: 500 13px Figtree, sans-serif; color: var(--ff-text); }
.ff-rvw-note--warn { background: var(--ff-tint-amber); border-color: var(--ff-hairline); }

.ff-rvw-day { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
.ff-rvw-day-l { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.ff-rvw-day-r { display: flex; gap: 10px; align-items: baseline; }
.ff-rvw-date { font: 700 15px Figtree, sans-serif; color: var(--ff-text); }
/* The claimed figure stays visible beside the approved one. A cut that hides what it cut is a
   number nobody can check. */
.ff-rvw-was { font: 500 13px Figtree, sans-serif; color: var(--ff-text-2); text-decoration: line-through; }
.ff-rvw-now { font: 700 16px Figtree, sans-serif; color: var(--ff-text); }
.ff-rvw-route { font: 500 12.5px Figtree, sans-serif; color: var(--ff-text-2); margin: 4px 0 10px; }
.ff-rvw-cut { color: var(--ff-error); font-weight: 700; }
.ff-rvw-why { font: 500 12.5px Figtree, sans-serif; color: var(--ff-text); font-style: italic; }
.ff-rvw-num { text-align: right; white-space: nowrap; }
.ff-rvw-rowacts { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }
.ff-rvw-quick { display: flex; gap: 8px; flex-wrap: wrap; margin: -4px 0 10px; }
.ff-rvw-chips { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }
.ff-rvw-ro { font: 600 14px Figtree, sans-serif; color: var(--ff-text); padding: 6px 0; }

.ff-rvw-tl { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.ff-rvw-tl > li { border-left: 2px solid var(--ff-hairline); padding: 0 0 0 12px; }
.ff-rvw-tl-h { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.ff-rvw-tl-amt { font: 700 14px Figtree, sans-serif; color: var(--ff-text); }

@media (max-width: 720px) {
    .ff-rvw-head { flex-direction: column; }
    .ff-rvw-actions { width: 100%; }
    .ff-rvw-rowacts { justify-content: flex-start; }
}

/* ---- Payment advice slips ------------------------------------------------------------------- */
.ff-advice { border: 1px solid var(--ff-border); border-radius: 10px; padding: 12px 14px; margin-bottom: 12px; }
.ff-advice-h { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; font: 700 15px Figtree, sans-serif; }
.ff-advice-h span { font: 500 12.5px Figtree, sans-serif; color: var(--ff-text-2); }

@media print {
    /* Only the slips. Printing the console around them gives finance a page of navigation with
       the figures somewhere inside it. */
    body.ff-printing-advice * { visibility: hidden; }
    body.ff-printing-advice #ff-advice, body.ff-printing-advice #ff-advice * { visibility: visible; }
    body.ff-printing-advice #ff-advice { position: absolute; inset: 0; margin: 0; padding: 0; }
    body.ff-printing-advice .ff-advice { break-inside: avoid; page-break-inside: avoid; }
}
