/* =============================================================================
   FieldForce admin — utility + component shim for custom dashboard views.

   Filament ships a *precompiled* stylesheet that only contains the utility
   classes its own Blade views use. Custom views (the realtime dashboard, the
   attendance boards, the KPI strip) reference grid / responsive-grid utilities
   that Filament never emits, so they render with NO css and collapse to a
   single column. This file is loaded AFTER Filament's app.css via the
   AdminPanelProvider HEAD_END render hook, so it fills those gaps and wins on
   equal specificity. Filament's own scoped rules (higher specificity) are
   untouched, so there is no regression inside Filament components.

   If a proper Filament custom theme + Tailwind build is wired up later, this
   file can be retired.
   ========================================================================== */

/* =============================================================================
   Design tokens (theme-foundation) — royal-blue signature + compact type scale.
   The .ff-* / .kpi-* component classes below consume these. Filament's own
   chrome (nav, buttons, focus rings) goes royal-blue via Color::hex in
   AdminPanelProvider; a global type-scale reduction across Filament's table/form
   text needs the real Vite/Tailwind theme (its text uses explicit text-* classes
   the shim can't reliably override) — that's the documented graduation.
   ========================================================================== */
:root {
    --ff-accent-50:  #eef1fc;
    --ff-accent-100: #dde4f9;
    --ff-accent-200: #c0cdf3;
    --ff-accent-400: #6a82e3;
    --ff-accent-500: #4361e0;
    --ff-accent-600: #3b5bdb;
    --ff-accent-700: #2f48b5;
    --ff-accent:        var(--ff-accent-600);
    --ff-accent-strong: var(--ff-accent-700);

    /* compact type scale (down from Filament's airy defaults) */
    --ff-text-xs:   11px;
    --ff-text-sm:   12px;
    --ff-text-base: 13px;
    --ff-text-lg:   15px;
    --ff-text-xl:   18px;
    --ff-text-2xl:  20px;
}

/* Gentle density nudge on the sidebar chrome (low-risk; no-ops if a Filament
   upgrade renames the class — never touches layout math / the rem root). */
.fi-sidebar-nav .fi-sidebar-item-button { padding-top: 0.4rem; padding-bottom: 0.4rem; }
.fi-sidebar-group-label { font-size: 0.6875rem; letter-spacing: 0.04em; }

/* Tighten pass — shrink Filament's oversized default page/section headings and
   pull the content up. Targeted (specific fi-* classes), so each rule simply
   no-ops if Filament renames a class in an upgrade; no global rem change. */
.fi-header-heading { font-size: 1.375rem; line-height: 1.3; font-weight: 600; }
.fi-header-subheading { font-size: 0.8125rem; }
.fi-section-header-heading { font-size: 0.9375rem; }
.fi-modal-heading { font-size: 1.0625rem; }
.fi-main { padding-top: 1.25rem; }
.fi-header { margin-bottom: 1rem; }

/* Compact pass for Filament's stock TABLES + FORMS. The custom Vite theme that
   would shrink these via a global rem root can't run on the no-build VPS deploy,
   so we approximate it with targeted overrides on the real v3.2 marker classes
   (verified against vendor/filament blades). All ADDITIVE — this CSS loads after
   Filament's via the HEAD_END hook, so it wins on equal specificity; a wrong/
   renamed selector simply no-ops and can NEVER strip Filament's own styling
   (that was the viteTheme failure mode). Values are gentle + easy to dial. */
/* tables: denser rows + smaller text */
.fi-ta-cell { padding-top: 0.5rem; padding-bottom: 0.5rem; }
.fi-ta-header-cell { padding-top: 0.5rem; padding-bottom: 0.5rem; }
.fi-ta-text-item-label,
.fi-ta-cell .fi-ta-text { font-size: 0.8125rem; }
.fi-ta-header-cell-label { font-size: 0.75rem; }
.fi-ta-empty-state-heading { font-size: 0.9375rem; }
/* forms: smaller labels + input text */
.fi-fo-field-wrp-label { font-size: 0.8125rem; }
.fi-input,
.fi-select-input { font-size: 0.8125rem; }

/* --- grid template columns (global; Filament only ships these scoped) ------ */
.grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
.grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid-cols-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); }

.col-span-1 { grid-column: span 1 / span 1; }
.col-span-2 { grid-column: span 2 / span 2; }
.col-span-3 { grid-column: span 3 / span 3; }

@media (min-width: 768px) {
    .md\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .md\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
    .lg\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .lg\:grid-cols-7 { grid-template-columns: repeat(7, minmax(0, 1fr)); }
    .lg\:col-span-1 { grid-column: span 1 / span 1; }
    .lg\:col-span-2 { grid-column: span 2 / span 2; }
    .lg\:col-span-3 { grid-column: span 3 / span 3; }
}

/* --- gap utilities (safety; some are scoped in Filament's build) ----------- */
.gap-0\.5 { gap: 0.125rem; }
.gap-1   { gap: 0.25rem; }
.gap-1\.5 { gap: 0.375rem; }
.gap-2   { gap: 0.5rem; }
.gap-3   { gap: 0.75rem; }
.gap-4   { gap: 1rem; }
.gap-6   { gap: 1.5rem; }

/* --- KPI strip ------------------------------------------------------------- */
.kpi-tile {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 0.3rem;
    min-height: 60px;
    padding: 0.6rem 0.75rem;
    border: 1px solid rgb(229 231 235);
    border-radius: 0.625rem;
    background: #fff;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.kpi-tile:hover {
    border-color: rgb(209 213 219);
    box-shadow: 0 1px 3px rgb(0 0 0 / 0.06);
    transform: translateY(-1px);
}
.dark .kpi-tile { border-color: rgb(255 255 255 / 0.1); background: rgb(255 255 255 / 0.03); }
.dark .kpi-tile:hover { border-color: rgb(255 255 255 / 0.2); }

