/* ─────────────────────────────────────────────────────────
   FieldOps CRM — Design System
   Variable names match the Master Build Context spec exactly
───────────────────────────────────────────────────────── */

:root {
  /* Backgrounds */
  --bg-main:        #F6F8FB;
  --surface:        #FFFFFF;
  --surface-muted:  #F1F5F9;

  /* Sidebar */
  --sidebar-bg:     #FFFFFF;
  --sidebar-active: #EAF2FF;

  /* Brand colours */
  --primary:        #2563EB;
  --primary-soft:   #DBEAFE;
  --secondary:      #0F766E;
  --accent:         #F59E0B;
  --success:        #16A34A;
  --warning:        #D97706;
  --danger:         #DC2626;

  /* Typography */
  --text-main:  #0F172A;
  --text-muted: #64748B;

  /* Structure */
  --border:        #E2E8F0;
  --radius-card:   10px;
  --shadow-card:   0 1px 4px rgba(0,0,0,0.07), 0 2px 12px rgba(0,0,0,0.04);
  --sidebar-width: 240px;
  --header-height: 60px;
  --transition:    0.18s ease;
}

/* ─── Reset / Base ──────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background: var(--bg-main);
  color: var(--text-main);
  font-size: 14px;
  line-height: 1.5;
}

a { text-decoration: none; }

/* ─── Layout ────────────────────────────────────────────── */

.fo-layout {
  display: flex;
  min-height: 100vh;
}

.fo-sidebar {
  width: var(--sidebar-width);
  background: var(--sidebar-bg);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: fixed;
  top: 0; left: 0; bottom: 0;
  z-index: 100;
  overflow-y: auto;
}

.fo-main {
  margin-left: var(--sidebar-width);
  flex: 1;
  /* Allow this flex item to shrink below its content's intrinsic width so wide
     tables scroll inside their own overflow-x wrappers instead of stretching
     the whole page horizontally. */
  min-width: 0;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.fo-header {
  height: var(--header-height);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  /* NOT sticky. The only thing that pins on a record page is the table's own
     column header, and it pins to the top of the VIEWPORT — so nothing may sit
     above it. `relative` (not `static`) purely to keep the account menu and
     search dropdown stacking above the content below; it carries no `top`, so
     it never shifts. */
  position: relative;
  z-index: 50;
  gap: 16px;
}

.fo-content {
  padding: 28px;
  flex: 1;
  min-width: 0;
}

/* ─── Sidebar Brand ─────────────────────────────────────── */

.fo-brand {
  display: block;
  padding: 0;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  flex-shrink: 0;
  overflow: hidden;
  background: transparent;  /* logos are transparent PNGs; sidebar shows through */
  transition: opacity .15s;
}

.fo-brand:hover {
  opacity: .75;
}

.fo-brand img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: contain;
  user-select: none;
}

/* Theme-aware logo swap: black mark in light, white "eɘ SALES" in dark.
   Selectors are scoped under .fo-brand so they outrank ".fo-brand img". */
.fo-brand .fo-brand-dark { display: none; }
html[data-theme="dark"] .fo-brand .fo-brand-light { display: none; }
html[data-theme="dark"] .fo-brand .fo-brand-dark  { display: block; }

.fo-brand-icon {
  width: 36px;
  height: 36px;
  background: var(--primary);
  border-radius: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 16px;
  font-weight: 800;
  flex-shrink: 0;
  letter-spacing: -0.5px;
}

.fo-brand-name {
  font-weight: 700;
  font-size: 15px;
  color: var(--text-main);
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.fo-brand-sub {
  font-size: 10px;
  color: var(--text-muted);
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* ─── Sidebar Navigation ────────────────────────────────── */

.fo-nav {
  padding: 10px 0 20px;
  flex: 1;
}

.fo-nav-section {
  padding: 12px 18px 4px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}

.fo-nav-item {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 14px;
  color: var(--text-muted);
  text-decoration: none;
  border-radius: 7px;
  margin: 1px 8px;
  font-size: 13.5px;
  font-weight: 500;
  transition: background var(--transition), color var(--transition);
  white-space: nowrap;
}

.fo-nav-item:hover {
  background: var(--surface-muted);
  color: var(--text-main);
}

.fo-nav-item.active {
  background: var(--sidebar-active);
  color: var(--primary);
  font-weight: 600;
}

.fo-nav-item .nav-icon {
  width: 18px;
  font-size: 14px;
  text-align: center;
  flex-shrink: 0;
}

/* ─── Sidebar modes: expanded / collapsed / hidden ──────────────────────────
   Controlled by html[data-sidebar]. The mobile drawer (≤1024px) overrides these
   below, so modes only shape the desktop layout. */

/* Desktop toggle button (in the header). Hidden on mobile — the burger is used
   there instead (see the ≤1024px media query). */
.fo-sidebar-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; margin-left: -4px;
  border: none; background: transparent; color: var(--text-muted);
  font-size: 18px; border-radius: 8px; cursor: pointer; flex-shrink: 0;
  transition: background .12s, color .12s;
}
.fo-sidebar-toggle:hover { background: var(--surface-muted); color: var(--text-main); }

/* Modes only shape the DESKTOP layout (>1024px). Below that the off-canvas
   drawer takes over and must always show full labels/sections. */
@media (min-width: 1025px) {
  /* Smooth width/offset changes when switching modes. */
  .fo-sidebar { transition: width .18s ease, transform .2s ease; }
  .fo-main    { transition: margin-left .18s ease; }

  /* Collapsed — icon-only rail. */
  html[data-sidebar="collapsed"] { --sidebar-width: 66px; }
  html[data-sidebar="collapsed"] .fo-nav-section { display: none; }
  html[data-sidebar="collapsed"] .nav-label { display: none; }
  html[data-sidebar="collapsed"] .fo-nav-item {
    justify-content: center; gap: 0; margin: 2px 12px; padding: 10px 0;
  }
  html[data-sidebar="collapsed"] .fo-nav-item .nav-icon { width: auto; font-size: 16px; }
  html[data-sidebar="collapsed"] .fo-brand { padding: 12px 6px; text-align: center; }
  /* The collapsed rail is 66px wide, 54px inside .fo-brand's padding. Capping
     only the HEIGHT clipped a wide mark: the brand is 1.64:1, so 34px tall is
     56px wide and .fo-brand's overflow:hidden cut the right-hand loop off.
     Both caps, and the narrower one wins. */
  html[data-sidebar="collapsed"] .fo-brand img {
    max-height: 34px; max-width: 100%; width: auto; height: auto; margin: 0 auto;
  }

  /* Hidden — sidebar off-canvas, main content spans full width. */
  html[data-sidebar="hidden"] .fo-sidebar { transform: translateX(-100%); }
  html[data-sidebar="hidden"] .fo-main { margin-left: 0; }
}

/* Hover tooltip for the collapsed rail — rendered position:fixed on <body> by
   JS so it is never clipped by the scrollable sidebar. */
.fo-nav-tip {
  position: fixed; z-index: 400; pointer-events: none;
  background: var(--surface); color: var(--text-main);
  border: 1px solid var(--border); border-radius: 8px;
  padding: 5px 10px; font-size: 12.5px; font-weight: 600; white-space: nowrap;
  box-shadow: 0 6px 20px rgba(0,0,0,.18);
  opacity: 0; transform: translateY(-50%) translateX(-4px);
  transition: opacity .12s ease, transform .12s ease;
}
.fo-nav-tip.show { opacity: 1; transform: translateY(-50%) translateX(0); }

/* ─── Header ────────────────────────────────────────────── */

.fo-header-left {
  display: flex;
  align-items: center;
  gap: 12px;
}

.fo-header-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-main);
}

.fo-breadcrumb {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: var(--text-muted);
}

.fo-breadcrumb a {
  color: var(--text-muted);
  text-decoration: none;
}

.fo-breadcrumb a:hover { color: var(--primary); }

.fo-breadcrumb-sep { color: var(--border); }

.fo-header-center {
  flex: 1;
  display: flex;
  justify-content: center;
}

.fo-search {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--surface-muted);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 14px;
  /* 380px, not the old 300px: the German placeholder ("Kunden, Projekte,
     Außendienstmitarbeiter suchen…") needs 316px of text plus 50px of icon,
     gap, padding and border, and was clipped by ~69px on every page.
     `max-width` lets the box give way instead of overflowing the header; the
     whole centre section is hidden below 1025px anyway. */
  width: 380px;
  max-width: 100%;
  color: var(--text-muted);
  font-size: 13px;
  cursor: text;
  transition: border-color .15s;
}
.fo-search:focus-within {
  border-color: var(--primary);
  background: var(--surface);
}
.fo-search-form { margin: 0; }
.fo-search-input-field {
  border: none;
  outline: none;
  background: transparent;
  font-family: inherit;
  font-size: 13px;
  color: var(--text-main);
  flex: 1;
  min-width: 0;
  width: 100%;
}
.fo-search-input-field::placeholder { color: var(--text-muted); }

.fo-header-right {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* ─── Admin Badge ───────────────────────────────────────── */

.fo-admin-badge {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 10px 5px 6px;
  background: var(--surface-muted);
  border: 1px solid var(--border);
  border-radius: 9px;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--transition);
}

.fo-admin-badge:hover { background: var(--primary-soft); }

.fo-admin-avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
  flex-shrink: 0;
}

.fo-admin-info { line-height: 1.2; }

.fo-admin-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-main);
}

.fo-admin-role {
  font-size: 10px;
  color: var(--text-muted);
  font-weight: 500;
}

/* ─── Page Header ───────────────────────────────────────── */

.fo-page-header {
  margin-bottom: 24px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}

.fo-page-header-text h1 {
  font-size: 22px;
  font-weight: 700;
  color: var(--text-main);
  margin: 0 0 2px;
}

.fo-page-header-text p {
  color: var(--text-muted);
  font-size: 13.5px;
  margin: 0;
}

/* ─── Cards ─────────────────────────────────────────────── */

.fo-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 20px;
}

.fo-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}

/* Flush cards have no body padding (so tables/lists span edge-to-edge),
   so the header carries its own padding to keep icon + title off the edge. */
.fo-card-flush {
  padding: 0;
  /* `clip`, not `hidden`. Both keep a table's corners inside the card's radius,
     but `hidden` makes the card a scroll container — and a sticky <th> pins to
     its nearest scroll container, so with `hidden` the column header would pin
     to the card and slide away with the page instead of holding at the top of
     the viewport. `clip` creates no scrollport, so the sticky header answers to
     the document. */
  overflow: clip;
}

/* THE card header band. Every card or tab panel that fronts a table or list
   uses this, so the treatment is defined once instead of being re-typed as
   inline styles per page — which is how five different paddings and four
   different title weights ended up shipping side by side.

   Deliberately NOT scoped to `.fo-card-flush >`: several of these bands head a
   tab panel rather than a card, and a descendant-scoped rule would silently
   drop their padding and divider. */
.fo-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
}

.fo-card-flush > .fo-card-header {
  padding: 16px 20px;
  margin-bottom: 0;
  border-bottom: 1px solid var(--border);
  gap: 10px;
  flex-wrap: wrap;
}

.fo-card-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-main);
  margin: 0;
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
}

/* Secondary text on the right of a card header ("Latest 4 imports"). */
.fo-card-header-meta {
  font-size: 12px;
  color: var(--text-muted);
  min-width: 0;
}

/* Controls on the right of a card header (buttons, filters). Wraps rather than
   overflowing, so a long filter row drops to a second line inside the band. */
.fo-card-header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  min-width: 0;
}

@media (max-width: 640px) {
  .fo-card-head,
  .fo-card-flush > .fo-card-header { padding: 12px 14px; }
}

/* ─── Stat Cards ────────────────────────────────────────── */

.fo-stat-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 18px 20px;
  display: flex;
  align-items: flex-start;
  gap: 14px;
  transition: box-shadow var(--transition);
}

.fo-stat-card:hover {
  box-shadow: 0 4px 16px rgba(0,0,0,0.09);
}

.fo-stat-icon {
  width: 46px;
  height: 46px;
  border-radius: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  flex-shrink: 0;
}