/* spotlight tile = panel primary (royal blue) */
.kpi-spotlight { border-color: #c0cdf3; background: #eef1fc; }
.kpi-spotlight:hover { border-color: #93a6ea; }
.dark .kpi-spotlight { border-color: rgb(59 91 219 / 0.35); background: rgb(59 91 219 / 0.12); }

.kpi-label {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.01em;
    text-transform: none;
    color: rgb(107 114 128);
}
.kpi-spotlight .kpi-label { color: #2f48b5; }
.dark .kpi-spotlight .kpi-label { color: #93a6ea; }

.kpi-value {
    font-size: var(--ff-text-2xl);
    line-height: 1.1;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: rgb(17 24 39);
}
.dark .kpi-value { color: #fff; }
.kpi-value--green { color: #16a34a; } .dark .kpi-value--green { color: #4ade80; }
.kpi-value--red   { color: #dc2626; } .dark .kpi-value--red   { color: #f87171; }
.kpi-value--blue  { color: #3b5bdb; } .dark .kpi-value--blue  { color: #6a82e3; }

.kpi-dot { flex: none; height: 0.4rem; width: 0.4rem; border-radius: 9999px; }
.kpi-dot--green { background: #22c55e; }
.kpi-dot--red   { background: #ef4444; }
.kpi-dot--blue  { background: #4361e0; }
.kpi-dot--slate { background: rgb(203 213 225); }
.dark .kpi-dot--slate { background: rgb(71 85 105); }

.kpi-spotlight-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 0.5rem; }
.kpi-delta { margin-top: 0.125rem; }

/* --- role-scope context banner --------------------------------------------
   Rendered by resources/views/filament/partials/role-scope-banner.blade.php at
   the top of role-scoped admin surfaces. Self-contained so it never depends on
   arbitrary Tailwind utilities the precompiled panel CSS doesn't ship. */
.ff-scope-banner {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1rem;
    padding: 0.625rem 0.875rem;
    border: 1px solid transparent;
    border-radius: 0.625rem;
    font-size: 0.875rem;
    line-height: 1.25rem;
}
.ff-scope-banner__icon { flex: none; height: 1.125rem; width: 1.125rem; }
.ff-scope-banner__text { font-weight: 500; }

.ff-scope-banner--info {
    color: #283d96;
    background: #eef1fc;
    border-color: #c0cdf3;
}
.dark .ff-scope-banner--info {
    color: #c0cdf3;
    background: rgb(59 91 219 / 0.12);
    border-color: rgb(59 91 219 / 0.35);
}

.ff-scope-banner--warning {
    color: #92400e;
    background: #fffbeb;
    border-color: #fde68a;
}
.dark .ff-scope-banner--warning {
    color: #fcd34d;
    background: rgb(245 158 11 / 0.12);
    border-color: rgb(245 158 11 / 0.35);
}

/* --- live map: named pins + status filter pills + client toggle (P1-B) ------
   The admin panel serves Filament's precompiled CSS (no custom Tailwind build),
   so every class the live-map blade uses must be defined here or it emits no
   style. See CLAUDE.md §4.2 "precompiled CSS". */

.ff-map-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.ff-map-filter-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
}

.ff-map-pill {
    cursor: pointer;
    padding: 0.25rem 0.625rem;
    border: 1px solid #d1d5db;
    border-radius: 9999px;
    background: #fff;
    color: #374151;
    font-size: 0.75rem;
    line-height: 1rem;
    font-weight: 500;
    white-space: nowrap;
    transition: background 120ms, border-color 120ms, color 120ms;
}
.ff-map-pill:hover { border-color: #9ca3af; }
.ff-map-pill--active {
    background: #3b5bdb;
    border-color: #3b5bdb;
    color: #fff;
}
.dark .ff-map-pill {
    background: rgb(30 41 59 / 0.6);
    border-color: rgb(71 85 105);
    color: #cbd5e1;
}
.dark .ff-map-pill--active {
    background: #3b5bdb;
    border-color: #3b5bdb;
    color: #fff;
}

.ff-map-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.8125rem;
    color: #374151;
    cursor: pointer;
    user-select: none;
}
.dark .ff-map-toggle { color: #cbd5e1; }

/* Rep marker: a small status dot with a name chip beside it, built as a Leaflet
   divIcon. Non-interactive layout (pointer-events stay on the Leaflet marker). */
.ff-rep-marker {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    white-space: nowrap;
}
.ff-rep-pin {
    flex: none;
    height: 0.75rem;
    width: 0.75rem;
    border-radius: 9999px;
    border: 2px solid #fff;
    box-shadow: 0 0 0 1px rgb(0 0 0 / 0.2);
}
.ff-rep-label {
    font-size: 0.6875rem;
    line-height: 1rem;
    font-weight: 600;
    color: #111827;
    background: rgb(255 255 255 / 0.9);
    border-radius: 0.25rem;
    padding: 0 0.25rem;
    box-shadow: 0 1px 2px rgb(0 0 0 / 0.15);
}

/* Live status colours (mirror the dashboard state palette). */
.ff-rep-dot--on_shift    { background: #22c55e; }   /* punched in / pinging */
.ff-rep-dot--punched_out { background: #6b7280; }   /* clocked out today */
.ff-rep-dot--on_leave    { background: #f59e0b; }
.ff-rep-dot--inactive    { background: #94a3b8; }

/* Ghost (last-known) pin — greyed + faded, clearly distinct from a live rep. */
.ff-rep-dot--ghost { background: #9ca3af; }
.ff-rep-marker--ghost { opacity: 0.55; }
.ff-rep-marker--ghost .ff-rep-pin {
    border-style: dashed;
    border-color: #d1d5db;
}
.ff-rep-marker--ghost .ff-rep-label {
    color: #6b7280;
    font-weight: 500;
    font-style: italic;
}

/* =============================================================================
   Reports hub (ReportsPage) — category sections + report cards.

   Self-contained classes (no dependency on Filament's `.grid`) so the layout
   renders regardless of which utilities the precompiled stylesheet happens to
   ship. The card grid is responsive via its own media queries.
   ========================================================================== */
.ff-reports-grid {
    display: grid;
    grid-template-columns: repeat(1, minmax(0, 1fr));
    gap: 0.875rem;
}
@media (min-width: 768px) {
    .ff-reports-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1280px) {
    .ff-reports-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.ff-report-card {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    height: 100%;
    padding: 1rem;
    border: 1px solid rgb(229 231 235);
    border-radius: 0.75rem;
    background: #fff;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.ff-report-card:hover {
    border-color: rgb(191 219 254);
    box-shadow: 0 1px 3px rgb(0 0 0 / 0.06);
    transform: translateY(-1px);
}
.dark .ff-report-card {
    border-color: rgb(255 255 255 / 0.1);
    background: rgb(255 255 255 / 0.03);
}
.dark .ff-report-card:hover { border-color: rgb(59 91 219 / 0.35); }

.ff-report-card__head {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
}
.ff-report-card__icon {
    flex: none;
    height: 1.5rem;
    width: 1.5rem;
    color: #3b5bdb;
}
.dark .ff-report-card__icon { color: #6a82e3; }
.ff-report-card__title {
    font-weight: 600;
    font-size: 0.9375rem;
    line-height: 1.3;
    color: #111827;
}
.dark .ff-report-card__title { color: #f9fafb; }
.ff-report-card__desc {
    font-size: 0.8125rem;
    line-height: 1.45;
    color: #4b5563;
}
.dark .ff-report-card__desc { color: #9ca3af; }
.ff-report-card__hint {
    font-size: 0.75rem;
    line-height: 1.45;
    color: #6b7280;
    font-style: italic;
}
.dark .ff-report-card__hint { color: #9ca3af; }
.ff-report-card__spacer { flex: 1 1 auto; }

/* =============================================================================
   Reusable dashboard component system (.ff-*).

   The admin panel serves Filament's precompiled CSS (no custom Tailwind build),
   so every custom view must use only Filament-shipped classes OR classes defined
   here. This block is the shared visual language for the redesigned Realtime
   Dashboard and any later custom surface: cards, responsive grids, metric tiles,
   list rows with status dots, attention tiles, and the greeting header.
   Light + dark variants are paired for every element.
   ========================================================================== */

/* --- vertical page stack --------------------------------------------------- */
.ff-stack { display: flex; flex-direction: column; gap: 1.25rem; }

/* --- greeting header ------------------------------------------------------- */
.ff-greeting { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem; margin-bottom: 1.25rem; }
.ff-greeting__title { font-size: 1rem; font-weight: 600; line-height: 1.2; color: #111827; }
.dark .ff-greeting__title { color: #f9fafb; }
.ff-greeting__sub { display: flex; align-items: center; gap: 0.4rem; margin-top: 0.15rem; font-size: 0.8125rem; color: #6b7280; }
.dark .ff-greeting__sub { color: #9ca3af; }
.ff-live-dot { display: inline-block; height: 0.5rem; width: 0.5rem; border-radius: 9999px; background: #22c55e; box-shadow: 0 0 0 3px rgb(34 197 94 / 0.2); }

/* --- responsive grid ------------------------------------------------------- */
.ff-grid { display: grid; gap: 1.25rem; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 1024px) {
    .ff-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .ff-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .ff-col-span-2 { grid-column: span 2 / span 2; }
}

/* --- card ------------------------------------------------------------------ */
.ff-card {
    background: #fff;
    border: 1px solid rgb(229 231 235);
    border-radius: 0.875rem;
    padding: 1.125rem 1.25rem;
}
.dark .ff-card { background: rgb(255 255 255 / 0.03); border-color: rgb(255 255 255 / 0.1); }
.ff-card--flush { padding: 0; overflow: hidden; }

.ff-card__head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 1rem; }
.ff-card--flush .ff-card__head { padding: 1rem 1.25rem; margin-bottom: 0; border-bottom: 1px solid rgb(229 231 235); }
.dark .ff-card--flush .ff-card__head { border-color: rgb(255 255 255 / 0.08); }
.ff-card__title { font-size: 0.9375rem; font-weight: 600; color: #111827; }
.dark .ff-card__title { color: #f9fafb; }
.ff-card__meta { font-size: 0.75rem; color: #9ca3af; }
.ff-card__link { font-size: 0.75rem; font-weight: 500; color: #3b5bdb; }
.dark .ff-card__link { color: #6a82e3; }
.ff-card__link:hover { text-decoration: underline; }

/* --- attendance ring + legend ---------------------------------------------- */
.ff-ring-row { display: flex; align-items: center; gap: 1.25rem; flex-wrap: wrap; }
.ff-ring-legend { flex: 1 1 140px; display: flex; flex-direction: column; gap: 0.5rem; font-size: 0.8125rem; }
.ff-ring-legend__row { display: flex; align-items: center; gap: 0.5rem; }
.ff-ring-legend__row span:first-child { height: 0.6rem; width: 0.6rem; border-radius: 9999px; flex: none; }
.ff-ring-legend__label { color: #4b5563; }
.dark .ff-ring-legend__label { color: #cbd5e1; }
.ff-ring-legend__value { margin-left: auto; font-weight: 600; font-variant-numeric: tabular-nums; color: #111827; }
.dark .ff-ring-legend__value { color: #f9fafb; }

/* --- metric tiles ---------------------------------------------------------- */
.ff-stat-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.75rem; }
@media (min-width: 768px) { .ff-stat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.ff-stat { background: rgb(249 250 251); border-radius: 0.625rem; padding: 0.875rem 1rem; }
.dark .ff-stat { background: rgb(255 255 255 / 0.04); }
.ff-stat__value { font-size: var(--ff-text-xl); font-weight: 700; line-height: 1.1; color: #111827; font-variant-numeric: tabular-nums; }
.dark .ff-stat__value { color: #f9fafb; }
.ff-stat__label { margin-top: 0.25rem; font-size: 0.75rem; color: #6b7280; }
.dark .ff-stat__label { color: #9ca3af; }
.ff-stat__sub { margin-top: 0.15rem; font-size: 0.6875rem; color: #9ca3af; }

/* --- "needs your attention" action tiles ----------------------------------- */
.ff-attn-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 0.75rem; }
.ff-attn {
    display: flex; align-items: center; gap: 0.75rem;
    padding: 0.75rem 0.875rem;
    background: rgb(249 250 251); border-radius: 0.625rem;
    border: 1px solid transparent;
    transition: border-color 0.15s ease, background 0.15s ease;
}
.ff-attn:hover { border-color: rgb(191 219 254); background: #eef1fc; }
.dark .ff-attn { background: rgb(255 255 255 / 0.04); }
.dark .ff-attn:hover { border-color: rgb(59 91 219 / 0.4); background: rgb(59 91 219 / 0.1); }
.ff-attn__icon { flex: none; height: 1.5rem; width: 1.5rem; }
.ff-attn__icon--warning { color: #d97706; } .dark .ff-attn__icon--warning { color: #fbbf24; }
.ff-attn__icon--info { color: #3b5bdb; } .dark .ff-attn__icon--info { color: #6a82e3; }
.ff-attn__icon--muted { color: #6b7280; } .dark .ff-attn__icon--muted { color: #9ca3af; }
.ff-attn__count { font-size: var(--ff-text-lg); font-weight: 700; line-height: 1; color: #111827; font-variant-numeric: tabular-nums; }
.dark .ff-attn__count { color: #f9fafb; }
.ff-attn__label { font-size: 0.75rem; color: #6b7280; line-height: 1.3; }
.dark .ff-attn__label { color: #9ca3af; }

/* --- list rows (live team, visit feed) ------------------------------------- */
.ff-list { display: flex; flex-direction: column; }
.ff-row {
    display: flex; align-items: center; gap: 0.75rem;
    padding: 0.75rem 1.25rem;
    border-bottom: 1px solid rgb(243 244 246);
    font-size: 0.875rem;
}
.dark .ff-row { border-color: rgb(255 255 255 / 0.05); }
.ff-row:last-child { border-bottom: 0; }
.ff-row--muted { opacity: 0.6; }
.ff-row__dot { flex: none; height: 0.6rem; width: 0.6rem; border-radius: 9999px; }
.ff-row__main { flex: 1 1 auto; min-width: 0; }
.ff-row__name { font-weight: 500; color: #111827; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dark .ff-row__name { color: #f9fafb; }
.ff-row__meta { font-size: 0.6875rem; color: #9ca3af; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ff-row__right { flex: none; font-size: 0.6875rem; color: #9ca3af; text-align: right; }
.ff-row__right--warn { color: #d97706; } .dark .ff-row__right--warn { color: #fbbf24; }

/* status dots (generic — mirror the attendance state palette) */
.ff-dot { display: inline-block; height: 0.6rem; width: 0.6rem; border-radius: 9999px; }
.ff-dot--on_shift    { background: #22c55e; }
.ff-dot--punched_out { background: #6b7280; }
.ff-dot--on_leave    { background: #f59e0b; }
.ff-dot--inactive    { background: #94a3b8; }
.ff-dot--holiday     { background: #a78bfa; }

/* --- leaderboard ----------------------------------------------------------- */
.ff-board { display: flex; flex-direction: column; gap: 0.625rem; }
.ff-board__row { display: flex; align-items: center; gap: 0.625rem; font-size: 0.8125rem; }
.ff-board__rank {
    flex: none; height: 1.375rem; width: 1.375rem; border-radius: 9999px;
    display: flex; align-items: center; justify-content: center;
    font-size: 0.6875rem; font-weight: 600;
    background: rgb(243 244 246); color: #4b5563;
}
.dark .ff-board__rank { background: rgb(255 255 255 / 0.07); color: #cbd5e1; }
.ff-board__row:first-child .ff-board__rank { background: #dde4f9; color: #2f48b5; }
.dark .ff-board__row:first-child .ff-board__rank { background: rgb(59 91 219 / 0.25); color: #93a6ea; }
.ff-board__name { flex: 1 1 auto; color: #111827; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dark .ff-board__name { color: #f9fafb; }
.ff-board__value { flex: none; font-weight: 600; font-variant-numeric: tabular-nums; color: #6b7280; }
.dark .ff-board__value { color: #9ca3af; }
.ff-board__caption { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.04em; color: #9ca3af; margin-bottom: 0.5rem; }
.ff-board + .ff-board__caption { margin-top: 1rem; }

/* --- empty state ----------------------------------------------------------- */
.ff-empty { padding: 1.5rem; text-align: center; font-size: 0.8125rem; color: #9ca3af; }

/* --- summary chips (day timeline header) ----------------------------------- */
.ff-chip-row { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.ff-chip {
    display: inline-flex; align-items: center; gap: 0.375rem;
    padding: 0.375rem 0.625rem; border-radius: 0.5rem;
    background: rgb(249 250 251); font-size: 0.8125rem; color: #374151;
    font-variant-numeric: tabular-nums;
}
.dark .ff-chip { background: rgb(255 255 255 / 0.04); color: #cbd5e1; }
.ff-chip__icon { height: 0.9375rem; width: 0.9375rem; color: #6b7280; }
.dark .ff-chip__icon { color: #9ca3af; }
/* A count that costs somebody money — amber, matching the warning tone used by
   the status dots, so a non-zero half-day tally reads at a glance. */
.ff-chip--warn { background: rgb(254 243 199); color: #92400e; }
.dark .ff-chip--warn { background: rgb(245 158 11 / 0.16); color: #fcd34d; }

/* --- underline tab bar (shared; e.g. Rep day) ------------------------------ */
.ff-tabs {
    display: flex; flex-wrap: wrap; gap: 0.25rem;
    border-bottom: 1px solid rgb(229 231 235);
}
.dark .ff-tabs { border-color: rgb(255 255 255 / 0.1); }
.ff-tab {
    padding: 0.5rem 0.9rem; font-size: 0.875rem; font-weight: 500;
    background: transparent; border: 0; border-bottom: 2px solid transparent;
    color: #6b7280; cursor: pointer; line-height: 1.4;
    margin-bottom: -1px;
}
.ff-tab:hover { color: #374151; }
.dark .ff-tab { color: #9ca3af; }
.dark .ff-tab:hover { color: #e5e7eb; }
.ff-tab--active { color: var(--ff-accent); border-bottom-color: var(--ff-accent); }
.ff-tab--active:hover { color: var(--ff-accent); }
.dark .ff-tab--active { color: var(--ff-accent-400); border-bottom-color: var(--ff-accent-400); }

/* --- segmented toggle (e.g. Route: Stops | Replay) ------------------------- */
.ff-seg {
    display: inline-flex; padding: 0.1875rem; gap: 0.1875rem;
    background: rgb(243 244 246); border-radius: 0.5rem;
}
.dark .ff-seg { background: rgb(255 255 255 / 0.06); }
.ff-seg__btn {
    padding: 0.3125rem 0.75rem; font-size: 0.8125rem; font-weight: 500;
    border: 0; border-radius: 0.375rem; background: transparent;
    color: #6b7280; cursor: pointer;
}
.ff-seg__btn:hover { color: #374151; }
.dark .ff-seg__btn { color: #9ca3af; }
.ff-seg__btn--active {
    background: #ffffff; color: var(--ff-accent);
    box-shadow: 0 1px 2px rgb(0 0 0 / 0.08);
}
.dark .ff-seg__btn--active { background: rgb(255 255 255 / 0.1); color: var(--ff-accent-400); }

/* --- resolved-context page heading (subject + date) ------------------------ */
.ff-subject-head { font-size: var(--ff-text-lg); font-weight: 600; color: #111827; }
.dark .ff-subject-head { color: #f9fafb; }

/* --- callout banner (ongoing session, notices) ----------------------------- */
.ff-callout {
    display: flex; align-items: flex-start; gap: 0.5rem;
    padding: 0.625rem 0.875rem; border-radius: 0.625rem;
    font-size: 0.8125rem; line-height: 1.4;
}
.ff-callout--ok {
    background: rgb(240 253 244); border: 1px solid rgb(187 247 208); color: #166534;
}
.dark .ff-callout--ok {
    background: rgb(22 101 52 / 0.2); border-color: rgb(22 101 52 / 0.4); color: #86efac;
}
.ff-callout--bad {
    background: rgb(254 242 242); border: 1px solid rgb(254 202 202); color: #991b1b;
}
.dark .ff-callout--bad {
    background: rgb(153 27 27 / 0.2); border-color: rgb(153 27 27 / 0.4); color: #fca5a5;
}
.ff-callout--muted {
    background: rgb(249 250 251); border: 1px solid rgb(229 231 235); color: #6b7280;
}
.dark .ff-callout--muted {
    background: rgb(255 255 255 / 0.04); border-color: rgb(255 255 255 / 0.08); color: #9ca3af;
}

/* --- plain-language tracking-gap list (under the quality ribbon) ------------ */
.ff-gap-list { margin-top: 0.75rem; display: flex; flex-direction: column; gap: 0.375rem; }
.ff-gap-list__title {
    font-size: var(--ff-text-xs, 0.6875rem); font-weight: 600; color: #6b7280;
    text-transform: uppercase; letter-spacing: 0.03em;
}
.dark .ff-gap-list__title { color: #9ca3af; }
.ff-gap-list__item {
    position: relative; padding-left: 0.875rem;
    font-size: 0.8125rem; line-height: 1.45; color: #374151;
}
.ff-gap-list__item::before {
    content: ''; position: absolute; left: 0; top: 0.45em;
    width: 0.375rem; height: 0.375rem; border-radius: 9999px; background: #dc2626;
}
.dark .ff-gap-list__item { color: #d1d5db; }
.ff-gap-list__item--expected { color: #6b7280; }
.ff-gap-list__item--expected::before { background: #9ca3af; }
.dark .ff-gap-list__item--expected { color: #9ca3af; }

/* --- vertical day timeline ------------------------------------------------- */
.ff-timeline { position: relative; padding-left: 1.625rem; }
.ff-timeline::before {
    content: ''; position: absolute; left: 0.5rem; top: 0.4rem; bottom: 0.4rem;
    width: 2px; background: rgb(229 231 235);
}
.dark .ff-timeline::before { background: rgb(255 255 255 / 0.1); }

.ff-tl-item { position: relative; margin-bottom: 0.875rem; }
.ff-tl-dot {
    position: absolute; left: -1.375rem; top: 0.15rem;
    width: 0.875rem; height: 0.875rem; border-radius: 9999px;
    border: 2px solid #fff;
}
.dark .ff-tl-dot { border-color: rgb(17 24 39); }
.ff-tl-dot--in       { background: #22c55e; }
.ff-tl-dot--out      { background: #ef4444; }
.ff-tl-dot--stop     { background: #3b5bdb; }
.ff-tl-dot--unmapped { background: #f59e0b; }

.ff-tl-line-text { font-size: 0.875rem; color: #374151; }
.dark .ff-tl-line-text { color: #e5e7eb; }
.ff-tl-line-text b { font-weight: 500; color: #111827; }
.dark .ff-tl-line-text b { color: #f9fafb; }

.ff-tl-travel {
    position: relative; margin-bottom: 0.875rem;
    font-size: 0.75rem; color: #9ca3af;
}
.ff-tl-travel__icon { height: 0.875rem; width: 0.875rem; position: absolute; left: -1.25rem; top: 0.1rem; }

.ff-tl-card {
    background: var(--color-background, #fff);
    border: 1px solid rgb(229 231 235); border-radius: 0.625rem; padding: 0.625rem 0.75rem;
}
.dark .ff-tl-card { background: rgb(255 255 255 / 0.03); border-color: rgb(255 255 255 / 0.1); }
.ff-tl-card__head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; }
.ff-tl-card__title { font-weight: 500; font-size: 0.8125rem; color: #111827; }
.dark .ff-tl-card__title { color: #f9fafb; }
.ff-tl-card__title--warn { color: #d97706; }
.dark .ff-tl-card__title--warn { color: #fbbf24; }
.ff-tl-card__time { font-size: 0.6875rem; color: #9ca3af; white-space: nowrap; }
.ff-tl-card__meta { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 0.4rem; font-size: 0.75rem; color: #6b7280; align-items: center; }
.dark .ff-tl-card__meta { color: #9ca3af; }

/* Evidence-photo thumbnails on a stop card (direct from task_photos). */
.ff-tl-thumbs { display: flex; flex-wrap: wrap; gap: 0.375rem; margin-top: 0.5rem; }
.ff-tl-thumb { display: block; width: 3.5rem; height: 3.5rem; border-radius: 0.375rem; overflow: hidden; border: 1px solid #e5e7eb; }
.dark .ff-tl-thumb { border-color: rgb(255 255 255 / 0.1); }
.ff-tl-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ff-tl-thumb--more { display: inline-flex; align-items: center; justify-content: center; font-size: 0.75rem; font-weight: 600; color: #6b7280; background: #f3f4f6; }
.dark .ff-tl-thumb--more { color: #9ca3af; background: rgb(255 255 255 / 0.06); }

/* Numbered stop pin for the Leaflet divIcon. */
.ff-tl-pin {
    width: 22px; height: 22px; border-radius: 9999px;
    background: #3b5bdb; color: #fff; border: 2px solid #fff;
    display: flex; align-items: center; justify-content: center;
    font-size: 11px; font-weight: 600; box-shadow: 0 1px 3px rgb(0 0 0 / 0.3);
}

/* --- rep card grid (Realtime Dashboard "Cards" tab) ------------------------ */
.ff-cards-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0.875rem; }

.ff-rep-card {
    background: #fff; border: 1px solid rgb(229 231 235); border-radius: 0.875rem; padding: 0.875rem 1rem;
    display: flex; flex-direction: column; gap: 0.625rem;
}
.dark .ff-rep-card { background: rgb(255 255 255 / 0.03); border-color: rgb(255 255 255 / 0.1); }
.ff-rep-card--muted { opacity: 0.72; }

.ff-rep-card__head { display: flex; align-items: center; gap: 0.625rem; }
.ff-rep-card__avatar {
    position: relative; flex: none; width: 2.25rem; height: 2.25rem; border-radius: 9999px;
    background: #dde4f9; color: #2f48b5; display: flex; align-items: center; justify-content: center;
    font-size: 0.8125rem; font-weight: 500;
}
.dark .ff-rep-card__avatar { background: rgb(59 91 219 / 0.25); color: #93a6ea; }
.ff-rep-card__pip { position: absolute; right: -1px; bottom: -1px; width: 0.7rem; height: 0.7rem; border-radius: 9999px; border: 2px solid #fff; }
.dark .ff-rep-card__pip { border-color: rgb(17 24 39); }
.ff-rep-card__id { min-width: 0; }
.ff-rep-card__name { font-weight: 500; font-size: 0.875rem; color: #111827; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dark .ff-rep-card__name { color: #f9fafb; }
.ff-rep-card__status { font-size: 0.6875rem; color: #6b7280; }
.dark .ff-rep-card__status { color: #9ca3af; }
.ff-rep-card__team { font-size: 0.75rem; color: #9ca3af; }
.ff-rep-card__stats { display: flex; gap: 0.875rem; font-size: 0.75rem; color: #6b7280; }
.ff-rep-card__stats b { font-size: 0.9375rem; color: #111827; font-variant-numeric: tabular-nums; }
.dark .ff-rep-card__stats { color: #9ca3af; }
.dark .ff-rep-card__stats b { color: #f9fafb; }
.ff-rep-card__foot { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; border-top: 1px solid rgb(243 244 246); padding-top: 0.625rem; }
.dark .ff-rep-card__foot { border-color: rgb(255 255 255 / 0.06); }
.ff-rep-card__chips { display: inline-flex; align-items: center; gap: 0.375rem; font-size: 0.6875rem; color: #9ca3af; }
.ff-rep-card__chip-icon { height: 0.875rem; width: 0.875rem; }

/* device-health pill (Card chips) + compliance square share a status palette */
.ff-hpill { display: inline-flex; align-items: center; gap: 0.125rem; padding: 0.0625rem 0.3125rem; border-radius: 0.375rem; font-size: 0.625rem; font-weight: 500; }
.ff-hpill--good    { background: #dcfce7; color: #15803d; }
.ff-hpill--partial { background: #fef3c7; color: #b45309; }
.ff-hpill--bad     { background: #fee2e2; color: #b91c1c; }
.ff-hpill--nodata  { background: #f3f4f6; color: #9ca3af; }
.dark .ff-hpill--good    { background: rgb(34 197 94 / 0.18); color: #4ade80; }
.dark .ff-hpill--partial { background: rgb(245 158 11 / 0.2); color: #fbbf24; }
.dark .ff-hpill--bad     { background: rgb(239 68 68 / 0.18); color: #f87171; }
.dark .ff-hpill--nodata  { background: rgb(255 255 255 / 0.06); color: #9ca3af; }
/* informational (no judgement) pill + a readable size for the Device status card */
.ff-hpill--neutral { background: #e5e7eb; color: #374151; }
.dark .ff-hpill--neutral { background: rgb(255 255 255 / 0.08); color: #d1d5db; }
.ff-hpill--md { font-size: 0.75rem; padding: 0.1875rem 0.5rem; }

/* --- compliance status grid (ComplianceStatusPage) ------------------------- */
.ff-comp-banner {
    display: flex; align-items: center; gap: 0.625rem; margin-bottom: 1rem;
    padding: 0.75rem 1rem; border-radius: 0.625rem; font-size: 0.875rem;
    background: #fef2f2; color: #b91c1c; border: 1px solid #fecaca;
}
.dark .ff-comp-banner { background: rgb(239 68 68 / 0.12); color: #fca5a5; border-color: rgb(239 68 68 / 0.35); }
.ff-comp-banner--ok { background: #f0fdf4; color: #15803d; border-color: #bbf7d0; }
.dark .ff-comp-banner--ok { background: rgb(34 197 94 / 0.12); color: #86efac; border-color: rgb(34 197 94 / 0.35); }
.ff-comp-banner__icon { height: 1.25rem; width: 1.25rem; flex: none; }

.ff-comp-legend { display: flex; flex-wrap: wrap; gap: 0.375rem 1rem; margin-bottom: 0.875rem; font-size: 0.6875rem; color: #6b7280; }
.dark .ff-comp-legend { color: #9ca3af; }
.ff-comp-legend__item { display: inline-flex; align-items: center; gap: 0.375rem; }

.ff-comp { display: flex; flex-direction: column; }
.ff-comp__row { display: flex; align-items: stretch; border-bottom: 1px solid rgb(243 244 246); }
.dark .ff-comp__row { border-color: rgb(255 255 255 / 0.05); }
.ff-comp__row--head { background: rgb(249 250 251); font-weight: 500; }
.dark .ff-comp__row--head { background: rgb(255 255 255 / 0.04); }
.ff-comp__name { flex: none; width: 150px; padding: 0.5rem 0.625rem; font-size: 0.75rem; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; color: #111827; }
.dark .ff-comp__name { color: #f9fafb; }
.ff-comp__dim { flex: none; width: 92px; padding: 0.5rem 0.5rem; font-size: 0.6875rem; color: #6b7280; display: flex; align-items: center; }
.ff-comp__day { flex: none; width: 26px; padding: 0.5rem 0; text-align: center; font-size: 0.625rem; color: #9ca3af; }
.ff-comp__cell { flex: none; width: 26px; display: flex; align-items: center; justify-content: center; padding: 0.1875rem 0; }
.ff-comp__notify { flex: none; width: 64px; display: flex; align-items: center; justify-content: center; }

.ff-hc { width: 18px; height: 18px; border-radius: 4px; }
.ff-hc--good    { background: #22c55e; }
.ff-hc--partial { background: #f59e0b; }
.ff-hc--bad     { background: #ef4444; }
.ff-hc--nodata  { background: #e5e7eb; }
.dark .ff-hc--good    { background: #16a34a; }
.dark .ff-hc--partial { background: #d97706; }
.dark .ff-hc--bad     { background: #dc2626; }
.dark .ff-hc--nodata  { background: rgb(255 255 255 / 0.08); }

/* --- attendance muster matrix (AttendanceStatusPage) ----------------------- */
.ff-muster-legend { display: flex; flex-wrap: wrap; gap: 0.375rem 1rem; margin-bottom: 0.875rem; font-size: 0.6875rem; color: #6b7280; }
.dark .ff-muster-legend { color: #9ca3af; }
.ff-muster-legend__item { display: inline-flex; align-items: center; gap: 0.375rem; }

.ff-muster { display: flex; flex-direction: column; }
.ff-muster__row { display: flex; align-items: stretch; border-bottom: 1px solid rgb(243 244 246); }
.dark .ff-muster__row { border-color: rgb(255 255 255 / 0.05); }
.ff-muster__row--head { background: rgb(249 250 251); font-weight: 500; border-bottom: 1px solid rgb(229 231 235); }
.dark .ff-muster__row--head { background: rgb(255 255 255 / 0.04); border-color: rgb(255 255 255 / 0.1); }

.ff-muster__name {
    flex: none; width: 150px; padding: 0.5rem 0.625rem; font-size: 0.75rem; font-weight: 500;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: #111827;
    display: flex; align-items: center;
}
.dark .ff-muster__name { color: #f9fafb; }
.ff-muster__row--head .ff-muster__name { color: #6b7280; font-weight: 500; }

.ff-muster__day {
    flex: none; width: 30px; padding: 0.5rem 0; text-align: center; font-size: 0.6875rem; color: #9ca3af;
}
.ff-muster__day--off { color: #d97706; }
.dark .ff-muster__day--off { color: #fbbf24; }

.ff-muster__cell { flex: none; width: 30px; display: flex; align-items: center; justify-content: center; padding: 0.25rem 0; }
.ff-muster__totals { flex: none; width: 96px; display: flex; align-items: center; justify-content: center; font-size: 0.6875rem; font-variant-numeric: tabular-nums; color: #6b7280; }
.ff-muster__totals--head { color: #6b7280; }

.ff-muster__select { width: 26px; font-size: 10px; padding: 0 1px; height: 22px; border-radius: 4px; }

.ff-muster__hint { margin-top: 0.875rem; font-size: 0.6875rem; color: #9ca3af; line-height: 1.5; }

/* attendance code chip */
.ff-mc {
    display: flex; align-items: center; justify-content: center;
    width: 24px; height: 22px; border-radius: 4px;
    font-size: 10px; font-weight: 600; letter-spacing: 0.01em;
}
.ff-mc--editable { cursor: pointer; }
.ff-mc--editable:hover { outline: 1px solid rgb(37 99 235 / 0.5); }
.ff-mc--ovr { box-shadow: 0 0 0 1.5px #3b5bdb; }

.ff-mc--present { background: #dcfce7; color: #15803d; }
.ff-mc--absent  { background: #fee2e2; color: #b91c1c; }
.ff-mc--leave-c { background: #dde4f9; color: #2f48b5; }
.ff-mc--leave-s { background: #fef3c7; color: #b45309; }
.ff-mc--leave-e { background: #ede9fe; color: #6d28d9; }
.ff-mc--leave-u { background: #f3f4f6; color: #4b5563; }
.ff-mc--weekoff { background: #f3f4f6; color: #9ca3af; }
.ff-mc--holiday { background: #ede9fe; color: #7c3aed; }
.ff-mc--future  { background: transparent; color: #d1d5db; }
.ff-mc--unknown { background: #f3f4f6; color: #4b5563; }

.dark .ff-mc--present { background: rgb(34 197 94 / 0.18); color: #4ade80; }
.dark .ff-mc--absent  { background: rgb(239 68 68 / 0.18); color: #f87171; }
.dark .ff-mc--leave-c { background: rgb(59 91 219 / 0.2); color: #6a82e3; }
.dark .ff-mc--leave-s { background: rgb(245 158 11 / 0.2); color: #fbbf24; }
.dark .ff-mc--leave-e { background: rgb(139 92 246 / 0.2); color: #a78bfa; }
.dark .ff-mc--leave-u { background: rgb(255 255 255 / 0.06); color: #cbd5e1; }
.dark .ff-mc--weekoff { background: rgb(255 255 255 / 0.05); color: #6b7280; }
.dark .ff-mc--holiday { background: rgb(139 92 246 / 0.2); color: #a78bfa; }
.dark .ff-mc--future  { background: transparent; color: #4b5563; }
.dark .ff-mc--unknown { background: rgb(255 255 255 / 0.06); color: #cbd5e1; }

/* Late check-in policy codes.
   HD is amber, not red: a half day is a penalty but it is NOT an absence, and
   colouring it like one makes a monthly grid read far worse than it is.
   OD (on duty, off-site) is a neutral working state — the rep worked, just not
   from a place they could clock in at. */
.ff-mc--halfday { background: #fef3c7; color: #92400e; }
.ff-mc--onduty  { background: #e0f2fe; color: #0369a1; }
.dark .ff-mc--halfday { background: rgb(245 158 11 / 0.22); color: #fbbf24; }
.dark .ff-mc--onduty  { background: rgb(14 165 233 / 0.2);  color: #38bdf8; }

/* A late arrival nobody has decided yet. Dashed ring so "waiting on a manager"
   is visibly different from a settled cell at a glance — without it an HR user
   cannot tell which cells still need them. */
.ff-mc--pending {
    outline: 1.5px dashed #f59e0b;
    outline-offset: -2px;
}
.dark .ff-mc--pending { outline-color: #fbbf24; }

/* =============================================================================
   Record combined-tabs (ViewUser / EditUser / EditCustomer).
   Filament renders the Overview + relation-manager tabs with <x-filament::tabs>
   in its NON-contained variant: `mx-auto rounded-xl bg-white p-2 shadow-sm
   ring-1` — i.e. a centred, shrink-to-fit floating white pill. On a wide record
   page that leaves large empty margins on both sides and reads as "floating /
   broken". Turn it into a left-aligned, full-width underline tab bar with a
   royal-blue active tab. Scoped to .fi-resource-relation-managers so form /
   infolist tabs elsewhere are untouched.
   ========================================================================== */
.fi-resource-relation-managers .fi-tabs {
    margin-inline: 0;
    width: 100%;
    justify-content: flex-start;
    background-color: transparent;
    box-shadow: none;                 /* drops shadow-sm + the ring */
    border-radius: 0;
    padding: 0 0 0.5rem 0;
    border-bottom: 1px solid rgb(17 24 39 / 0.08);
    gap: 0.25rem;
    overflow-x: auto;
}
.dark .fi-resource-relation-managers .fi-tabs {
    border-bottom-color: rgb(255 255 255 / 0.1);
}
/* Royal-blue active tab (Filament's default active is a flat gray-50 pill). */
.fi-resource-relation-managers .fi-tabs .fi-tabs-item.fi-active {
    background-color: var(--ff-accent-50);
    color: var(--ff-accent-strong);
}
.fi-resource-relation-managers .fi-tabs .fi-tabs-item.fi-active .fi-tabs-item-icon {
    color: var(--ff-accent);
}
.dark .fi-resource-relation-managers .fi-tabs .fi-tabs-item.fi-active {
    background-color: rgb(59 91 219 / 0.18);
    color: #c0cdf3;
}
.dark .fi-resource-relation-managers .fi-tabs .fi-tabs-item.fi-active .fi-tabs-item-icon {
    color: #8ea2ec;
}

/* =============================================================================
   Month calendar (Daily attendance page).
   The panel serves Filament's PRECOMPILED CSS + this shim only — raw Tailwind
   utilities (aspect-square, ring-2, bg-green-50, text-[11px], shadow-md …) DON'T
   render there, so the old markup collapsed to borderless, un-square numbers.
   This is the self-contained calendar component. Palette mirrors the muster
   (.ff-mc--*) / health (.ff-hc--*) green/amber/red/grey; accent ring uses
   var(--ff-accent), never a raw blue hex.
   ========================================================================== */
.ff-cal { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 0.375rem; }
.ff-cal__head { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 0.375rem; margin-bottom: 0.375rem; }
.ff-cal__dow {
    text-align: center;
    font-size: var(--ff-text-xs);
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: #9ca3af;
    padding: 0.25rem 0;
}
.dark .ff-cal__dow { color: #6b7280; }

/* Square cell (aspect-ratio, NOT the Tailwind aspect-square class). */
.ff-cal__cell {
    position: relative;
    aspect-ratio: 1 / 1;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.125rem;
    padding: 0.25rem;
    border: 1px solid rgb(229 231 235);
    border-radius: 0.625rem;
    background: rgb(249 250 251);
    color: #6b7280;
    cursor: pointer;
    text-align: center;
    transition: box-shadow 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
}
.dark .ff-cal__cell { border-color: rgb(255 255 255 / 0.08); background: rgb(255 255 255 / 0.03); color: #9ca3af; }
.ff-cal__cell:hover { box-shadow: 0 2px 6px rgb(17 24 39 / 0.12); }
.dark .ff-cal__cell:hover { box-shadow: 0 2px 6px rgb(0 0 0 / 0.4); }
.ff-cal__cell:focus-visible { outline: 2px solid var(--ff-accent); outline-offset: 1px; }

/* Empty padding cell (days outside the month) — occupies grid space, no chrome. */
.ff-cal__cell--pad { background: transparent; border-color: transparent; cursor: default; }
.ff-cal__cell--pad:hover { box-shadow: none; }

.ff-cal__num { font-size: var(--ff-text-sm); font-weight: 600; line-height: 1; }
.ff-cal__code { font-size: var(--ff-text-xs); font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.ff-cal__sub { font-size: 10px; line-height: 1; opacity: 0.7; }

/* Band modifiers — green (present/good), amber (partial), red (poor),
   grey (absent), faint (upcoming), plus muster-parity leave/holiday/weekoff. */
.ff-cal__cell--present { background: #dcfce7; border-color: #bbf7d0; color: #15803d; }
.ff-cal__cell--partial { background: #fef3c7; border-color: #fde68a; color: #b45309; }
.ff-cal__cell--poor    { background: #fee2e2; border-color: #fecaca; color: #b91c1c; }
.ff-cal__cell--absent  { background: #f3f4f6; border-color: #e5e7eb; color: #9ca3af; }
.ff-cal__cell--leave   { background: #dde4f9; border-color: #c0cdf3; color: #2f48b5; }
.ff-cal__cell--holiday { background: #ede9fe; border-color: #ddd6fe; color: #7c3aed; }
.ff-cal__cell--weekoff { background: #f3f4f6; border-color: #e5e7eb; color: #9ca3af; }
.ff-cal__cell--upcoming { background: transparent; border-style: dashed; border-color: rgb(229 231 235); color: #d1d5db; }

.dark .ff-cal__cell--present { background: rgb(34 197 94 / 0.18); border-color: rgb(34 197 94 / 0.3); color: #4ade80; }
.dark .ff-cal__cell--partial { background: rgb(245 158 11 / 0.2); border-color: rgb(245 158 11 / 0.3); color: #fbbf24; }
.dark .ff-cal__cell--poor    { background: rgb(239 68 68 / 0.18); border-color: rgb(239 68 68 / 0.3); color: #f87171; }
.dark .ff-cal__cell--absent  { background: rgb(255 255 255 / 0.04); border-color: rgb(255 255 255 / 0.08); color: #6b7280; }
.dark .ff-cal__cell--leave   { background: rgb(59 91 219 / 0.2); border-color: rgb(59 91 219 / 0.3); color: #6a82e3; }
.dark .ff-cal__cell--holiday { background: rgb(139 92 246 / 0.2); border-color: rgb(139 92 246 / 0.3); color: #a78bfa; }
.dark .ff-cal__cell--weekoff { background: rgb(255 255 255 / 0.04); border-color: rgb(255 255 255 / 0.08); color: #6b7280; }
.dark .ff-cal__cell--upcoming { background: transparent; border-color: rgb(255 255 255 / 0.08); color: #4b5563; }

/* Today + selected — accent ring, never a raw blue hex. Selected wins. */
.ff-cal__cell--today { border-color: var(--ff-accent); }
.ff-cal__cell--selected { box-shadow: 0 0 0 2px var(--ff-accent); border-color: var(--ff-accent); }
.ff-cal__cell--selected:hover { box-shadow: 0 0 0 2px var(--ff-accent); }

/* Legend row under the calendar. */
.ff-cal__legend { display: flex; flex-wrap: wrap; gap: 1rem; margin-top: 1rem; font-size: var(--ff-text-xs); color: #6b7280; }
.dark .ff-cal__legend { color: #9ca3af; }
.ff-cal__legend-item { display: inline-flex; align-items: center; gap: 0.375rem; }
.ff-cal__legend-swatch { width: 0.75rem; height: 0.75rem; border-radius: 0.25rem; border: 1px solid transparent; }
.ff-cal__legend-swatch--present { background: #dcfce7; border-color: #bbf7d0; }
.ff-cal__legend-swatch--partial { background: #fef3c7; border-color: #fde68a; }
.ff-cal__legend-swatch--poor    { background: #fee2e2; border-color: #fecaca; }
.ff-cal__legend-swatch--absent  { background: #f3f4f6; border-color: #e5e7eb; }

/* Month-navigation header for the calendar card. */
.ff-cal__nav { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; }
.ff-cal__nav-title { font-size: var(--ff-text-lg); font-weight: 600; color: #111827; }
.dark .ff-cal__nav-title { color: #f9fafb; }
.ff-cal__nav-btn {
    display: inline-flex; align-items: center; justify-content: center;
    height: 2rem; width: 2rem; border-radius: 0.5rem;
    color: #6b7280; transition: background-color 0.15s ease;
}
.ff-cal__nav-btn:hover { background: rgb(243 244 246); color: #111827; }
.ff-cal__nav-btn svg { width: 1.25rem; height: 1.25rem; }
.dark .ff-cal__nav-btn { color: #9ca3af; }
.dark .ff-cal__nav-btn:hover { background: rgb(255 255 255 / 0.06); color: #f9fafb; }

/* ---------------------------------------------------------------------------
   Compliance grid — flagged-today emphasis (attendance-ux-refactor)
   Reps whose today App/Location health can stop tracking get a subtle amber
   left bar + faint tint on BOTH sub-rows, a plain-language status badge next
   to the name, and float to the top (sort in ComplianceGridService).
--------------------------------------------------------------------------- */
.ff-comp__row--flagged { background: #fff7ed; box-shadow: inset 3px 0 0 #f59e0b; }
.dark .ff-comp__row--flagged { background: rgb(245 158 11 / 0.09); box-shadow: inset 3px 0 0 #d97706; }

/* Name cell needs a touch more room once a status badge sits beside the name;
   overrides the 150px base rule above (later rule wins, equal specificity). */
.ff-comp__name { width: 224px; gap: 0.375rem; }
.ff-comp__name-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.ff-comp__badge { flex: none; }

/* ---------------------------------------------------------------------------
   Visits-by-rep report (expandable rows)

   Extends .ff-row rather than restyling it: a rep row IS a list row that
   happens to be clickable, so it keeps the same height and rhythm as every
   other .ff-list on the panel. Only the affordances are new.
   --------------------------------------------------------------------------- */
.ff-row--button {
    width: 100%;
    background: none;
    border-left: 0; border-right: 0; border-top: 0;
    text-align: left;
    cursor: pointer;
    font: inherit;
}
.ff-row--button:hover { background: rgb(249 250 251); }
.dark .ff-row--button:hover { background: rgb(255 255 255 / 0.04); }
/* Keyboard focus must stay visible — the whole row is the control. */
.ff-row--button:focus-visible {
    outline: 2px solid var(--ff-accent);
    outline-offset: -2px;
}
.ff-row__chevron {
    flex: none; height: 1rem; width: 1rem; color: #9ca3af;
}
.ff-row--button .ff-row__right { font-size: 0.8125rem; font-weight: 600; color: #374151; }
.dark .ff-row--button .ff-row__right { color: #e5e7eb; }

.ff-row--total {
    border-top: 1px solid rgb(229 231 235);
    border-bottom: 0;
    background: rgb(249 250 251);
    font-weight: 600;
}
.dark .ff-row--total { border-color: rgb(255 255 255 / 0.1); background: rgb(255 255 255 / 0.03); }

/* The expanded visits. Indented and quieter than the rep rows so the report
   still reads as a list of people with detail underneath, not two tables. */
.ff-sublist { background: rgb(249 250 251); }
.dark .ff-sublist { background: rgb(255 255 255 / 0.02); }
.ff-subrow {
    display: flex; align-items: center; gap: 0.75rem;
    padding: 0.5rem 1.25rem 0.5rem 3rem;
    font-size: 0.8125rem;
    color: #4b5563;
    border-bottom: 1px solid rgb(243 244 246);
}
.dark .ff-subrow { color: #d1d5db; border-color: rgb(255 255 255 / 0.05); }
.ff-subrow:last-child { border-bottom: 0; }
.ff-subrow__date { flex: none; width: 5.5rem; color: #9ca3af; }
.ff-subrow__main { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ff-subrow__meta { flex: none; font-size: 0.75rem; color: #9ca3af; }
.ff-subrow--empty { color: #9ca3af; font-style: italic; }

@media (max-width: 640px) {
    .ff-subrow { padding-left: 2rem; }
    .ff-subrow__date { width: 4.5rem; }
}

/* =============================================================================
   Missing Tailwind utilities used by custom Filament views (dead-class sweep).

   The panel serves Filament's PRECOMPILED stylesheet, which only contains the
   utility classes Filament's own Blade views happen to use. Every class below
   is referenced by a view in resources/views/filament/** and resolved to
   NOTHING before this block existed — silently, because a missing utility has
   no error surface: php -l passes, the Blade compiles, view:cache succeeds, and
   only the rendered page is wrong.

   What that actually cost (all verified in the browser-equivalent CSS, 2026-08-19):
     • .mt-4 absent in 6 files — the Rep Day "Load" button sat flush against the
       picker with no gap (the reported "controls look overlapping").
     • .text-red-600 / .text-amber-600 / .text-green-600 absent — the Team
       Attendance Board rendered "N device(s) went silent", the integrity-flag
       count and "N tracking live" as ordinary black text, so its entire
       colour-coded severity signalling was invisible.
     • .h-40 / .w-40 / .-rotate-90 / .fill-gray-900 absent — the Realtime
       Dashboard attendance ring had no size and no rotation while its centre
       <text> still counter-rotated, so the rep count rendered SIDEWAYS in an
       unsized SVG.

   Dark variants use Filament's own :is(.dark *) form so they behave identically
   to the classes it does ship. Keep this block additive-only — it must never
   override a Filament rule (that was the ->viteTheme failure mode, §10).

   NOTE FOR FUTURE WORK: adding a class here is the documented fix (§4.2), but
   prefer an .ff-* component class for anything reusable. Guarded by
   tests/Feature/Filament/DashboardCssUtilitiesTest.php, which re-scans every
   custom Filament view and fails on a class this file cannot render.
   ========================================================================== */

/* --- spacing --------------------------------------------------------------- */
.mt-4 { margin-top: 1rem; }
.mb-1 { margin-bottom: 0.25rem; }
.mb-3 { margin-bottom: 0.75rem; }
.mb-6 { margin-bottom: 1.5rem; }
.ml-1 { margin-left: 0.25rem; }
.pb-2 { padding-bottom: 0.5rem; }
.pr-4 { padding-right: 1rem; }

/* --- sizing ---------------------------------------------------------------- */
.h-24 { height: 6rem; }
.h-40 { height: 10rem; }
.h-48 { height: 12rem; }
.w-40 { width: 10rem; }
.h-\[120px\] { height: 120px; }
.w-\[160px\] { width: 160px; }

/* --- transform ------------------------------------------------------------- */
.-rotate-90 { transform: rotate(-90deg); }

/* --- typography ------------------------------------------------------------ */
.uppercase      { text-transform: uppercase; }
.tracking-wide  { letter-spacing: 0.025em; }
.tabular-nums   { font-variant-numeric: tabular-nums; }
.text-\[10px\]  { font-size: 10px; line-height: 1.2; }

/* --- text colour ----------------------------------------------------------- */
.text-gray-900    { color: rgb(17 24 39); }
.text-red-600     { color: rgb(220 38 38); }
.text-green-600   { color: rgb(22 163 74); }
.text-amber-600   { color: rgb(217 119 6); }
.text-yellow-500  { color: rgb(234 179 8); }
.dark\:text-gray-300:is(.dark *) { color: rgb(209 213 219); }

/* --- svg fill (the attendance ring's centre text) -------------------------- */
.fill-gray-500 { fill: rgb(107 114 128); }
.fill-gray-900 { fill: rgb(17 24 39); }
.dark\:fill-white:is(.dark *) { fill: #fff; }

/* --- borders / dividers ---------------------------------------------------- */
.border-dashed { border-style: dashed; }
.last\:border-0:last-child { border-width: 0; }
.dark\:divide-gray-700:is(.dark *) > :not([hidden]) ~ :not([hidden]) { border-color: rgb(55 65 81); }

/* --- background ------------------------------------------------------------ */
.dark\:bg-gray-800\/50:is(.dark *) { background-color: rgb(31 41 55 / 0.5); }

/* --- interaction states ---------------------------------------------------- */
.hover\:underline:hover  { text-decoration-line: underline; }
.focus\:outline-none:focus { outline: 2px solid transparent; outline-offset: 2px; }
/* Composes with Filament's own .focus:ring-2, which supplies the ring width. */
.focus\:ring-primary-500:focus { --tw-ring-color: var(--ff-accent); }

/* =============================================================================
   Shared sticky grid — used by BOTH the Attendance muster (reps × 31 days) and
   the Device health compliance grid (reps × N days).

   Both are wide horizontally-scrolling grids where the day-number header row and
   the employee-name column scroll away, leaving anonymous cells in unidentified
   columns. One primitive rather than two copies, because they have the identical
   problem and drifting apart is how the two grids stop looking like one product.

   HOW IT WORKS (the parts that are easy to get wrong):
     • position: sticky resolves against the NEAREST scrolling ancestor, so the
       scroller must be .ff-sgrid-scroll and nothing between it and the sticky
       cell may set overflow (a sticky child of an overflow:hidden ancestor is
       silently not sticky — no error, it just scrolls away).
     • Sticky cells MUST have an opaque background or the content slides visibly
       underneath them. They inherit the row background here.
     • The top-left corner cell is sticky in BOTH axes and therefore needs a
       higher z-index than either the header row or the name column, or one of
       them paints over it at the intersection.
     • The scroller needs a max-height for vertical stickiness to mean anything;
       without it the page scrolls, not the container, and `top: 0` never engages.
   ========================================================================== */

.ff-sgrid-scroll {
    overflow: auto;
    max-height: min(72vh, 44rem);
    /* Own stacking context so the sticky z-indexes below cannot escape and
       paint over Filament's own chrome (modals, dropdowns, the sidebar). */
    position: relative;
    isolation: isolate;
}

/* Header row: sticks to the top of the scroller. */
.ff-sgrid-head {
    position: sticky;
    top: 0;
    z-index: 2;
    background: rgb(249 250 251);
}
.ff-sgrid-head:is(.dark *) { background: rgb(31 37 46); }

/* First column: sticks to the left edge. */
.ff-sgrid-col {
    position: sticky;
    left: 0;
    z-index: 1;
    background: #fff;
    /* A hairline that reads as an edge once content scrolls under it. */
    box-shadow: 1px 0 0 rgb(229 231 235);
}
.ff-sgrid-col:is(.dark *) { background: rgb(24 29 36); box-shadow: 1px 0 0 rgb(255 255 255 / 0.08); }

/* The intersection cell — sticky in both axes, so it must outrank both. */
.ff-sgrid-head .ff-sgrid-col {
    z-index: 3;
    background: rgb(249 250 251);
}
.ff-sgrid-head .ff-sgrid-col:is(.dark *) { background: rgb(31 37 46); }

/* Keep the sticky column opaque on the alternating / highlighted row states the
   two grids apply, otherwise cells show through it while scrolling. */
.ff-comp__row--flagged .ff-sgrid-col { background: #fff7ed; }
.ff-comp__row--flagged .ff-sgrid-col:is(.dark *) { background: rgb(62 45 22); }

/* --- filter bar (muster + compliance share the shape) ---------------------- */
.ff-filters {
    display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.625rem;
    margin-bottom: 0.875rem;
}
.ff-filters__field { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.ff-filters__label {
    font-size: 0.6875rem; font-weight: 500; color: #6b7280; letter-spacing: 0.01em;
}
.ff-filters__label:is(.dark *) { color: #9ca3af; }
/* NOTE: background-COLOR, never the `background` shorthand.
   Filament ships @tailwindcss/forms, whose base layer gives every bare <select>
   `appearance: none` PLUS a chevron `background-image` and the padding-right to
   sit it in. The shorthand resets background-image, so `background: #fff` here
   silently fought that base layer and the select rendered with a doubled arrow
   and text running under it. Set the colour and the image as separate
   properties, and own the arrow explicitly rather than depending on whatever
   Filament's base layer happens to do. */
.ff-filters__input,
.ff-filters__select {
    font-size: 0.8125rem; padding: 0.3rem 0.5rem; min-width: 9.5rem;
    border: 1px solid rgb(209 213 219); border-radius: 0.375rem;
    background-color: #fff; color: #111827;
}
.ff-filters__select {
    -webkit-appearance: none; -moz-appearance: none; appearance: none;
    /* One chevron, ours, positioned deliberately — and room for it, so a long
       option like "All departments" never runs underneath. */
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");
    background-position: right 0.5rem center;
    background-repeat: no-repeat;
    background-size: 1.1em 1.1em;
    padding-right: 2rem;
}
.ff-filters__input:is(.dark *),
.ff-filters__select:is(.dark *) {
    background-color: rgb(24 29 36); color: #f9fafb; border-color: rgb(255 255 255 / 0.12);
}
.ff-filters__input:focus,
.ff-filters__select:focus { outline: 2px solid var(--ff-accent); outline-offset: 1px; }
.ff-filters__clear {
    font-size: 0.75rem; color: var(--ff-accent); background: none; border: 0;
    cursor: pointer; padding: 0.35rem 0.25rem; text-decoration: underline;
}

/* --- muster readability (client: "it is too cramped to read") -------------- */
.ff-muster__day  { width: 34px; font-size: 0.75rem; }
.ff-muster__cell { width: 34px; padding: 0.3rem 0; }
.ff-muster__name { width: 190px; font-size: 0.8125rem; }
.ff-muster__totals { width: 132px; font-size: 0.75rem; }
.ff-mc { width: 28px; height: 26px; font-size: 11px; }
.ff-muster__select { width: 30px; height: 26px; font-size: 11px; }
.ff-muster__totals-key { font-size: 0.625rem; color: #9ca3af; letter-spacing: 0.02em; }

/* Weekend / holiday columns get a faint wash so the week structure is readable
   at a glance rather than having to count columns. */
.ff-muster__cell--off { background: rgb(249 250 251); }
.ff-muster__cell--off:is(.dark *) { background: rgb(255 255 255 / 0.03); }

.ff-note {
    margin-top: 0.75rem; font-size: 0.75rem; color: #6b7280; line-height: 1.5;
}
.ff-note:is(.dark *) { color: #9ca3af; }

/* --- device health: today's action list ------------------------------------ */
.ff-row--flagged { background: #fff7ed; box-shadow: inset 3px 0 0 #f59e0b; }
.ff-row--flagged:is(.dark *) { background: rgb(245 158 11 / 0.09); box-shadow: inset 3px 0 0 #d97706; }
/* The "what to ask them to do" line — the only actionable sentence on the row,
   so it reads as instruction rather than as more status text. */
.ff-row__meta--action { color: var(--ff-accent); font-weight: 500; }
.ff-row__meta--action:is(.dark *) { color: var(--ff-accent-400); }

/* --- Rep Day: check-in / check-out locations (point 1) ---------------------
   The two ends of the shift, side by side. A shift with no check-out position
   is a real and common state (the 11 PM auto-stop closes a shift the rep never
   ended), so the "none" variant is styled to read as an explanation, not as a
   value that failed to load. */
.ff-punch-grid {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem; margin-bottom: 0.875rem;
}
@media (max-width: 640px) { .ff-punch-grid { grid-template-columns: minmax(0, 1fr); } }
.ff-punch {
    border: 1px solid #e5e7eb; border-radius: 0.5rem; padding: 0.625rem 0.75rem;
    background: rgb(249 250 251);
}
.ff-punch:is(.dark *) { border-color: rgb(255 255 255 / 0.1); background: rgb(255 255 255 / 0.03); }
.ff-punch__time { font-size: var(--ff-text-lg); font-weight: 600; color: #111827; font-variant-numeric: tabular-nums; }
.ff-punch__time:is(.dark *) { color: #f9fafb; }
.ff-punch__place { font-size: 0.75rem; color: #374151; margin-top: 0.125rem; }
.ff-punch__place:is(.dark *) { color: #d1d5db; }
.ff-punch__place--none { color: #9ca3af; font-style: italic; }
.ff-punch__place--none:is(.dark *) { color: #9ca3af; }

/* --- Rep Day: tracking verdict (point 3) -----------------------------------
   Words first, number second. The percentage is honest and unchanged; on its
   own nobody could tell whether it was good, what it measured, or whose problem
   it was. The --note variant carries the SECOND cause — a missed check-out —
   which is a different problem with a different owner and must not read as a
   tracking failure. */
.ff-verdict {
    border-radius: 0.5rem; padding: 0.75rem 0.875rem; margin-bottom: 0.875rem;
    border: 1px solid transparent;
}
.ff-verdict__label {
    font-size: var(--ff-text-xs); text-transform: uppercase; letter-spacing: 0.04em;
    font-weight: 600; opacity: 0.7; margin-bottom: 0.125rem;
}
.ff-verdict__head { font-size: var(--ff-text-lg); font-weight: 600; }
.ff-verdict__body { font-size: 0.8125rem; margin-top: 0.125rem; }
.ff-verdict__detail { font-size: 0.75rem; opacity: 0.75; margin-top: 0.25rem; font-variant-numeric: tabular-nums; }
.ff-verdict__note {
    font-size: 0.75rem; margin-top: 0.5rem; padding-top: 0.5rem;
    border-top: 1px solid rgb(0 0 0 / 0.08); line-height: 1.5;
}
.ff-verdict__note:is(.dark *) { border-top-color: rgb(255 255 255 / 0.12); }
.ff-verdict--ok   { background: #f0fdf4; border-color: #bbf7d0; color: #14532d; }
.ff-verdict--warn { background: #fffbeb; border-color: #fde68a; color: #78350f; }
.ff-verdict--bad  { background: #fef2f2; border-color: #fecaca; color: #7f1d1d; }
.ff-verdict--ok:is(.dark *)   { background: rgb(34 197 94 / 0.12);  border-color: rgb(34 197 94 / 0.3);  color: #bbf7d0; }
.ff-verdict--warn:is(.dark *) { background: rgb(245 158 11 / 0.12); border-color: rgb(245 158 11 / 0.3); color: #fde68a; }
.ff-verdict--bad:is(.dark *)  { background: rgb(239 68 68 / 0.12);  border-color: rgb(239 68 68 / 0.3);  color: #fecaca; }

/* --- Rep Day: stops outside working hours (point 8c) -----------------------
   Kept, never hidden — the rep really was there — but greyed and labelled, and
   left out of the day's stop count. */
.ff-tl-item--out .ff-tl-card { opacity: 0.62; border-style: dashed; }
.ff-tl-dot--out { background: #9ca3af; }
.ff-tl-card__flag {
    display: inline-block; margin-top: 0.3rem; font-size: 0.625rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.03em;
    color: #6b7280; background: #f3f4f6; border-radius: 0.25rem; padding: 0.0625rem 0.3125rem;
}
.ff-tl-card__flag:is(.dark *) { color: #9ca3af; background: rgb(255 255 255 / 0.07); }
.ff-tl-card__title a { color: var(--ff-accent); text-decoration: none; }
.ff-tl-card__title a:hover { text-decoration: underline; }
.ff-tl-card__title a:is(.dark *) { color: var(--ff-accent-400); }
.ff-tl-card__map {
    margin-top: 0.4rem; font-size: 0.6875rem; font-weight: 500;
    color: var(--ff-accent); background: none; border: 0; padding: 0; cursor: pointer;
}
.ff-tl-card__map:hover { text-decoration: underline; }
.ff-tl-card__map:is(.dark *) { color: var(--ff-accent-400); }
/* A numbered pin for a stop the rep made off-shift. */
.ff-tl-pin--out { background: #9ca3af; }

/* --- Rep Day / Route Playback map furniture (point 8b) ---------------------
   A track with no direction, no start, no end and no key is a scribble. All
   pure Leaflet divIcons + one control — no JS chart library, same reasoning as
   the server-rendered SVG ribbons. */
.ff-map-arrow { font-size: 11px; line-height: 1; color: #3b5bdb; text-shadow: 0 0 2px #fff; }
.ff-map-arrow:is(.dark *) { text-shadow: 0 0 2px rgb(17 24 39); }
.ff-map-endpoint {
    display: flex; align-items: center; justify-content: center;
    width: 46px; height: 20px; border-radius: 9999px;
    font-size: 10px; font-weight: 700; letter-spacing: 0.02em;
    color: #fff; border: 2px solid #fff; box-shadow: 0 1px 3px rgb(0 0 0 / 0.35);
}
.ff-map-endpoint--start { background: #16a34a; }
.ff-map-endpoint--end   { background: #dc2626; }
.ff-map-cursor {
    width: 22px; height: 22px; border-radius: 9999px;
    background: #fff; border: 4px solid #3b5bdb;
    box-shadow: 0 0 0 4px rgb(59 91 219 / 0.25), 0 1px 4px rgb(0 0 0 / 0.35);
}
.ff-map-legend {
    background: rgb(255 255 255 / 0.94); border: 1px solid #e5e7eb; border-radius: 0.375rem;
    padding: 0.375rem 0.5rem; font-size: 11px; color: #374151;
    box-shadow: 0 1px 3px rgb(0 0 0 / 0.15);
    display: flex; flex-direction: column; gap: 0.125rem;
}
.ff-map-legend__row { display: flex; align-items: center; gap: 0.375rem; white-space: nowrap; }
.ff-map-legend__key { display: inline-block; width: 12px; height: 12px; border-radius: 9999px; flex: none; }
.ff-map-legend__key--track  { height: 3px; border-radius: 2px; background: #3b5bdb; }
.ff-map-legend__key--start  { background: #16a34a; }
.ff-map-legend__key--end    { background: #dc2626; }
.ff-map-legend__key--stop   { background: #ef4444; }
.ff-map-legend__key--cursor { background: #fff; border: 3px solid #3b5bdb; }
.ff-map-legend__key--pin    { background: #3b5bdb; }
.ff-map-legend__key--pin-out { background: #9ca3af; }

/* =============================================================================
   Live map controls — geofence layer, rep focus, and the "not reporting" banner.

   All three are client-side Alpine state by necessity: the map container is
   wire:ignore, so anything that triggers a Livewire re-render destroys the
   Leaflet instance. Nothing here may imply a server round-trip.
   ========================================================================== */

/* Reps who are clocked in but whose phone stopped reporting. Amber, not red:
   this is "worth knowing", not "something failed" — and an always-red banner on
   a page where half the workforce is routinely quiet stops being read. */
.ff-map-alert {
    display: flex; align-items: center; gap: 0.5rem;
    margin-bottom: 0.75rem; padding: 0.5rem 0.75rem;
    border: 1px solid #fde68a; border-radius: 0.5rem;
    background: #fffbeb; color: #92400e; font-size: 0.8125rem;
}
.ff-map-alert:is(.dark *) {
    background: rgb(245 158 11 / 0.1); border-color: rgb(245 158 11 / 0.3); color: #fcd34d;
}
.ff-map-alert__icon { height: 1rem; width: 1rem; flex: none; }

/* --- rep search / focus ----------------------------------------------------
   The control row must sit ABOVE the Leaflet map, and that needs a stacking
   context — not just a bigger number on the dropdown.

   Leaflet's panes run 200 (tiles) → 400 (overlay) → 600 (markers) → 700 (popup)
   → 800 (controls) → 1000 (the control corners), and `.leaflet-container` sets
   NO z-index of its own, so it does not isolate them: every one of those panes
   competes directly with these controls in the ROOT stacking context. The
   search dropdown was z-index 20 and therefore lost to literally every layer of
   the map, which is why it rendered behind it.

   Fixing it here rather than on the dropdown means anything else added to this
   row (a date picker, another menu) is above the map by construction instead of
   needing to rediscover the ladder. 1100 clears Leaflet's 1000 ceiling; inside
   this context the dropdown's own z-index only has to beat its siblings. */
.ff-map-controls { position: relative; z-index: 1100; }
.ff-map-search { position: relative; }
.ff-map-search__input {
    font-size: 0.8125rem; padding: 0.3rem 0.55rem; min-width: 11rem;
    border: 1px solid rgb(209 213 219); border-radius: 0.375rem;
    /* background-COLOR, not the shorthand — see the note on .ff-filters__select.
       No chevron to clobber on a search input, but the same latent trap. */
    background-color: #fff; color: #111827;
}
.ff-map-search__input:is(.dark *) {
    background-color: rgb(24 29 36); color: #f9fafb; border-color: rgb(255 255 255 / 0.12);
}
.ff-map-search__input:focus { outline: 2px solid var(--ff-accent); outline-offset: 1px; }
.ff-map-search__results {
    position: absolute; z-index: 1; top: calc(100% + 0.25rem); left: 0;
    min-width: 13rem; max-height: 14rem; overflow-y: auto;
    background: #fff; border: 1px solid rgb(229 231 235); border-radius: 0.5rem;
    box-shadow: 0 6px 18px rgb(0 0 0 / 0.12);
}
.ff-map-search__results:is(.dark *) { background: rgb(24 29 36); border-color: rgb(255 255 255 / 0.1); }
.ff-map-search__item {
    display: flex; align-items: center; gap: 0.5rem; width: 100%;
    padding: 0.4rem 0.625rem; font-size: 0.8125rem; text-align: left;
    background: none; border: 0; cursor: pointer; color: #111827;
}
.ff-map-search__item:is(.dark *) { color: #f9fafb; }
.ff-map-search__item:hover { background: var(--ff-accent-50); }
.ff-map-search__item:hover:is(.dark *) { background: rgb(255 255 255 / 0.06); }

.ff-map-focus {
    display: inline-flex; align-items: center; gap: 0.5rem;
    font-size: 0.8125rem; color: #374151;
}
.ff-map-focus:is(.dark *) { color: #d1d5db; }

/* --- geofence selector ----------------------------------------------------- */
.ff-map-geofences {
    margin-bottom: 0.75rem; padding: 0.625rem 0.75rem;
    border: 1px solid rgb(229 231 235); border-radius: 0.5rem; background: rgb(249 250 251);
}
.ff-map-geofences:is(.dark *) { background: rgb(255 255 255 / 0.03); border-color: rgb(255 255 255 / 0.08); }
.ff-map-geofences__head { display: flex; gap: 0.5rem; align-items: center; margin-bottom: 0.5rem; flex-wrap: wrap; }
.ff-map-geofences__list {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
    gap: 0.125rem 0.75rem; max-height: 11rem; overflow-y: auto;
}
.ff-map-geofences__item {
    display: flex; align-items: center; gap: 0.4rem;
    font-size: 0.8125rem; color: #374151; cursor: pointer; padding: 0.15rem 0;
}
.ff-map-geofences__item:is(.dark *) { color: #d1d5db; }
.ff-map-geofences__radius { margin-left: auto; font-size: 0.6875rem; color: #9ca3af; font-variant-numeric: tabular-nums; }

/* --- "clocked in, but the phone stopped reporting" pin ---------------------
   Deliberately NOT the grey ghost used for a rep who has finished: these two
   states look identical on a map and mean opposite things. Amber, dashed ring,
   still legible as on-shift. */
.ff-rep-dot--stale { background: #f59e0b; }
.ff-rep-marker--stale { opacity: 0.8; }
.ff-rep-marker--stale .ff-rep-pin {
    box-shadow: 0 0 0 2px #fff, 0 0 0 4px rgb(245 158 11 / 0.45);
}
.ff-rep-marker--stale .ff-rep-label {
    border-style: dashed;
    color: #92400e;
}
.ff-rep-marker--stale .ff-rep-label:is(.dark *) { color: #fcd34d; }

/* The one rep currently being followed. */
.ff-rep-marker--focus .ff-rep-label {
    border-color: var(--ff-accent);
    box-shadow: 0 0 0 2px var(--ff-accent-200);
    font-weight: 600;
}

/* =============================================================================
   Rep Day — watching one rep live (client decision 2026-08-19).

   Shown only when the selected date is today (IST). Everything here is driven
   by the repDayRoute Alpine component: the map container is wire:ignore, so the
   bar must be able to say "updated 4 min ago" without a server round-trip.
   ========================================================================== */
.ff-live-bar {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
    gap: 0.5rem; padding: 0.5rem 0.75rem;
    border-bottom: 1px solid #e5e7eb;
    font-size: 0.8125rem;
}
.ff-live-bar:is(.dark *) { border-color: rgb(255 255 255 / 0.08); }
.ff-live-bar__state { display: inline-flex; align-items: center; gap: 0.4rem; color: #166534; }
.ff-live-bar__state:is(.dark *) { color: #86efac; }
.ff-live-bar__actions { display: inline-flex; align-items: center; gap: 0.625rem; }

/* Quiet is amber, never red: a phone that has gone quiet is the ordinary case
   for roughly half of a shift, and a permanently red bar stops being read. */
.ff-live-bar__state--quiet { color: #92400e; }
.ff-live-bar__state--quiet:is(.dark *) { color: #fcd34d; }
.ff-live-bar__state--none { color: #6b7280; }
.ff-live-bar__state--none:is(.dark *) { color: #9ca3af; }

.ff-live-dot {
    flex: none; height: 0.5rem; width: 0.5rem; border-radius: 9999px;
    background: #16a34a; box-shadow: 0 0 0 3px rgb(22 163 74 / 0.2);
}
.ff-live-bar__state--quiet .ff-live-dot {
    background: #f59e0b; box-shadow: 0 0 0 3px rgb(245 158 11 / 0.22);
}
.ff-live-bar__state--none .ff-live-dot {
    background: #9ca3af; box-shadow: 0 0 0 3px rgb(156 163 175 / 0.2);
}

/* The live position itself — a filled accent dot with a halo, deliberately
   louder than the numbered stop pins so "where they are now" is findable on a
   dense day's track. */
.ff-live-pin {
    height: 0.75rem; width: 0.75rem; margin: 0.25rem; border-radius: 9999px;
    background: var(--ff-accent); border: 2px solid #fff;
    box-shadow: 0 0 0 4px rgb(59 91 219 / 0.28), 0 1px 3px rgb(0 0 0 / 0.3);
}
.ff-map-legend__key--live { background: var(--ff-accent); border: 2px solid #fff; }