.fo-stat-icon.blue   { background: var(--primary-soft);  color: var(--primary); }
.fo-stat-icon.teal   { background: #CCFBF1;               color: var(--secondary); }
.fo-stat-icon.amber  { background: #FEF3C7;               color: var(--accent); }
.fo-stat-icon.green  { background: #DCFCE7;               color: var(--success); }
.fo-stat-icon.red    { background: #FEE2E2;               color: var(--danger); }
.fo-stat-icon.orange { background: #FFEDD5;               color: var(--warning); }
.fo-stat-icon.purple { background: #F3E8FF;               color: #7C3AED; }
.fo-stat-icon.gray   { background: var(--surface-muted);  color: var(--text-muted); }

.fo-stat-body { flex: 1; min-width: 0; }

.fo-stat-value {
  font-size: 28px;
  font-weight: 700;
  color: var(--text-main);
  line-height: 1;
  letter-spacing: -0.5px;
}

.fo-stat-label {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 5px;
  font-weight: 500;
}

.fo-stat-meta {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 6px;
}

/* ─── Badges ────────────────────────────────────────────── */

.fo-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}

.fo-badge-blue    { background: var(--primary-soft);  color: var(--primary); }
.fo-badge-green   { background: #DCFCE7;               color: var(--success); }
.fo-badge-amber   { background: #FEF3C7;               color: var(--warning); }
.fo-badge-red     { background: #FEE2E2;               color: var(--danger); }
.fo-badge-teal    { background: #CCFBF1;               color: var(--secondary); }
.fo-badge-gray    { background: var(--surface-muted);  color: var(--text-muted); }
.fo-badge-orange  { background: #FFEDD5;               color: var(--warning); }

/* ─── Tables ────────────────────────────────────────────── */

/* A horizontal scroller ONLY where one is needed.
   `overflow-x: auto` computes `overflow-y` to `auto` as well (CSS Overflow 3:
   a `visible` paired with a non-visible value becomes `auto`), which makes this
   wrapper a scroll container in both axes — and that is what a sticky <th>
   would pin to. Since the wrapper never scrolls vertically, the header would
   simply travel with the page.
   Below 641px these tables are re-laid out as cards (.fo-cards-mobile) and
   their <thead> is hidden, so the scroller is free there and the sticky header
   is moot. Above it the table is `width: 100%` and compresses rather than
   overflowing, so the wrapper has nothing to scroll and can step out of the
   way. */
@media (max-width: 640px) {
  .fo-table-wrap {
    overflow-x: auto;
  }
}

.fo-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}

.fo-table th {
  padding: 10px 14px;
  text-align: left;
  font-weight: 700;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  background: var(--surface-muted);
  border-bottom: 1px solid var(--border);
}

.fo-table td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  color: var(--text-main);
  vertical-align: middle;
}

.fo-table tbody tr:hover { background: var(--surface-muted); }
.fo-table tbody tr:last-child td { border-bottom: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   STICKY COLUMN HEADERS — record tables only
   ---------------------------------------------------------------------------
   A genuine record list keeps its column header while its rows scroll. The page
   itself scrolls exactly as before: this is `position: sticky` against the
   DOCUMENT, not a fixed-height scroll box around the table (which would create
   a second scrollbar and change how every one of these pages reads).

   For that to work nothing between the <th> and the document may be a scroll
   container, because sticky pins to the nearest one. Three things had to give
   way, and they are the whole implementation:

     .fo-header        was `position: sticky` — the column header would have
                       pinned underneath it, or behind it
     .fo-card-flush    was `overflow: hidden`  → `overflow: clip`
     .fo-table-wrap    was `overflow-x: auto`  → only below 641px

   Applied to the two shared record-table classes, so a page gets this by using
   the component rather than by patching itself. Deliberately NOT applied to
   form layouts, dashboard widgets, key/value summaries or settings forms —
   none of which are record lists — and moot under 641px, where
   `.fo-cards-mobile` turns rows into cards and hides the header entirely.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 641px) {
  .fo-table thead th,
  .fo-mini-table thead th {
    position: sticky;
    top: 0;
    /* Above its own rows, below the app's overlays (modals sit at 1400+). */
    z-index: 2;
  }

  /* `border-collapse: collapse` gives the borders to the TABLE, which does not
     travel with the sticky cell — the header's underline would be left behind
     on the row it started next to. An inset shadow is painted by the cell
     itself, so it moves with it. */
  .fo-table thead th,
  .fo-mini-table thead th {
    box-shadow: inset 0 -1px 0 var(--border);
  }
}

/* ─── Buttons ───────────────────────────────────────────── */

.fo-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 16px;
  border-radius: 7px;
  font-size: 13px;
  font-weight: 600;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: all var(--transition);
  line-height: 1.4;
  white-space: nowrap;
  font-family: inherit;
}

.fo-btn-primary {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
.fo-btn-primary:hover {
  background: #1d4ed8;
  border-color: #1d4ed8;
  color: #fff;
}

.fo-btn-secondary {
  background: var(--surface);
  color: var(--text-main);
  border-color: var(--border);
}
.fo-btn-secondary:hover { background: var(--surface-muted); }

.fo-btn-success {
  background: var(--success);
  color: #fff;
  border-color: var(--success);
}
.fo-btn-success:hover { background: #15803d; }

.fo-btn-danger {
  background: var(--danger);
  color: #fff;
  border-color: var(--danger);
}
.fo-btn-danger:hover { background: #b91c1c; }

.fo-btn-sm { padding: 4px 11px; font-size: 12px; }
.fo-btn-lg { padding: 10px 22px; font-size: 14px; }

.fo-btn-group {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* ─── Forms ─────────────────────────────────────────────── */

/* Central form-field label style — slightly larger + bold for readability.
   Shared by every form in the CRM (custom fields, task collection/detail,
   client/project/contract, imports, PDF Center, Form Workflow popups, Opt In,
   modals). Colour stays theme-aware; the required asterisk (.fo-req-marker) and
   helper text (.fo-hint / .fo-info-label) are separate classes and unaffected. */
.fo-label {
  font-size: 1.05rem;   /* ~16.8px — clearly larger than body/input text */
  font-weight: 700;
  line-height: 1.35;
  color: var(--text-main);
  margin-bottom: 6px;
  display: block;
}

.fo-input {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 7px;
  font-size: 13.5px;
  color: var(--text-main);
  background: var(--surface);
  transition: border-color var(--transition), box-shadow var(--transition);
  outline: none;
  font-family: inherit;
}

.fo-input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

.fo-input::placeholder { color: var(--text-muted); }
.fo-input[readonly], .fo-input:disabled, .fo-input-readonly {
  background: var(--surface-muted);
  cursor: not-allowed;
  opacity: 1;
}

.fo-hint {
  font-size: 11.5px;
  color: var(--text-muted);
  margin-top: 4px;
}

.fo-form-row {
  margin-bottom: 18px;
}

/* ─── Alerts / Messages ─────────────────────────────────── */

.fo-alert {
  padding: 11px 14px;
  border-radius: 8px;
  font-size: 13px;
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin-bottom: 14px;
  border-left: 3px solid transparent;
}

.fo-alert-success { background: #DCFCE7; color: #14532D; border-color: var(--success); }
.fo-alert-error   { background: #FEE2E2; color: #7F1D1D; border-color: var(--danger); }
.fo-alert-warning { background: #FEF3C7; color: #78350F; border-color: var(--accent); }
.fo-alert-info    { background: var(--primary-soft); color: #1e3a8a; border-color: var(--primary); }

/* ─── Empty State ───────────────────────────────────────── */

.fo-empty {
  text-align: center;
  padding: 56px 24px;
  color: var(--text-muted);
}

.fo-empty-icon {
  font-size: 46px;
  margin-bottom: 14px;
  opacity: 0.3;
  display: block;
}

.fo-empty h3 {
  font-size: 16px;
  color: var(--text-main);
  font-weight: 600;
  margin: 0 0 6px;
}

.fo-empty p {
  font-size: 13.5px;
  margin: 0 0 18px;
}

/* ─── Coming Soon / Placeholder ─────────────────────────── */

.fo-coming-soon {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 80px 24px;
  text-align: center;
}

.fo-coming-soon-icon {
  width: 72px;
  height: 72px;
  border-radius: 18px;
  background: var(--primary-soft);
  color: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
  margin-bottom: 20px;
}

.fo-coming-soon h2 {
  font-size: 20px;
  font-weight: 700;
  color: var(--text-main);
  margin: 0 0 8px;
}

.fo-coming-soon p {
  font-size: 14px;
  color: var(--text-muted);
  max-width: 380px;
  margin: 0 0 24px;
  line-height: 1.6;
}

/* ─── Login Page ────────────────────────────────────────── */

.fo-login-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-main);
}

.fo-login-wrap {
  width: 100%;
  max-width: 420px;
  padding: 16px;
}

.fo-login-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 4px 24px rgba(0,0,0,0.08);
  padding: 40px 36px;
}

.fo-login-brand {
  text-align: center;
  margin-bottom: 30px;
}

.fo-login-brand-icon {
  width: 52px;
  height: 52px;
  background: #000;  /* matches the logo's black background */
  border-radius: 13px;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  font-weight: 800;
  color: #fff;
  margin-bottom: 12px;
}

.fo-login-brand h2 {
  font-size: 20px;
  font-weight: 700;
  margin: 0 0 4px;
  color: var(--text-main);
}

.fo-login-brand p {
  font-size: 13px;
  color: var(--text-muted);
  margin: 0;
}

/* ─── Divider ───────────────────────────────────────────── */

.fo-divider {
  height: 1px;
  background: var(--border);
  margin: 20px 0;
}

/* ─── Utility ───────────────────────────────────────────── */

.text-muted   { color: var(--text-muted) !important; }
.text-primary { color: var(--primary) !important; }
.text-success { color: var(--success) !important; }
.text-danger  { color: var(--danger) !important; }
.text-warning { color: var(--warning) !important; }
.fw-500 { font-weight: 500; }
.fw-600 { font-weight: 600; }
.fw-700 { font-weight: 700; }
.fs-12  { font-size: 12px; }
.fs-13  { font-size: 13px; }

/* ─── Select widget arrow ────────────────────────────────── */

select.fo-input {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%2364748B' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 14px;
  padding-right: 38px;
  appearance: none;
  -webkit-appearance: none;
}

/* ─── Detail page header ─────────────────────────────────── */

.fo-detail-header {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 20px 24px;
  margin-bottom: 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}

.fo-detail-header-left {
  display: flex;
  align-items: center;
  gap: 14px;
}

.fo-detail-avatar {
  width: 48px;
  height: 48px;
  border-radius: 12px;
  background: var(--primary-soft);
  color: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  font-weight: 700;
  flex-shrink: 0;
}

.fo-detail-title {
  font-size: 20px;
  font-weight: 700;
  color: var(--text-main);
  margin: 0 0 2px;
  line-height: 1.2;
}

.fo-detail-subtitle {
  font-size: 13px;
  color: var(--text-muted);
  margin: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* ─── Mini stat pills (detail pages) ─────────────────────── */

.fo-mini-stats {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}

.fo-mini-stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 12px 18px;
  flex: 1;
  min-width: 110px;
  text-align: center;
}

.fo-mini-stat-value {
  font-size: 22px;
  font-weight: 700;
  color: var(--text-main);
  line-height: 1;
}

.fo-mini-stat-label {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 4px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* ─── Progress bar ────────────────────────────────────────── */

.fo-progress-wrap {
  height: 6px;
  background: var(--surface-muted);
  border-radius: 99px;
  overflow: hidden;
}

.fo-progress-bar {
  height: 100%;
  background: var(--primary);
  border-radius: 99px;
  transition: width 0.4s ease;
}

.fo-progress-bar.green  { background: var(--success); }
.fo-progress-bar.amber  { background: var(--accent); }
.fo-progress-bar.danger { background: var(--danger); }

/* ─── Percentage stat card ──────────────────────────────────
   The Metric card plus a progress bar. Deliberately built from the SAME
   tokens and the SAME .fo-progress-wrap/.fo-progress-bar the rest of the CRM
   uses, so a percentage widget cannot look like a component from another app —
   which also means dark mode, radii and shadows come for free.

   The card is its own query container so the "12 of 20" detail can be dropped
   when the card is narrow. Width here comes from the widget's grid SPAN, not
   from the viewport, so a media query would ask the wrong question. */
.fo-stat-card.is-percentage {
  container: fo-pct / inline-size;
}
.fo-stat-pct { margin-top: 10px; }
.fo-stat-pct-detail {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 6px;
}
/* Priority when space runs out: percentage, then title, then the bar. The
   detail line is the first thing to go. */
@container fo-pct (max-width: 190px) {
  .fo-stat-pct-detail { display: none; }
}
/* No container-query support: keep the detail rather than hide it forever. */
@supports not (container-type: inline-size) {
  .fo-stat-pct-detail { display: block; }
}

/* ─── Tab navigation (detail pages) ─────────────────────── */

.fo-tabs-nav {
  display: flex;
  gap: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card) var(--radius-card) 0 0;
  overflow-x: auto;
  border-bottom: none;
  padding: 0 8px;
}

.fo-tabs-nav .nav-link {
  color: var(--text-muted);
  font-size: 13.5px;
  font-weight: 600;
  padding: 12px 16px;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  white-space: nowrap;
  transition: color var(--transition), border-color var(--transition);
}

.fo-tabs-nav .nav-link:hover {
  color: var(--text-main);
  background: var(--surface-muted);
}

.fo-tabs-nav .nav-link.active {
  color: var(--primary);
  border-bottom-color: var(--primary);
  background: transparent;
}

.fo-tab-content {
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: none;
  border-radius: 0 0 var(--radius-card) var(--radius-card);
  padding: 20px;
}

/* ─── Info list (key-value pairs in detail cards) ─────────── */

.fo-info-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.fo-info-list li {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 9px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13.5px;
}

.fo-info-list li:last-child { border-bottom: none; }

.fo-info-label {
  min-width: 130px;
  color: var(--text-muted);
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding-top: 2px;
  flex-shrink: 0;
}

.fo-info-value {
  color: var(--text-main);
  flex: 1;
}

/* ─── Form layout ─────────────────────────────────────────── */

.fo-form-section {
  margin-bottom: 28px;
}

.fo-form-section-title {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  margin-bottom: 14px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}

.fo-form-grid {
  display: grid;
  gap: 16px;
}

.fo-form-grid-2 { grid-template-columns: 1fr 1fr; }
.fo-form-grid-3 { grid-template-columns: 1fr 1fr 1fr; }

@media (max-width: 640px) {
  .fo-form-grid-2,
  .fo-form-grid-3 { grid-template-columns: 1fr; }
}

/* ─── Inline mini table (inside cards) ───────────────────── */

.fo-mini-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.fo-mini-table th {
  padding: 8px 12px;
  text-align: left;
  font-weight: 700;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  background: var(--surface-muted);
  border-bottom: 1px solid var(--border);
}

.fo-mini-table td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

.fo-mini-table tr:last-child td { border-bottom: none; }
.fo-mini-table tbody tr:hover   { background: var(--surface-muted); }

/* ─── Code/Monospace tag ──────────────────────────────────── */

.fo-code-tag {
  font-family: monospace;
  font-size: 12px;
  background: var(--surface-muted);
  padding: 2px 8px;
  border-radius: 5px;
  color: var(--primary);
  border: 1px solid var(--border);
  white-space: nowrap;
}

/* ─── Confirm modal helper ───────────────────────────────── */

.fo-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* ─── Filter bar ──────────────────────────────────────────── */

.fo-filter-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.fo-search-input {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 7px 12px;
  font-size: 13px;
  color: var(--text-muted);
  min-width: 240px;
  flex: 1;
}

.fo-search-input input {
  border: none;
  outline: none;
  background: transparent;
  font-family: inherit;
  font-size: 13px;
  color: var(--text-main);
  flex: 1;
  min-width: 0;
}

.fo-search-input input::placeholder { color: var(--text-muted); }

/* ─── Checkbox input ─────────────────────────────────────── */

.fo-checkbox {
  width: 16px;
  height: 16px;
  accent-color: var(--primary);
  cursor: pointer;
  flex-shrink: 0;
}

/* ─── Form field wrapper & error ─────────────────────────── */

.fo-field {
  display: flex;
  flex-direction: column;
  margin-bottom: 4px;
}

.fo-field-error {
  font-size: 11.5px;
  color: var(--danger);
  margin-top: 4px;
}

.fo-field .fo-input:has(~ .fo-field-error),
.fo-field .fo-input.is-invalid {
  border-color: var(--danger);
}

/* ─── Tab link alias ─────────────────────────────────────── */

.fo-tabs-nav .fo-tab-link {
  color: var(--text-muted);
  font-size: 13.5px;
  font-weight: 600;
  padding: 12px 16px;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  white-space: nowrap;
  text-decoration: none;
  display: inline-block;
  transition: color var(--transition), border-color var(--transition);
}

.fo-tabs-nav .fo-tab-link:hover {
  color: var(--text-main);
  background: var(--surface-muted);
}

.fo-tabs-nav .fo-tab-link.active {
  color: var(--primary);
  border-bottom-color: var(--primary);
  background: transparent;
}

/* ─── File input ──────────────────────────────────────────── */

.fo-file-input {
  display: block;
  width: 100%;
  margin-top: 10px;
  font-size: 13px;
  color: var(--text-muted);
}

.fo-file-input::file-selector-button {
  padding: 6px 14px;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--surface);
  color: var(--text-main);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  margin-right: 10px;
  transition: background var(--transition);
}

.fo-file-input::file-selector-button:hover {
  background: var(--surface-muted);
}

/* ─── Collection Form Grid ──────────────────────────────── */

.fo-collect-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 16px 20px;
  align-items: start;
}

/* Column spans — desktop (12 virtual cols). Existing widths keep the same
   proportions (half 6/12 = 50%, one third 4/12 = 33%, …); quarter and
   three-quarters are the new integer spans. */
.fo-col-full           { grid-column: span 12; }
.fo-col-three-quarters { grid-column: span 9; }
.fo-col-two-thirds     { grid-column: span 8; }
.fo-col-half           { grid-column: span 6; }
.fo-col-third          { grid-column: span 4; }
.fo-col-quarter        { grid-column: span 3; }

/* Tablet: 4 virtual columns (coarser — wide widths fill the row) */
@media (max-width: 900px) {
  .fo-collect-grid   { grid-template-columns: repeat(4, 1fr); }
  .fo-col-full, .fo-col-three-quarters, .fo-col-two-thirds { grid-column: span 4; }
  .fo-col-half, .fo-col-third, .fo-col-quarter             { grid-column: span 2; }
}

/* Mobile: single column */
@media (max-width: 540px) {
  .fo-collect-grid { grid-template-columns: 1fr; }
  .fo-col-full, .fo-col-three-quarters, .fo-col-two-thirds,
  .fo-col-half, .fo-col-third, .fo-col-quarter {
    grid-column: span 1;
  }
}

/* Label row with inline badges */
.fo-collect-label-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 5px;
  flex-wrap: wrap;
}

.fo-collect-label-row .fo-label {
  margin-bottom: 0;
  flex: 1;
  min-width: 0;
  /* Collection-form field titles read as labels, not headings: sized to match
     the input text (.fo-input is 13.5px) with a medium weight so the title is
     still clearly distinguishable from the value below. Compact line-height
     keeps long German questions from taking excess vertical space. */
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.fo-req-marker {
  color: var(--danger);
  font-size: 11px;
  margin-left: 1px;
  font-weight: 700;
}

.fo-badge-imported {
  font-size: 10px;
  background: var(--primary-soft);
  color: var(--primary);
  padding: 1px 6px;
  border-radius: 10px;
  font-weight: 600;
  letter-spacing: .3px;
  white-space: nowrap;
  flex-shrink: 0;
}

.fo-badge-readonly {
  font-size: 10px;
  background: var(--surface-muted);
  color: var(--text-muted);
  padding: 1px 6px;
  border-radius: 10px;
  font-weight: 600;
  letter-spacing: .3px;
  white-space: nowrap;
  flex-shrink: 0;
}

/* Inline checkbox group */
/* ── Visible choice lists (radio single-choice + multi checkbox) ───────────
   Column count is DERIVED (ceil(options / MAX_CHOICE_ROWS)) in the template and
   passed in as --choice-cols. The wrapper is a query container, so a list in a
   narrow field column collapses to one column even on a wide screen — the count
   is a ceiling, not a promise. Each option row is ≥44px (tappable). */
.fo-choice-container { container-type: inline-size; }

.fo-checkbox-group,
.fo-singlechoice-group {
  display: grid;
  grid-template-columns: repeat(var(--choice-cols, 1), minmax(0, 1fr));
  gap: 8px 18px;
  padding: 3px 0;
}

.fo-checkbox-item,
.fo-singlechoice-item {
  display: flex;
  align-items: center;
  gap: 7px;
  min-height: 44px;          /* tappable option row */
  font-size: 13px;
  line-height: 1.4;
  min-width: 0;              /* let long labels wrap, never overflow the track */
}
.fo-checkbox-item input[type="checkbox"],
.fo-singlechoice-item input[type="radio"] {
  width: 15px;
  height: 15px;
  accent-color: var(--primary);
  flex-shrink: 0;
  margin: 0;
}

/* A narrow field column can't fit multiple option columns → collapse to one. */
@container (max-width: 22rem) {
  .fo-checkbox-group,
  .fo-singlechoice-group { grid-template-columns: 1fr; }
}
/* Fallback for engines without container queries: collapse on small viewports. */
@supports not (container-type: inline-size) {
  @media (max-width: 640px) {
    .fo-checkbox-group,
    .fo-singlechoice-group { grid-template-columns: 1fr; }
  }
}

/* ── Change A: compact inputs for short numeric/date/time values ───────────
   Cap the INPUT (not its column — the author owns column width). ch units so
   the cap tracks the font. Stays ≥44px tall and never a sliver in a wide col. */
.fo-input-num, .fo-input-date, .fo-input-time {
  width: 100%;
  min-height: 44px;
}
.fo-input-num  { max-width: 12ch; }
.fo-input-date { max-width: 18ch; }
.fo-input-time { max-width: 11ch; }

/* Upload drop zone */
.fo-upload-zone {
  border: 2px dashed var(--border);
  border-radius: 9px;
  padding: 18px 16px;
  text-align: center;
  background: var(--surface-muted);
  transition: border-color var(--transition);
}

.fo-upload-zone:hover {
  border-color: var(--primary);
}

.fo-upload-icon {
  font-size: 26px;
  color: var(--text-muted);
  display: block;
  margin-bottom: 6px;
}

.fo-upload-hint {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 5px;
}

/* ─── Form Layout Row/Item (designer + live task form) ─── */

.form-layout-row {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  margin: 0 -8px 14px;
}

.form-layout-item {
  box-sizing: border-box;
  padding: 0 8px;
  min-width: 0;
  flex-shrink: 0;
}

@media (max-width: 640px) {
  .form-layout-row { flex-wrap: wrap; margin: 0 0 8px; }
  .form-layout-item { width: 100% !important; padding: 0 0 12px; }
}

/* ─── Visual Form Layout Designer ──────────────────────── */

.dsr-toolbar {
  padding: 12px 20px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.dsr-canvas-wrap { padding: 14px; }

.dsr-container {
  display: flex;
  flex-wrap: wrap;
  margin: 0 -6px;
}

.dsr-item {
  box-sizing: border-box;
  padding: 0 6px 10px;
  flex-shrink: 0;
  position: relative;
}

.dsr-ghost { opacity: 0.3 !important; }

.dsr-card {
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: 9px;
  overflow: hidden;
  position: relative;
  transition: box-shadow 0.12s, border-color 0.12s;
}

.dsr-card:hover { box-shadow: 0 0 0 2px var(--primary); border-color: var(--primary); }

.dsr-drag-handle {
  position: absolute; top: 6px; left: 6px;
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  cursor: grab; color: var(--text-muted); opacity: .6; font-size: 15px; z-index: 5; border-radius: 4px;
}
.dsr-drag-handle:hover { color: var(--primary); background: var(--primary-soft); }
.dsr-drag-handle:active { cursor: grabbing; }

/* Change B: drag-to-resize grip on the card's trailing edge. Desktop-only
   affordance (hidden where a pointer drag can't work). */
.dsr-resize-grip {
  position: absolute;
  top: 50%;
  right: 2px;
  transform: translateY(-50%);
  width: 18px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-muted);
  cursor: ew-resize;
  border-radius: 5px;
  z-index: 3;
  touch-action: none;
  font-size: 12px;
}
.dsr-resize-grip:hover,
.dsr-resize-grip:focus-visible {
  color: var(--primary);
  background: var(--primary-soft);
  outline: none;
}
.dsr-item.dsr-resizing-active { outline: 2px dashed var(--primary); outline-offset: -3px; }
body.dsr-resizing { user-select: none; }
@media (max-width: 640px) {
  .dsr-resize-grip { display: none; }
}

.dsr-head {
  padding: 8px 10px 8px 30px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-muted);
}

.dsr-label { font-size: 12px; font-weight: 700; color: var(--text-main); line-height: 1.3; }
.dsr-badges { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 4px; }
.dsr-badge { font-size: 9px; padding: 1px 5px; border-radius: 5px; font-weight: 700; }
.dsr-badge-req     { background: #fee2e2; color: #dc2626; }
.dsr-badge-csv     { background: var(--primary-soft); color: var(--primary); }
.dsr-badge-inactive{ background: var(--surface-muted); color: var(--text-muted); border: 1px solid var(--border); }
html[data-theme="dark"] .dsr-badge-req { background: rgba(239,68,68,0.18); color: #fca5a5; }

.dsr-preview { padding: 10px; min-height: 44px; }
.dsr-preview .fo-input,
.dsr-preview input, .dsr-preview select, .dsr-preview textarea {
  width: 100% !important; font-size: 12px !important; padding: 5px 8px !important;
  pointer-events: none; opacity: 0.65; background: var(--surface-muted);
}

.dsr-footer {
  padding: 5px 8px; background: var(--surface-muted);
  border-top: 1px solid var(--border);
  display: flex; align-items: center; gap: 5px; font-size: 10px;
}

.dsr-type { color: var(--text-muted); flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.dsr-width-label {
  font-size: 10px; font-weight: 700; color: var(--primary);
  background: var(--primary-soft); padding: 1px 6px; border-radius: 6px;
  min-width: 34px; text-align: center; flex-shrink: 0;
}

.dsr-quick-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 4px;
  border: 1px solid var(--border); background: var(--surface);
  cursor: pointer; font-size: 10px; color: var(--text-muted);
  padding: 0; line-height: 1; flex-shrink: 0;
}
.dsr-quick-btn:hover { color: var(--primary); border-color: var(--primary); }
.dsr-quick-btn.dsr-active { color: var(--primary); border-color: var(--primary); background: var(--primary-soft); }
.dsr-quick-btn.dsr-del { color: var(--danger); }
.dsr-quick-btn.dsr-del:hover { color: #fff; background: var(--danger); border-color: var(--danger); }

.dsr-edit-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 4px;
  border: 1px solid var(--border); background: var(--surface);
  font-size: 10px; color: var(--text-muted); text-decoration: none; flex-shrink: 0;
}
.dsr-edit-btn:hover { color: var(--primary); border-color: var(--primary); }

.dsr-resize-handle {
  position: absolute; right: 0; top: 0; bottom: 10px;
  width: 10px; cursor: col-resize; z-index: 20;
  display: flex; align-items: center; justify-content: center;
}
.dsr-resize-handle::after {
  content: ''; width: 3px; height: 32px;
  background: var(--border); border-radius: 3px;
  transition: background 0.12s, height 0.12s;
}
.dsr-resize-handle:hover::after, .dsr-resize-handle.is-resizing::after {
  background: var(--primary); height: 46px;
}

/* ─── Task Detail — 2-column collection form ────────────── */

.task-collection-grid {
  align-items: start;
}

.task-collection-field {
  display: flex;
  flex-direction: column;
}

.task-collection-field label.fo-label {
  display: block;
  margin-bottom: 5px;
  /* Match the collection form: label sized to the input text, medium weight —
     not a heading. (See .fo-collect-label-row .fo-label.) */
  font-weight: 600;
  font-size: 13.5px;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.task-collection-field .fo-input,
.task-collection-field input[type="text"],
.task-collection-field input[type="number"],
.task-collection-field input[type="tel"],
.task-collection-field input[type="email"],
.task-collection-field input[type="date"],
.task-collection-field input[type="time"],
.task-collection-field select,
.task-collection-field textarea {
  width: 100%;
}

.task-collection-field--special {
  margin-top: 2px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   MOBILE SHELL — burger drawer + responsive polish (2026)
   Desktop (≥1025px) layout is unchanged. Everything below is scoped to the
   burger controls or the ≤1024px breakpoint so it never affects desktop.
═══════════════════════════════════════════════════════════════════════════ */

/* Chrome that only exists on mobile — hidden on desktop by default */
.fo-burger,
.fo-sidebar-close { display: none; }

/* Dim overlay behind the open drawer */
.fo-sidebar-overlay {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, 0.45);
  z-index: 190;
  opacity: 0; visibility: hidden;
  transition: opacity var(--transition);
}
body.fo-menu-open .fo-sidebar-overlay { opacity: 1; visibility: visible; }

@media (max-width: 1024px) {
  /* The desktop 3-mode toggle is replaced by the burger on mobile. */
  .fo-sidebar-toggle { display: none; }

  /* Sidebar becomes an off-canvas drawer. The desktop collapsed/hidden modes do
     not apply here (they are scoped to ≥1025px), so the drawer always shows the
     full sidebar with labels and section headers. */
  .fo-sidebar {
    transform: translateX(-100%);
    transition: transform 0.25s ease;
    z-index: 200;
    width: min(84vw, 300px);
    box-shadow: 0 0 40px rgba(0, 0, 0, 0.18);
  }
  body.fo-menu-open .fo-sidebar { transform: translateX(0); }
  body.fo-menu-open { overflow: hidden; }            /* lock page scroll */

  .fo-main { margin-left: 0; }

  /* Burger button in the header */
  .fo-burger {
    display: inline-flex; align-items: center; justify-content: center;
    width: 42px; height: 42px; margin-left: -6px;
    border: none; background: transparent; cursor: pointer;
    font-size: 22px; color: var(--text-main); border-radius: 8px;
    flex-shrink: 0;
  }
  .fo-burger:active { background: var(--surface-muted); }

  /* Close button inside the open drawer (top-right) */
  .fo-sidebar-close {
    display: inline-flex; align-items: center; justify-content: center;
    position: absolute; top: 12px; right: 12px; z-index: 5;
    width: 38px; height: 38px; border-radius: 8px;
    border: 1px solid var(--border); background: rgba(255, 255, 255, 0.92);
    color: var(--text-main); font-size: 16px; cursor: pointer;
  }

  /* Header declutter — keep burger + title + account, drop the wide search */
  .fo-header { padding: 0 14px; gap: 10px; }
  .fo-header-center { display: none; }
  .fo-admin-info { display: none; }
  .fo-header-title { font-size: 15px; }

  .fo-content { padding: 16px 14px; }

  /* Comfortable tap targets */
  .fo-nav-item { padding-top: 12px; padding-bottom: 12px; }
  /* .fo-btn mobile sizing now lives in the responsive button scale at the end
     of this file (compact, 36px) — deliberately not re-declared here. */
}

/* Stack page headers + make primary actions easy to tap on phones */
@media (max-width: 640px) {
  .fo-page-header,
  .fo-detail-header { flex-direction: column; align-items: stretch; gap: 12px; }

  /* Filters: full-width search, no cramped min-width */
  .fo-filter-bar { gap: 10px; }
  .fo-search-input { min-width: 0; width: 100%; }

  .fo-content { padding: 14px 12px; }
}

/* Wide tables scroll smoothly on touch (wrappers already set overflow-x) */
@media (max-width: 1024px) {
  .fo-table-wrap { -webkit-overflow-scrolling: touch; }
}

/* Visible keyboard focus everywhere it matters */
.fo-nav-item:focus-visible,
.fo-btn:focus-visible,
.fo-burger:focus-visible,
.fo-sidebar-close:focus-visible,
.fo-search-input-field:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* Honour reduced-motion preferences */
@media (prefers-reduced-motion: reduce) {
  .fo-sidebar,
  .fo-sidebar-overlay { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   WHOLE-CRM MOBILE RESPONSIVENESS (2026)
   Fixes the real root causes: inline multi-column grids that media queries
   can't reach, clipped tab bars, and horizontal body overflow. Desktop
   (≥1025px) is untouched.
═══════════════════════════════════════════════════════════════════════════ */

/* 1. Never let the page scroll sideways. Wide data tables keep their own
      .fo-table-wrap (overflow-x:auto) and still scroll internally. */
/* `html` carries the sideways clamp: its overflow propagates to the viewport,
   so the page still cannot be dragged left/right.
   `body` gets `clip` rather than `hidden` deliberately. With the root already
   non-visible, propagation stops there and <body>'s own `hidden` would make
   BODY a scroll container in both axes — and a sticky <th> pins to its nearest
   scroll container. Body's height grows with its content, so it never scrolls
   internally, and every sticky column header would have sat still relative to
   body while the page scrolled past: the feature would silently do nothing.
   `clip` clamps without creating a scrollport. */
html { max-width: 100%; overflow-x: hidden; }
body { max-width: 100%; overflow-x: clip; }

/* 2. Tab bars scroll horizontally instead of clipping / wrapping (all widths). */
.fo-tabs-nav { overflow-x: auto; flex-wrap: nowrap; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
.fo-tabs-nav::-webkit-scrollbar { display: none; }
.fo-tabs-nav > a, .fo-tabs-nav .fo-tab-link, .fo-tabs-nav .nav-link { flex-shrink: 0; white-space: nowrap; }

/* 3. Tablet: dense stat rows drop to 2 columns rather than staying 3–4 wide. */
@media (max-width: 1024px) and (min-width: 641px) {
  .fo-form-grid-3 { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 640px) {
  /* 4. Reflow rigid inline grids on phones. Templates set these inline, which a
        media query can only reach by overriding the inline declaration here.
        auto-fit / auto-fill grids already reflow (excluded); class-based grids
        like .crm-map-layout have their own breakpoints.
        - Content + sidebar / two-column layouts ("1fr 360px", "2fr 1fr", …)
          → a single full-width column (kills horizontal overflow).
        - Dense stat / mini-card rows (repeat(N,1fr)) → two compact columns,
          which reads far better than one tall stack. */
  [style*="grid-template-columns"]:not([style*="auto-fill"]):not([style*="auto-fit"]):not([style*="repeat("]) {
    grid-template-columns: 1fr !important;
  }
  [style*="grid-template-columns:repeat("]:not([style*="auto-fill"]):not([style*="auto-fit"]),
  [style*="grid-template-columns: repeat("]:not([style*="auto-fill"]):not([style*="auto-fit"]) {
    grid-template-columns: repeat(2, 1fr) !important;
  }
  .fo-form-grid-2, .fo-form-grid-3, .fo-collect-grid { grid-template-columns: 1fr !important; }

  /* 5. Filter/search bars wrap cleanly; the per-control sizing (which has to
        reach through the display:contents forms) lives in the CONTROL SIZING
        section at the end of this file. */
  .fo-filter-bar { flex-wrap: wrap; }

  /* 6. Cards never keep a fixed inline width that overflows the screen. */
  .fo-content [style*="width:3"][style*="px"],
  .fo-content [style*="width:4"][style*="px"],
  .fo-content [style*="max-width:6"][style*="px"] { max-width: 100% !important; }

  /* 7. Comfortable page padding + readable stat numbers on small screens. */
  .fo-mini-stat-value { font-size: 22px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Responsive table → cards (opt-in via .fo-cards-mobile). On phones each row
   becomes a labelled card; wide horizontal tables become tap-friendly stacks.
═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  table.fo-cards-mobile { width: 100%; }
  table.fo-cards-mobile thead { display: none; }
  table.fo-cards-mobile tbody,
  table.fo-cards-mobile tr,
  table.fo-cards-mobile td { display: block; width: 100%; }

  table.fo-cards-mobile tr {
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    box-shadow: var(--shadow-card);
    padding: 12px 14px;
    margin: 0 0 12px;
  }
  table.fo-cards-mobile td {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    padding: 6px 0; border: none; text-align: right; white-space: normal;
    max-width: none !important;
  }
  table.fo-cards-mobile td::before {
    content: attr(data-label);
    font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
    color: var(--text-muted); text-align: left; flex: 0 0 auto;
  }
  /* Cells without a data-label print no label */
  table.fo-cards-mobile td:not([data-label])::before { content: ""; }

  /* Main cell (task title + address) spans the full card width at the top */
  table.fo-cards-mobile td.fo-card-main {
    display: block; text-align: left; padding-top: 0; margin-bottom: 4px;
    border-bottom: 1px solid var(--border); padding-bottom: 8px;
  }
  table.fo-cards-mobile td.fo-card-main::before { display: none; }
  table.fo-cards-mobile td.fo-card-main * {
    white-space: normal !important; overflow: visible !important; text-overflow: clip !important;
  }
  table.fo-cards-mobile td.fo-card-main > div:first-child { font-size: 15px !important; }

  /* Select checkbox: compact labelled row ("Select" · checkbox) */
  table.fo-cards-mobile td.fo-card-check { padding-top: 8px; }
  table.fo-cards-mobile td.fo-card-check::before { content: "Select"; display: inline; }

  /* Actions become a full-width, tap-friendly button row */
  table.fo-cards-mobile td.fo-card-actions { padding-top: 10px; }
  table.fo-cards-mobile td.fo-card-actions::before { display: none; }
  table.fo-cards-mobile td.fo-card-actions > div { width: 100%; gap: 8px; }
  table.fo-cards-mobile td.fo-card-actions form { flex: 1; display: flex; }
  table.fo-cards-mobile td.fo-card-actions form .fo-btn { width: 100%; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Tasks "Files" view — project/subproject rows stack cleanly on phones so the
   code/status badges no longer collide with the stat pills and the progress
   bar / View button no longer overflow the screen edge.
═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  .fo-projrow { flex-wrap: wrap; align-items: center; row-gap: 12px; }
  .fo-projrow-identity { flex: 1 1 auto; }
  .fo-projrow-stats {
    order: 5; flex: 1 1 100%; justify-content: space-between; gap: 6px !important;
  }
  .fo-projrow-stats > div { flex: 1; min-width: 0 !important; }
  .fo-projrow-progress { order: 6; flex: 1 1 100%; width: 100% !important; }
  .fo-projrow-view { order: 7; flex: 1 1 100%; justify-content: center; min-height: 40px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Dashboard stat cards — 2 per row on phones. The Bootstrap grid gives the
   2-up columns (col-6); here we make each card a compact, equal-height stack
   (icon → number → label → link) so two fit side-by-side without crowding.
   Preserves the desktop design (colors, shadow, radius, border) unchanged.
═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  .fo-stat-card {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    padding: 14px;
    height: 100%;              /* equal height across the 2-up row */
  }
  .fo-stat-icon { width: 40px; height: 40px; font-size: 18px; border-radius: 10px; }
  .fo-stat-value { font-size: 24px; }
  .fo-stat-label { font-size: 11.5px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   LIGHT THEME — frosted "shell"
   Mirrors the dark theme's floating layout (rounded glass header + large rounded
   content panel + soft gradient backdrop) in a light palette, so both themes
   share the exact same design language. Scoped to html[data-theme="light"] (the
   no-flash script always sets an explicit theme), leaving the bare base rules as
   a flat, no-JS fallback.
═══════════════════════════════════════════════════════════════════════════ */
html[data-theme="light"] {
  /* Glass helpers used by the shell / cards below */
  --glass-panel:  linear-gradient(180deg, #FFFFFF, #FBFCFE);
  --glass-border: #E6ECF4;
}

/* ── Backdrop: cool off-white with soft brand-tinted glows ── */
html[data-theme="light"] body {
  background:
    radial-gradient(1100px 620px at 62% -8%, rgba(37,99,235,0.06), transparent 60%),
    radial-gradient(900px 700px at 100% 100%, rgba(15,118,110,0.045), transparent 55%),
    var(--bg-main);
  background-attachment: fixed;
}

/* ── Frosted shell: header floats, content sits in a rounded panel ── */
html[data-theme="light"] .fo-main {
  padding: 16px 18px 22px 18px;
}
html[data-theme="light"] .fo-header {
  background: rgba(255,255,255,0.82);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  backdrop-filter: blur(16px) saturate(140%);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  /* No `top`: the header is not sticky, and on a positioned box this
     offset simply pushes it down the page. */
  margin-bottom: 16px;
  box-shadow: 0 4px 18px rgba(15,23,42,0.06), 0 1px 3px rgba(15,23,42,0.04);
}
html[data-theme="light"] .fo-content {
  background: var(--glass-panel);
  border: 1px solid var(--glass-border);
  border-radius: 20px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 12px 40px rgba(15,23,42,0.05);
}

/* Cards read as crisp white panels on the soft grey backdrop */
html[data-theme="light"] .fo-card,
html[data-theme="light"] .fo-stat-card {
  border-color: var(--glass-border);
}

/* On phones, drop the shell insets so the panels go edge-to-edge */
@media (max-width: 640px) {
  html[data-theme="light"] .fo-main { padding: 10px 10px 16px 10px; }
  /* `top` removed with the sticky positioning: it existed to inset a
     PINNED header, and on a positioned-but-not-sticky box it simply
     pushes the header 10px down the page. */
  html[data-theme="light"] .fo-header { margin-bottom: 12px; border-radius: 14px; }
  html[data-theme="light"] .fo-content { border-radius: 16px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   DARK THEME
   Activated by html[data-theme="dark"]. The whole design system is token-driven,
   so overriding the custom properties reskins every surface. Below the token
   block we patch the few components that hardcode light-only colours (pastel
   chips, Bootstrap dropdowns, button hovers, glass overlays).
   Deep charcoal base + blue-grey glass panels to match the dark reference.
═══════════════════════════════════════════════════════════════════════════ */
html[data-theme="dark"] {
  color-scheme: dark;

  /* Backgrounds — deep blue-black, matches the reference backdrop */
  --bg-main:        #090C12;
  --surface:        #141B27;   /* solid fallback (dropdowns, popovers) */
  --surface-muted:  #1B2431;

  /* Sidebar — near-black */
  --sidebar-bg:     #080B11;
  --sidebar-active: rgba(96,165,250,0.16);

  /* Brand colours (brighter for contrast on dark) */
  --primary:        #5B9BF5;
  --primary-soft:   rgba(91,155,245,0.18);
  --secondary:      #2DD4BF;
  --accent:         #FBBF24;
  --success:        #22C55E;
  --warning:        #F59E0B;
  --danger:         #EF4444;

  /* Typography */
  --text-main:  #E8EEF6;
  --text-muted: #93A2B8;

  /* Structure */
  --border:      rgba(148,163,184,0.14);
  --shadow-card: 0 1px 3px rgba(0,0,0,0.40), 0 12px 32px rgba(0,0,0,0.38);

  /* Glass helpers used by the shell / cards below */
  --glass-panel:  linear-gradient(180deg, rgba(148,163,184,0.07), rgba(148,163,184,0.025));
  --glass-card:   linear-gradient(180deg, rgba(148,163,184,0.09), rgba(148,163,184,0.035));
  --glass-border: rgba(148,163,184,0.13);
}

/* ── Backdrop: blue-black with a soft blue-grey glow toward the top ── */
html[data-theme="dark"] body {
  color: var(--text-main);
  background:
    radial-gradient(1100px 620px at 62% -8%, rgba(90,120,170,0.20), transparent 60%),
    radial-gradient(900px 700px at 100% 100%, rgba(40,58,92,0.18), transparent 55%),
    var(--bg-main);
  background-attachment: fixed;
}

/* ── Sidebar: near-black, hairline divider ── */
html[data-theme="dark"] .fo-sidebar { border-right: 1px solid rgba(148,163,184,0.07); }

/* ═══════════════════════════════════════════════════════════════════════
   Frosted "shell" — the header floats as a rounded glass bar and the page
   content sits in a large rounded glass panel, exactly like the reference.
   Applied only in dark mode; the light layout is untouched.
═══════════════════════════════════════════════════════════════════════ */
html[data-theme="dark"] .fo-main {
  padding: 16px 18px 22px 18px;
}
html[data-theme="dark"] .fo-header {
  background: rgba(19,26,38,0.62);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  backdrop-filter: blur(16px) saturate(140%);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  /* No `top`: the header is not sticky, and on a positioned box this
     offset simply pushes it down the page. */
  margin-bottom: 16px;
  box-shadow: 0 8px 28px rgba(0,0,0,0.30);
}
html[data-theme="dark"] .fo-content {
  background: var(--glass-panel);
  border: 1px solid var(--glass-border);
  border-radius: 20px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.03), 0 12px 40px rgba(0,0,0,0.30);
}

/* ── Cards → translucent frosted glass ── */
html[data-theme="dark"] .fo-card,
html[data-theme="dark"] .fo-stat-card {
  background: var(--glass-card);
  border: 1px solid var(--glass-border);
  box-shadow: 0 1px 0 rgba(255,255,255,0.03) inset, 0 6px 20px rgba(0,0,0,0.22);
}
html[data-theme="dark"] .fo-stat-card:hover {
  border-color: rgba(148,163,184,0.24);
  box-shadow: 0 1px 0 rgba(255,255,255,0.04) inset, 0 10px 28px rgba(0,0,0,0.30);
}
html[data-theme="dark"] .fo-card-header { border-color: var(--glass-border); }

/* ── Search + secondary buttons → translucent to match the glass surfaces ── */
html[data-theme="dark"] .fo-search { background: rgba(148,163,184,0.07); border-color: var(--glass-border); }
html[data-theme="dark"] .fo-search:focus-within { background: rgba(148,163,184,0.10); }
html[data-theme="dark"] .fo-btn-secondary { background: rgba(148,163,184,0.06); border-color: var(--glass-border); }
html[data-theme="dark"] .fo-btn-secondary:hover { background: rgba(148,163,184,0.12); }
html[data-theme="dark"] .fo-admin-badge:hover { background: rgba(148,163,184,0.10); }

/* ── Tables → let the frosted card show through ── */
html[data-theme="dark"] .fo-mini-table th,
html[data-theme="dark"] .fo-table th { background: rgba(148,163,184,0.06); }
html[data-theme="dark"] .fo-mini-table tbody tr:hover,
html[data-theme="dark"] .fo-table tbody tr:hover { background: rgba(148,163,184,0.05); }

/* ── Stat-icon tiles → uniform light-glass tiles (as in the reference) ── */
html[data-theme="dark"] .fo-stat-icon,
html[data-theme="dark"] .fo-stat-icon.blue,
html[data-theme="dark"] .fo-stat-icon.teal,
html[data-theme="dark"] .fo-stat-icon.amber,
html[data-theme="dark"] .fo-stat-icon.green,
html[data-theme="dark"] .fo-stat-icon.red,
html[data-theme="dark"] .fo-stat-icon.orange,
html[data-theme="dark"] .fo-stat-icon.purple,
html[data-theme="dark"] .fo-stat-icon.gray {
  background: rgba(148,163,184,0.10);
  border: 1px solid rgba(148,163,184,0.16);
  color: #C7D3E3;
}

/* ── Badges → translucent tints (semantic colour kept) ── */
html[data-theme="dark"] .fo-badge         { background: rgba(148,163,184,0.12); color: var(--text-muted); }
html[data-theme="dark"] .fo-badge-blue    { background: rgba(91,155,245,0.18);  color: #A9C7F8; }
html[data-theme="dark"] .fo-badge-green   { background: rgba(34,197,94,0.16);   color: #6EE7A3; }
html[data-theme="dark"] .fo-badge-amber   { background: rgba(245,158,11,0.16);  color: #FCD34D; }
html[data-theme="dark"] .fo-badge-red     { background: rgba(239,68,68,0.16);   color: #FCA5A5; }
html[data-theme="dark"] .fo-badge-teal    { background: rgba(45,212,191,0.16);  color: #5EEAD4; }
html[data-theme="dark"] .fo-badge-orange  { background: rgba(249,115,22,0.16);  color: #FDBA74; }

/* Alerts */
html[data-theme="dark"] .fo-alert-success { background: rgba(34,197,94,0.14);  color: #B4F1CB; }
html[data-theme="dark"] .fo-alert-error   { background: rgba(239,68,68,0.14);  color: #F8C6C6; }
html[data-theme="dark"] .fo-alert-warning { background: rgba(245,158,11,0.14);  color: #F6DCA6; }
html[data-theme="dark"] .fo-alert-info    { background: rgba(91,155,245,0.14);  color: #BBD3F8; }

/* Button hovers (light theme darkens; dark theme brightens) */
html[data-theme="dark"] .fo-btn-primary:hover { background: #77ADF7; border-color: #77ADF7; }
html[data-theme="dark"] .fo-btn-success:hover { background: #16A34A; }
html[data-theme="dark"] .fo-btn-danger:hover  { background: #DC2626; }

/* Bootstrap dropdown (admin menu) */
html[data-theme="dark"] .dropdown-menu {
  background-color: var(--surface);
  border-color: var(--border);
  box-shadow: var(--shadow-card);
}
html[data-theme="dark"] .dropdown-item { color: var(--text-main); }
html[data-theme="dark"] .dropdown-item:hover,
html[data-theme="dark"] .dropdown-item:focus { background-color: var(--surface-muted); color: var(--text-main); }
html[data-theme="dark"] .dropdown-item-text { color: var(--text-muted); }
html[data-theme="dark"] .dropdown-divider { border-top-color: var(--border); }

/* Mobile drawer close button glass */
html[data-theme="dark"] .fo-sidebar-close { background: rgba(21,28,40,0.92); color: var(--text-main); }

/* On phones, drop the shell insets so the panels go edge-to-edge */
@media (max-width: 640px) {
  html[data-theme="dark"] .fo-main { padding: 10px 10px 16px 10px; }
  /* `top` removed with the sticky positioning: it existed to inset a
     PINNED header, and on a positioned-but-not-sticky box it simply
     pushes the header 10px down the page. */
  html[data-theme="dark"] .fo-header { margin-bottom: 12px; border-radius: 14px; }
  html[data-theme="dark"] .fo-content { border-radius: 16px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THEME TOGGLE — segmented Light/Dark control in the header
═══════════════════════════════════════════════════════════════════════════ */
.fo-theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  background: var(--surface-muted);
  border: 1px solid var(--border);
  border-radius: 9px;
}
.fo-theme-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border: 0;
  background: transparent;
  color: var(--text-muted);
  font-size: 12.5px;
  font-weight: 600;
  border-radius: 7px;
  cursor: pointer;
  line-height: 1;
  transition: background var(--transition), color var(--transition);
}
.fo-theme-btn i { font-size: 14px; }
.fo-theme-btn:hover { color: var(--text-main); }
.fo-theme-btn[aria-pressed="true"] {
  background: var(--surface);
  color: var(--text-main);
  box-shadow: 0 1px 2px rgba(0,0,0,0.12);
}
html[data-theme="dark"] .fo-theme-btn[aria-pressed="true"] {
  background: var(--primary);
  color: #fff;
  box-shadow: none;
}
@media (max-width: 640px) {
  .fo-theme-btn-label { display: none; }
  .fo-theme-btn { padding: 6px 8px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Projects page — status filter tabs
   Desktop: underline tabs (unchanged look). Mobile: horizontally-scrollable,
   tap-friendly chips with a clear active state. Theme-aware via CSS vars.
═══════════════════════════════════════════════════════════════════════════ */
.fo-status-tabs {
  display: flex;
  gap: 2px;
  overflow-x: auto;
  flex-wrap: nowrap;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.fo-status-tabs::-webkit-scrollbar { display: none; }
.fo-status-tab {
  flex: 0 0 auto;
  white-space: nowrap;
  text-decoration: none;
  padding: 12px 18px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  border-bottom: 2px solid transparent;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: color var(--transition), border-color var(--transition), background var(--transition);
}
.fo-status-tab:hover { color: var(--text-main); }
.fo-status-tab.is-active { color: var(--primary); border-bottom-color: var(--primary); }
.fo-status-tab-count {
  background: var(--surface-muted);
  color: var(--text-muted);
  padding: 1px 8px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 700;
}
.fo-status-tab.is-active .fo-status-tab-count { background: var(--primary-soft); color: var(--primary); }

@media (max-width: 900px) {
  /* Card wrapper loses its box so chips read as a clean scrollable row. */
  .fo-status-tabs-card { border: none !important; background: transparent !important; box-shadow: none !important; padding: 0 !important; }
  .fo-status-tabs { gap: 8px; padding: 2px 1px 6px; }
  .fo-status-tab {
    border-bottom: none;
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 9px 15px;
    min-height: 40px;
    background: var(--surface);
  }
  .fo-status-tab.is-active {
    background: var(--primary);
    color: #fff;
    border-color: var(--primary);
  }
  .fo-status-tab.is-active .fo-status-tab-count { background: rgba(255,255,255,0.25); color: #fff; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Projects page — table → cards on tablet/phone (≤900px)
   Same table, same data, same row-click handler; each row becomes a readable,
   tappable card. No horizontal page scroll. Desktop (>900px) is untouched.
═══════════════════════════════════════════════════════════════════════════ */
.fo-card-action-label { display: none; }   /* icon-only buttons on desktop */

@media (max-width: 900px) {
  table.fo-projects-cards,
  table.fo-projects-cards tbody { display: block; width: 100%; }
  table.fo-projects-cards thead { display: none; }

  table.fo-projects-cards tr {
    display: block;
    width: 100%;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    box-shadow: var(--shadow-card);
    padding: 12px 14px;
    margin: 0 0 12px;
  }
  /* Branch cards: always visible on mobile (no collapse), gently nested. */
  table.fo-projects-cards tr.proj-branch-row {
    display: block !important;
    background: var(--surface-muted);
    margin-left: 14px;
  }
  table.fo-projects-cards tr:hover { background: var(--surface); }
  table.fo-projects-cards tr.proj-branch-row:hover { background: var(--surface-muted); }

  table.fo-projects-cards td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 6px 0;
    border: none;
    text-align: right;
    white-space: normal;
    min-width: 0;
    max-width: none !important;
  }
  table.fo-projects-cards td::before {
    content: attr(data-label);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--text-muted);
    text-align: left;
    flex: 0 0 auto;
    white-space: nowrap;
  }
  table.fo-projects-cards td:not([data-label])::before { content: ""; }
  /* Long values wrap instead of forcing horizontal overflow. */
  table.fo-projects-cards td > a,
  table.fo-projects-cards td > span { overflow-wrap: anywhere; min-width: 0; }

  /* Expand caret column is desktop-only. */
  table.fo-projects-cards td.fo-card-caret { display: none; }

  /* Project name = full-width title block at the top of the card. */
  table.fo-projects-cards td.fo-card-main {
    display: block;
    text-align: left;
    padding: 0 0 8px;
    margin-bottom: 6px;
    border-bottom: 1px solid var(--border);
  }
  table.fo-projects-cards td.fo-card-main::before { display: none; }
  table.fo-projects-cards td.fo-card-main > a { font-size: 15px; overflow-wrap: anywhere; }
  table.fo-projects-cards td.fo-card-main .fo-badge { white-space: nowrap; }

  /* Progress bar keeps a usable width beside its label. */
  table.fo-projects-cards td.fo-card-progress > div { flex: 1; min-width: 0; }

  /* Actions become a full-width, tap-friendly button row with labels. */
  table.fo-projects-cards td.fo-card-actions {
    display: block;
    padding-top: 10px;
    margin-top: 4px;
    border-top: 1px solid var(--border);
  }
  table.fo-projects-cards td.fo-card-actions::before { display: none; }
  table.fo-projects-cards td.fo-card-actions > div { display: flex; width: 100%; gap: 8px; }
  table.fo-projects-cards td.fo-card-actions form { flex: 1; display: flex; }
  table.fo-projects-cards td.fo-card-actions form .fo-btn { width: 100%; }
  table.fo-projects-cards .fo-card-action-label { display: inline; }

  /* Filter/search inputs go full width when the list is in card mode. The
     `> form >` arm is required — the filter forms are display:contents. */
  .fo-filter-bar > .fo-search-input,
  .fo-filter-bar > form > .fo-search-input { flex: 1 1 100%; min-width: 0; }
}

/* ── Task detail: compact top metadata strip + location line ──────────────
   Replaces the old Task Overview / Location cards. Wraps cleanly; never causes
   horizontal overflow at 320px; long External IDs truncate with a tooltip. */
.task-meta-strip {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px;
  min-width: 0;
}
.task-meta-chip { display: inline-flex; align-items: center; gap: 6px; min-width: 0; max-width: 100%; }
.task-meta-chip-label {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px;
  color: var(--text-muted); white-space: nowrap;
}
.task-meta-extid {
  max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: inline-block; vertical-align: bottom;
}
.task-location-line {
  display: flex; align-items: flex-start; gap: 8px;
  font-size: 13px; color: var(--text-muted); line-height: 1.5; min-width: 0;
}
@media (max-width: 640px) {
  .task-meta-extid { max-width: 130px; }
  .task-meta-strip { gap: 8px 12px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Responsive Form Layout Designer — published 12-column grid.

   Distinct from .fo-collect-grid ON PURPOSE: the legacy mobile overrides
   (.fo-collect-grid{grid-template-columns:1fr!important}, .form-layout-item
   {width:100%!important}) do NOT target these classes, so a per-breakpoint span
   survives on mobile instead of being force-stacked. All classes are
   server-generated from validated ints/enums (see projects/form_layout.py) —
   never from raw config — so this stylesheet is the only place widths live.

   Breakpoint bands are MUTUALLY EXCLUSIVE (min+max), so exactly one profile's
   rules apply at any viewport width. That makes "start new row" and input-width
   deterministic per breakpoint with no cross-breakpoint leakage.
   ════════════════════════════════════════════════════════════════════════ */
.form-layout-grid{
  display:grid;
  grid-template-columns:repeat(12, minmax(0, 1fr));
  gap:var(--form-layout-row-gap,14px) var(--form-layout-column-gap,18px);
  inline-size:100%;
  min-inline-size:0;
}
.form-layout-field{
  min-inline-size:0;
  max-inline-size:100%;
  box-sizing:border-box;
  /* Safe default so an unknown/pre-CSS state never collapses to a sliver. */
  grid-column:span 12;
}
.form-layout-field > *{ min-inline-size:0; max-inline-size:100%; box-sizing:border-box; }
.form-layout-field .fo-input,
.form-layout-field select,
.form-layout-field textarea{ max-inline-size:100%; box-sizing:border-box; }
/* Long labels / badges / errors wrap instead of forcing overflow. */
.form-layout-field .fo-collect-label-row{ flex-wrap:wrap; }
.form-layout-field .fo-label{ min-inline-size:0; overflow-wrap:anywhere; }


@media (min-width:1025px) {
  .form-span-desktop-1{ grid-column-end:span 1; }
  .form-span-desktop-2{ grid-column-end:span 2; }
  .form-span-desktop-3{ grid-column-end:span 3; }
  .form-span-desktop-4{ grid-column-end:span 4; }
  .form-span-desktop-5{ grid-column-end:span 5; }
  .form-span-desktop-6{ grid-column-end:span 6; }
  .form-span-desktop-7{ grid-column-end:span 7; }
  .form-span-desktop-8{ grid-column-end:span 8; }
  .form-span-desktop-9{ grid-column-end:span 9; }
  .form-span-desktop-10{ grid-column-end:span 10; }
  .form-span-desktop-11{ grid-column-end:span 11; }
  .form-span-desktop-12{ grid-column-end:span 12; }
  .form-iw-desktop-fill .fo-input,
  .form-iw-desktop-fill select,
  .form-iw-desktop-fill textarea{ inline-size:100%; max-inline-size:100%; }
  .form-iw-desktop-compact .fo-input,
  .form-iw-desktop-compact select{ inline-size:auto; max-inline-size:18ch; min-inline-size:44px; }
  /* Pairs with grid-column-END on the span rules: setting only the start
     here would otherwise overwrite a `grid-column: span N` shorthand and
     collapse the field to a single column. */
  .form-newrow-desktop{ grid-column-start:1; }
}

@media (min-width:641px) and (max-width:1024px) {
  .form-span-tablet-1{ grid-column-end:span 1; }
  .form-span-tablet-2{ grid-column-end:span 2; }
  .form-span-tablet-3{ grid-column-end:span 3; }
  .form-span-tablet-4{ grid-column-end:span 4; }
  .form-span-tablet-5{ grid-column-end:span 5; }
  .form-span-tablet-6{ grid-column-end:span 6; }
  .form-span-tablet-7{ grid-column-end:span 7; }
  .form-span-tablet-8{ grid-column-end:span 8; }
  .form-span-tablet-9{ grid-column-end:span 9; }
  .form-span-tablet-10{ grid-column-end:span 10; }
  .form-span-tablet-11{ grid-column-end:span 11; }
  .form-span-tablet-12{ grid-column-end:span 12; }
  .form-iw-tablet-fill .fo-input,
  .form-iw-tablet-fill select,
  .form-iw-tablet-fill textarea{ inline-size:100%; max-inline-size:100%; }
  .form-iw-tablet-compact .fo-input,
  .form-iw-tablet-compact select{ inline-size:auto; max-inline-size:18ch; min-inline-size:44px; }
  .form-newrow-tablet{ grid-column-start:1; }
}

@media (min-width:401px) and (max-width:640px) {
  .form-span-mobile-1{ grid-column-end:span 1; }
  .form-span-mobile-2{ grid-column-end:span 2; }
  .form-span-mobile-3{ grid-column-end:span 3; }
  .form-span-mobile-4{ grid-column-end:span 4; }
  .form-span-mobile-5{ grid-column-end:span 5; }
  .form-span-mobile-6{ grid-column-end:span 6; }
  .form-span-mobile-7{ grid-column-end:span 7; }
  .form-span-mobile-8{ grid-column-end:span 8; }
  .form-span-mobile-9{ grid-column-end:span 9; }
  .form-span-mobile-10{ grid-column-end:span 10; }
  .form-span-mobile-11{ grid-column-end:span 11; }
  .form-span-mobile-12{ grid-column-end:span 12; }
  .form-iw-mobile-fill .fo-input,
  .form-iw-mobile-fill select,
  .form-iw-mobile-fill textarea{ inline-size:100%; max-inline-size:100%; }
  .form-iw-mobile-compact .fo-input,
  .form-iw-mobile-compact select{ inline-size:auto; max-inline-size:18ch; min-inline-size:44px; }
  .form-newrow-mobile{ grid-column-start:1; }
}

@media (max-width:400px) {
  .form-span-small_mobile-1{ grid-column-end:span 1; }
  .form-span-small_mobile-2{ grid-column-end:span 2; }
  .form-span-small_mobile-3{ grid-column-end:span 3; }
  .form-span-small_mobile-4{ grid-column-end:span 4; }
  .form-span-small_mobile-5{ grid-column-end:span 5; }
  .form-span-small_mobile-6{ grid-column-end:span 6; }
  .form-span-small_mobile-7{ grid-column-end:span 7; }
  .form-span-small_mobile-8{ grid-column-end:span 8; }
  .form-span-small_mobile-9{ grid-column-end:span 9; }
  .form-span-small_mobile-10{ grid-column-end:span 10; }
  .form-span-small_mobile-11{ grid-column-end:span 11; }
  .form-span-small_mobile-12{ grid-column-end:span 12; }
  .form-iw-small_mobile-fill .fo-input,
  .form-iw-small_mobile-fill select,
  .form-iw-small_mobile-fill textarea{ inline-size:100%; max-inline-size:100%; }
  .form-iw-small_mobile-compact .fo-input,
  .form-iw-small_mobile-compact select{ inline-size:auto; max-inline-size:18ch; min-inline-size:44px; }
  .form-newrow-small_mobile{ grid-column-start:1; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Clear-selection action — Task Collection Form selectable fields
   ---------------------------------------------------------------------------
   Scoped to .fo-clear-selection inside a collection form; unrelated danger
   buttons (.fo-btn-danger, .text-danger, …) are untouched. Colours come from
   the shared theme so both html[data-theme="light"] and ="dark" stay readable.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Reserves no permanent blank space: the row collapses to 0 height while the
   button is hidden, and the small top margin keeps the reveal from nudging the
   neighbouring field. */
.fo-field-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
  min-width: 0;
}
.fo-field-actions:empty { display: none; }

.fo-clear-selection {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  max-width: 100%;
  min-height: 32px;            /* compact, still tappable next to 44px controls */
  padding: 4px 10px;
  border: 1px solid color-mix(in srgb, var(--danger) 42%, transparent);
  border-radius: 7px;
  background: transparent;
  color: var(--danger);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
  text-align: left;
  white-space: normal;         /* long German labels wrap instead of overflowing */
  overflow-wrap: anywhere;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.fo-clear-selection[hidden] { display: none; }

.fo-clear-selection-x {
  font-size: 15px;
  line-height: 1;
  flex-shrink: 0;
}

.fo-clear-selection:hover {
  background: color-mix(in srgb, var(--danger) 10%, transparent);
  border-color: var(--danger);
}
.fo-clear-selection:focus-visible {
  outline: 2px solid var(--danger);
  outline-offset: 2px;
}
.fo-clear-selection:active {
  background: color-mix(in srgb, var(--danger) 18%, transparent);
}
.fo-clear-selection:disabled {
  opacity: .55;
  cursor: not-allowed;
}

/* Engines without color-mix() still get a legible tinted state. */
@supports not (background: color-mix(in srgb, red 10%, transparent)) {
  .fo-clear-selection        { border-color: var(--danger); }
  .fo-clear-selection:hover  { background: var(--surface-muted); }
  .fo-clear-selection:active { background: var(--surface-muted); }
}

/* Dark mode: --danger is already the brighter #EF4444; lift the resting border
   a little so the outline reads against the glass surfaces. */
html[data-theme="dark"] .fo-clear-selection {
  border-color: color-mix(in srgb, var(--danger) 55%, transparent);
}
html[data-theme="dark"] .fo-clear-selection:hover {
  background: color-mix(in srgb, var(--danger) 16%, transparent);
}

@media (max-width: 640px) {
  /* Full-width tap target on phones, wrapping below the control. */
  .fo-clear-selection { min-height: 36px; }
}

@media (prefers-reduced-motion: reduce) {
  .fo-clear-selection { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Visually-hidden utility + hidden field titles (live collection form)
   ---------------------------------------------------------------------------
   .fo-sr-only removes an element from the visual layout while keeping it in the
   accessibility tree — never use `display:none` / `aria-hidden` for a label.
   .task-sr-only is the pre-existing name used by the shared collection widget;
   it is declared here too so it also works on pages that load only this
   stylesheet (e.g. the Form Display layout preview), not just task-form.css.
   ═══════════════════════════════════════════════════════════════════════════ */
.fo-sr-only,
.task-sr-only {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

/* Title hidden via ProjectField.hide_title_in_live_form. The label is taken out
   of flow by .fo-sr-only, so the row keeps no title height; dropping its bottom
   margin removes the leftover gap. Any remaining badges (Prefilled / Read-only)
   still lay out normally and set the row's height themselves — nothing else
   about the field's width, column or order changes. */
.fo-collect-label-row-title-hidden {
  margin-bottom: 0;
  row-gap: 0;
}
.task-form-body .fo-collect-label-row-title-hidden { margin-bottom: 0; }

/* ── AI "Apply All" action (Submission Detail, right-side AI card) ─────────── */
.ai-apply-all-row{
  display:flex; flex-direction:column; gap:6px; align-items:stretch;
  padding:10px 14px; border-bottom:1px solid var(--border); min-width:0;
}
.ai-apply-all-btn{
  width:100%; justify-content:center; white-space:normal; overflow-wrap:anywhere;
  min-height:36px;
}
.ai-apply-all-btn:disabled{ opacity:.6; cursor:progress; }
.ai-apply-all-btn:focus-visible{ outline:2px solid var(--primary); outline-offset:2px; }
/* Reserves no space until it says something; not colour-only. */
.ai-apply-all-status{
  margin:0; font-size:11.5px; line-height:1.45; color:var(--text-muted);
  min-width:0; overflow-wrap:anywhere;
}
.ai-apply-all-status:empty{ display:none; }

/* ── Background AI job status card (Submission Detail) ─────────────────────── */
.ai-job-card{ padding:12px 14px; display:flex; flex-direction:column; gap:8px; min-width:0; }
.ai-job-head{ display:flex; align-items:center; justify-content:space-between;
  gap:8px; flex-wrap:wrap; min-width:0; }
.ai-job-title{ font-size:13px; font-weight:700; color:var(--text-main); }
.ai-job-title .bi{ margin-right:6px; color:var(--primary); }
/* Status is text, never colour alone. */
.ai-job-badge{ font-size:11px; font-weight:700; padding:2px 8px; border-radius:8px;
  background:var(--surface-muted); color:var(--text-muted);
  min-width:0; overflow-wrap:anywhere; }
.ai-job-badge-queued,
.ai-job-badge-processing{ background:var(--primary-soft); color:var(--primary); }
.ai-job-badge-completed{ background:color-mix(in srgb, var(--success) 16%, transparent);
  color:var(--success); }
.ai-job-badge-failed{ background:color-mix(in srgb, var(--danger) 14%, transparent);
  color:var(--danger); }
.ai-job-error{ margin:0; font-size:11.5px; line-height:1.45; color:var(--danger);
  overflow-wrap:anywhere; }
.ai-job-note{ margin:0; font-size:11.5px; line-height:1.45; color:var(--text-muted);
  overflow-wrap:anywhere; }
.ai-job-retry{ margin:0; }
.ai-job-retry .fo-btn{ width:100%; justify-content:center; }
@supports not (background: color-mix(in srgb, red 16%, transparent)) {
  .ai-job-badge-completed{ background:var(--surface-muted); color:var(--success); }
  .ai-job-badge-failed{ background:var(--surface-muted); color:var(--danger); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Responsive button scale — compact on phones, desktop untouched
   ---------------------------------------------------------------------------
   Everything here lives inside max-width media queries, so no desktop button
   changes size. Only the shared button classes are touched (.fo-btn and its
   size/variant modifiers) — no page-specific selectors, no inline styles, and
   no template needs its own mobile button CSS.

   Earlier mobile rules made buttons LARGER than desktop (min-height 40–44px,
   full-width page-header actions, equal-flex card rows). That is what made
   phone screens feel button-heavy. This block replaces that with a compact
   scale that still clears a practical tap target:

     .fo-btn      36px min-height  (was 40)
     .fo-btn-sm   32px min-height
     .fo-btn-lg   40px min-height  — primary actions stay a step more prominent

   36px with surrounding gap keeps the effective touch area comfortable while
   the *visual* weight drops. Nothing goes below 32px.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  .fo-btn {
    min-height: 36px;
    padding: 6px 11px;
    font-size: 12.5px;
    border-radius: 6px;
    gap: 5px;
    /* Long German labels wrap instead of forcing a scrollbar. */
    white-space: normal;
    overflow-wrap: anywhere;
    text-align: center;
    justify-content: center;
  }
  .fo-btn-sm { min-height: 32px; padding: 4px 9px;  font-size: 11.5px; }
  .fo-btn-lg { min-height: 40px; padding: 8px 16px; font-size: 13px; }

  /* Icon-only buttons stay square rather than stretching to a text width. */
  .fo-btn.fo-btn-icon {
    min-width: 36px; padding-inline: 0; aspect-ratio: 1 / 1;
  }
  .fo-btn-sm.fo-btn-icon { min-width: 32px; }

  /* Page / detail headers: wrap into a compact row instead of a tall stack of
     full-width buttons. A PRIMARY action may still stretch — it is the one
     action worth the width. */
  .fo-page-header,
  .fo-detail-header { gap: 8px; }
  .fo-page-header > .fo-btn,
  .fo-page-header > a.fo-btn,
  .fo-page-header > button.fo-btn,
  .fo-detail-header > .fo-btn {
    width: auto;
    min-height: 36px;
    flex: 0 1 auto;
  }
  .fo-page-header > .fo-btn-primary,
  .fo-page-header > a.fo-btn-primary,
  .fo-page-header > button.fo-btn-primary,
  .fo-detail-header > .fo-btn-primary { flex: 1 1 100%; min-height: 40px; }

  /* Any header/toolbar div holding buttons wraps with a tight gap. */
  .fo-page-header > div,
  .fo-detail-header > div { display: flex; flex-wrap: wrap; gap: 7px; min-width: 0; }

  /* Card action rows: let buttons flow (2–3 per row as they fit) rather than
     forcing one equal-width column each. */
  table.fo-cards-mobile td.fo-card-actions > div,
  table.fo-projects-cards td.fo-card-actions > div { gap: 7px; flex-wrap: wrap; }
  table.fo-cards-mobile td.fo-card-actions .fo-btn,
  table.fo-projects-cards td.fo-card-actions .fo-btn {
    flex: 1 1 auto;
    min-width: 44%;          /* two per row when they fit, one when text is long */
    min-height: 36px;
  }
  table.fo-cards-mobile td.fo-card-actions form,
  table.fo-projects-cards td.fo-card-actions form { flex: 1 1 auto; min-width: 44%; }

  /* Filter / action bars: compact wrapping, never a horizontal scroller. */
  .fo-filter-bar { gap: 7px; flex-wrap: wrap; }
  /* `> form >` arm required: the filter forms are display:contents. */
  .fo-filter-bar > .fo-btn,
  .fo-filter-bar > form > .fo-btn { flex: 0 1 auto; }

  /* Task collection form: the submit stays the most prominent control on the
     page, just not oversized. */
  .task-submit-button { min-height: 42px; min-width: 0; width: 100%;
                        font-size: 13.5px; padding: 10px 16px; }

  /* Field Work / map toolbars share the same compact scale. */
  .fw-map-toolbar-actions { gap: 6px; }
  .fw-map-btn { width: 36px; height: 36px; }
  .fw-map-pill { padding: 7px 12px; font-size: 12.5px; }
  .crm-map-control-bar { gap: 6px; }
  .crm-btn { padding: 7px 10px; font-size: 12.5px; min-height: 36px; }
}

/* Very small phones (≤400px): one more notch tighter, still ≥32px. */
@media (max-width: 400px) {
  .fo-btn    { padding: 6px 9px;  font-size: 12px; }
  .fo-btn-sm { padding: 4px 7px;  font-size: 11px; min-height: 32px; }
  .fo-btn-lg { padding: 8px 13px; font-size: 12.5px; }
  .fo-page-header > div,
  .fo-detail-header > div { gap: 6px; }
  table.fo-cards-mobile td.fo-card-actions .fo-btn,
  table.fo-projects-cards td.fo-card-actions .fo-btn { min-width: 100%; }
  table.fo-cards-mobile td.fo-card-actions form,
  table.fo-projects-cards td.fo-card-actions form { min-width: 100%; }
  .fw-map-pill { padding: 6px 10px; font-size: 12px; }
  .crm-btn { padding: 6px 9px; font-size: 12px; }
}

/* Focus and disabled states must survive the size change (never colour-only). */
@media (max-width: 640px) {
  .fo-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
  .fo-btn:disabled,
  .fo-btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }
}

/* ── Workflow template dialogs (Form Workflow Builder) ─────────────────────── */
.wt-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:9400;
  display:flex;align-items:center;justify-content:center;padding:16px;}
.wt-backdrop[hidden]{display:none;}
.wt-dialog{background:var(--surface);color:var(--text-main);
  border:1px solid var(--border);border-radius:14px;width:100%;max-width:520px;
  max-height:90dvh;display:flex;flex-direction:column;min-width:0;
  box-shadow:0 20px 60px rgba(0,0,0,.28);}
.wt-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;
  padding:15px 18px 11px;border-bottom:1px solid var(--border);}
.wt-title{font-size:15.5px;font-weight:800;margin:0;min-width:0;overflow-wrap:anywhere;}
.wt-x{border:none;background:none;font-size:24px;line-height:1;cursor:pointer;
  color:var(--text-muted);padding:0 4px;min-width:32px;min-height:32px;}
.wt-body{padding:14px 18px;overflow-y:auto;display:flex;flex-direction:column;
  gap:12px;min-width:0;}
.wt-field{display:flex;flex-direction:column;gap:4px;min-width:0;}
.wt-label{font-size:11px;font-weight:700;text-transform:uppercase;
  letter-spacing:.02em;color:var(--text-muted);}
.wt-hint{margin:0;font-size:11.5px;color:var(--text-muted);line-height:1.5;
  overflow-wrap:anywhere;}
.wt-error{margin:0;font-size:11.5px;color:var(--danger);overflow-wrap:anywhere;}
.wt-error[hidden]{display:none;}
.wt-warn{margin:0;font-size:11.5px;color:var(--warning);line-height:1.5;
  overflow-wrap:anywhere;}
.wt-warn[hidden]{display:none;}
.wt-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;
  gap:6px;max-height:230px;overflow-y:auto;min-width:0;}
.wt-item-btn{width:100%;text-align:left;background:var(--surface-muted);
  border:1px solid var(--border);border-radius:8px;padding:8px 10px;cursor:pointer;
  display:flex;flex-direction:column;gap:2px;color:var(--text-main);font:inherit;
  min-width:0;}
.wt-item.is-selected .wt-item-btn{border-color:var(--primary);
  background:var(--primary-soft);}
.wt-item-btn:focus-visible{outline:2px solid var(--primary);outline-offset:2px;}
.wt-item-name{font-size:13px;font-weight:700;overflow-wrap:anywhere;}
.wt-item-meta{font-size:11px;color:var(--text-muted);overflow-wrap:anywhere;}
.wt-empty{font-size:12px;color:var(--text-muted);padding:8px 2px;}
.wt-report{background:var(--surface-muted);border:1px solid var(--border);
  border-radius:8px;padding:10px 12px;font-size:12.5px;min-width:0;}
.wt-report[hidden]{display:none;}
/* Status is TEXT plus colour, never colour alone. */
.wt-status{margin:0 0 8px;font-weight:800;font-size:12.5px;}
.wt-status-compatible{color:var(--success);}
.wt-status-compatible_after_mapping{color:var(--warning);}
.wt-status-incompatible{color:var(--danger);}
.wt-report-list{list-style:none;margin:0;padding:0;display:flex;
  flex-direction:column;gap:3px;}
.wt-report-list li{display:flex;justify-content:space-between;gap:10px;
  min-width:0;overflow-wrap:anywhere;}
.wt-report-list li span{color:var(--text-muted);}
.wt-report-issues{margin:8px 0 0;padding-left:18px;font-size:11.5px;
  color:var(--danger);overflow-wrap:anywhere;}
.wt-foot{display:flex;justify-content:flex-end;gap:8px;flex-wrap:wrap;
  padding:12px 18px 14px;border-top:1px solid var(--border);}
#wt-apply[disabled]{opacity:.55;cursor:not-allowed;}
.wt-dialog :focus-visible{outline:2px solid var(--primary);outline-offset:2px;}
@media (max-width:600px){
  .wt-backdrop{align-items:flex-end;padding:0;}
  .wt-dialog{max-width:none;border-radius:14px 14px 0 0;max-height:94dvh;}
  .wt-foot{flex-direction:column-reverse;}
  .wt-foot .fo-btn{width:100%;justify-content:center;}
}

/* ── Project Tasks bulk toolbar + Assign-by-PLZ dialog ─────────────────────── */
.proj-bulk-btn{ background:var(--surface); color:var(--primary); border:none;
  font-weight:600; }
/* Unassign is distinguishable but NOT styled like a destructive delete — it
   only removes an assignment. */
.proj-bulk-btn-outline{ background:transparent; color:#fff;
  border:1px solid rgba(255,255,255,.65); }
.proj-bulk-btn-outline:hover{ background:rgba(255,255,255,.14); color:#fff; }
.proj-bulk-btn:disabled,.proj-bulk-btn-outline:disabled{ opacity:.6; cursor:progress; }
.proj-bulk-close{ background:transparent; border:none; color:#fff; cursor:pointer;
  padding:4px; min-width:32px; min-height:32px; }
#proj-bulk-bar .fo-btn:focus-visible,
.proj-bulk-close:focus-visible{ outline:2px solid #fff; outline-offset:2px; }

@media (max-width:640px){
  /* Controlled wrap: count on its own line, agent full width, actions paired.
     No absolute positioning, no fixed desktop widths. */
  #proj-bulk-bar{ flex-wrap:wrap; gap:8px; padding:10px 12px; }
  #proj-bulk-count{ flex:1 1 100%; }
  #proj-bulk-bar input[name="due_date"],
  #proj-bulk-bar select[name="priority"]{ flex:1 1 46%; min-width:0; width:auto; }
  #proj-bulk-bar .proj-bulk-btn,
  #proj-bulk-bar .proj-bulk-btn-outline{ flex:1 1 46%; justify-content:center; }
  .proj-bulk-close{ flex:1 1 100%; }
}

/* ── Bulk-bar agent dropdown (multi-select) ────────────────────────────────
   Visually the <select> it replaces: same .fo-input box, same chevron, same
   place in the toolbar. A native <select multiple> cannot show checkboxes and
   is unusable on touch, so this is a button + popover whose rows are ordinary
   checkboxes bound to the bulk form by id. */
.bulk-agents{ position:relative; }
.bulk-agents__toggle{
  display:inline-flex; align-items:center; justify-content:space-between; gap:8px;
  cursor:pointer; text-align:left; white-space:nowrap;
}
.bulk-agents__caret{ font-size:10px; opacity:.7; flex-shrink:0; transition:transform .15s; }
.bulk-agents__toggle[aria-expanded="true"] .bulk-agents__caret{ transform:rotate(180deg); }

.bulk-agents__menu{
  position:absolute; top:calc(100% + 4px); left:0; z-index:1200;
  min-width:100%; width:max-content; max-width:min(88vw,300px);
  background:var(--surface); color:var(--text-main);
  border:1px solid var(--border); border-radius:8px;
  box-shadow:0 10px 28px rgba(0,0,0,.20);
  /* The LIST scrolls, not the whole menu, so the search box stays visible
     while filtering and the Add link stays reachable at the bottom. */
  display:flex; flex-direction:column; max-height:320px;
}
/* Opens upward when the bar sits too low for a 320px menu — otherwise the
   Add New Agent link at the bottom falls below the fold, which is exactly the
   item a user goes looking for. */
.bulk-agents__menu.is-above{ top:auto; bottom:calc(100% + 4px); }
.bulk-agents__search{ padding:6px; border-bottom:1px solid var(--border); }
.bulk-agents__search .fo-input{ width:100%; font-size:13px; height:32px; }
.bulk-agents__list{ padding:4px; overflow-y:auto; flex:1; min-height:0; }
.bulk-agents__add{
  display:flex; align-items:center; gap:7px; padding:9px 12px;
  border-top:1px solid var(--border); font-size:13px; font-weight:600;
  color:var(--primary); text-decoration:none; min-height:40px; flex-shrink:0;
}
.bulk-agents__add:hover{ background:var(--primary-soft); text-decoration:underline; }
.bulk-agents__add:focus-visible{ outline:2px solid var(--primary); outline-offset:-2px; }
.bulk-agents__menu[hidden]{ display:none; }
.bulk-agents__opt{
  display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:6px;
  cursor:pointer; font-size:13px; min-height:40px;      /* tappable */
}
.bulk-agents__opt:hover{ background:var(--surface-muted); }
.bulk-agents__opt input{ width:15px; height:15px; accent-color:var(--primary);
  flex-shrink:0; margin:0; }
.bulk-agents__opt input:focus-visible{ outline:2px solid var(--primary); outline-offset:2px; }
.bulk-agents__name{ min-width:0; overflow-wrap:anywhere; }
.bulk-agents__empty{ margin:0; padding:12px 10px; font-size:12.5px;
  color:var(--text-muted); text-align:center; }

@media (max-width:640px){
  #proj-bulk-bar .bulk-agents{ flex:1 1 100%; min-width:0; }
  #proj-bulk-bar .bulk-agents__toggle{ width:100%; }
  /* A 300px popover would hang off a 320px screen. */
  .bulk-agents__menu{ left:0; right:0; max-width:none; }
}

.plz-backdrop{ position:fixed; inset:0; background:rgba(0,0,0,.45); z-index:9300;
  display:flex; align-items:center; justify-content:center; padding:16px; }
.plz-backdrop[hidden]{ display:none; }
.plz-dialog{ background:var(--surface); color:var(--text-main);
  border:1px solid var(--border); border-radius:14px; width:100%; max-width:460px;
  max-height:90dvh; display:flex; flex-direction:column; min-width:0;
  box-shadow:0 20px 60px rgba(0,0,0,.28); }
.plz-dialog form{ display:flex; flex-direction:column; min-height:0; }
.plz-head{ display:flex; align-items:flex-start; justify-content:space-between;
  gap:12px; padding:15px 18px 11px; border-bottom:1px solid var(--border); }
.plz-title{ font-size:15.5px; font-weight:800; margin:0; display:flex;
  align-items:center; gap:8px; min-width:0; overflow-wrap:anywhere; }
.plz-title .bi{ color:var(--primary); }
.plz-x{ border:none; background:none; font-size:24px; line-height:1; cursor:pointer;
  color:var(--text-muted); padding:0 4px; min-width:32px; min-height:32px; }
.plz-body{ padding:14px 18px; overflow-y:auto; display:flex; flex-direction:column;
  gap:12px; min-width:0; }
.plz-row{ display:flex; gap:10px; flex-wrap:wrap; min-width:0; }
.plz-row .plz-field{ flex:1 1 46%; min-width:0; }
.plz-field{ display:flex; flex-direction:column; gap:4px; min-width:0; }
.plz-label{ font-size:11px; font-weight:700; text-transform:uppercase;
  letter-spacing:.02em; color:var(--text-muted); }
.plz-fixed{ font-size:13.5px; font-weight:700; background:var(--surface-muted);
  border:1px solid var(--border); border-radius:8px; padding:9px 11px;
  overflow-wrap:anywhere; }
.plz-error{ margin:0; font-size:11.5px; color:var(--danger); overflow-wrap:anywhere; }
.plz-error[hidden]{ display:none; }
.plz-check{ display:flex; align-items:flex-start; gap:9px; font-size:12.5px;
  line-height:1.45; cursor:pointer; min-width:0; overflow-wrap:anywhere; }
.plz-preview{ background:var(--surface-muted); border:1px solid var(--border);
  border-radius:8px; padding:10px 12px; font-size:12.5px; min-width:0; }
.plz-preview[hidden]{ display:none; }
.plz-preview-list{ list-style:none; margin:0; padding:0; display:flex;
  flex-direction:column; gap:4px; }
.plz-preview-list li{ display:flex; justify-content:space-between; gap:10px;
  min-width:0; overflow-wrap:anywhere; }
.plz-preview-list li span{ color:var(--text-muted); }
.plz-foot{ display:flex; justify-content:flex-end; gap:8px; flex-wrap:wrap;
  padding:12px 18px 14px; border-top:1px solid var(--border); }
#plz-submit[disabled]{ opacity:.55; cursor:not-allowed; }
.plz-dialog :focus-visible{ outline:2px solid var(--primary); outline-offset:2px; }
@media (max-width:600px){
  .plz-backdrop{ align-items:flex-end; padding:0; }
  .plz-dialog{ max-width:none; border-radius:14px 14px 0 0; max-height:94dvh; }
  .plz-foot{ flex-direction:column-reverse; }
  .plz-foot .fo-btn{ width:100%; justify-content:center; }
}

/* ── Import → Configure Fields: Address components ──────────────────────────
   Theme variables only, so light/dark both follow the app. The four dropdowns
   sit in an auto-fitting grid: four across on desktop, stacking safely down to
   320px without ever forcing the page to scroll sideways. */
.addr-map{ margin-bottom:20px; }
.addr-map__title{
  font-size:13px; font-weight:700; letter-spacing:.02em;
  color:var(--text-main); margin:0 0 6px;
}
.addr-map__hint{
  font-size:12px; color:var(--text-muted); margin:0 0 14px; line-height:1.6;
}
.addr-map__grid{
  display:grid; gap:14px;
  grid-template-columns:repeat(auto-fit, minmax(190px, 1fr));
}
.addr-map__row{ margin-bottom:14px; }
.addr-map__field{ display:flex; flex-direction:column; gap:6px; min-width:0; }
.addr-map__label{
  font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.04em;
  color:var(--text-muted);
}
.addr-map__select{ width:100%; max-width:100%; }
.addr-map__select:focus-visible{ outline:2px solid var(--primary); outline-offset:1px; }
/* Status is TEXT, never colour alone. */
.addr-map__status{ font-size:11px; color:var(--text-muted); min-height:1em; }
.addr-map__preview{
  margin-top:16px; padding:12px 14px; border-radius:8px;
  background:var(--surface-muted); border:1px solid var(--border);
}
.addr-map__preview-lines{
  margin-top:6px; font-size:13px; color:var(--text-main); line-height:1.7;
  overflow-wrap:anywhere; word-break:break-word;
}
.addr-map__muted{ color:var(--text-muted); }
.addr-map__warn{
  font-size:12px; margin:10px 0 0; line-height:1.6;
  color:var(--warning-text, #92400e);
}
.addr-map__error{
  font-size:12px; margin:10px 0 0; line-height:1.6;
  color:var(--danger, #b91c1c);
}
.addr-map__warn[hidden]{ display:none; }
@media (max-width:480px){
  .addr-map__grid{ grid-template-columns:1fr; }
}

/* ── Create Subproject source chooser + Link Existing Project ────────────────
   Theme tokens only — these dialogs must not be light-only surfaces. Source
   cards and list rows are real <label>+<input> pairs, never clickable divs. */
.csm-card{
  display:flex; align-items:flex-start; gap:14px; padding:14px 16px;
  border:2px solid var(--border); border-radius:10px; cursor:pointer;
  transition:border-color .15s; background:var(--surface);
}
.csm-card:focus-within{ outline:2px solid var(--primary); outline-offset:2px; }
.csm-card__title{
  font-size:13px; font-weight:700; color:var(--text-main); margin-bottom:3px;
}
.csm-card__desc{
  font-size:12px; color:var(--text-muted); line-height:1.6; overflow-wrap:anywhere;
}
.csm-back{
  background:none; border:none; cursor:pointer; color:var(--text-muted);
  font-size:13px; padding:0; margin-bottom:16px;
}
.csm-back:focus-visible{ outline:2px solid var(--primary); outline-offset:2px; }
.csm-note{
  padding:12px 14px; background:var(--surface-muted); border:1px solid var(--border);
  border-radius:8px; margin-bottom:18px; font-size:13px; color:var(--text-main);
  line-height:1.6;
}
.csm-label{
  font-size:12px; font-weight:700; color:var(--text-muted); text-transform:uppercase;
  letter-spacing:.04em; display:block; margin-bottom:6px;
}
/* A scrolling list, never a wide table forced into a phone-width dialog. */
.csm-file-list{
  display:flex; flex-direction:column; gap:8px;
  max-height:260px; overflow-y:auto; padding:2px;
}
.csm-file{
  display:flex; align-items:flex-start; gap:12px; padding:10px 12px;
  border:1px solid var(--border); border-radius:8px; cursor:pointer;
  background:var(--surface); min-width:0;
}
.csm-file:hover{ border-color:var(--primary); }
.csm-file:focus-within{ outline:2px solid var(--primary); outline-offset:1px; }
.csm-file > span{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.csm-file__name{
  font-size:13px; font-weight:600; color:var(--text-main);
  overflow-wrap:anywhere; word-break:break-word;
}
.csm-file__meta{ font-size:11px; color:var(--text-muted); overflow-wrap:anywhere; }
/* Status through text, not colour alone. */
.csm-error{ font-size:12px; color:var(--danger,#b91c1c); margin:12px 0 0; line-height:1.6; }
.csm-error[hidden], .csm-warn[hidden]{ display:none; }
.csm-warn{
  font-size:12px; line-height:1.6; margin:14px 0 0; padding:10px 12px;
  border-radius:8px; background:var(--surface-muted);
  border:1px solid var(--border); color:var(--text-main);
}
.lnk-dialog{
  background:var(--surface); color:var(--text-main); border-radius:12px;
  width:560px; max-width:96vw; max-height:90vh; overflow-y:auto;
  box-shadow:0 20px 60px rgba(0,0,0,.25); border:1px solid var(--border);
}
.lnk-parent{
  padding:10px 12px; border-radius:8px; background:var(--surface-muted);
  border:1px solid var(--border);
}
@media (max-width:480px){
  .csm-card{ padding:12px; gap:10px; }
  .csm-file-list{ max-height:44vh; }
  .lnk-dialog{ width:100%; max-width:100vw; }
}

/* ── Duplicate Project dialog ───────────────────────────────────────────────
   Tokens only. Mode/relationship are real radio groups in <fieldset>s; the value
   list is real checkboxes in a scrolling column, never a wide table squeezed
   into a phone-width dialog. */
.dup-dialog{
  background:var(--surface); color:var(--text-main); border-radius:12px;
  width:680px; max-width:96vw; max-height:90vh; overflow-y:auto;
  box-shadow:0 20px 60px rgba(0,0,0,.25); border:1px solid var(--border);
}
.dup-fieldset{
  border:none; margin:0 0 16px; padding:0;
  display:flex; flex-direction:column; gap:10px; min-width:0;
}
.dup-fieldset legend{ padding:0; margin-bottom:6px; }
.dup-grid{
  display:grid; gap:12px;
  grid-template-columns:repeat(auto-fit, minmax(220px, 1fr));
}
.dup-toolbar{
  display:flex; gap:8px; flex-wrap:wrap; margin:10px 0 8px;
}
.dup-dialog code{
  background:var(--surface-muted); border:1px solid var(--border);
  border-radius:4px; padding:1px 5px; font-size:11px;
}
.dup-dialog a.csm-file{ color:inherit; }
.dup-dialog a.csm-file:hover{ border-color:var(--primary); }
@media (max-width:480px){
  .dup-dialog{ width:100%; max-width:100vw; }
  .dup-grid{ grid-template-columns:1fr; }
  .dup-toolbar .fo-btn{ flex:1 1 auto; justify-content:center; }
}

/* ── Project detail: header action row ───────────────────────────────────────
   Up to eight actions live here (Work Mode, Project Info, Create Sub Project,
   Link Existing, Duplicate, Edit, All Projects, Delete). Unwrapped they overflow
   the card and clip the last button, so the row wraps and the buttons are a
   touch more compact than the global .fo-btn — enough that they usually fit on
   one line at desktop width and stack tidily below that. */
.proj-actions{
  display:flex; flex-wrap:wrap; align-items:center;
  gap:6px; justify-content:flex-end;
  min-width:0; max-width:100%;
  /* Claim the rest of the header line. .fo-detail-header uses space-between, so
     without this the row is sized to its own content and leaves ~50px of the
     line unused — enough to push the last button onto a second row for nothing.
     Buttons stay right-aligned via justify-content. */
  flex:1 1 auto;
}
.proj-actions .fo-btn{
  padding:6px 12px; font-size:12.5px; gap:5px;
}
.proj-actions .fo-btn i{ font-size:13px; }
.proj-actions form{ display:inline-flex; }
/* Laptop widths: shave a little more rather than stranding one button on its
   own line. Measured on a 1512px window: the eight buttons needed 1056px in a
   1016px row, so ~5px per button had to go — taken from horizontal padding and
   the two gaps, not from the font size. */
@media (max-width:1500px){
  .proj-actions{ gap:5px; }
  .proj-actions .fo-btn{ padding:6px 8px; font-size:12px; gap:4px; }
  .proj-actions .fo-btn i{ font-size:12px; }
}
@media (max-width:768px){
  /* Wrap left-aligned at natural width. Deliberately NOT flex-grow: stretching
     the items made the destructive "Delete Project" span nearly the full row,
     giving it more visual weight on a phone than any other action. */
  .proj-actions{ justify-content:flex-start; }
}

/* ─── Shared pagination component ─────────────────────────────── */

.fo-pagination-bar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 12px 20px; border-top: 1px solid var(--border);
  background: var(--surface); font-size: 13px; color: var(--text-main);
}
.fo-pagination-summary { margin: 0; color: var(--text-muted); min-width: 0; overflow-wrap: anywhere; }
.fo-pagesize { display: flex; align-items: center; gap: 8px; margin: 0; }
.fo-pagesize__label { font-size: 12px; color: var(--text-muted); white-space: nowrap; }
.fo-pagesize__select { width: auto; min-width: 72px; padding-block: 6px; }
.fo-pagination { display: flex; align-items: center; gap: 4px; margin-left: auto; flex-wrap: wrap; }
.fo-page-numbers { display: inline-flex; align-items: center; gap: 4px; }
.fo-page-link {
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  min-width: 36px; min-height: 36px; padding: 0 10px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface); color: var(--text-main);
  font-size: 13px; font-weight: 600; text-decoration: none;
}
.fo-page-link:hover { border-color: var(--primary); color: var(--primary); }
.fo-page-link:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.fo-page-link.is-current { background: var(--primary); border-color: var(--primary); color: #fff; }
.fo-page-link.is-disabled { opacity: .45; cursor: default; }
.fo-page-link.is-disabled:hover { border-color: var(--border); color: var(--text-main); }
.fo-page-gap { padding: 0 4px; color: var(--text-muted); }
.fo-page-compact { display: none; color: var(--text-muted); font-size: 12.5px; white-space: nowrap; }

/* First («) / Last (»): icon-only, so they cost one square each and never
   widen the bar. Hidden on narrow screens, where Previous / Next + "Page x of y"
   is the whole control. */
.fo-page-edge { padding-inline: 8px; }

@media (max-width: 720px) {
  .fo-pagination-bar { padding: 12px 14px; gap: 10px; }
  .fo-pagination { margin-left: 0; width: 100%; justify-content: space-between; }
  /* Numbered list would overflow a 320px viewport — show Previous / Page x of y
     / Next instead, which always fits. */
  .fo-page-numbers { display: none; }
  .fo-page-edge { display: none; }
  .fo-page-compact { display: inline; }
  .fo-pagination-summary { flex-basis: 100%; }
}
@media (max-width: 380px) {
  .fo-page-link__text { display: none; }   /* icon-only Previous/Next */
}

/* ─── All Tasks: project row name link ────────────────────────── */
/* A real anchor to the project's task list. Keeps the row's existing
   typography — no button styling — but gains a visible hover and focus state so
   it does not rely on colour alone to read as interactive. */
.fo-projrow-name {
  font-weight: 700;
  font-size: 14px;
  color: var(--text-main);
  text-decoration: none;
  min-width: 0;
  overflow-wrap: anywhere;
}
.fo-projrow-name:hover {
  color: var(--primary);
  text-decoration: underline;
}
.fo-projrow-name:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ─── Disabled action controls (capability-denied) ────────────── */
/* An action the user may not perform stays VISIBLE but inert, so the interface
   does not silently change shape per role. Greyed with theme tokens (readable in
   light and dark), and never colour-only — every disabled control carries a
   visually-hidden explanation via aria-describedby. */
.fo-btn[disabled],
.fo-btn:disabled {
  opacity: .5;
  cursor: not-allowed;
  filter: grayscale(35%);
}
.fo-btn[disabled]:hover,
.fo-btn:disabled:hover {
  /* No hover affordance — it is not actionable. */
  box-shadow: none;
  transform: none;
}
/* Link-shaped actions that had to stay anchors: no href, not focusable, and
   pointer/keyboard activation removed. */
a.fo-btn[aria-disabled="true"] {
  opacity: .5;
  cursor: not-allowed;
  pointer-events: none;
  filter: grayscale(35%);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Sortable table headers (shared component — partials/sortable_header.html)
   ═══════════════════════════════════════════════════════════════════════════
   The control is a real link inside the <th>, sized to the header text so a
   sortable column is never wider than a plain one. State is carried by the icon
   AND the weight/colour, never by colour alone. */
.fo-sort-th { white-space: nowrap; }
.fo-sort {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
  color: inherit;
  text-decoration: none;
  border-radius: 5px;
  padding: 2px 3px;
  margin: -2px -3px;                    /* keeps the header height unchanged */
  cursor: pointer;
  /* The control is an <a> in the server-rendered partial and a <button> in the
     JS-rendered tables. A button carries native chrome (border, background) and
     does NOT inherit font from its <th>, so without these resets the same class
     rendered as a boxed chip in Title Case beside plain uppercase headers.
     Resetting here keeps ONE component correct for both tags. */
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  text-align: inherit;
}
.fo-sort-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.fo-sort-icon {
  flex: 0 0 auto;
  font-size: 11px;
  line-height: 1;
  opacity: .45;                          /* neutral: present but quiet */
  transition: opacity .12s, color .12s;
}
.fo-sort:hover { color: var(--primary); }
.fo-sort:hover .fo-sort-icon { opacity: 1; }
.fo-sort:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}
/* Active column: darker label + full-strength primary icon, so the ordering
   column is identifiable without relying on hue. */
.fo-sort.is-active { color: var(--primary); font-weight: 800; }
.fo-sort.is-active .fo-sort-icon { opacity: 1; color: var(--primary); }
.fo-sort-th.is-sorted { background: var(--primary-soft); }

/* ══ Dashboard grid (Dashboard Designer runtime) ══════════════════════════
   A 24-column logical grid. Each widget carries six CSS custom properties set
   server-side from VALIDATED INTEGERS — span and flow order per breakpoint:

       --sd / --st / --sm   span   (1..24) desktop / tablet / mobile
       --od / --ot / --om   order  (0..999)

   Nothing but integers reaches the style attribute; no configuration string is
   ever interpolated into CSS. Using `order` on grid items means a widget can sit
   in a different position on each device WITHOUT duplicating the widget — one
   identity, three placements.

   Because the layout is pure flow (span + order, auto-placement), two widgets
   can never overlap and none can be orphaned off-canvas: an invalid layout is
   not merely rejected, it is unrepresentable.

   Breakpoints are CONTAINER queries, not viewport media queries: the grid does
   not occupy the viewport (sidebar + padding take ~296px on desktop, ~56px once
   the sidebar goes off-canvas). Thresholds are CONTENT widths, and the designer
   sizes its preview canvas by the same arithmetic, so preview and runtime agree
   by construction. See registry.content_width_for / breakpoint_for_content. */
/* The QUERY CONTAINER is this wrapper, not the grid itself. A @container rule
   can only style DESCENDANTS of its container — never the container element —
   so putting container-type on .fo-dash-grid made every rule that targeted the
   grid (notably the mobile gap) silently dead. */
.fo-dash-scope {
  container-type: inline-size;
  container-name: fo-dash;
}
.fo-dash-grid {
  display: grid;
  grid-template-columns: repeat(24, minmax(0, 1fr));
  /* COLUMN gap is deliberately separate from ROW gap. With 24 columns there are
     23 column gaps, and their total is a hard floor on the grid's width:
     23 × 16px = 368px, which is wider than the ~338px a 390px phone actually
     offers — so the grid overflowed and the right-hand cards were clipped. Row
     spacing has no such multiplier, so it stays comfortable. */
  column-gap: 16px;
  row-gap: 16px;
  align-items: stretch;
}
.fo-dash-grid > .fo-dw {
  min-width: 0;
  grid-column: span var(--sd, 8);
  order: var(--od, 0);
}
.fo-dash-grid > .fo-dw > * { height: 100%; margin-bottom: 0; }

@container fo-dash (max-width: 980px) {
  .fo-dash-grid > .fo-dw { grid-column: span var(--st, 12); order: var(--ot, 0); }
}
@container fo-dash (max-width: 600px) {
  /* 23 × 8px = 184px of column gap — comfortably inside a phone's content
     width, so the grid can no longer overflow. Rows keep their spacing. */
  .fo-dash-grid { column-gap: 8px; row-gap: 12px; }
  .fo-dash-grid > .fo-dw { grid-column: span var(--sm, 24); order: var(--om, 0); }
}

/* Fallback for browsers without container queries (pre-2023): viewport-based,
   gated so the two rule sets can never both apply. */
@supports not (container-type: inline-size) {
  @media (max-width: 1024px) {
    .fo-dash-grid > .fo-dw { grid-column: span var(--st, 12); order: var(--ot, 0); }
  }
  @media (max-width: 640px) {
    .fo-dash-grid { column-gap: 8px; row-gap: 12px; }
    .fo-dash-grid > .fo-dw { grid-column: span var(--sm, 24); order: var(--om, 0); }
  }
}

/* Compact metric presentation — a denser card for narrow spans. */
.fo-stat-card.is-compact { padding: 14px; gap: 10px; }
.fo-stat-card.is-compact .fo-stat-icon { width: 32px; height: 32px; font-size: 15px; }
.fo-stat-card.is-compact .fo-stat-value { font-size: 22px; }
.fo-stat-card.is-compact .fo-stat-label { font-size: 11px; }

/* Wide content keeps its scrolling inside the card. */
.fo-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* List-widget rows */
.fo-dash-row {
  padding: 10px 16px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.fo-dash-row:last-child { border-bottom: 0; }
.fo-dash-row-title {
  font-size: 12px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fo-dash-row-meta { font-size: 11px; color: var(--text-muted); }
.fo-dash-row-more {
  padding: 10px 16px; border-top: 1px solid var(--border);
  background: var(--surface-muted); text-align: center; font-size: 12px;
}
.fo-dash-row-more a { color: var(--primary); text-decoration: none; }

/* Quick actions */
.fo-quick-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 8px;
}
.fo-quick-actions .fo-btn { width: 100%; justify-content: flex-start; }
.fo-qa-primary   { color: var(--primary); }
.fo-qa-secondary { color: var(--secondary); }
.fo-qa-accent    { color: var(--accent); }
.fo-qa-success   { color: var(--success); }
.fo-qa-warning   { color: var(--warning); }
.fo-qa-danger    { color: var(--danger); }

/* ══ Dashboard Designer (visual builder) ════════════════════════════════════
   The canvas frame is sized to the REAL content width of the selected viewport —
   never a scaled-down desktop — so the grid inside crosses the same container
   breakpoints a real device does. */

.fo-dsg-toolbar {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end;
  justify-content: space-between; margin-bottom: 12px;
}
.fo-dsg-toolbar-title h1 { margin: 0; }
.fo-dsg-toolbar-title p { margin: 2px 0 0; font-size: 13px; color: var(--text-muted); }
.fo-dsg-toolbar-controls { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

.fo-dsg-devices { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.fo-dsg-device {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 12px; font-size: 13px; font-weight: 600;
  background: var(--surface); color: var(--text-muted);
  border: 0; border-right: 1px solid var(--border); cursor: pointer;
}
.fo-dsg-device:last-child { border-right: 0; }
.fo-dsg-device.is-active { background: var(--primary); color: #fff; }
.fo-dsg-viewport { max-width: 210px; }
.fo-dsg-custom-w { max-width: 110px; }

.fo-dsg-status { border-radius: 8px; padding: 10px 14px; font-size: 13px; margin-bottom: 12px; }
.fo-dsg-status.is-ok { border: 1px solid var(--success); color: var(--success); }
.fo-dsg-status.is-error { border: 1px solid var(--danger); color: var(--danger); }

.fo-dsg-editing { display: flex; align-items: center; gap: 8px; font-size: 13px; margin-bottom: 10px; }
.fo-dsg-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--primary); }

/* Canvas: the frame is an exact device content width, centred, and scrolls
   horizontally rather than being scaled if it exceeds the editor. */
.fo-dsg-canvas-wrap {
  border: 1px dashed var(--border); border-radius: 10px;
  background: var(--surface-muted); padding: 16px;
  overflow-x: auto;
}
.fo-dsg-frame {
  margin: 0 auto; max-width: 100%;
  background: var(--bg, var(--surface-muted));
  transition: width .18s ease;
}
.fo-dsg-frame[data-bp="tablet"],
.fo-dsg-frame[data-bp="mobile"] {
  outline: 1px solid var(--border); border-radius: 12px;
  padding: 10px; background: var(--surface);
}

/* Editor card chrome around the live preview. */
.fo-dsg-item { position: relative; }
.fo-dsg-item.is-dragging { opacity: .6; }
.fo-dsg-item.is-resizing .fo-dsg-widget { outline: 2px solid var(--primary); }
.fo-dsg-widget {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 10px; overflow: hidden; height: 100%;
  display: flex; flex-direction: column; position: relative;
}
.fo-dsg-widget-head {
  display: flex; align-items: center; gap: 4px;
  padding: 6px 8px; border-bottom: 1px solid var(--border); background: var(--surface-muted);
}
.fo-dsg-widget-title {
  font-size: 12px; font-weight: 700; flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fo-dsg-handle { cursor: grab; color: var(--text-muted); padding: 2px 4px; touch-action: none; }
.fo-dsg-handle:active { cursor: grabbing; }
.fo-dsg-modes { display: inline-flex; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
.fo-dsg-mode {
  border: 0; background: var(--surface); color: var(--text-muted);
  padding: 3px 7px; font-size: 12px; cursor: pointer;
}
.fo-dsg-mode.is-active { background: var(--primary); color: #fff; }
.fo-dsg-tool {
  border: 1px solid var(--border); background: var(--surface); color: var(--text-muted);
  border-radius: 6px; padding: 3px 6px; font-size: 12px; cursor: pointer;
}
.fo-dsg-tool:disabled { opacity: .4; cursor: default; }
.fo-dsg-tool.is-danger { color: var(--danger); }

.fo-dsg-preview { padding: 10px; flex: 1; }
.fo-dsg-preview-loading { color: var(--text-muted); font-size: 20px; text-align: center; padding: 20px; }

.fo-dsg-widget-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 5px 9px; border-top: 1px solid var(--border);
  font-size: 11px; color: var(--text-muted); background: var(--surface-muted);
}
.fo-dsg-inherit { font-style: italic; }

/* Right-edge resize grip. */
.fo-dsg-resize {
  position: absolute; top: 0; right: 0; width: 12px; height: 100%;
  cursor: ew-resize; touch-action: none;
  background: linear-gradient(to right, transparent, rgba(0,0,0,.05));
}
.fo-dsg-resize::after {
  content: ""; position: absolute; top: 50%; right: 4px;
  width: 3px; height: 26px; margin-top: -13px; border-radius: 2px;
  background: var(--border);
}
.fo-dsg-item:hover .fo-dsg-resize::after { background: var(--primary); }

/* Settings panel inside a card. */
.fo-dsg-settings { padding: 10px; display: grid; gap: 8px; flex: 1; }
.fo-dsg-field { display: grid; gap: 4px; }
.fo-dsg-field > label {
  font-size: 10px; font-weight: 700; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: .02em;
}
.fo-dsg-static { font-size: 13px; font-weight: 600; }
.fo-dsg-width-row { display: grid; gap: 6px; }
.fo-dsg-slider { width: 100%; }
.fo-dsg-checks { display: flex; flex-wrap: wrap; gap: 6px; }
.fo-dsg-checks label {
  display: inline-flex; align-items: center; gap: 5px; font-size: 12px;
  padding: 3px 7px; border: 1px solid var(--border); border-radius: 6px; cursor: pointer;
}
.fo-dsg-hint { font-size: 11px; color: var(--text-muted); display: block; }

/* Add-widget picker. */
.fo-dsg-picker {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(15, 23, 42, .45);
  display: flex; align-items: flex-start; justify-content: center;
  /* dvh, not vh: iOS Safari resolves vh against the LARGE viewport (address bar
     hidden), so a vh-sized overlay extends under the browser chrome and its
     bottom controls become unreachable. The vh line is the fallback for
     browsers without dvh (iOS < 15.4 / Chrome < 108); without it they would get
     no bound at all. Matches .wt-dialog / .plz-dialog, which already use dvh. */
  padding: 6vh 16px;
  padding: 6dvh 16px;
}
.fo-dsg-picker[hidden] { display: none; }
.fo-dsg-picker-panel {
  background: var(--surface); border-radius: 12px; width: min(560px, 100%);
  max-height: 80vh;
  max-height: 80dvh;
  display: flex; flex-direction: column; overflow: hidden;
  box-shadow: 0 20px 60px rgba(0,0,0,.25);
}
.fo-dsg-picker-list { overflow-y: auto; padding: 0 12px 12px; }
.fo-dsg-picker-group {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  color: var(--text-muted); letter-spacing: .02em; padding: 10px 4px 6px;
}
.fo-dsg-picker-item {
  display: flex; gap: 10px; align-items: flex-start; width: 100%; text-align: left;
  padding: 10px 12px; margin-bottom: 6px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 8px; background: var(--surface);
}
.fo-dsg-picker-item:hover { border-color: var(--primary); background: var(--primary-soft); }
.fo-dsg-picker-item .bi { color: var(--primary); }
.fo-dsg-picker-item strong { display: block; font-size: 13px; }

/* ══ Map Monitoring: empty-map overlay ═══════════════════════════════════
   Shown when a user has no authorized markers, so an empty map reads as a
   clear state rather than a broken one. pointer-events:none keeps the map
   itself pannable underneath. The wording is chosen server-side and is never
   allowed to hint at tasks the viewer may not see. */
.fo-map-shell { position: relative; }
.fo-map-empty {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 0 24px; text-align: center;
  pointer-events: none;
  background: color-mix(in srgb, var(--surface) 72%, transparent);
  color: var(--text-muted);
}
.fo-map-empty[hidden] { display: none; }
.fo-map-empty .bi { font-size: 40px; opacity: .35; }
.fo-map-empty p { margin: 0; font-size: 13.5px; font-weight: 600; }

/* ══ Shared pagination (partials/_pagination.html) ═══════════════════════
   One control for every list page. Design tokens only — no hardcoded white or
   grey, so light and dark mode both work. */
.fo-pager {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  padding: 12px 4px 4px; margin-top: 8px;
  border-top: 1px solid var(--border);
}
.fo-pager-summary { margin: 0; font-size: 13px; color: var(--text-muted); flex: 1 1 auto; min-width: 0; }
.fo-pager-size { display: flex; align-items: center; gap: 6px; margin: 0; }
.fo-pager-size label { font-size: 12px; color: var(--text-muted); white-space: nowrap; }
.fo-pager-size select {
  font-size: 13px; padding: 5px 8px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--surface); color: var(--text-main);
}
.fo-pager-nav { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.fo-pager-btn, .fo-pager-num {
  display: inline-flex; align-items: center; gap: 5px;
  min-width: 34px; height: 34px; padding: 0 10px; justify-content: center;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface); color: var(--text-main);
  font-size: 13px; font-weight: 600; text-decoration: none;
}
.fo-pager-btn:hover, .fo-pager-num:hover { border-color: var(--primary); color: var(--primary); }
.fo-pager-btn:focus-visible, .fo-pager-num:focus-visible,
.fo-pager-size select:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
/* Active page is bold + filled, never colour alone. */
.fo-pager-num.is-current {
  background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 800;
}
.fo-pager-btn.is-disabled { opacity: .45; cursor: default; }
.fo-pager-btn.is-disabled:hover { border-color: var(--border); color: var(--text-main); }
.fo-pager-gap { padding: 0 2px; color: var(--text-muted); }
.fo-pager-pages { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.fo-pager-compact { display: none; font-size: 13px; color: var(--text-muted); padding: 0 6px; }

/* Phones: numbered buttons would overflow 320px, so collapse to
   "Previous · Page 2 of 8 · Next" and keep both arrows reachable. */
@media (max-width: 640px) {
  .fo-pager { gap: 10px; }
  .fo-pager-summary { flex: 1 1 100%; }
  .fo-pager-nav { width: 100%; justify-content: space-between; }
  .fo-pager-pages { display: none; }
  .fo-pager-compact { display: inline-block; }
}
@media (max-width: 380px) {
  .fo-pager-btn-text { display: none; }   /* arrows only — never overflow */
  .fo-pager-btn { padding: 0 12px; }
}

/* ══ All Tasks — clickable project name ═════════════════════════════════
   On the All Tasks page a project row is a task-grouping entry, so its name is
   a link to that project's task list (same destination as "View tasks").
   Typography is unchanged; the link reads as text until hovered or focused, so
   the row does not become visually noisy. Never colour alone: hover adds an
   underline, focus adds a ring. */
.fo-projrow-name {
  font-weight: 700;
  font-size: 14px;
  color: var(--text-main);
  text-decoration: none;
  border-radius: 4px;
}
.fo-projrow-name:hover { color: var(--primary); text-decoration: underline; }
.fo-projrow-name:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  text-decoration: underline;
}

/* ═══════════════════════════════════════════════════════════════════════════
   CONTROL SIZING — filter bars, native date/time fields, header controls
   ───────────────────────────────────────────────────────────────────────────
   Two defects this section fixes, both caused by shared rules rather than by
   any one page:

   1. `.fo-input` is `width:100%` (correct for stacked forms). Inside a flex
      filter bar that makes every control claim a full row, so a desktop filter
      bar rendered as ~10 stacked full-width selects. Inline `min-width` on the
      templates could never fix it — `width:100%` already exceeds any floor.

   2. The mobile rules below used `.fo-filter-bar > *`, but EVERY filter form is
      `display:contents`, so the controls are flex items of the bar while
      remaining DOM children of the <form>. The child selector matched only the
      form itself and the rules did nothing — which is why phone filter bars
      crushed two search boxes onto one 375px row instead of stacking them.
      Every selector here carries a `> form >` arm for that reason.

   The model: controls size to their own content (a <select> is as wide as its
   widest option, so the selected value is always readable), never grow past the
   bar, and wrap to the next line before shrinking below a legible floor.
═══════════════════════════════════════════════════════════════════════════ */

.fo-filter-bar > .fo-input,
.fo-filter-bar > form > .fo-input,
.fo-filter-bar > label,
.fo-filter-bar > form > label {
  /* `width:auto` is the fix: it hands sizing back to flex-basis:auto, i.e. the
     control's intrinsic content width. */
  width: auto;
  flex: 0 1 auto;
  max-width: 100%;
}

/* Text/search fields have no meaningful intrinsic width (the UA default is 20
   characters), so they get an explicit basis and are the ones allowed to
   absorb the leftover space. */
.fo-filter-bar > input.fo-input:is([type="text"], [type="search"], [type="email"], [type="tel"]),
.fo-filter-bar > form > input.fo-input:is([type="text"], [type="search"], [type="email"], [type="tel"]) {
  flex: 1 1 12rem;
  min-width: 9rem;
}

/* Selects: intrinsic width already includes the 38px arrow gutter, so the only
   floor needed is one that keeps a truncated value legible while wrapping. */
.fo-filter-bar > select.fo-input,
.fo-filter-bar > form > select.fo-input {
  min-width: 8rem;
}

/* The search box is the primary control — it takes the widest basis, grows
   first and shrinks last, and its floor is set by the longest placeholder we
   actually ship ("Titel, Standort, Außendienstmitarbeiter suchen…"). */
.fo-filter-bar > .fo-search-input,
.fo-filter-bar > form > .fo-search-input {
  flex: 3 1 22rem;
  min-width: 15rem;
  max-width: 100%;
}

/* Buttons and links keep their natural size; they must never be stretched or
   squeezed by the wrapping of the fields beside them. */
.fo-filter-bar > .fo-btn,
.fo-filter-bar > form > .fo-btn {
  flex: 0 0 auto;
}

/* ── Native date / time fields ────────────────────────────────────────────
   Chrome lays these out as a fixed segmented editor (dd.mm.yyyy) plus a picker
   icon it draws inside the box — content the field cannot scroll or ellipsise,
   so anything narrower simply clips the year or the icon. Measured minimums at
   13.5px are 145px (date), 95px (time) and 193px (datetime-local); expressing
   them in `em` keeps the floor correct for the 12px and 13px filter variants
   and under browser zoom.

   `min-width` deliberately: it outranks the fragile inline `width:130px…150px`
   still present on some filters without needing `!important`, and without
   stopping a template from making a field WIDER on purpose. */
.fo-input[type="date"]           { min-width: 11.5em; }
.fo-input[type="time"]           { min-width: 7.5em; }
.fo-input[type="datetime-local"] { min-width: 15em; }

/* Inside a filter bar they still size to that floor rather than a full row. */
.fo-filter-bar > .fo-input:is([type="date"], [type="time"], [type="datetime-local"]),
.fo-filter-bar > form > .fo-input:is([type="date"], [type="time"], [type="datetime-local"]) {
  flex: 0 0 auto;
}

/* ── Phones: one control per row ──────────────────────────────────────────
   Restores the intent of the older `.fo-filter-bar > *` rule, now with a
   selector that actually reaches through the display:contents forms. */
@media (max-width: 640px) {
  .fo-filter-bar > .fo-input,
  .fo-filter-bar > form > .fo-input,
  .fo-filter-bar > .fo-search-input,
  .fo-filter-bar > form > .fo-search-input {
    flex: 1 1 100%;
    min-width: 0;
    width: 100%;
  }
  /* Date/time keep their legible floor and sit two-up when they fit. */
  .fo-filter-bar > .fo-input:is([type="date"], [type="time"], [type="datetime-local"]),
  .fo-filter-bar > form > .fo-input:is([type="date"], [type="time"], [type="datetime-local"]) {
    flex: 1 1 11.5em;
    width: auto;
  }
  .fo-filter-bar > .fo-btn,
  .fo-filter-bar > form > .fo-btn { flex: 1 1 auto; }
}

/* ── Shared header ────────────────────────────────────────────────────────
   The centre search was a hard 300px, which clipped the German placeholder
   ("Kunden, Projekte, Außendienstmitarbeiter suchen…") by ~69px on every page:
   that string needs 316px of text plus 50px of icon, gap, padding and border.

   `.fo-header-center` keeps its default `min-width:auto` on purpose — that is
   what reserves the search's width against the title and account badge. Only
   `max-width` is added, so the box can still give way rather than overflow. The
   centre is hidden altogether below 1025px, so no phone case depends on it. */
/* The account badge must not be squeezed by a long name, nor push the search
   out of the header. Ellipsis is right here: this is a display label, not a
   value the user has to read in full — the full name stays in the menu. */
.fo-header-right { flex-shrink: 0; }
.fo-admin-badge { max-width: 220px; }
.fo-admin-info { min-width: 0; }
.fo-admin-name,
.fo-admin-role {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Account menu: long emails wrap instead of widening the menu off-screen. */
.fo-header-right .dropdown-menu { max-width: min(88vw, 320px); }
.fo-header-right .dropdown-item-text {
  white-space: normal;
  overflow-wrap: anywhere;
}


/* ── Submissions table: inline value editing ───────────────────────────────
   Deliberately the same grammar as the rest of the CRM's inline edits: a muted
   pencil that only asserts itself on hover, and a compact control that replaces
   the value in place rather than opening a form or a modal. */
.sv-cell{ position:relative; }
.sv-pencil{ background:none; border:0; padding:0; margin-left:6px; cursor:pointer;
  width:20px; height:20px; border-radius:4px; font-size:10px; color:var(--text-muted);
  display:inline-flex; align-items:center; justify-content:center;
  opacity:0; transition:opacity .12s ease; vertical-align:middle; }
.sv-cell:hover .sv-pencil,
.sv-pencil:focus-visible{ opacity:1; }
.sv-pencil:hover{ background:var(--surface-muted); color:var(--primary); }
.sv-pencil:focus-visible{ outline:2px solid var(--primary); outline-offset:1px; }
/* Touch has no hover, so the affordance must be permanently visible there. */
@media (hover:none){ .sv-pencil{ opacity:.75; } }

.sv-edit{ display:flex; align-items:center; gap:4px; min-width:0; }
.sv-input{ font-size:12px; height:28px; padding:2px 6px; min-width:0; flex:1 1 auto;
  max-width:190px; }
textarea.sv-input{ height:auto; min-height:46px; }
select.sv-input{ padding-inline-end:24px; }
.sv-ok,.sv-cancel{ background:none; border:0; padding:0; cursor:pointer; flex-shrink:0;
  width:22px; height:22px; border-radius:4px; font-size:11px;
  display:inline-flex; align-items:center; justify-content:center; color:var(--text-muted); }
.sv-ok{ color:var(--success); }
.sv-ok:hover,.sv-cancel:hover{ background:var(--surface-muted); }
.sv-cancel:hover{ color:var(--danger); }
.sv-ok:focus-visible,.sv-cancel:focus-visible{ outline:2px solid var(--primary); outline-offset:1px; }
.sv-ok:disabled,.sv-cancel:disabled{ opacity:.45; cursor:progress; }
.sv-err{ display:none; font-size:11px; color:var(--danger); margin-top:3px; overflow-wrap:anywhere; }
.sv-err.on{ display:block; }

@media (max-width:640px){
  /* In the card layout the cell is a row, so the control may use its width. */
  .sv-input{ max-width:100%; }
}


/* AI check block, shown under its field inside the Submitted Form. */
.sub-ai-check{ margin-top:10px; padding:9px 11px; border-radius:8px;
  border:1px solid var(--border); background:var(--surface-muted); }
.sub-ai-check[data-status="mismatch"]{ border-color:#fecaca; background:rgba(239,68,68,.07); }
.sub-ai-check[data-status="match"],
.sub-ai-check[data-status="applied"]{ border-color:#bbf7d0; background:rgba(34,197,94,.08); }
.sub-ai-check-head{ font-size:11px; font-weight:700; text-transform:uppercase;
  letter-spacing:.04em; color:var(--text-muted); margin-bottom:4px; }
.sub-ai-check-head .bi{ margin-right:4px; color:#7c3aed; }


/* A .fo-filter-bar used INSIDE a card/tab panel rather than at page level.
   Same bar, aligned to the panel's inset instead of the page gutter, so the
   filters line up under the header band above them. */
.fo-filter-bar-inset{
  padding:12px 20px 0;
  margin-bottom:0;
}
@media (max-width:640px){
  .fo-filter-bar-inset{ padding:10px 14px 0; }
}


/* ── Global Submissions: project rows ──────────────────────────────────────
   A row per project rather than a table: the counts read as a small stat
   cluster, and the completion bar has no sensible table column. Collapses to a
   stacked card on narrow screens. */
.sub-proj-row{
  display:flex; align-items:center; gap:18px;
  padding:14px 20px;
  border-bottom:1px solid var(--border);
}
.sub-proj-row:last-child{ border-bottom:0; }
.sub-proj-row:hover{ background:var(--surface-muted); }

.sub-proj-main{ flex:1 1 auto; min-width:0; }
.sub-proj-title{ display:flex; align-items:center; gap:7px; flex-wrap:wrap; min-width:0; }
.sub-proj-title a{ font-size:14px; font-weight:700; color:var(--text-main); text-decoration:none;
                   overflow-wrap:anywhere; }
.sub-proj-title a:hover{ color:var(--primary); }
.sub-proj-client{ font-size:12px; color:var(--text-muted); margin-top:3px; overflow-wrap:anywhere; }

.sub-proj-stats{ display:flex; align-items:flex-start; gap:20px; flex-shrink:0; }
.sub-proj-stat{ text-align:center; min-width:56px; }
.sub-proj-num{ font-size:16px; font-weight:700; line-height:1.15;
               font-variant-numeric:tabular-nums; color:var(--text-main); }
.sub-proj-num.is-review{ color:var(--warning,#d97706); }
.sub-proj-num.is-approved{ color:var(--success); }
.sub-proj-lbl{ font-size:9.5px; font-weight:700; text-transform:uppercase;
               letter-spacing:.04em; color:var(--text-muted); margin-top:2px; white-space:nowrap; }

.sub-proj-progress{ display:flex; align-items:center; gap:8px; flex:0 0 auto; width:120px; }
.sub-proj-track{ flex:1 1 auto; height:5px; border-radius:3px; background:var(--surface-muted);
                 overflow:hidden; min-width:0; }
.sub-proj-fill{ height:100%; border-radius:3px; background:var(--success); }
.sub-proj-pct{ font-size:11px; color:var(--text-muted); font-variant-numeric:tabular-nums;
               white-space:nowrap; }

.sub-proj-action{ flex-shrink:0; }
.sub-proj-action .fo-btn{ white-space:nowrap; }

/* A .fo-filter-bar that IS the card (page-level, boxed) rather than a bare row. */
.fo-filter-bar-card{
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--radius-card,10px); box-shadow:var(--shadow-card);
  padding:12px 14px;
}

@media (max-width:900px){
  /* Stack: the stat cluster and the action move under the project name rather
     than squeezing the name into a sliver. */
  .sub-proj-row{ flex-wrap:wrap; gap:12px; }
  .sub-proj-main{ flex:1 1 100%; }
  .sub-proj-stats{ gap:16px; }
  .sub-proj-progress{ width:100px; }
  .sub-proj-action{ margin-left:auto; }
}
@media (max-width:520px){
  .sub-proj-row{ padding:12px 14px; }
  .sub-proj-stats{ flex:1 1 100%; justify-content:space-between; gap:8px; }
  .sub-proj-progress{ flex:1 1 100%; width:auto; }
  .sub-proj-action{ flex:1 1 100%; margin-left:0; }
  .sub-proj-action .fo-btn{ width:100%; justify-content:center; }
}


/* ── Submission Detail: compact metadata disclosure ────────────────────────*/
.sub-meta{
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--radius-card,10px); box-shadow:var(--shadow-card);
}
.sub-meta > summary{
  list-style:none; cursor:pointer;
  display:flex; align-items:center; gap:8px; flex-wrap:wrap;
  padding:11px 16px; font-size:13px; color:var(--text-main);
}
.sub-meta > summary::-webkit-details-marker{ display:none; }
.sub-meta > summary:hover{ background:var(--surface-muted); border-radius:var(--radius-card,10px); }
.sub-meta > summary:focus-visible{ outline:2px solid var(--primary); outline-offset:-2px;
                                   border-radius:var(--radius-card,10px); }
.sub-meta-id{ font-weight:700; }
.sub-meta-sep{ color:var(--text-muted); }
.sub-meta-item{ color:var(--text-muted); min-width:0; overflow-wrap:anywhere; }
.sub-meta-chevron{ margin-left:auto; font-size:11px; color:var(--text-muted);
                   transition:transform .15s ease; flex-shrink:0; }
.sub-meta[open] > summary{ border-bottom:1px solid var(--border); border-radius:0; }
.sub-meta[open] .sub-meta-chevron{ transform:rotate(180deg); }

.sub-meta-grid{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
  gap:0;
}
.sub-meta-cell{ padding:12px 16px; border-top:1px solid var(--border); min-width:0; }
.sub-meta-lbl{ font-size:10px; font-weight:700; color:var(--text-muted);
               text-transform:uppercase; letter-spacing:.05em; margin-bottom:3px; }
.sub-meta-link{ font-size:13px; font-weight:600; color:var(--primary);
                text-decoration:none; overflow-wrap:anywhere; }
.sub-meta-link:hover{ text-decoration:underline; }

/* ── Submitted values: a subtle "this was filled in" hint ──────────────────
   Deliberately LOW specificity (one class + one element = 0,2,0). The project's
   own generated styling is emitted at 0,3,1 / 0,4,1, so a field that configures
   its own background keeps it — this tint only fills the gap where the project
   said nothing. Themed, never a hardcoded light grey. */
:root{ --sub-filled-bg:#f8fafc; }
html[data-theme="dark"]{ --sub-filled-bg:rgba(148,163,184,.07); }

/* Scoped with .task-form-body so it outranks that sheet's own
   `.task-form-body .fo-input{background:var(--surface)}` (both 0,2,0 — task-form.css
   loads later and would otherwise win), while still sitting BELOW the project's
   generated rules, which are emitted at (0,3,0)+ in a later inline <style>. */
/* Read-only submitted form.
   Inert WITHOUT the browser's disabled treatment: `disabled` sets
   -webkit-text-fill-color, which wins over `color` and discards whatever text
   colour the project configured. Only the controls are made non-interactive —
   photo thumbnails and links inside the form stay clickable, because inspecting
   the evidence is the whole point of the page. */
.sub-readonly input,
.sub-readonly select,
.sub-readonly textarea,
.sub-readonly .fo-choice,
.sub-readonly .fo-choice-card,
.sub-readonly .fo-rating label{
  pointer-events:none;
}

.task-form-body.sub-filled .fo-input,
.task-form-body.sub-filled input,
.task-form-body.sub-filled select,
.task-form-body.sub-filled textarea{
  background-color:var(--sub-filled-bg);
  cursor:default;
}
/* Choice inputs are drawn by the browser; tinting their box does nothing useful
   and would fight the project's own control styling. */
.task-form-body.sub-filled input[type="checkbox"],
.task-form-body.sub-filled input[type="radio"]{ background-color:transparent; }

/* A disabled fieldset (read-only viewers) must not add the UA's own grey on top
   of the tint — the layout and typography stay exactly as the live form. */
.sub-filled fieldset[disabled] .fo-input,
.sub-filled fieldset[disabled] input,
.sub-filled fieldset[disabled] select,
.sub-filled fieldset[disabled] textarea,
.sub-filled input:disabled,
.sub-filled select:disabled,
.sub-filled textarea:disabled{
  opacity:1;
  color:var(--text-main);
  -webkit-text-fill-color:var(--text-main);
}
