/*
 * dt-cf-patterns.css
 *
 * Shared stylesheet for the two table/filter/pagination component
 * patterns approved by the user: "dt-" (list-page — page owns its
 * whole table: toolbar, filter panel, sortable/pinned table,
 * pagination) and "cf-" (card-filter — a standalone filter card for
 * pages whose table is bespoke and stays untouched).
 *
 * Source of truth for the design: docs/list-page-pattern.html and
 * docs/card-filter-pattern.html (both previewed in isolation at
 * /ui-preview/list-page/ and /ui-preview/card-filter/ before being
 * approved for real pages).
 *
 * Adapted for real integration vs. the standalone previews in three
 * ways:
 *   1. Dark mode is server-driven here (daaptech/templates/index.html
 *      renders <body class="{{request.session.theme}}">), so every
 *      dark-mode rule keys off `body.dark`, not `html[data-theme]`.
 *      There is no client-side theme toggle or `prefers-color-scheme`
 *      auto-detect on real pages -- the app already has one global
 *      toggle.
 *   2. Every rule -- tokens, fonts, resets included -- is scoped under
 *      `.dt-app` / `.cf-app` so nothing here can leak into the rest of
 *      the site (sidebar, other pages' headings/buttons/inputs).
 *   3. One shared file loaded via {% block styles %} instead of a
 *      ~600-line <style> block duplicated per page -- the entire point
 *      of this project was to stop that pattern.
 *
 * Never hand-edit static/build/css/style.min.css; this file is
 * additive and independent of it.
 */

/* ============ THEME TOKENS (scoped, not :root) ============
   Four blocks: Standard light/dark (unprefixed / body.dark -- unchanged
   values, so real pages that never set data-theme are byte-for-byte
   identical to before) and Coolio light/dark (new, gated behind
   body[data-theme="coolio"] so it stays completely inert everywhere
   except /style-guide/, whose page-local theme switcher is the only
   thing that ever sets data-theme on <body>). Source order here IS the
   override mechanism -- no !important needed. */
.dt-app, .cf-app, .dt-dialog-backdrop {
  --canvas:#F3F5F7;
  --surface:#FFFFFF;
  --surface-2:#FAFBFC;
  --surface-hover:#F5F7F9;
  --border:#E3E7EB;
  --border-strong:#D2D8DF;
  --text-primary:#151A21;
  --text-secondary:#5B6572;
  --text-tertiary:#98A2AE;
  --accent:#111827;
  --accent-hover:#1F2937;
  --accent-soft:#F1F2F4;
  --accent-contrast:#FFFFFF;
  --amber:#B4590A;
  --amber-soft:#FBEEDF;
  --success:#157A47;
  --success-soft:#E3F6EA;
  --danger:#C4291B;
  --danger-soft:#FBEAE8;
  --slate:#3E4C63;
  --slate-soft:#E9ECF2;
  --plum:#7C3AA0;
  --plum-soft:#F3E8F8;
  --info:#2563AC;
  --info-soft:#E4EEFA;
  --shadow-sm: 0 1px 2px rgba(16,24,32,.06);
  --shadow-md: 0 8px 24px rgba(16,24,32,.12), 0 2px 6px rgba(16,24,32,.06);
  --focus-ring: 0 0 0 3px rgba(17,24,39,.18);
  --radius-lg:14px; --radius-sm:10px;
  --font-display:-apple-system,"Segoe UI",Roboto,sans-serif;
  --font-body:-apple-system,"Segoe UI",Roboto,sans-serif;
  --font-mono:ui-monospace,'SF Mono',Menlo,Consolas,monospace;
  --navy-deep:#111827; --navy-deep-2:#1F2937; --grid-line: transparent;
  --on-navy:#FFFFFF; --on-navy-soft:#C7CDD6; --on-navy-faint:#9AA3AE;
}
body.dark .dt-app, body.dark .cf-app, body.dark .dt-dialog-backdrop {
  --canvas:#0A0D11;
  --surface:#12161C;
  --surface-2:#171C23;
  --surface-hover:#1B212A;
  --border:#242B34;
  --border-strong:#313A46;
  --text-primary:#EEF1F4;
  --text-secondary:#9BA5B2;
  --text-tertiary:#6B7480;
  --accent:#F3F4F6;
  --accent-hover:#E5E7EB;
  --accent-soft:rgba(243,244,246,.12);
  --accent-contrast:#111827;
  --amber:#F0A23D;
  --amber-soft:rgba(240,162,61,.12);
  --success:#3FD98A;
  --success-soft:rgba(63,217,138,.12);
  --danger:#F1685C;
  --danger-soft:rgba(241,104,92,.12);
  --slate:#9AABC7;
  --slate-soft:rgba(154,171,199,.12);
  --plum:#C89AE8;
  --plum-soft:rgba(200,154,232,.12);
  --info:#6FA8E0;
  --info-soft:rgba(111,168,224,.14);
  --shadow-sm: 0 1px 2px rgba(0,0,0,.4);
  --shadow-md: 0 12px 28px rgba(0,0,0,.5), 0 2px 8px rgba(0,0,0,.35);
  --focus-ring: 0 0 0 3px rgba(243,244,246,.25);
  --radius-lg:14px; --radius-sm:10px;
  --font-display:-apple-system,"Segoe UI",Roboto,sans-serif;
  --font-body:-apple-system,"Segoe UI",Roboto,sans-serif;
  --font-mono:ui-monospace,'SF Mono',Menlo,Consolas,monospace;
  --navy-deep:#F3F4F6; --navy-deep-2:#E5E7EB; --grid-line: transparent;
  --on-navy:#111827; --on-navy-soft:#3E4C63; --on-navy-faint:#5B6572;
}
/* ---- Coolio / light (mawaridna values, mapped onto the neutral names) ---- */
body[data-theme="coolio"] .dt-app, body[data-theme="coolio"] .cf-app, body[data-theme="coolio"] .dt-dialog-backdrop {
  --canvas:#EEF1ED;
  --surface:#FFFFFF;
  --surface-2:#F8F9F7;
  --surface-hover:#F1F3EF;
  --border:#DEE3DD;
  --border-strong:#C7CFC5;
  --text-primary:#16233B;
  --text-secondary:#5B6472;
  --text-tertiary:#8892A0;
  --accent:#147D6F;
  --accent-hover:#106459;
  --accent-soft:#E3F1EE;
  --accent-contrast:#FFFFFF;
  --amber:#CE8A2E;
  --amber-soft:#FAEEDB;
  --success:#147D6F;
  --success-soft:#E3F1EE;
  --danger:#BE4A30;
  --danger-soft:#F8E7E1;
  --slate:#6B7686;
  --slate-soft:#EAECF0;
  --plum:#7C3AA0;
  --plum-soft:#F3E8F8;
  --info:#2563AC;
  --info-soft:#E4EEFA;
  --shadow-sm: 0 1px 2px rgba(14,24,38,.05);
  --shadow-md: 0 10px 24px -14px rgba(14,24,38,.18), 0 1px 2px rgba(14,24,38,.06);
  --focus-ring: 0 0 0 3px rgba(206,138,46,.35);
  --radius-lg:14px; --radius-sm:9px;
  --font-display:'Space Grotesk', 'Segoe UI', sans-serif;
  --font-body:'Inter', 'Segoe UI', sans-serif;
  --font-mono:'IBM Plex Mono', 'SFMono-Regular', Menlo, monospace;
  --navy-deep:#0E1826; --navy-deep-2:#152238; --grid-line: rgba(14,24,38,.045);
  --on-navy:#EDEFF4; --on-navy-soft:#B7C2D2; --on-navy-faint:#8FA0B8;
}
/* ---- Coolio / dark (authored directly against these neutral names --
   not a mechanical inversion: keeps navy as the ground so it reads as
   "instrument panel at night" rather than a generic dark-mode grey) ---- */
body.dark[data-theme="coolio"] .dt-app, body.dark[data-theme="coolio"] .cf-app, body.dark[data-theme="coolio"] .dt-dialog-backdrop {
  --canvas:#0B1219;
  --surface:#121C28;
  --surface-2:#16212F;
  --surface-hover:#1B2836;
  --border:#24313F;
  --border-strong:#33455A;
  --text-primary:#E8EDF2;
  --text-secondary:#9DAEC0;
  --text-tertiary:#6B7F94;
  --accent:#2FA895;
  --accent-hover:#3BC1AB;
  --accent-soft:rgba(47,168,149,.16);
  --accent-contrast:#04120F;
  --amber:#E0A44A;
  --amber-soft:rgba(224,164,74,.16);
  --success:#2FA895;
  --success-soft:rgba(47,168,149,.16);
  --danger:#D96A50;
  --danger-soft:rgba(217,106,80,.16);
  --slate:#8FA3B8;
  --slate-soft:rgba(143,163,184,.16);
  --plum:#C89AE8;
  --plum-soft:rgba(200,154,232,.14);
  --info:#6FA8E0;
  --info-soft:rgba(111,168,224,.16);
  --shadow-sm: 0 1px 2px rgba(0,0,0,.4);
  --shadow-md: 0 12px 28px -14px rgba(0,0,0,.55), 0 2px 8px rgba(0,0,0,.4);
  --focus-ring: 0 0 0 3px rgba(224,164,74,.4);
  --radius-lg:14px; --radius-sm:9px;
  --font-display:'Space Grotesk', 'Segoe UI', sans-serif;
  --font-body:'Inter', 'Segoe UI', sans-serif;
  --font-mono:'IBM Plex Mono', 'SFMono-Regular', Menlo, monospace;
  --navy-deep:#060B12; --navy-deep-2:#0A121C; --grid-line: rgba(255,255,255,.035);
  --on-navy:#DCE6F0; --on-navy-soft:#93A6BC; --on-navy-faint:#6E82A0;
}

/* ============ SCOPED RESET ============
   Typography now goes through --font-body/--font-display/--font-mono
   (added in the token layer above) instead of being left to inherit --
   that's what lets Coolio's Space Grotesk/Inter/IBM Plex Mono stack
   apply on /style-guide/ without touching real pages: the Standard
   block's font tokens are set to the exact same system stack real
   pages already inherited, so this is a no-op there. */
.dt-app, .cf-app {
  color: var(--text-primary);
  font-family: var(--font-body);
}
.dt-app h1, .dt-app h2, .dt-app h3,
.cf-app h1, .cf-app h2, .cf-app h3{ margin:0; font-family:var(--font-display); }
.dt-app button, .cf-app button{ font-family:inherit; }
.dt-app input, .dt-app select,
.cf-app input, .cf-app select{ color:inherit; font-family:inherit; }
/* Buttons deliberately do NOT get color:inherit here -- that descendant
   selector (.dt-app button) out-specifies single-class rules like
   .dt-btn--primary{ color:var(--accent-contrast) }, which silently made
   primary-button text invisible (near-black text inherited onto a
   near-black button background). Each .dt-btn/.dt-btn--primary variant
   sets its own explicit color instead. */
.dt-app :focus-visible, .cf-app :focus-visible{ outline:none; box-shadow:var(--focus-ring); border-radius:8px; }
.dt-app .mono, .cf-app .mono{ font-family:var(--font-mono); }

@media (prefers-reduced-motion: reduce){
  .dt-app *, .cf-app *{ animation-duration:.001ms !important; transition-duration:.001ms !important; }
}

/* ============ APP SHELL ============
   Self-contained width -- does NOT depend on Horilla's .oh-wrapper class.
   Matches the same visual result (95% of the content column, centered)
   as an independent rule owned entirely by this component system. */
.dt-app, .cf-app {
  max-width: 95%;
  width: 100%;
  margin-left: auto;
  margin-right: auto;
  padding: 24px 0 40px;
  box-sizing: border-box;
}

.dt-header{
  display:flex; align-items:flex-start; justify-content:space-between;
  gap:16px; margin-bottom:24px;
}
.dt-header h1{ font-size:22px; font-weight:700; letter-spacing:-.01em; }
.dt-header p{ margin:4px 0 0; font-size:13px; color:var(--text-secondary); }
.dt-header p span{ color:var(--text-tertiary); }

.cf-page-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:16px; margin-bottom:20px; }
.cf-page-head h1{ font-size:22px; font-weight:700; letter-spacing:-.01em; }

/* ============ TOOLBAR ============ */
.dt-toolbar{ display:flex; gap:12px; margin-bottom:12px; position:relative; }
/* height:40px pinned explicitly -- .dt-search is a flex item inside
   .dt-toolbar (display:flex), and flex items default to
   align-items:stretch on the cross axis. With no height of its own,
   .dt-search was being stretched to match its tallest .dt-toolbar
   sibling (e.g. the Filter button), not just sized to its 40px input --
   so the icon's top:50%/translateY(-50%) was centering against that
   taller, stretched box while the input (and its placeholder text)
   still only occupied the top 40px of it. A real structural mismatch,
   not a sub-pixel one -- a per-icon nudge (tried first, reverted) was
   solving the wrong problem. Locking .dt-search to height:40px makes
   top:50% resolve against the same 40px box the input actually renders
   at, so the two centers match with no icon-side correction needed. */
.dt-search{ position:relative; flex:1 1 auto; min-width:0; height:40px; }
.dt-search svg{ position:absolute; left:13px; top:50%; transform:translateY(-50%); width:16px; height:16px; color:var(--text-tertiary); pointer-events:none; }
.dt-search input{
  width:100%; height:40px; padding:0 36px; border-radius:10px;
  border:1px solid var(--border); background:var(--surface); font-size:14px;
  color:var(--text-primary); transition:border-color .15s ease, background .15s ease;
}
.dt-search input::placeholder{ color:var(--text-tertiary); }
.dt-search input:hover{ border-color:var(--border-strong); }
.dt-search-clear{
  position:absolute; right:8px; top:50%; transform:translateY(-50%);
  width:24px; height:24px; display:none; align-items:center; justify-content:center;
  border:none; background:transparent; color:var(--text-tertiary); border-radius:6px; cursor:pointer;
}
.dt-search-clear:hover{ background:var(--surface-hover); color:var(--text-primary); }
.dt-search-clear.visible{ display:flex; }
.dt-search-clear svg{ position:static; width:13px; height:13px; transform:none; }

.dt-filter-wrap{ position:relative; flex-shrink:0; }

.dt-btn, .cf-btn{
  display:inline-flex; align-items:center; gap:8px; height:40px; padding:0 16px;
  border-radius:10px; border:1px solid var(--border); background:var(--surface);
  color:var(--text-primary); font-size:14px; font-weight:500; cursor:pointer;
  white-space:nowrap; transition:background .15s ease, border-color .15s ease, color .15s ease;
}
.cf-btn{ height:38px; border-radius:9px; font-size:13.5px; }
.dt-btn:hover, .cf-btn:hover{ background:var(--surface-hover); border-color:var(--border-strong); }
.dt-btn svg, .cf-btn svg{ width:14px; height:14px; }
.dt-btn--primary, .cf-btn--primary{ background:var(--accent); border-color:var(--accent); color:var(--accent-contrast); }
.dt-btn--primary:hover, .cf-btn--primary:hover{ background:var(--accent-hover); border-color:var(--accent-hover); }
/* .dt-btn--danger is defined further down, in the "Danger button variants"
   section alongside .dt-btn--danger-outline -- it already existed there;
   don't redefine it here (a duplicate briefly existed at this exact spot
   this session, since removed -- grep before adding a .dt-btn--* rule,
   this file is 1200+ lines and things hide). */
.dt-btn--ghost{ background:transparent; border-color:transparent; }
.dt-btn--ghost:hover{ background:var(--surface-hover); }
.dt-btn--full{ width:100%; justify-content:center; }

.dt-filter-badge{
  display:inline-flex; align-items:center; justify-content:center; min-width:18px; height:18px;
  padding:0 5px; border-radius:999px; background:var(--accent); color:var(--accent-contrast);
  font-size:11px; font-weight:600;
}
.dt-chev{ transition:transform .15s ease; }
.dt-filter-btn[aria-expanded="true"] .dt-chev{ transform:rotate(180deg); }

/* ============ dt- FILTER PANEL (inline, pushes content down; bottom-sheet on phone) ============ */
.dt-filter-panel{
  background:var(--surface); border:1px solid var(--border); border-radius:14px;
  box-shadow:var(--shadow-sm); padding:16px 18px; margin-bottom:16px;
  animation:dt-drop-in .14s ease;
}
@keyframes dt-drop-in{ from{ opacity:0; transform:translateY(-6px); } to{ opacity:1; transform:translateY(0); } }
.dt-filter-panel[hidden]{ display:none; }
.dt-filter-panel-head{ display:flex; align-items:center; justify-content:space-between; margin-bottom:14px; }
.dt-filter-panel-head h2{ font-size:14px; font-weight:600; }
.dt-filter-close{
  width:26px; height:26px; display:flex; align-items:center; justify-content:center;
  border:none; background:transparent; color:var(--text-tertiary); border-radius:6px; cursor:pointer;
}
.dt-filter-close:hover{ background:var(--surface-hover); color:var(--text-primary); }
.dt-filter-close svg{ width:14px; height:14px; }

.dt-filter-grid{ display:flex; flex-wrap:wrap; gap:14px 12px; }
.dt-filter-field{ flex:1 1 150px; min-width:150px; }
.dt-filter-field label{
  display:block; font-size:11px; font-weight:600; letter-spacing:.04em; text-transform:uppercase;
  color:var(--text-tertiary); margin-bottom:6px; white-space:nowrap;
}

/* Vertical form field group (dialogs -- Users Create/Edit and anything
   else stacking fields top-to-bottom, as opposed to .dt-filter-field's
   horizontal-grid column). .dt-filter-field itself is the wrong fit here:
   flex:1 1 150px/min-width:150px size it as a flex-grid column, and its
   label forces white-space:nowrap, both meaningless once fields stack
   full-width. Reuses the same label token values (font-size/weight/
   letter-spacing/color) for a consistent look, via gap instead of
   margin-bottom so the group owns its own spacing rhythm: 6px tight
   between a label and its own control (same value .dt-filter-field
   already uses), .dt-dialog-body's own gap:14px is what separates one
   field group from the next -- unchanged, already the right token for
   "space between groups", it just never had a smaller sibling to
   contrast against before this existed. */
.dt-form-field{ display:flex; flex-direction:column; gap:6px; }
.dt-form-field label{
  font-size:11px; font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:var(--text-tertiary);
}

.dt-select, .dt-date, .cf-input, .cf-select, .cf-date{
  box-sizing:border-box; width:100%; min-width:0; height:36px; padding:0 10px; border-radius:8px; border:1px solid var(--border);
  background:var(--surface-2); color:var(--text-primary); font-size:13px; appearance:none;
}
.cf-input, .cf-select, .cf-date{ height:38px; padding:0 12px; border-radius:9px; font-size:13.5px; }
.dt-select--surface{ background:var(--surface); }
/* Tag-qualified on purpose: .dt-select/.cf-select are also put on plain
   text/password inputs for shared box chrome (border/height/padding from
   the rule above -- e.g. UserForm.__init__ sets "dt-select dt-select--surface"
   on username/password/name/employee_codes, none of which are <select>
   elements). The dropdown arrow + its reserved right padding are select-
   only -- tag-qualifying the selector is what stops a plain <input> from
   picking up a chevron it isn't. */
select.dt-select, select.cf-select{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%2398A2AE' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 10px center; padding-right:26px;
}
select.cf-select{ padding-right:28px; }
.dt-select:hover, .dt-date:hover, .cf-input:hover, .cf-select:hover, .cf-date:hover{ border-color:var(--border-strong); }
/* No :disabled rule existed for this box-chrome family at all before --
   .dt-app .oh-input:disabled (below) only ever covered the legacy oh-
   compat layer. Surfaced by crew_form.html's dt-searchselect fields
   needing to disable their visible input when task_source toggles which
   fields are active -- disabling worked functionally (a disabled input
   is dropped from FormData) but looked identical to enabled, no visual
   cue at all. Same opacity/cursor values .dt-page-btn:disabled already
   uses, for consistency across "disabled" state anywhere in this file. */
.dt-select:disabled, .dt-date:disabled, .cf-input:disabled, .cf-select:disabled, .cf-date:disabled{ opacity:.55; cursor:not-allowed; }
select.dt-select[multiple]{ height:auto; padding:6px; background-image:none; }
.dt-date, .cf-date{ color-scheme:light; }
body.dark .dt-date, body.dark .cf-date{ color-scheme:dark; }
.cf-input::placeholder{ color:var(--text-tertiary); }

.dt-filter-divider{ height:1px; background:var(--border); margin:14px 0; border:none; }
.dt-filter-actions{ display:flex; gap:8px; }
.dt-filter-actions .dt-btn{ flex:1; }

/* ============ ACTIVE FILTER CHIPS (shared) ============ */
.dt-chips, .cf-chips{ display:flex; flex-wrap:wrap; gap:8px; margin-bottom:16px; }
.dt-chips[hidden], .cf-chips[hidden]{ display:none; }
.dt-chip, .cf-chip{
  display:inline-flex; align-items:center; gap:6px; height:28px; padding:0 6px 0 10px;
  border-radius:999px; background:var(--accent-soft); color:var(--accent); font-size:12.5px; font-weight:500;
}
.dt-chip button, .cf-chip button{
  display:flex; align-items:center; justify-content:center; width:16px; height:16px;
  border:none; background:transparent; color:currentColor; cursor:pointer; border-radius:50%; opacity:.75;
}
.dt-chip button:hover, .cf-chip button:hover{ opacity:1; background:rgba(0,0,0,.08); }
.dt-chip button svg, .cf-chip button svg{ width:9px; height:9px; }
.dt-chip-clear{
  height:28px; padding:0 10px; border-radius:999px; border:1px dashed var(--border-strong);
  background:transparent; color:var(--text-secondary); font-size:12.5px; cursor:pointer;
}
.dt-chip-clear:hover{ color:var(--text-primary); border-color:var(--text-tertiary); }

/* ============ dt- TABLE ============ */
.dt-table-wrap{ background:var(--surface); border:1px solid var(--border); border-radius:14px; overflow:hidden; }
.dt-table-scroll{ overflow-x:auto; position:relative; }
table.dt-table{ width:100%; border-collapse:collapse; min-width:640px; }
/* Opt-in (generic/dt_list_table.html's view.scrollable_table) for a page
   whose row count would otherwise push the whole page into scrolling --
   caps the table's own height and scrolls the rows inside it instead,
   header pinned via position:sticky so it stays visible. The 340px
   offset is an estimate of the chrome above the table (topbar, page
   header, toolbar, spacing) on this app's layout -- not exact for every
   viewport, but close; min-height keeps it from collapsing on short
   screens. */
.dt-table-scroll--capped{ max-height:calc(100vh - 340px); min-height:280px; overflow-y:auto; }
.dt-table-scroll--capped table.dt-table thead th{ position:sticky; top:0; z-index:3; }

.dt-table th[data-pin], .dt-table td[data-pin]{ position:sticky; z-index:2; background:var(--surface-2); }
.dt-table tbody td[data-pin]{ background:var(--surface); z-index:1; }
.dt-table tbody tr:hover td[data-pin]{ background:var(--surface-hover); }
.dt-table th[data-pin-last], .dt-table td[data-pin-last]{ box-shadow:1px 0 0 var(--border-strong); }
.dt-table-scroll.is-scrolled th[data-pin-last], .dt-table-scroll.is-scrolled td[data-pin-last]{ box-shadow:3px 0 6px -2px rgba(16,24,32,.16); }
body.dark .dt-table-scroll.is-scrolled th[data-pin-last],
body.dark .dt-table-scroll.is-scrolled td[data-pin-last]{ box-shadow:3px 0 8px -2px rgba(0,0,0,.5); }

.dt-table thead th{
  text-align:left; font-size:11px; font-weight:600; letter-spacing:.05em; text-transform:uppercase;
  color:var(--text-tertiary); padding:11px 16px; background:var(--surface-2);
  border-bottom:1px solid var(--border); white-space:nowrap;
}
.dt-table thead th.sortable{ cursor:pointer; user-select:none; }
.dt-table thead th.sortable:hover{ color:var(--text-secondary); }
.dt-th-inner{ display:inline-flex; align-items:center; gap:5px; }
.dt-sort-icon{ width:11px; height:11px; opacity:.4; }
.dt-sort-icon.active{ opacity:1; color:var(--accent); }

.dt-table tbody td{ padding:9px 16px; font-size:13.5px; border-bottom:1px solid var(--border); vertical-align:middle; }
.dt-table tbody tr:last-child td{ border-bottom:none; }
.dt-table tbody tr{ transition:background .1s ease; }
.dt-table tbody tr:hover{ background:var(--surface-hover); }
/* Bulk-select: set by highlightRow() (static/index/index.js) on each row
   checkbox's change event -- an accent background instead of a visually
   loud checked checkbox, same call the standalone's own multi-select
   already makes for its option rows. */
.dt-table tbody tr.highlight-selected{ background:var(--accent-soft); }
.dt-table tbody tr.highlight-selected:hover{ background:var(--accent-soft); }
.dt-row-check{ width:15px; height:15px; accent-color:var(--accent); cursor:pointer; }

.dt-employee-cell{ display:flex; align-items:center; gap:10px; }
.dt-avatar{ width:30px; height:30px; border-radius:9px; display:flex; align-items:center; justify-content:center; font-size:11.5px; font-weight:700; flex-shrink:0; }
.dt-avatar--0{ background:var(--accent-soft); color:var(--accent); }
.dt-avatar--1{ background:var(--amber-soft); color:var(--amber); }
.dt-avatar--2{ background:var(--plum-soft); color:var(--plum); }
.dt-avatar--3{ background:var(--slate-soft); color:var(--slate); }
.dt-avatar--4{ background:var(--danger-soft); color:var(--danger); }

/* ============ DETAIL DIALOG (read-only profile header + field grid) ========
   A generic "view details" dialog body: an optional profile-style header
   (avatar image + title + subtitle) followed by a responsive 2-column
   grid of label/value pairs, any of which can span the full width via
   .dt-detail-grid__item--wide. Meant for a .dt-dialog-body's content --
   pairs with confirm_dialog.html's shell shape but this one is read-only,
   no footer actions of its own (add a .dt-dialog-footer alongside it if
   a page needs actions). First use: attendance Records row-detail popup
   (crew/attendance/cbv/attendance_activity.py's BetaRecordDetailView) --
   demoed in daaptech/templates/daaptech/patterns/unified_demo.html. */
.dt-detail-header{ display:flex; align-items:center; gap:12px; padding-bottom:16px; margin-bottom:4px; border-bottom:1px solid var(--border); }
.dt-detail-header img{ width:44px; height:44px; border-radius:10px; object-fit:cover; flex:none; background:var(--surface-2); }
.dt-detail-header__title{ font-size:15px; font-weight:700; color:var(--text-primary); }
.dt-detail-header__subtitle{ font-size:12.5px; color:var(--text-secondary); margin-top:2px; }
.dt-detail-grid{ display:grid; grid-template-columns:repeat(2,1fr); gap:16px 20px; }
.dt-detail-grid__item--wide{ grid-column:1 / -1; }
.dt-detail-grid__label{ display:block; font-size:11px; font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:var(--text-tertiary); margin-bottom:4px; }
.dt-detail-grid__value{ font-size:13.5px; color:var(--text-primary); font-weight:500; word-break:break-word; }
@media (max-width:520px){ .dt-detail-grid{ grid-template-columns:1fr; } }

.dt-name{ font-weight:600; color:var(--text-primary); }

.dt-muted{ color:var(--text-tertiary); }
.dt-tag{ color:var(--accent); font-weight:500; }
.dt-pill{ display:inline-block; background:var(--surface-2); border-radius:4px; padding:1px 8px; font-size:11.5px; color:var(--text-secondary); }

.dt-badge{ display:inline-flex; align-items:center; gap:5px; height:22px; padding:0 9px; border-radius:999px; font-size:12px; font-weight:600; }
.dt-badge::before{ content:''; width:6px; height:6px; border-radius:50%; background:currentColor; }
.dt-badge--active{ background:var(--success-soft); color:var(--success); }
.dt-badge--inactive{ background:var(--danger-soft); color:var(--danger); }
.dt-badge--pending{ background:var(--amber-soft); color:var(--amber); }
.dt-badge--info{ background:var(--info-soft); color:var(--info); }

/* ============ dt- ROW ACTION ICON BUTTONS (table cell actions) ============ */
.dt-actions{ display:flex; gap:2px; align-items:center; }
.dt-icon-btn{
  border:none; background:transparent; cursor:pointer; color:var(--text-secondary);
  padding:6px; border-radius:7px; font-size:16px; line-height:1;
  display:inline-flex; align-items:center; justify-content:center; transition:background .12s;
}
.dt-icon-btn:hover{ background:var(--surface-hover); color:var(--text-primary); }
.dt-icon-btn svg, .dt-icon-btn ion-icon{ width:16px; height:16px; font-size:16px; }
.dt-icon-btn--danger:hover{ background:var(--danger-soft); color:var(--danger); }
.dt-icon-btn--amber:hover{ background:var(--amber-soft); color:var(--amber); }
.dt-icon-btn--success:hover{ background:var(--success-soft); color:var(--success); }

/* ============ EMPTY STATE ============ */
.dt-empty{ display:none; flex-direction:column; align-items:center; text-align:center; padding:64px 24px; color:var(--text-secondary); }
.dt-empty.visible{ display:flex; }
.dt-empty svg{ width:34px; height:34px; color:var(--text-tertiary); margin-bottom:14px; }
.dt-empty h3{ font-size:14px; color:var(--text-primary); margin-bottom:4px; }
.dt-empty p{ font-size:13px; margin:0 0 16px; max-width:320px; }
table.dt-table.dt-table--empty{ display:none; }

/* ============ dt- PAGINATION ============ */
.dt-pagination{ display:flex; align-items:center; justify-content:space-between; gap:16px; padding:14px 20px; border-top:1px solid var(--border); flex-wrap:wrap; }
.dt-page-size{ display:flex; align-items:center; gap:8px; font-size:13px; color:var(--text-secondary); }
.dt-page-size .dt-select{ width:auto; height:32px; font-size:13px; padding-right:24px; }
.dt-page-info{ font-size:13px; color:var(--text-secondary); }
.dt-page-info b{ color:var(--text-primary); font-weight:600; }
.dt-page-controls{ display:flex; align-items:center; gap:4px; }
.dt-page-btn{
  min-width:30px; height:30px; padding:0 6px; display:flex; align-items:center; justify-content:center;
  border-radius:8px; border:1px solid transparent; background:transparent; color:var(--text-secondary);
  font-size:13px; cursor:pointer; text-decoration:none;
}
.dt-page-btn:hover:not(:disabled){ background:var(--surface-hover); color:var(--text-primary); }
.dt-page-btn:disabled, .dt-page-btn--disabled{ opacity:.35; cursor:not-allowed; pointer-events:none; }
.dt-page-btn.active, .dt-page-btn--active{ background:var(--accent); border-color:var(--accent); color:var(--accent-contrast); }
.dt-page-btn svg{ width:15px; height:15px; }
.dt-page-ellipsis{ width:24px; text-align:center; color:var(--text-tertiary); font-size:13px; }

/* ============ cf- CARD (Timesheets-style filter-only pages) ============ */
.cf-card{ background:var(--surface); border:1px solid var(--border); border-radius:14px; box-shadow:var(--shadow-sm); padding:20px 22px; margin-bottom:24px; }
.cf-card-top{ display:flex; align-items:center; justify-content:flex-end; gap:10px; margin-bottom:18px; font-size:13px; color:var(--text-secondary); }
.cf-card-top .cf-date-label{ font-weight:600; color:var(--text-primary); margin-right:4px; white-space:nowrap; }
.cf-range{ display:flex; gap:12px; flex-wrap:wrap; align-items:flex-end; }
.cf-field{ display:flex; flex-direction:column; gap:6px; min-width:0; }
.cf-field label{ font-size:11px; font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:var(--text-tertiary); white-space:nowrap; }
.cf-combo{ position:relative; }
.cf-combo svg{ position:absolute; right:11px; top:50%; transform:translateY(-50%); width:13px; height:13px; color:var(--text-tertiary); pointer-events:none; }

.cf-disclosure{ border-top:1px solid var(--border); padding-top:16px; }
.cf-disclosure-trigger{
  display:flex; align-items:center; gap:8px; background:transparent; border:none; padding:6px 2px;
  font-size:14px; font-weight:600; color:var(--text-primary); cursor:pointer; margin:-6px 0 4px -2px;
}
.cf-disclosure-trigger:hover{ color:var(--accent); }
.cf-disclosure-trigger svg{ width:15px; height:15px; transition:transform .18s ease; color:var(--text-tertiary); }
.cf-disclosure-trigger[aria-expanded="true"] svg{ transform:rotate(180deg); color:var(--accent); }
.cf-disclosure-body{ display:grid; grid-template-rows:0fr; transition:grid-template-rows .2s ease; }
.cf-disclosure-body.open{ grid-template-rows:1fr; }
.cf-disclosure-body-inner{ overflow:hidden; }
.cf-grid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(220px, 1fr)); gap:16px 18px; padding-top:14px; }

.cf-card-actions{ display:flex; justify-content:flex-end; gap:10px; padding-top:18px; margin-top:4px; }

/* ============ RESPONSIVE ============ */
@media (max-width: 720px){
  .dt-toolbar{ flex-wrap:wrap; }
  .dt-search{ flex-basis:100%; }
  .dt-filter-wrap{ flex:1; }
  .dt-btn{ width:100%; justify-content:center; }
  .dt-pagination{ justify-content:center; text-align:center; }
  .dt-page-info{ order:3; width:100%; text-align:center; }
}
@media (max-width:640px){
  .cf-card-top{ justify-content:space-between; }
  .cf-range{ width:100%; }
  .cf-range .cf-field{ flex:1 1 45%; }
  .cf-card-actions{ justify-content:stretch; }
  .cf-card-actions .cf-btn{ flex:1; justify-content:center; }
}

/* The backdrop only exists on phones; everywhere else it must stay off.
   This default HAS to sit ABOVE the media query, not below it: a media
   query contributes nothing to specificity, so this rule and the
   .dt-filter-backdrop rule inside @media are both (0,1,0) and plain
   source order decides. With this line underneath the block, it won
   unconditionally -- the phone `display:block` was dead at EVERY viewport
   width and the bottom-sheet opened over an undimmed page, which read as
   "the panel isn't an overlay at all". */
.dt-filter-backdrop{ display:none; }

/* Phone: dt- filter panel becomes a bottom-sheet popover instead of an
   inline row, since a wide field grid can't line up on a phone screen. */
@media (max-width: 560px){
  /* Head and the divider+Apply/Clear row are pinned and only .dt-filter-grid
     scrolls, so the primary action is on screen however many fields a page
     puts in its panel. Capping the panel and letting the whole thing scroll
     as one block (what this did before) hid the actions below the sheet's
     own fold with nothing to signal they were there: Employee Directory's 8
     fields come to ~685px against a min(70vh,560px) cap, so Apply Filters
     sat ~125px past the bottom edge and the sheet looked like it simply
     ended after the last visible field. Same head/body/footer split as
     .dt-dialog below, for the same reason. */
  .dt-filter-panel{
    position:fixed; left:12px; right:12px; bottom:12px; top:auto; margin-bottom:0;
    max-height:min(70vh, 560px); z-index:1040; box-shadow:var(--shadow-md);
    display:flex; flex-direction:column;
  }
  .dt-filter-panel-head, .dt-filter-divider, .dt-filter-actions{ flex:none; }
  /* min-height:0 is load-bearing: a flex item defaults to min-height:auto,
     which refuses to shrink below its content -- the grid would push the
     panel past its own max-height and never become a scroll container. */
  .dt-filter-grid{ flex:1 1 auto; min-height:0; overflow-y:auto; flex-direction:column; }
  .dt-filter-field{ flex-basis:auto; min-width:0; }
  /* .dt-filter-field's own min-width:0 above only lets the FIELD shrink --
     white-space:nowrap on the label (needed on desktop, where labels sit
     in short grid columns) still renders its full text on one line
     regardless, painting past the field's edge since nothing clips it.
     A label like "BIOMETRIC STATUS" is then wider than the phone
     viewport, and because .dt-filter-grid has overflow-y:auto, the
     overflow-x/y coupling rule (a UA can't leave one axis visible while
     the other isn't) forces overflow-x:auto too -- so the grid became
     horizontally scrollable instead of clipping or wrapping the label.
     Single column here has the vertical room a wrapped 2-line label
     needs, so just let it wrap. */
  .dt-filter-field label{ white-space:normal; }
  .dt-filter-backdrop{ display:block; position:fixed; inset:0; background:rgba(10,13,17,.45); z-index:1035; }
  .dt-filter-backdrop[hidden]{ display:none; }
}

/* ============ DIALOG (modal) ============
   Self-contained, same tokens as everything else in this system.
   Structure:
     <button data-dt-dialog-open="ID">...</button>
     <div class="dt-dialog-backdrop" data-dt-dialog="ID" hidden>
       <div class="dt-dialog" role="dialog" aria-modal="true">
         <div class="dt-dialog-header"><h2>...</h2><button data-dt-dialog-close>...</button></div>
         <div class="dt-dialog-body">...</div>
         <div class="dt-dialog-footer">
           <button class="dt-btn" data-dt-dialog-close>Cancel</button>
           <button class="dt-btn dt-btn--primary" type="submit">...</button>
         </div>
       </div>
     </div>
   Wired by initDialogs() in static/js/dt-cf-patterns.js -- opens/closes
   on trigger click, close-button click, backdrop click (not inner
   click), and Escape. z-index sits above the phone filter-panel
   backdrop (1035) and Horilla's own .oh-modal (1021). */
.dt-dialog-backdrop{
  display:flex; align-items:center; justify-content:center;
  position:fixed; inset:0; z-index:1060;
  background:rgba(10,13,17,.45); padding:20px;
}
.dt-dialog-backdrop[hidden]{ display:none; }
/* A2: .dt-dialog is a static frame, not the scrolling element -- overflow
   would otherwise have to be non-visible on at least one axis to cap a
   long form, which unavoidably clips any absolutely-positioned dropdown
   panel opened inside it (an overflow-scrolling ancestor clips descendants
   regardless of z-index or position:absolute -- see the dialog-clipping
   diagnosis this replaces). max-height still caps the box; header/footer
   stay pinned via flex, .dt-dialog-body alone scrolls, so long forms are
   still fully scrollable -- just inside the body, not the whole dialog. */
.dt-dialog{
  background:var(--surface); border-radius:16px; box-shadow:var(--shadow-md);
  width:100%; max-width:440px; max-height:90vh; overflow:visible;
  display:flex; flex-direction:column;
  animation:dt-dialog-in .16s ease;
}
@keyframes dt-dialog-in{ from{ opacity:0; transform:translateY(-8px) scale(.98); } to{ opacity:1; transform:translateY(0) scale(1); } }

.dt-dialog-header{
  flex:none;
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:20px 22px 0;
}
.dt-dialog-header h2{ font-size:16px; font-weight:700; }
.dt-dialog-close{
  width:28px; height:28px; flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
  border:none; background:transparent; color:var(--text-tertiary);
  border-radius:8px; cursor:pointer;
}
.dt-dialog-close:hover{ background:var(--surface-hover); color:var(--text-primary); }
.dt-dialog-close svg{ width:15px; height:15px; }

/* gap:20px on .dt-dialog-body itself only spaces its own DIRECT
   children -- fine for a simple body (confirm_dialog.html's icon +
   <p>, two direct children), a no-op for cbv/user_form.html's dialog:
   its response is one <form> wrapping every field, so .dt-form-field
   and .dt-switch are grandchildren of .dt-dialog-body, never touched
   by this gap. Reused the same 20px on the form itself below, where
   it actually reaches the fields -- not a new value, the header
   above already uses it. Needs to read clearly against
   .dt-form-field's own 6px label-to-control gap: a field group has
   to look like ONE unit and read as clearly apart from the next, not
   just numerically different. */
.dt-dialog-body{
  flex:1 1 auto; min-height:0; overflow-y:auto;
  padding:20px 22px; display:flex; flex-direction:column; gap:20px;
}
.dt-dialog-body p{ margin:0; font-size:13.5px; color:var(--text-secondary); line-height:1.5; }
/* The actual group-to-group spacing for a form-bodied dialog (only
   cbv/user_form.html today) -- see the comment above .dt-dialog-body. */
.dt-dialog-body > form{ display:flex; flex-direction:column; gap:20px; }
/* .dt-switch (the Active toggle) is a bare label, not wrapped in
   .dt-form-field -- it already gets the same 20px as every other
   field-to-field gap from being a sibling in the flex column above,
   this adds a bit more on top so a different CONTROL TYPE (not just
   a different field) reads as a deliberate break, not a rounding
   difference. 6px is .dt-form-field's own internal gap value, not a
   new number -- "one more small-unit past the standard gap". */
.dt-dialog-body > form > .dt-switch{ margin-top:6px; }

/* border-top gives the footer an actual boundary against the last
   field, rather than relying on stacked padding (.dt-dialog-body's own
   bottom padding + this one's top padding) to read as a deliberate gap
   with nothing marking where the content ends and the actions begin. */
.dt-dialog-footer{
  flex:none;
  display:flex; justify-content:flex-end; gap:8px;
  padding:16px 22px 22px;
  border-top:1px solid var(--border);
}
.dt-dialog-footer .dt-btn{ height:38px; }

@media (max-width:520px){
  .dt-dialog-footer{ flex-direction:column-reverse; }
  .dt-dialog-footer .dt-btn{ width:100%; justify-content:center; }
  .dt-dialog-footer input{ width:100%; flex:none; }
}

body.dt-dialog-open-lock{ overflow:hidden; }

/* ============ ROW ACTION ICONS ============
   New, purpose-named icon-button set for row actions (Edit/Archive/
   Delete/etc) -- distinct from .dt-icon-btn (used ad-hoc in Crew today):
   bordered "chip" look instead of a borderless hover-fill, and each
   variant is named by INTENT (--edit/--archive/--delete), not by color,
   so a future action (e.g. "Restore") just picks the right semantic
   class instead of a color that happens to look right. */
.dt-row-actions{ display:flex; gap:6px; align-items:center; }
.dt-row-action{
  width:32px; height:32px; border-radius:9px;
  border:1px solid var(--border); background:var(--surface); color:var(--text-secondary);
  display:inline-flex; align-items:center; justify-content:center;
  cursor:pointer; transition:background .12s ease, border-color .12s ease, color .12s ease;
  flex-shrink:0;
}
.dt-row-action svg{ width:16px; height:16px; }
.dt-row-action:hover{ background:var(--surface-hover); border-color:var(--border-strong); color:var(--text-primary); }
.dt-row-action--edit:hover{ background:var(--accent-soft); border-color:var(--accent); color:var(--accent); }
.dt-row-action--archive:hover{ background:var(--amber-soft); border-color:var(--amber); color:var(--amber); }
.dt-row-action--delete:hover{ background:var(--danger-soft); border-color:var(--danger); color:var(--danger); }
.dt-row-action--restore:hover{ background:var(--success-soft); border-color:var(--success); color:var(--success); }

/* ============ MULTI-SELECT DROPDOWN (inline expand) ============
   Compact, closed-by-default multi-value filter -- replaces the native
   <select multiple> listbox, which renders as a tall always-open box.
   Floats as an absolute overlay (aligned with search-select/multi-search
   below) instead of pushing following grid rows down; themed scrollbar +
   drop-in animation to match the others. No Select2/jQuery dependency;
   checkboxes submit as repeated GET params under the same field name,
   exactly like a native multi-select would. Checkbox itself is visually
   hidden -- selection highlights via an accent background/text instead.
   Structure: see components/dt/multiselect.html. */
.dt-multiselect{ display:flex; flex-direction:column; gap:6px; position:relative; }
.dt-multiselect-trigger{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  width:100%; text-align:left; cursor:pointer; background-image:none;
}
.dt-multiselect-trigger span{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.dt-multiselect-trigger .dt-chev{ flex-shrink:0; width:12px; height:12px; color:var(--text-tertiary); transition:transform .15s ease; }
.dt-multiselect[data-open="true"] .dt-multiselect-trigger .dt-chev{ transform:rotate(180deg); }
.dt-multiselect-panel{
  /* At least as wide as the trigger (so it's never narrower than the
     field), free to grow wider to fit long option text (e.g. location
     codes) up to a cap so it can't sprawl on a very wide/narrow-field
     layout like the filter grid. */
  position:absolute; top:calc(100% + 4px); left:0; z-index:30;
  min-width:100%; width:max-content; max-width:320px;
  background:var(--surface-2); border:1px solid var(--border); border-radius:10px;
  padding:6px; max-height:180px; overflow-y:auto;
  box-shadow:var(--shadow-md);
  animation:dt-drop-in .14s ease;
  scrollbar-width:thin; scrollbar-color:var(--border-strong) transparent;
}
.dt-multiselect-panel[hidden]{ display:none; }
.dt-multiselect-panel::-webkit-scrollbar{ width:8px; }
.dt-multiselect-panel::-webkit-scrollbar-track{ background:transparent; }
.dt-multiselect-panel::-webkit-scrollbar-thumb{ background:var(--border-strong); border-radius:8px; border:2px solid var(--surface-2); }
.dt-multiselect-panel::-webkit-scrollbar-thumb:hover{ background:var(--text-tertiary); }
/* Optional live-filter input (searchable=True on components/dt/
   multiselect.html) -- sticky at the panel's own scroll top so it stays
   visible while scrolling a long option list, background matches the
   panel so scrolled-past options don't show through underneath it. */
.dt-multiselect-search{
  box-sizing:border-box; width:100%; height:30px; padding:0 8px; margin-bottom:6px;
  border-radius:7px; border:1px solid var(--border); background:var(--surface-2); color:var(--text-primary);
  font-size:12.5px; position:sticky; top:0; z-index:1;
}
.dt-multiselect-search:focus-visible{ outline:none; border-color:var(--accent); }
.dt-multiselect-option{
  display:flex; align-items:center; gap:9px; padding:7px 8px; border-radius:7px;
  font-size:13px; color:var(--text-primary); cursor:pointer;
  transition:background .12s ease;
}
.dt-multiselect-option:hover{ background:var(--surface-hover); }
.dt-multiselect-option input{ position:absolute; opacity:0; width:1px; height:1px; pointer-events:none; }
.dt-multiselect-option span{ color:var(--text-primary); }
.dt-multiselect-option:has(input:checked){ background:var(--accent-soft); }
.dt-multiselect-option:has(input:checked) span{ color:var(--accent); font-weight:600; }
.dt-multiselect-option.is-selected{ background:var(--accent-soft); color:var(--accent); font-weight:600; }
.dt-multiselect-empty{ padding:10px 8px; font-size:12.5px; color:var(--text-tertiary); }

/* ============ SEARCH SELECT (type-ahead combobox) ============
   Single-value field for a large option list (hundreds of rows) where
   a checkbox panel (.dt-multiselect) or a plain <select> would be
   unusable -- e.g. searching project/task codes by number or name.
   Typing filters the option list live. Floats as an absolutely-
   positioned overlay: a type-ahead list is expected to sit above
   surrounding content, not push it down the page as you type.
   Structure: see components/dt/searchselect.html. */
.dt-searchselect{ position:relative; }
.dt-searchselect-input{ padding-right:30px; background-image:none; }
.dt-searchselect-clear{
  position:absolute; top:50%; right:8px; transform:translateY(-50%);
  width:18px; height:18px; padding:0; border:none; background:none;
  color:var(--text-tertiary); cursor:pointer; display:none; align-items:center; justify-content:center;
}
.dt-searchselect[data-has-value="true"] .dt-searchselect-clear{ display:flex; }
.dt-searchselect-panel{
  position:absolute; top:calc(100% + 4px); left:0; z-index:30;
  min-width:100%; width:max-content; max-width:320px;
  background:var(--surface-2); border:1px solid var(--border); border-radius:10px;
  padding:6px; max-height:220px; overflow-y:auto; box-shadow:var(--shadow-md);
  animation:dt-drop-in .14s ease;
  scrollbar-width:thin; scrollbar-color:var(--border-strong) transparent;
}
.dt-searchselect-panel[hidden]{ display:none; }
.dt-searchselect-panel::-webkit-scrollbar{ width:8px; }
.dt-searchselect-panel::-webkit-scrollbar-track{ background:transparent; }
.dt-searchselect-panel::-webkit-scrollbar-thumb{ background:var(--border-strong); border-radius:8px; border:2px solid var(--surface-2); }
.dt-searchselect-panel::-webkit-scrollbar-thumb:hover{ background:var(--text-tertiary); }
.dt-searchselect-option{
  padding:7px 9px; border-radius:7px; font-size:13px; color:var(--text-primary); cursor:pointer;
}
.dt-searchselect-option:hover, .dt-searchselect-option.is-active{ background:var(--surface-hover); }
.dt-searchselect-option[hidden]{ display:none; }
.dt-searchselect-empty{ padding:10px 9px; font-size:12.5px; color:var(--text-tertiary); }
.dt-searchselect-empty[hidden]{ display:none; }

/* ============ MULTI SEARCH (type-ahead combobox, multiple selection) ============
   Tag-style multi-value search field for option lists too large to
   scan as a checkbox panel (.dt-multiselect) -- e.g. picking employees
   by name. Selected values render as removable rows stacked inside
   the bordered box (not inline chips -- labels here run long: "Name -
   Role (ID)"); typing below them filters an overlay panel, same
   overlay approach as .dt-searchselect. Requires >=1 typed character
   before showing matches -- scanning hundreds of rows unfiltered
   isn't useful -- so the panel shows a hint instead of the option
   list until then. Structure: see components/dt/multisearch.html. */
.dt-multisearch{ position:relative; }
.dt-multisearch-box{
  display:flex; flex-direction:column; width:100%; min-height:36px;
  padding:2px 8px; border-radius:8px; border:1px solid var(--border);
  background:var(--surface-2); cursor:text;
}
.dt-multisearch-box:hover{ border-color:var(--border-strong); }
.dt-multisearch[data-open="true"] .dt-multisearch-box{ border-color:var(--accent); box-shadow:var(--focus-ring); }
.dt-multisearch-tag{
  display:flex; align-items:center; gap:7px; padding:6px 2px;
  border-bottom:1px solid var(--border); font-size:13px; color:var(--info); line-height:1.3;
}
.dt-multisearch-tag:last-child{ border-bottom:none; }
.dt-multisearch-tag span{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.dt-multisearch-tag--invalid{ color:var(--danger); }
.dt-multisearch-tag--invalid span::after{ content:" — not found"; color:var(--text-tertiary); font-weight:400; }
.dt-multisearch-remove{
  flex-shrink:0; width:16px; height:16px; padding:0; border:none; background:none;
  color:var(--text-tertiary); cursor:pointer; display:flex; align-items:center; justify-content:center;
}
.dt-multisearch-remove:hover{ color:var(--danger); }
.dt-multisearch-input{
  width:100%; border:none; outline:none; background:none; padding:6px 2px;
  font-size:13px; color:var(--text-primary);
}
.dt-multisearch-input:focus-visible{ box-shadow:none; }
.dt-multisearch-input::placeholder{ color:var(--text-tertiary); }
.dt-multisearch-panel{
  position:absolute; top:calc(100% + 4px); left:0; z-index:30;
  min-width:100%; width:max-content; max-width:320px;
  background:var(--surface-2); border:1px solid var(--border); border-radius:10px;
  padding:6px; max-height:240px; overflow-y:auto; box-shadow:var(--shadow-md);
  animation:dt-drop-in .14s ease;
  scrollbar-width:thin; scrollbar-color:var(--border-strong) transparent;
}
.dt-multisearch-panel[hidden]{ display:none; }
.dt-multisearch-panel::-webkit-scrollbar{ width:8px; }
.dt-multisearch-panel::-webkit-scrollbar-track{ background:transparent; }
.dt-multisearch-panel::-webkit-scrollbar-thumb{ background:var(--border-strong); border-radius:8px; border:2px solid var(--surface-2); }
.dt-multisearch-panel::-webkit-scrollbar-thumb:hover{ background:var(--text-tertiary); }
.dt-multisearch-option{
  padding:7px 9px; border-radius:7px; font-size:13px; color:var(--text-primary); cursor:pointer;
}
.dt-multisearch-option:hover, .dt-multisearch-option.is-active{ background:var(--surface-hover); }
.dt-multisearch-option[hidden]{ display:none; }
.dt-multisearch-hint, .dt-multisearch-empty{ padding:10px 9px; font-size:12.5px; color:var(--text-tertiary); }
.dt-multisearch-hint[hidden], .dt-multisearch-empty[hidden]{ display:none; }

/* ============ AJAX MULTI SELECT (server-search combobox, multiple
   selection) ============
   Same tag-stack-in-a-box + overlay-panel shape as .dt-multisearch
   directly above, for the same reason (option labels here run long:
   "Name - Role (ID)") -- the difference is entirely behavioral, not
   visual: this one's [data-dt-ajaxmultiselect-results] is populated
   from whatever the last live search request returned rather than
   filtering a list that was already fully rendered. See
   components/dt/ajaxmultiselect.html and initAjaxMultiSelects() in
   dt-cf-patterns.js. */
.dt-ajaxmultiselect{ position:relative; }
.dt-ajaxmultiselect-box{
  display:flex; flex-direction:column; width:100%; min-height:36px;
  padding:2px 8px; border-radius:8px; border:1px solid var(--border);
  background:var(--surface-2); cursor:text;
}
.dt-ajaxmultiselect-box:hover{ border-color:var(--border-strong); }
.dt-ajaxmultiselect[data-open="true"] .dt-ajaxmultiselect-box{ border-color:var(--accent); box-shadow:var(--focus-ring); }
.dt-ajaxmultiselect-tag{
  display:flex; align-items:center; gap:7px; padding:6px 2px;
  border-bottom:1px solid var(--border); font-size:13px; color:var(--info); line-height:1.3;
}
.dt-ajaxmultiselect-tag:last-child{ border-bottom:none; }
.dt-ajaxmultiselect-tag span{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.dt-ajaxmultiselect-remove{
  flex-shrink:0; width:16px; height:16px; padding:0; border:none; background:none;
  color:var(--text-tertiary); cursor:pointer; display:flex; align-items:center; justify-content:center;
}
.dt-ajaxmultiselect-remove:hover{ color:var(--danger); }
.dt-ajaxmultiselect-input{
  width:100%; border:none; outline:none; background:none; padding:6px 2px;
  font-size:13px; color:var(--text-primary);
}
.dt-ajaxmultiselect-input:focus-visible{ box-shadow:none; }
.dt-ajaxmultiselect-input::placeholder{ color:var(--text-tertiary); }
.dt-ajaxmultiselect-panel{
  position:absolute; top:calc(100% + 4px); left:0; z-index:30;
  min-width:100%; width:max-content; max-width:320px;
  background:var(--surface-2); border:1px solid var(--border); border-radius:10px;
  padding:6px; max-height:240px; overflow-y:auto; box-shadow:var(--shadow-md);
  animation:dt-drop-in .14s ease;
  scrollbar-width:thin; scrollbar-color:var(--border-strong) transparent;
}
.dt-ajaxmultiselect-panel[hidden]{ display:none; }
.dt-ajaxmultiselect-panel::-webkit-scrollbar{ width:8px; }
.dt-ajaxmultiselect-panel::-webkit-scrollbar-track{ background:transparent; }
.dt-ajaxmultiselect-panel::-webkit-scrollbar-thumb{ background:var(--border-strong); border-radius:8px; border:2px solid var(--surface-2); }
.dt-ajaxmultiselect-panel::-webkit-scrollbar-thumb:hover{ background:var(--text-tertiary); }
.dt-ajaxmultiselect-loading{ padding:10px 9px; }
.dt-ajaxmultiselect-loading[hidden]{ display:none; }
.dt-ajaxmultiselect-option{
  padding:7px 9px; border-radius:7px; font-size:13px; color:var(--text-primary); cursor:pointer;
}
.dt-ajaxmultiselect-option:hover, .dt-ajaxmultiselect-option.is-active{ background:var(--surface-hover); }
.dt-ajaxmultiselect-hint, .dt-ajaxmultiselect-empty{ padding:10px 9px; font-size:12.5px; color:var(--text-tertiary); }
.dt-ajaxmultiselect-hint[hidden], .dt-ajaxmultiselect-empty[hidden]{ display:none; }

/* Selected-values summary, shown under the trigger once its own label
   has collapsed to "N selected" and stopped naming anything -- each chip
   removes its own value without opening the panel. */
.dt-multiselect-chips{ display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; }
.dt-multiselect-chips:empty{ display:none; margin-top:0; }
/* No fixed height -- a long label (e.g. "TGT UAE Electrical Division")
   wraps to 2 lines in a narrow filter field, and a fixed height crammed
   that wrapped text against the pill's top/bottom edges with zero
   breathing room. min-height + real vertical padding lets it grow.
   max-width/overflow-wrap is what actually MAKES that wrapping happen,
   though -- .dt-multiselect-chips' own flex-wrap only spreads MULTIPLE
   chips across lines, it can't shrink a SINGLE chip's unconstrained
   content. Without a width cap here, one long label just rendered on
   one unbroken line wider than the field -- invisible on a spacious
   desktop grid column, but on a phone's single-column filter panel
   (whose .dt-filter-grid has overflow-y:auto, forcing overflow-x:auto
   too via the same axis-coupling rule the label fix above deals with)
   that one oversized chip dragged the whole grid into horizontal
   scroll the moment enough options got selected to show it. */
.dt-multiselect-chip{ display:inline-flex; align-items:center; gap:4px; min-height:22px; max-width:100%; padding:4px 6px 4px 9px; border-radius:999px; background:var(--accent-soft); color:var(--accent); font-size:11.5px; font-weight:600; overflow-wrap:anywhere; }
.dt-multiselect-chip button{ display:flex; align-items:center; justify-content:center; width:14px; height:14px; border:none; background:none; padding:0; color:inherit; opacity:.65; cursor:pointer; border-radius:50%; }
.dt-multiselect-chip button:hover{ opacity:1; background:rgba(0,0,0,.08); }
.dt-multiselect-chip svg{ width:9px; height:9px; }

/* Coolio: every table header goes navy/mono/uppercase, matching the
   grouped-report table's look -- placed here (before .dt-table--grouped's
   own rules further down) so a grouped table's group/sub-row backgrounds
   still win on the source-order tie-break. */
[data-theme="coolio"] .dt-table thead th{ background:var(--navy-deep); color:var(--on-navy); font-family:var(--font-display); font-weight:600; letter-spacing:.04em; }
[data-theme="coolio"] .dt-table thead th.sortable:hover{ color:var(--on-navy-soft); }
[data-theme="coolio"] .dt-table th[data-pin]{ background:var(--navy-deep); }
[data-theme="coolio"] .dt-sort-icon.active{ color:var(--amber); }

/* Coolio: the dropdown/search family -- same markup and the same
   data-dt-* JS as Standard, only the trigger/input chrome, the floating
   panel, and the open-state accent change. Option-row LABEL TEXT stays
   on --font-body (not mono) since these lists are full of proper nouns
   (names, locations) that mono would hurt. */
[data-theme="coolio"] .dt-filter-field label{ font-family:var(--font-mono); }
[data-theme="coolio"] .dt-select, [data-theme="coolio"] .dt-date, [data-theme="coolio"] .cf-input, [data-theme="coolio"] .cf-select, [data-theme="coolio"] .cf-date{
  font-family:var(--font-mono); font-size:12.5px; background:var(--surface); border-radius:var(--radius-sm);
}
[data-theme="coolio"] .dt-select:hover, [data-theme="coolio"] .dt-date:hover, [data-theme="coolio"] .cf-input:hover, [data-theme="coolio"] .cf-select:hover, [data-theme="coolio"] .cf-date:hover{ border-color:var(--text-tertiary); }
[data-theme="coolio"] .dt-multiselect[data-open="true"] .dt-multiselect-trigger{ border-color:var(--accent); }
[data-theme="coolio"] .dt-searchselect-input:focus-visible{ border-color:var(--accent); }
[data-theme="coolio"] .dt-multisearch-box{ font-family:var(--font-mono); font-size:12.5px; background:var(--surface); border-radius:var(--radius-sm); }
[data-theme="coolio"] .dt-multisearch[data-open="true"] .dt-multisearch-box{ border-color:var(--accent); }
[data-theme="coolio"] .dt-multisearch-tag{ color:var(--accent); font-family:var(--font-body); }
[data-theme="coolio"] .dt-multisearch-input{ font-family:var(--font-body); }
[data-theme="coolio"] .dt-ajaxmultiselect-box{ font-family:var(--font-mono); font-size:12.5px; background:var(--surface); border-radius:var(--radius-sm); }
[data-theme="coolio"] .dt-ajaxmultiselect[data-open="true"] .dt-ajaxmultiselect-box{ border-color:var(--accent); }
[data-theme="coolio"] .dt-ajaxmultiselect-tag{ color:var(--accent); font-family:var(--font-body); }
[data-theme="coolio"] .dt-ajaxmultiselect-input{ font-family:var(--font-body); }
[data-theme="coolio"] .dt-multiselect-panel, [data-theme="coolio"] .dt-searchselect-panel, [data-theme="coolio"] .dt-multisearch-panel, [data-theme="coolio"] .dt-ajaxmultiselect-panel{
  background:var(--surface); border-radius:var(--radius-sm); border-color:var(--border-strong);
}
[data-theme="coolio"] .dt-multiselect-panel::-webkit-scrollbar-thumb, [data-theme="coolio"] .dt-searchselect-panel::-webkit-scrollbar-thumb, [data-theme="coolio"] .dt-multisearch-panel::-webkit-scrollbar-thumb, [data-theme="coolio"] .dt-ajaxmultiselect-panel::-webkit-scrollbar-thumb{ border-color:var(--surface); }
[data-theme="coolio"] .dt-multiselect-option, [data-theme="coolio"] .dt-searchselect-option, [data-theme="coolio"] .dt-multisearch-option, [data-theme="coolio"] .dt-ajaxmultiselect-option{
  font-family:var(--font-body); font-size:13px; border-radius:6px;
}
[data-theme="coolio"] .dt-multiselect-empty, [data-theme="coolio"] .dt-searchselect-empty, [data-theme="coolio"] .dt-multisearch-empty, [data-theme="coolio"] .dt-multisearch-hint, [data-theme="coolio"] .dt-ajaxmultiselect-empty, [data-theme="coolio"] .dt-ajaxmultiselect-hint{ font-family:var(--font-mono); }

/* ============================================================
   Loading state -- skeleton rows preview the real column shapes (pill
   for badge columns, wider bar for the name column) instead of a
   generic centered spinner, plus a small active spinner + label up in
   the header while the fetch is in flight.
   ============================================================ */
.dt-skeleton-row td{ padding:15px 20px; }
.dt-skeleton-bar{ display:inline-block; height:11px; border-radius:5px; background:var(--border); position:relative; overflow:hidden; }
.dt-skeleton-bar::after{
  content:''; position:absolute; inset:0; transform:translateX(-100%);
  background:linear-gradient(90deg, transparent, var(--surface-hover), transparent);
}
@media (prefers-reduced-motion:no-preference){
  .dt-skeleton-bar::after{ animation:dt-shimmer 1.4s ease-in-out infinite; }
}
@keyframes dt-shimmer{ to{ transform:translateX(100%); } }
.dt-loading-flag{ display:inline-flex; align-items:center; gap:7px; font-size:12.5px; color:var(--text-secondary); }
.dt-spinner{ width:12px; height:12px; border-radius:50%; border:2px solid var(--border-strong); border-top-color:var(--accent); flex-shrink:0; }
@media (prefers-reduced-motion:no-preference){
  .dt-spinner{ animation:dt-spin .7s linear infinite; }
}
@keyframes dt-spin{ to{ transform:rotate(360deg); } }

/* htmx's own default indicator behavior only exists if htmx.css is
   included, which this project doesn't load -- so .dt-loading-flag
   needs its own hidden/shown rule to work as an hx-indicator target. */
.htmx-indicator{ display:none; }
.htmx-request.htmx-indicator, .htmx-request .htmx-indicator{ display:inline-flex; }

/* htmxLoadIndicator() (static/index/index.js) is a legacy helper written
   for the old oh-table/fixed-table markup: on submit it blanks every
   <th>/<td> in the target's <table> so the .oh-table.is-loading /
   .fixed-table.is-loading shimmer CSS (style.min.css) can take over. dt-
   tables have no such shimmer rule, so that blanking used to leave rows
   with borders/padding but no content -- dense, blank-looking striped
   rows during any search/filter/sort request. htmxLoadIndicator() now
   skips the blanking for dt- tables and instead marks the whole view
   (the .dt-app wrapper dt_list_table.html renders, badge/table/pagination
   together) as loading here, so the current rows just dim in place
   instead of being destroyed or looking broken. */
.dt-app.is-loading{ opacity:.5; pointer-events:none; transition:opacity .15s ease; }

/* ============================================================
   Dashboard / hierarchy / provisioning primitives, ported verbatim
   (class names and token references) from docs/style-guide-standalone.html.
   Everything below is token-driven, so it already works under all four
   theme x mode combinations with no extra rules -- Coolio's distinct
   look (corner ticks, navy app-bar, blueprint grid, the three Google
   fonts) comes entirely from the --navy-deep/--on-navy/--font-* values
   Coolio's token block sets, not from separate markup.
   ============================================================ */

body[data-theme="coolio"]{ background:
      linear-gradient(var(--grid-line) 1px, transparent 1px) 0 0 / 42px 42px,
      linear-gradient(90deg, var(--grid-line) 1px, transparent 1px) 0 0 / 42px 42px,
      var(--canvas); }
body[data-theme="coolio"] .dt-app, body[data-theme="coolio"] .cf-app{ -webkit-font-smoothing:antialiased; }

/* ---- App bar (topbar/brand/bell/avatar) ---- */
.dt-appbar{ display:flex; align-items:center; justify-content:space-between; gap:16px; padding:14px 28px; background:var(--navy-deep); border-bottom:2px solid var(--amber); border-radius:var(--radius-lg) var(--radius-lg) 0 0; color:var(--on-navy); margin-bottom:24px; }
.dt-appbar__left{ display:flex; align-items:center; gap:14px; }
.dt-appbar__burger{ display:flex; flex-direction:column; gap:3px; width:18px; cursor:pointer; }
.dt-appbar__burger span{ height:2px; background:var(--on-navy-faint); border-radius:2px; }
.dt-appbar__brand{ display:flex; align-items:baseline; gap:8px; }
.dt-appbar__brand-word{ font-family:var(--font-display); font-weight:700; font-size:18px; letter-spacing:.2px; color:var(--on-navy); }
.dt-appbar__brand-ar{ font-size:13px; color:var(--on-navy-faint); }
.dt-appbar__right{ display:flex; align-items:center; gap:18px; }
.dt-appbar__sync{ display:flex; align-items:center; gap:7px; font-family:var(--font-mono); font-size:11px; color:var(--on-navy-faint); letter-spacing:.03em; }
.dt-appbar__sync-dot{ width:6px; height:6px; border-radius:50%; background:var(--success); box-shadow:0 0 0 3px var(--success-soft); }
.dt-appbar__bell{ position:relative; width:32px; height:32px; display:grid; place-items:center; border-radius:8px; }
.dt-appbar__bell svg{ width:17px; height:17px; stroke:var(--on-navy-soft); }
.dt-appbar__bell-badge{ position:absolute; top:3px; right:4px; width:14px; height:14px; border-radius:50%; background:var(--amber); color:var(--navy-deep); font-size:9px; font-weight:700; display:grid; place-items:center; font-family:var(--font-mono); }
.dt-appbar__avatar{ display:flex; align-items:center; gap:9px; padding:5px 10px 5px 5px; border:1px solid rgba(255,255,255,.12); border-radius:20px; }
.dt-appbar__avatar-pic{ width:24px; height:24px; border-radius:50%; background:var(--success); display:grid; place-items:center; font-size:10px; font-weight:700; color:var(--on-navy); font-family:var(--font-display); }
.dt-appbar__avatar-name{ font-size:12.5px; color:var(--on-navy-soft); }
.dt-appbar__bell:focus-visible, .dt-appbar__avatar:focus-visible{ outline:2px solid var(--amber); outline-offset:2px; }

/* ---- Date stamp pill (small mono date/range readout) ---- */
.dt-datestamp{ font-family:var(--font-mono); font-size:11.5px; color:var(--text-secondary); background:var(--surface); border:1px solid var(--border); padding:7px 12px; border-radius:8px; }

/* ---- Vertical section stack ----
   Spacing between stacked page sections lives here, not on the sections
   themselves: only the *-grid wrappers (.dt-stat-grid, .dt-charts-grid,
   .dt-summary-grid) carry their own margin-bottom, so a bare .dt-card or
   table panel placed after one sits flush against it. Wrap a page's
   sections in .dt-stack and every child is spaced consistently regardless
   of which kind it is. Child margins are zeroed so the gap is the single
   source of spacing (otherwise a grid's margin-bottom would add to it). */
.dt-stack{ display:flex; flex-direction:column; gap:16px; }
.dt-stack > *{ margin-bottom:0; }

/* ---- Equal-height cards inside the dt- grids ----
   A grid already stretches its tracks, but a card wrapped in a link (the
   common case -- a whole tile that navigates somewhere) doesn't inherit
   that height, so tiles with less content than their neighbours (no bar,
   no caption) render short. Make the wrapper stretch and the card fill it,
   so a row of tiles always lines up regardless of which optional parts
   each one happens to use. */
.dt-stat-grid > *, .dt-summary-grid > *, .dt-charts-grid > *{ min-width:0; }
.dt-stat-grid > a, .dt-summary-grid > a, .dt-charts-grid > a{ display:flex; text-decoration:none; }
.dt-stat-grid > a > .dt-card, .dt-summary-grid > a > .dt-card, .dt-charts-grid > a > .dt-card{ flex:1; }
.dt-stat-grid > .dt-card, .dt-summary-grid > .dt-card, .dt-charts-grid > .dt-card{ height:100%; }

/* ---- Card (generalizes .cf-card; adds Coolio's corner-tick + accent-rail
   treatment as a markup-superset the Standard skin just hides) ---- */
.dt-card{ position:relative; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-lg); box-shadow:var(--shadow-sm); padding:20px 20px 18px 22px; isolation:isolate; }
.dt-card::before{ content:""; position:absolute; left:0; top:14px; bottom:14px; width:3px; background:var(--card-accent, var(--accent)); border-radius:0 3px 3px 0; display:none; }
[data-theme="coolio"] .dt-card::before{ display:block; }
.dt-card__corner{ position:absolute; width:11px; height:11px; border-color:var(--card-accent, var(--accent)); opacity:.4; pointer-events:none; display:none; }
[data-theme="coolio"] .dt-card__corner{ display:block; }
.dt-card__corner--tl{ top:9px; right:12px; border-top:1.4px solid; border-right:1.4px solid; }
.dt-card__corner--br{ bottom:9px; right:12px; border-bottom:1.4px solid; }
.dt-card--lift{ transition: transform .18s ease, box-shadow .18s ease; }
.dt-card--lift:hover{ transform:translateY(-3px); box-shadow:var(--shadow-md); }
.dt-card--column{ display:flex; flex-direction:column; }

/* Accent swap for a card and its descendants (stat icon, rail, corners).
   Named --card-accent (not --accent) so it can't shadow the theme's own
   --accent used elsewhere (e.g. .dt-btn--primary) for anyone nesting a
   primary button inside an accented card. */
/* .dt-dialog-backdrop is included alongside .dt-app/.cf-app on every
   rule below -- a data-accent element inside a dialog rendered as a
   sibling of .dt-app (the established placement for every dialog in
   this system) would otherwise get no --card-accent/--card-accent-soft
   at all, the same "theme tokens don't reach outside .dt-app" failure
   documented for the four base theme-token blocks. Fixed the same way:
   add the overlay's root class to the token selector list, never by
   moving tokens to :root or relocating the dialog into .dt-app. First
   hit by crew Hierarchy's dialog badge (data-accent on #hierModalBadge,
   inside #hierOverlay). */
.dt-app [data-accent="teal"], .cf-app [data-accent="teal"], .dt-dialog-backdrop [data-accent="teal"]{ --card-accent: var(--success); --card-accent-soft: var(--success-soft); }
.dt-app [data-accent="amber"], .cf-app [data-accent="amber"], .dt-dialog-backdrop [data-accent="amber"]{ --card-accent: var(--amber); --card-accent-soft: var(--amber-soft); }
.dt-app [data-accent="red"], .cf-app [data-accent="red"], .dt-dialog-backdrop [data-accent="red"]{ --card-accent: var(--danger); --card-accent-soft: var(--danger-soft); }
.dt-app [data-accent="slate"], .cf-app [data-accent="slate"], .dt-dialog-backdrop [data-accent="slate"]{ --card-accent: var(--slate); --card-accent-soft: var(--slate-soft); }
.dt-app [data-accent="navy"], .cf-app [data-accent="navy"], .dt-dialog-backdrop [data-accent="navy"]{ --card-accent: var(--navy-deep); --card-accent-soft: var(--slate-soft); }

.dt-card__head{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; margin-bottom:10px; flex-wrap:wrap; }
.dt-card__head h2{ font-family:var(--font-display); font-size:15px; font-weight:600; margin:0; display:flex; align-items:center; gap:8px; }
.dt-card__head h2 svg{ width:15px; height:15px; stroke:var(--card-accent, var(--accent)); fill:none; stroke-width:1.7; }
.dt-card__sub{ font-size:11px; color:var(--text-tertiary); font-family:var(--font-mono); }
.dt-card__foot{ margin-top:auto; padding-top:12px; font-size:10.5px; color:var(--text-tertiary); font-family:var(--font-mono); border-top:1px dashed var(--border); text-align:center; }

/* ---- Stat cards (icon + big mono value + progress bar) ---- */
.dt-stat-grid{ display:grid; grid-template-columns:repeat(4,1fr); gap:16px; margin-bottom:18px; }
.dt-stat__eyebrow{ display:flex; align-items:center; gap:8px; color:var(--text-secondary); font-size:12px; font-weight:600; text-transform:uppercase; letter-spacing:.06em; margin-bottom:14px; }
.dt-stat__icon{ width:26px; height:26px; border-radius:7px; display:grid; place-items:center; background:var(--card-accent-soft, var(--accent-soft)); flex:none; }
.dt-stat__icon svg{ width:14px; height:14px; stroke:var(--card-accent, var(--accent)); fill:none; stroke-width:1.7; }
.dt-stat__value{ font-family:var(--font-mono); font-weight:600; font-size:32px; letter-spacing:-.01em; color:var(--text-primary); line-height:1; margin-bottom:14px; }
.dt-stat__bar{ height:4px; border-radius:3px; background:var(--slate-soft); overflow:hidden; margin-bottom:8px; }
.dt-stat__bar span{ display:block; height:100%; background:var(--card-accent, var(--accent)); border-radius:3px; }
.dt-stat__pct{ font-size:11.5px; color:var(--text-tertiary); font-family:var(--font-mono); }

/* ---- Donut charts + legend (Chart.js canvas wrapper) ---- */
.dt-charts-grid{ display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-bottom:16px; }
.dt-donut{ position:relative; width:168px; height:168px; margin:6px auto 4px; }
.dt-donut__center{ position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; pointer-events:none; }
.dt-donut__center strong{ font-family:var(--font-mono); font-size:19px; font-weight:600; color:var(--text-primary); }
.dt-donut__center span{ font-size:10.5px; color:var(--text-tertiary); text-transform:uppercase; letter-spacing:.05em; margin-top:2px; }
.dt-legend{ list-style:none; margin:14px 0 0; padding:0; }
.dt-legend li{ display:flex; align-items:center; gap:9px; padding:7px 0; border-bottom:1px solid var(--border); font-size:12.5px; }
.dt-legend li:last-child{ border-bottom:none; }
.dt-legend__dot{ width:8px; height:8px; border-radius:2px; flex:none; }
.dt-legend__lbl{ flex:1; color:var(--text-secondary); }
.dt-legend b{ font-family:var(--font-mono); font-weight:600; color:var(--text-primary); font-size:12px; }

/* ---- Summary cards (label + big value + note, no icon/bar) ---- */
.dt-summary-grid{ display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-bottom:16px; }
.dt-summary__label{ font-size:12px; font-weight:600; text-transform:uppercase; letter-spacing:.06em; color:var(--text-secondary); margin-bottom:10px; }
.dt-summary__row{ display:flex; align-items:baseline; justify-content:space-between; }
.dt-summary__value{ font-family:var(--font-mono); font-weight:600; font-size:30px; color:var(--text-primary); }
.dt-summary__note{ font-size:11.5px; color:var(--text-tertiary); font-family:var(--font-mono); }

/* ---- Meters (two-column labeled progress-bar comparison) ---- */
.dt-meter-grid{ display:grid; grid-template-columns:1fr 1fr; gap:22px; margin-top:8px; }
.dt-meter__top{ display:flex; align-items:baseline; justify-content:space-between; margin-bottom:8px; }
.dt-meter__value{ font-family:var(--font-mono); font-weight:600; font-size:24px; }
.dt-meter__label{ font-size:12px; color:var(--text-secondary); }
.dt-meter__pct{ font-family:var(--font-mono); font-size:12px; font-weight:600; }
.dt-meter__bar{ height:6px; border-radius:4px; background:var(--slate-soft); overflow:hidden; }
.dt-meter__bar span{ display:block; height:100%; border-radius:4px; }

/* ---- Grouped/report table (two-tier header) -- a TABLE-SHAPE variant
   available in both themes, not a theme concern. Layers on top of the
   base .dt-table styling defined earlier in this file. ---- */
.dt-table--grouped{ min-width:820px; }
.dt-table--grouped thead th{ background:none; }
.dt-table--grouped thead .dt-table__group-row th{ background:var(--navy-deep); color:var(--on-navy); font-family:var(--font-display); font-size:11.5px; font-weight:600; letter-spacing:.04em; padding:10px 14px; text-transform:uppercase; border-bottom:none; }
.dt-table--grouped thead .dt-table__sub-row th{ background:var(--navy-deep-2); color:var(--on-navy-soft); font-family:var(--font-mono); font-size:10.5px; font-weight:500; letter-spacing:.04em; padding:8px 14px; text-transform:uppercase; border-top:1px solid rgba(255,255,255,.08); border-bottom:none; }
.dt-table--grouped thead .dt-table__group-row th:first-child, .dt-table--grouped thead .dt-table__sub-row th:first-child{ text-align:left; }
.dt-table--grouped th, .dt-table--grouped td{ text-align:right; white-space:nowrap; }
.dt-table--grouped td{ padding:10px 14px; font-family:var(--font-mono); font-size:12.5px; color:var(--text-primary); border-bottom:1px solid var(--border); }
.dt-table--grouped .dt-table__cell--label{ text-align:left; font-family:var(--font-body); font-weight:600; font-size:12.5px; color:var(--text-primary); }
.dt-table--grouped tbody tr:nth-child(even){ background:var(--surface-2); }
.dt-table--grouped tbody tr:hover{ background:var(--accent-soft); }
.dt-table--grouped .dt-table__cell--warn{ color:var(--amber); }
.dt-table--grouped .dt-table__cell--danger{ color:var(--danger); }
.dt-table--grouped .dt-table__cell--grand{ font-weight:600; color:var(--text-primary); background:var(--slate-soft) !important; }
.dt-table--grouped tfoot td{ font-family:var(--font-mono); font-weight:700; font-size:12.5px; border-top:2px solid var(--text-primary); border-bottom:none; background:var(--surface-hover); padding:12px 14px; }
.dt-table--grouped tfoot .dt-table__cell--label{ font-family:var(--font-display); text-transform:uppercase; letter-spacing:.04em; font-size:11.5px; }
.dt-table--grouped ~ .dt-table-foot, .dt-table-foot{ display:flex; justify-content:center; padding:16px 20px 20px; }

/* ---- Tables on phone: shrink type + padding so more columns fit before
   .dt-table-scroll's overflow-x:auto has to kick in, rather than just
   relying on horizontal scroll at full desktop sizing. ---- */
@media (max-width:640px){
  table.dt-table{ min-width:520px; }
  .dt-table thead th{ font-size:10px; padding:10px 12px; }
  .dt-table tbody td{ padding:9px 12px; font-size:12px; }
  .dt-employee-cell{ gap:8px; }
  .dt-avatar{ width:26px; height:26px; font-size:10px; }
  .dt-badge{ height:20px; padding:0 7px; font-size:11px; }
  .dt-icon-btn{ padding:5px; }

  .dt-table--grouped{ min-width:640px; }
  .dt-table--grouped thead .dt-table__group-row th{ font-size:10px; padding:8px 10px; }
  .dt-table--grouped thead .dt-table__sub-row th{ font-size:9px; padding:6px 10px; }
  .dt-table--grouped td{ font-size:11px; padding:8px 10px; }
  .dt-table--grouped .dt-table__cell--label{ font-size:11px; }
  .dt-table--grouped tfoot td{ font-size:11px; padding:10px 10px; }
}

/* ---- Buttons: pill variant, warn variant ---- */
.dt-btn--pill{ border-radius:999px; font-family:var(--font-mono); font-size:12px; height:auto; padding:9px 16px; }
.dt-btn--pill:hover{ border-color:var(--accent); color:var(--accent); }
.dt-btn--warn{ background:var(--amber); border-color:var(--amber); color:#fff; }
.dt-btn--warn:hover{ filter:brightness(1.08); }

/* ---- Field (labeled input/select shell for the newer full-page examples) ---- */
.dt-field-row{ display:flex; flex-wrap:wrap; align-items:flex-end; gap:18px; margin-bottom:18px; }
.dt-field{ display:flex; flex-direction:column; }
.dt-field__label{ font-family:var(--font-mono); font-size:10.5px; font-weight:600; letter-spacing:.07em; text-transform:uppercase; color:var(--text-tertiary); margin-bottom:7px; }
.dt-field__control{ display:inline-flex; align-items:center; gap:8px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-sm); padding:9px 12px; font-family:var(--font-mono); font-size:12.5px; color:var(--text-primary); }
.dt-field__control:focus-within{ border-color:var(--text-tertiary); }
.dt-field__control--wide{ min-width:230px; }
.dt-field__control svg{ width:13px; height:13px; stroke:var(--text-tertiary); fill:none; stroke-width:1.8; flex:none; }
.dt-field__control input{ border:none; background:none; font:inherit; color:inherit; padding:0; outline:none; min-width:0; }
.dt-field-actions{ display:flex; gap:10px; margin-left:auto; }

/* ---- Hint / callout ---- */
.dt-hint{ font-size:12.5px; line-height:1.6; color:var(--text-secondary); background:var(--canvas); border:1px dashed var(--border); border-radius:var(--radius-sm); padding:12px 14px; }
.dt-hint b{ color:var(--text-primary); font-weight:600; }

/* ---- Legend row (horizontal, e.g. above the day-strip) ---- */
.dt-legend-row{ display:flex; flex-wrap:wrap; gap:16px; list-style:none; margin:0 0 16px; padding:0 0 16px; border-bottom:1px solid var(--border); }
.dt-legend-row li{ display:flex; align-items:center; gap:7px; font-size:11.5px; color:var(--text-secondary); }

/* ---- Day-strip calendar (provisioning ledger) ---- */
.dt-daystrip{ display:grid; grid-template-columns:repeat(11, 1fr); gap:8px; }
.dt-day{ position:relative; border-radius:9px; padding:10px 4px 9px; text-align:center; font-family:var(--font-mono); cursor:pointer; border:1px solid transparent; transition:transform .12s ease; background:none; }
.dt-day:hover{ transform:translateY(-2px); }
.dt-day__dow{ display:block; font-size:9.5px; font-weight:600; letter-spacing:.05em; opacity:.75; margin-bottom:3px; }
.dt-day__num{ display:block; font-size:16px; font-weight:600; line-height:1; margin-bottom:6px; }
.dt-day__mark{ display:flex; align-items:center; justify-content:center; }
.dt-day__mark svg{ width:11px; height:11px; stroke-width:2.6; fill:none; }
.dt-day__mark span{ width:5px; height:5px; border-radius:50%; display:block; }
.dt-day--done{ background:var(--success-soft); color:var(--success); }
.dt-day--done .dt-day__mark svg{ stroke:var(--success); }
.dt-day--pending{ background:var(--amber-soft); color:var(--amber); }
.dt-day--pending .dt-day__mark span{ background:var(--amber); }
.dt-day--missing{ background:var(--danger-soft); color:var(--danger); }
.dt-day--missing .dt-day__mark svg{ stroke:var(--danger); }
.dt-day--future{ background:transparent; border:1px dashed var(--border); color:var(--text-tertiary); }
.dt-day--future .dt-day__mark span{ background:var(--text-tertiary); }
.dt-day.is-selected{ box-shadow:0 0 0 2px var(--navy-deep); }
.dt-day:focus-visible{ outline:2px solid var(--amber); outline-offset:2px; }

/* ---- Meta rows (footnote lines under a card/table) ---- */
.dt-card__foot-meta{ display:flex; flex-wrap:wrap; align-items:center; gap:10px; margin-top:16px; padding-top:14px; border-top:1px solid var(--border); font-size:12.5px; color:var(--text-secondary); }
.dt-card__foot-meta b{ font-family:var(--font-mono); color:var(--text-primary); font-weight:600; }
.dt-card__foot-meta .dt-divider-dot{ width:3px; height:3px; border-radius:50%; background:var(--border); flex:none; }
.dt-meta-row{ display:flex; flex-wrap:wrap; justify-content:space-between; gap:10px; font-size:12px; color:var(--text-tertiary); font-family:var(--font-mono); }
.dt-table-meta{ display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:12px; padding:0 20px 16px 0; }
.dt-table-meta .count{ font-size:13px; color:var(--text-secondary); }
.dt-table-meta .count b{ font-family:var(--font-mono); color:var(--text-primary); font-weight:600; }

/* ---- Badge icon variant + Coolio's mono/uppercase pill look
   (.dt-badge--active/--pending already carry the right colors) ---- */
.dt-badge--icon::before{ display:none; }
.dt-badge--icon svg{ width:9px; height:9px; stroke-width:2.6; fill:none; }
[data-theme="coolio"] .dt-badge{ font-family:var(--font-mono); text-transform:uppercase; letter-spacing:.03em; font-size:10.5px; border-radius:5px; height:auto; padding:3px 8px; }

/* ---- Table-panel padding variant (asymmetric, clears the accent rail) ---- */
.dt-table-panel{ padding:20px 0 0 22px; }
.dt-table-panel .dt-card__head{ padding-right:20px; margin-bottom:14px; }
/* The bottom padding normally comes from .dt-table-foot's "show more"
   button. A table short enough not to need one (or with the foot hidden)
   would otherwise run flush into the card's bottom edge, so give the
   scroller its own bottom padding when it IS the last thing in the panel. */
.dt-table-panel > .dt-table-scroll:last-child{ padding-bottom:20px; }

/* Scoped + prefixed deliberately: `.anim` is a generic class name already
   used by ~39 other Horilla templates, and this file is loaded on real
   pages now -- an unscoped `.anim{opacity:0}` would blank their content
   until an animation this file owns happened to run. Same reason the
   keyframe is `dt-rise`, not `rise`. */
@media (prefers-reduced-motion: no-preference){
  .dt-app .anim, .cf-app .anim{ opacity:0; transform:translateY(10px); animation:dt-rise .5s ease forwards; }
}
@keyframes dt-rise{ to{ opacity:1; transform:translateY(0); } }

@media (max-width:980px){
  .dt-stat-grid{ grid-template-columns:1fr 1fr; }
  .dt-charts-grid, .dt-summary-grid, .dt-meter-grid{ grid-template-columns:1fr; }
  .dt-daystrip{ grid-template-columns:repeat(6, 1fr); }
  .dt-field-actions{ margin-left:0; width:100%; }
  .dt-field-actions .dt-btn{ flex:1; justify-content:center; }
}
@media (max-width:560px){
  .dt-stat-grid{ grid-template-columns:1fr; }
  .dt-appbar{ padding:12px 16px; }
}

/* ============================================================
   New components: tooltips, status colors, danger-zone actions,
   toggle switch, tabs, alert banner. All token-driven, so they
   already work under both themes x both modes with no extra rules.
   ============================================================ */

/* ---- Status: badge variants + a standalone status dot ---- */
.dt-badge--warning{ background:var(--amber-soft); color:var(--amber); }
.dt-badge--neutral{ background:var(--slate-soft); color:var(--slate); }

.dt-status-dot-row{ display:inline-flex; align-items:center; gap:8px; font-size:13px; color:var(--text-secondary); }
.dt-status-dot{ position:relative; display:inline-block; width:8px; height:8px; border-radius:50%; flex:none; background:var(--slate); }
.dt-status-dot--success{ background:var(--success); }
.dt-status-dot--warning{ background:var(--amber); }
.dt-status-dot--danger{ background:var(--danger); }
.dt-status-dot--neutral{ background:var(--slate); }
.dt-status-dot--live::after{ content:''; position:absolute; inset:-4px; border-radius:50%; background:var(--success); opacity:.35; }
@media (prefers-reduced-motion:no-preference){
  .dt-status-dot--live::after{ animation:dt-status-pulse 1.8s ease-out infinite; }
}
@keyframes dt-status-pulse{ 0%{ transform:scale(.6); opacity:.5; } 100%{ transform:scale(1.9); opacity:0; } }

/* ---- Tooltip: pure CSS, any element becomes a trigger via data-tooltip.
   Needs no JS; add tabindex="0" on non-interactive elements so
   :focus-visible can reach them for keyboard users.
   MUST stay scoped under .dt-app/.cf-app: templates/floating_button.html
   (the round FAB buttons on every page) already puts data-tooltip on its
   own buttons AND ships its own content:attr(data-tooltip) pseudo-element.
   An unscoped rule here double-renders their tooltip and re-anchors the
   buttons via position:relative. ---- */
.dt-app [data-tooltip], .cf-app [data-tooltip]{ position:relative; }
.dt-app [data-tooltip]::after, .cf-app [data-tooltip]::after{
  content:attr(data-tooltip); position:absolute; bottom:calc(100% + 8px); left:50%;
  transform:translate(-50%,2px); background:var(--navy-deep); color:var(--on-navy);
  font-size:11.5px; font-weight:500; white-space:nowrap; padding:6px 9px; border-radius:6px;
  box-shadow:var(--shadow-md); opacity:0; pointer-events:none; z-index:40;
  transition:opacity .12s ease, transform .12s ease;
}
.dt-app [data-tooltip]::before, .cf-app [data-tooltip]::before{
  content:''; position:absolute; bottom:calc(100% + 2px); left:50%; transform:translate(-50%,2px);
  border:5px solid transparent; border-top-color:var(--navy-deep); opacity:0; pointer-events:none; z-index:40;
  transition:opacity .12s ease, transform .12s ease;
}
.dt-app [data-tooltip]:hover::after, .dt-app [data-tooltip]:focus-visible::after,
.cf-app [data-tooltip]:hover::after, .cf-app [data-tooltip]:focus-visible::after{ opacity:1; transform:translate(-50%,0); }
.dt-app [data-tooltip]:hover::before, .dt-app [data-tooltip]:focus-visible::before,
.cf-app [data-tooltip]:hover::before, .cf-app [data-tooltip]:focus-visible::before{ opacity:1; transform:translate(-50%,0); }

/* ---- Danger button variants ---- */
.dt-btn--danger{ background:var(--danger); border-color:var(--danger); color:#fff; }
.dt-btn--danger:hover{ filter:brightness(1.08); }
.dt-btn--danger-outline{ background:transparent; border-color:var(--danger); color:var(--danger); }
.dt-btn--danger-outline:hover{ background:var(--danger-soft); }

/* ---- Danger zone: an irreversible-actions panel for settings-style pages ---- */
.dt-danger-zone{ border:1px solid var(--danger); border-radius:var(--radius-lg); overflow:hidden; background:var(--surface); }
.dt-danger-zone__head{ padding:14px 20px; background:var(--danger-soft); }
.dt-danger-zone__head h2{ font-size:14px; font-weight:700; color:var(--danger); margin:0 0 2px; }
.dt-danger-zone__head p{ margin:0; font-size:12.5px; color:var(--text-secondary); }
.dt-danger-zone__row{ display:flex; align-items:center; justify-content:space-between; gap:16px; padding:16px 20px; border-top:1px solid var(--border); flex-wrap:wrap; }
.dt-danger-zone__row-label{ font-size:13.5px; font-weight:600; color:var(--text-primary); margin:0 0 2px; }
.dt-danger-zone__row-desc{ font-size:12.5px; color:var(--text-secondary); margin:0; max-width:46ch; }

/* ---- Dialog icon chip (for a destructive-confirm dialog variant) ---- */
.dt-dialog__icon{ width:40px; height:40px; border-radius:10px; display:flex; align-items:center; justify-content:center; background:var(--danger-soft); color:var(--danger); flex:none; }
.dt-dialog__icon svg{ width:20px; height:20px; }

/* ---- Toggle switch ---- */
.dt-switch{ display:inline-flex; align-items:center; gap:9px; cursor:pointer; user-select:none; }
.dt-switch input{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }
.dt-switch__track{ position:relative; width:36px; height:20px; border-radius:999px; background:var(--border-strong); transition:background .15s ease; flex:none; }
.dt-switch__thumb{ position:absolute; top:2px; left:2px; width:16px; height:16px; border-radius:50%; background:#fff; box-shadow:var(--shadow-sm); transition:transform .15s ease; }
.dt-switch:has(input:checked) .dt-switch__track{ background:var(--success); }
.dt-switch:has(input:checked) .dt-switch__thumb{ transform:translateX(16px); }
.dt-switch:has(input:focus-visible) .dt-switch__track{ box-shadow:var(--focus-ring); }
.dt-switch:has(input:disabled){ opacity:.5; cursor:default; }
.dt-switch__label{ font-size:13.5px; color:var(--text-primary); }

/* ---- Tabs ---- */
.dt-tabs{ display:flex; align-items:center; gap:4px; border-bottom:1px solid var(--border); margin-bottom:18px; overflow-x:auto; }
.dt-tab{ position:relative; display:inline-flex; align-items:center; gap:7px; padding:10px 4px; margin-right:22px; border:none; background:none; cursor:pointer; font-family:var(--font-display); font-size:13.5px; font-weight:600; color:var(--text-tertiary); white-space:nowrap; }
.dt-tab:hover{ color:var(--text-secondary); }
.dt-tab[aria-selected="true"]{ color:var(--text-primary); }
.dt-tab[aria-selected="true"]::after{ content:''; position:absolute; left:0; right:0; bottom:-1px; height:2px; background:var(--accent); border-radius:2px 2px 0 0; }
.dt-tab .dt-badge{ height:18px; font-size:10.5px; padding:0 6px; }
.dt-tab:focus-visible{ outline:none; box-shadow:var(--focus-ring); border-radius:6px; }
.dt-tab-panel[hidden]{ display:none; }

/* ---- Alert banner (page-level feedback; louder/more transient than .dt-hint) ---- */
.dt-alert{ display:flex; align-items:flex-start; gap:11px; padding:13px 16px; border-radius:var(--radius-sm); border:1px solid; font-size:13px; line-height:1.5; }
.dt-alert svg{ width:17px; height:17px; flex:none; margin-top:1px; }
.dt-alert strong{ display:block; margin-bottom:2px; }
.dt-alert p{ margin:0; color:var(--text-secondary); }
.dt-alert--success{ background:var(--success-soft); border-color:var(--success); color:var(--success); }
.dt-alert--warning{ background:var(--amber-soft); border-color:var(--amber); color:var(--amber); }
.dt-alert--danger{ background:var(--danger-soft); border-color:var(--danger); color:var(--danger); }
.dt-alert--info{ background:var(--info-soft); border-color:var(--info); color:var(--info); }
.dt-alert-close{ margin-left:auto; flex:none; border:none; background:none; color:inherit; opacity:.6; cursor:pointer; padding:2px; display:flex; }
.dt-alert-close:hover{ opacity:1; }
.dt-alert-close svg{ width:14px; height:14px; margin-top:0; }

/* ============================================================
   Crew Hierarchy: dialog--wide, draggable level/crew rows, computed
   org-chart SVG, export menu.
   ============================================================ */

.dt-dialog--wide{ max-width:820px; }
@media (max-width:900px){ .dt-dialog--wide{ max-width:calc(100vw - 32px); } }

.dt-level-list{ display:flex; flex-direction:column; gap:8px; }
.dt-level{ display:flex; align-items:center; gap:12px; padding:12px 14px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-sm); cursor:pointer; transition:border-color .12s ease, box-shadow .12s ease, opacity .12s ease; }
.dt-level:hover{ border-color:var(--accent); }
.dt-level.is-dragging{ opacity:.35; }
.dt-level.drag-over-top{ box-shadow:inset 0 2px 0 var(--accent); }
.dt-level.drag-over-bottom{ box-shadow:inset 0 -2px 0 var(--accent); }
.dt-level__handle{ flex:none; display:grid; grid-template-columns:repeat(2,3px); grid-auto-rows:3px; gap:3px; width:16px; padding:6px; border:none; background:none; cursor:grab; border-radius:6px; }
.dt-level__handle:hover{ background:var(--surface-hover); }
.dt-level__handle:active{ cursor:grabbing; }
.dt-level__handle span{ width:3px; height:3px; border-radius:50%; background:var(--text-tertiary); }
.dt-level__num{ flex:none; width:26px; height:26px; border-radius:50%; background:var(--accent); color:var(--accent-contrast); display:flex; align-items:center; justify-content:center; font-family:var(--font-mono); font-weight:700; font-size:12px; }
.dt-level__info{ flex:1; min-width:0; }
.dt-level__role{ font-size:13.5px; font-weight:600; color:var(--text-primary); }
.dt-level__emp{ font-size:12.5px; color:var(--text-secondary); margin-top:1px; }
.dt-level__emp.is-unassigned{ color:var(--text-tertiary); font-style:italic; }
.dt-level__meta{ display:flex; align-items:center; flex-wrap:wrap; gap:8px; margin-top:6px; }
.dt-level__task{ font-family:var(--font-mono); font-size:11.5px; color:var(--text-tertiary); }
.dt-level__actions{ flex:none; display:flex; align-items:center; gap:6px; }
.dt-level-edit{ display:flex; flex-direction:column; gap:14px; background:var(--surface-2); border:1px solid var(--border); border-top:none; border-radius:0 0 var(--radius-sm) var(--radius-sm); margin-top:-8px; padding:16px 14px 14px; }
.dt-level-edit[hidden]{ display:none; }
.dt-level-edit .dt-filter-field label{ display:flex; align-items:baseline; gap:6px; }
.dt-level-edit .dt-filter-field label .hint{ font-weight:400; text-transform:none; letter-spacing:0; color:var(--text-tertiary); }
.dt-level-edit__actions{ display:flex; justify-content:flex-end; gap:8px; padding-top:2px; border-top:1px solid var(--border); }

.dt-crew-list{ display:flex; flex-direction:column; gap:8px; }
.dt-crew{ display:flex; align-items:center; gap:12px; padding:12px 14px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-sm); cursor:pointer; transition:border-color .12s ease, box-shadow .12s ease, opacity .12s ease; }
.dt-crew:hover{ border-color:var(--accent); }
.dt-crew.is-dragging{ opacity:.35; }
.dt-crew.drag-over-top{ box-shadow:inset 0 2px 0 var(--accent); }
.dt-crew.drag-over-bottom{ box-shadow:inset 0 -2px 0 var(--accent); }
.dt-crew__handle{ flex:none; display:grid; grid-template-columns:repeat(2,3px); grid-auto-rows:3px; gap:3px; width:16px; padding:6px; border:none; background:none; cursor:grab; border-radius:6px; }
.dt-crew__handle:hover{ background:var(--surface-hover); }
.dt-crew__handle span{ width:3px; height:3px; border-radius:50%; background:var(--text-tertiary); }
.dt-crew__tag{ flex:none; font-family:var(--font-mono); font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; color:var(--slate); background:var(--slate-soft); padding:3px 7px; border-radius:5px; }
.dt-crew__info{ flex:1; min-width:0; }
.dt-crew__name{ font-size:13.5px; font-weight:600; color:var(--text-primary); }
.dt-crew__meta{ font-size:12px; color:var(--text-tertiary); margin-top:1px; }

/* Org chart: real branching tree, drawn as SVG so layout is computed
   (not faked with CSS pseudo-elements) and export comes for free. */
.dt-orgchart-scroll{ overflow-x:auto; padding:4px 4px 12px; }
.dt-orgchart-scroll svg{ display:block; }
.dt-orgchart-node rect{ fill:var(--accent-soft); stroke:var(--accent); stroke-width:1; }
.dt-orgchart-node text{ font-family:var(--font-body); }
.dt-orgchart-node .dt-orgchart-node__level{ font-family:var(--font-mono); font-weight:600; letter-spacing:.05em; fill:var(--text-tertiary); }
.dt-orgchart-node .dt-orgchart-node__role{ font-family:var(--font-display); font-weight:700; fill:var(--accent); }
.dt-orgchart-node .dt-orgchart-node__emp{ font-family:var(--font-mono); fill:var(--text-secondary); }
.dt-orgchart-connector{ fill:none; stroke:var(--text-tertiary); stroke-width:1.4; }
.dt-orgchart-dot{ stroke:var(--surface); stroke-width:2; }

/* ---- Export menu (small popover under the Export button) ---- */
.dt-export-menu{ position:absolute; top:calc(100% + 4px); right:0; z-index:30; min-width:150px; background:var(--surface); border:1px solid var(--border); border-radius:10px; box-shadow:var(--shadow-md); padding:6px; animation:dt-drop-in .14s ease; }
.dt-export-menu[hidden]{ display:none; }
.dt-export-menu button{ display:flex; align-items:center; gap:9px; width:100%; padding:8px 9px; border:none; background:none; border-radius:7px; font-size:13px; color:var(--text-primary); cursor:pointer; text-align:left; }
.dt-export-menu button:hover{ background:var(--surface-hover); }

/* ============================================================
   oh-* compat layer — restyles legacy Horilla form chrome with dt
   tokens for pages still rendering generic/form.html. Per
   .claude/MIGRATION.md "Forms": this is chrome only (borders, spacing,
   focus states) — it cannot and does not touch field grouping, label
   placement, column layout, or generic/form.html's wrapper markup.
   Every rule is scoped under .dt-app, so legacy pages that never load
   inside a .dt-app shell are untouched. No class renames, no Python
   changes — these are exactly the classes oh-* code already emits
   (horilla_views/cbv_methods.py, base/forms.py, employee/forms.py,
   generic/form.html).
   ============================================================ */

/* Inputs: text/number/date/time/email/password/file. oh-input--password
   and oh-input--text are always co-classed with oh-input in the markup
   that emits them, so they inherit this without a separate rule. */
.dt-app .oh-input{ box-sizing:border-box; width:100%; min-width:0; height:36px; padding:0 10px; border-radius:8px; border:1px solid var(--border); background:var(--surface-2); color:var(--text-primary); font-size:13px; font-family:var(--font-body); transition:border-color .12s ease, box-shadow .12s ease; }
.dt-app .oh-input::placeholder{ color:var(--text-tertiary); }
.dt-app .oh-input:hover{ border-color:var(--border-strong); }
.dt-app .oh-input:focus{ outline:none; border-color:var(--accent); box-shadow:var(--focus-ring); }
.dt-app .oh-input:disabled{ opacity:.55; cursor:not-allowed; }
.dt-app .oh-input[type="date"], .dt-app .oh-input[type="time"]{ color-scheme:light; }
body.dark .dt-app .oh-input[type="date"], body.dark .dt-app .oh-input[type="time"]{ color-scheme:dark; }
.dt-app .oh-input-group{ margin-bottom:10px; }

/* Native <select> chrome — the fallback for before/unless Select2 attaches. */
.dt-app .oh-select{
  box-sizing:border-box; width:100%; min-width:0; height:36px; padding:0 26px 0 10px; border-radius:8px;
  border:1px solid var(--border); background:var(--surface-2); color:var(--text-primary); font-size:13px;
  font-family:var(--font-body); appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%2398A2AE' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:right 10px center;
}
.dt-app .oh-select:hover{ border-color:var(--border-strong); }
.dt-app .oh-select:focus{ outline:none; border-color:var(--accent); box-shadow:var(--focus-ring); }

/* Select2 chrome — htmxSelect2.js attaches Select2 to every .oh-select-2/
   .oh-select2 element on htmx:afterSettle (see .claude/MIGRATION.md,
   "Legacy JS re-initialises swapped fragments"), which replaces the
   visible control with its own .select2-container markup and hides the
   real <select>. The .oh-select rule above rarely shows through in
   practice because of this — these rules restyle what's actually on
   screen for the common case. Still .dt-app-scoped, no new markup. */
.dt-app .select2-container .select2-selection--single{ height:36px; border-radius:8px; border:1px solid var(--border); background:var(--surface-2); }
.dt-app .select2-container .select2-selection--single .select2-selection__rendered{ line-height:34px; padding-left:10px; padding-right:26px; color:var(--text-primary); font-size:13px; }
.dt-app .select2-container .select2-selection--single .select2-selection__arrow{ height:34px; right:8px; }
.dt-app .select2-container .select2-selection--multiple{ min-height:36px; border-radius:8px; border:1px solid var(--border); background:var(--surface-2); }
.dt-app .select2-container--default .select2-selection--multiple .select2-selection__choice{ background:var(--accent-soft); border:none; color:var(--accent); border-radius:999px; padding:2px 8px; font-size:12.5px; }
.dt-app .select2-container--default.select2-container--focus .select2-selection--single,
.dt-app .select2-container--default.select2-container--focus .select2-selection--multiple{ border-color:var(--accent); box-shadow:var(--focus-ring); }
.dt-app .select2-dropdown{ border-radius:8px; border:1px solid var(--border); background:var(--surface); box-shadow:var(--shadow-md); }
.dt-app .select2-search--dropdown .select2-search__field{ border-radius:6px; border:1px solid var(--border); background:var(--surface-2); color:var(--text-primary); }
.dt-app .select2-results__option--highlighted[aria-selected]{ background:var(--accent-soft) !important; color:var(--accent) !important; }

/* Field label */
.dt-app .oh-label{ display:block; font-size:12px; font-weight:600; color:var(--text-secondary); margin-bottom:6px; }
.dt-app .oh-label.required-star::after{ content:" *"; color:var(--danger); }
.dt-app .oh-label__info{ display:flex; align-items:center; gap:6px; }
.dt-app .oh-info{ display:inline-flex; align-items:center; justify-content:center; width:14px; height:14px; border-radius:50%; background:var(--surface-hover); color:var(--text-tertiary); font-size:10px; cursor:help; }

/* Field-level validation errors — Django's default <ul class="errorlist"> */
.dt-app ul.errorlist{ list-style:none; margin:6px 0 0; padding:0; font-size:12px; color:var(--danger); }
.dt-app ul.errorlist li{ margin-top:2px; }

/* Checkbox-as-switch: generic/form.html wraps a single checkbox input in
   a bare .oh-switch div with no other markup to hook, so this restyles
   the checkbox itself via appearance:none + pseudo-elements -- same look
   as .dt-switch, no new DOM. The !important on width counters the
   inline style="width: 30px" generic/form.html puts on the wrapper. */
.dt-app .oh-switch{ display:inline-flex; align-items:center; width:36px !important; height:20px; padding:0; }
.dt-app .oh-switch__checkbox{ appearance:none; -webkit-appearance:none; position:relative; flex:none; width:36px; height:20px; margin:0; border-radius:999px; background:var(--border-strong); cursor:pointer; transition:background .15s ease; }
.dt-app .oh-switch__checkbox::after{ content:""; position:absolute; top:2px; left:2px; width:16px; height:16px; border-radius:50%; background:#fff; box-shadow:var(--shadow-sm); transition:transform .15s ease; }
.dt-app .oh-switch__checkbox:checked{ background:var(--success); }
.dt-app .oh-switch__checkbox:checked::after{ transform:translateX(16px); }
.dt-app .oh-switch__checkbox:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
.dt-app .oh-switch__checkbox:disabled{ opacity:.5; cursor:default; }
.dt-export-menu svg{ width:15px; height:15px; color:var(--text-tertiary); flex:none; }

/* ---- Employee-codes list row (Users' "View Employees" dialog) ----
   Same bordered-row shape as .dt-crew/.dt-level (mono tag + info +
   action), under its own name -- this is an unrelated feature, so
   reusing the crew-hierarchy class names here would just be coupling
   by coincidence of look, not an actual shared component. Per-row
   valid/not-found status reuses .dt-badge--icon (already meant to pair
   with --active/--inactive for an icon instead of the default dot --
   see the "Status: badge variants" section). */
.dt-code-list-summary{ display:flex; align-items:center; justify-content:space-between; padding-bottom:10px; margin-bottom:2px; border-bottom:1px solid var(--border); font-size:12px; font-weight:700; color:var(--text-secondary); }
.dt-code-list{ display:flex; flex-direction:column; gap:8px; }
.dt-code-row{ display:flex; align-items:center; gap:10px; padding:10px 12px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-sm); }
.dt-code-row__code{ flex:none; min-width:76px; font-family:var(--font-mono); font-size:12px; font-weight:700; color:var(--text-primary); }
.dt-code-row__name{ flex:1; min-width:0; font-size:12.5px; color:var(--text-secondary); }
.dt-code-row__name--missing{ color:var(--danger); font-style:italic; }
.dt-code-row__remove{ flex:none; width:24px; height:24px; display:flex; align-items:center; justify-content:center; border:none; background:none; color:var(--text-tertiary); border-radius:6px; cursor:pointer; }
.dt-code-row__remove:hover{ background:var(--danger-soft); color:var(--danger); }
.dt-code-row__remove svg{ width:13px; height:13px; }
.dt-code-empty{ text-align:center; padding:20px 0; color:var(--text-tertiary); font-size:13px; }
/* ============================================================
   AUTH SHELL -- pre-auth split-screen login (Mawaridna brand panel
   + form pane). Source of truth: docs/mawaridna-login.html (previewed
   standalone before being approved), wired into daaptech/templates/
   login.html.

   Deliberately its OWN token family (--ink/--sand/--canvas/--fg/...),
   not the dt-app tokens: this is a pre-auth, unauthenticated page with
   its own brand moment (ink + warm sand accent, Space Grotesk display
   face) -- it never appears alongside a dt-app page, so there's no
   need to share the neutral in-app palette. Everything is scoped under
   .auth-shell, same discipline as .dt-app/.cf-app, so it can sit next
   to those systems on this same style-guide page without leaking.
   Dark mode here is the page's OWN toggle (data-theme attribute set by
   its own JS + localStorage), independent of the app's session-driven
   body.dark -- correct for a page nobody is logged into yet.
   Needs Space Grotesk / Inter / IBM Plex Mono loaded via <link> in the
   consuming page's <head> (see login.html) -- not this stylesheet's
   job to pull web fonts in for every page that loads it. */
.auth-shell{
  --ink:#0B0B0D; --ink-2:#141418; --sand:#D8C7A3; --sand-dim:#A8946E;
  --canvas:#F5F6F7; --surface:#FFFFFF; --surface-2:#FAFAFB; --line:#E3E5E8; --line-strong:#D2D6DB;
  --fg:#0B0B0D; --fg-subtle:#6A7280; --fg-muted:#9AA0A8; --on-ink:#FFFFFF; --on-ink-soft:#C8CBD2;
  /* Button + alert colors are pinned to the dt-app Standard theme's own
     --accent/--danger/--amber/--success values (static/css/dt-cf-patterns.css's
     .dt-app light block) so the submit button and the invalid-credentials
     alert match the rest of the app, not this page's own ink/sand accent. */
  --action-bg:#111827; --action-hover:#1F2937; --action-fg:#FFFFFF;
  --danger:#C4291B; --danger-bg:#FBEAE8;
  --amber:#B4590A; --amber-soft:#FBEEDF;
  --success:#157A47; --success-soft:#E3F6EA;
  --field-bg:#FFFFFF; --ring: rgba(216,199,163,.45);
  --radius:10px; --radius-lg:14px; --ease: cubic-bezier(.16, 1, .3, 1);
  --font-display:'Space Grotesk', 'Segoe UI', sans-serif;
  --font-body:'Inter', 'Segoe UI', sans-serif;
  --font-mono:'IBM Plex Mono', ui-monospace, Menlo, monospace;
  display:grid; grid-template-columns:1fr; min-height:100dvh;
  font-family:var(--font-body); background:var(--canvas); color:var(--fg);
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
}
.auth-shell[data-theme="dark"]{
  --canvas:#101014; --surface:#17171C; --surface-2:#1C1C22; --line:#26262D; --line-strong:#33333C;
  --fg:#F2F3F5; --fg-subtle:#9AA0A8; --fg-muted:#6A7280;
  --action-bg:#F3F4F6; --action-hover:#E5E7EB; --action-fg:#111827;
  --danger:#F1685C; --danger-bg:rgba(241,104,92,.14);
  --amber:#F0A23D; --amber-soft:rgba(240,162,61,.12);
  --success:#3FD98A; --success-soft:rgba(63,217,138,.12);
  --field-bg:#1C1C22; --ring: rgba(216,199,163,.30);
}
.auth-shell, .auth-shell *, .auth-shell *::before, .auth-shell *::after{ box-sizing:border-box; }
.auth-shell img{ display:block; }
.auth-shell a{ color:inherit; }
@media (min-width:1024px){ .auth-shell{ grid-template-columns:1.05fr 0.95fr; } }

/* ---- Brand panel -- inline-start, desktop only ---- */
.auth-shell .brand{
  position:relative; display:none; flex-direction:column; overflow:hidden; padding:4rem;
  background: radial-gradient(120% 90% at 8% 0%, #1A1A20 0%, var(--ink) 55%);
  color:var(--on-ink);
}
@media (min-width:1024px){ .auth-shell .brand{ display:flex; } }
.auth-shell .brand__grid{
  position:absolute; inset:0; pointer-events:none;
  background-image:radial-gradient(rgba(255,255,255,.055) 1px, transparent 1px);
  background-size:22px 22px;
  -webkit-mask-image:radial-gradient(120% 100% at 30% 20%, #000 0%, transparent 75%);
          mask-image:radial-gradient(120% 100% at 30% 20%, #000 0%, transparent 75%);
}
.auth-shell .brand__glow{
  position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(1100px 520px at 12% 6%, rgba(216,199,163,.16), transparent 60%);
  animation:auth-breathe 9s ease-in-out infinite;
}
@keyframes auth-breathe{ 0%,100%{ opacity:.9 } 50%{ opacity:1 } }
.auth-shell .tick{ position:absolute; width:18px; height:18px; pointer-events:none; border:0 solid rgba(255,255,255,.16); }
.auth-shell .tick--tl{ top:26px; inset-inline-start:26px; border-top-width:1px; border-inline-start-width:1px; }
.auth-shell .tick--tr{ top:26px; inset-inline-end:26px;   border-top-width:1px; border-inline-end-width:1px; }
.auth-shell .tick--bl{ bottom:26px; inset-inline-start:26px; border-bottom-width:1px; border-inline-start-width:1px; }
.auth-shell .tick--br{ bottom:26px; inset-inline-end:26px;   border-bottom-width:1px; border-inline-end-width:1px; }
.auth-shell .brand__inner{ position:relative; display:flex; flex:1; flex-direction:column; justify-content:space-between; gap:4rem; }
.auth-shell .lockup{ display:flex; align-items:center; gap:1.125rem; }
.auth-shell .lockup__target{ height:30px; width:auto; color:#fff; }
.auth-shell .lockup__target svg, .auth-shell .lockup__target img{ height:100%; width:auto; display:block; }
.auth-shell .lockup__product{  width:10rem; }
.auth-shell .attribution{ display:flex; align-items:center; gap:.75rem; font-size:.75rem; letter-spacing:.02em; color:rgba(255,255,255,.45); }
.auth-shell .attribution__rule{ width:2rem; height:1px; background:rgba(255,255,255,.15); }
.auth-shell .attribution img{ height:16px; width:auto; opacity:.7; }

/* ---- Form pane -- inline-end ---- */
.auth-shell .pane{ position:relative; display:flex; align-items:center; justify-content:center; padding:1.5rem; }
@media (min-width:640px){ .auth-shell .pane{ padding:2.5rem; } }
.auth-shell .pane__toggle{ position:absolute; top:1rem; inset-inline-end:1rem; }
.auth-shell .pane__mark{ position:absolute; top:1rem; inset-inline-start:1.5rem; display:flex; align-items:center; height:36px; }
.auth-shell .pane__mark img{  width:7rem; }
.auth-shell[data-theme="light"] .pane__mark img{ filter:invert(1); }
@media (min-width:1024px){ .auth-shell .pane__mark{ display:none; } }
.auth-shell .form-col{ width:100%; max-width:380px; }
.auth-shell .mobile-mark{ margin-bottom:2.25rem; }
@media (min-width:1024px){ .auth-shell .mobile-mark{ display:none; } }
.auth-shell .mobile-mark__chip{ display:inline-flex; align-items:center; gap:.875rem; background:var(--ink); color:#fff; padding:.75rem 1rem; border-radius:12px; }
.auth-shell .mobile-mark__chip .lockup__target{ height:22px; }
.auth-shell .form-eyebrow{ margin:0; font-family:var(--font-mono); font-size:.6875rem; font-weight:500; letter-spacing:.18em; text-transform:uppercase; color:var(--sand-dim); }
.auth-shell[data-theme="dark"] .form-eyebrow{ color:var(--sand); }
.auth-shell .form-title{ margin:.625rem 0 0; font-family:var(--font-display); font-size:1.75rem; font-weight:700; line-height:1.2; letter-spacing:-.015em; }
.auth-shell .form-sub{ margin:.5rem 0 2rem; font-size:.875rem; color:var(--fg-subtle); }
.auth-shell form{ display:flex; flex-direction:column; gap:1.25rem; }
.auth-shell .field{ display:flex; flex-direction:column; gap:.4375rem; }
.auth-shell .field__label{ font-size:.8125rem; font-weight:500; color:var(--fg); }
.auth-shell .field__label .req{ color:var(--sand-dim); margin-inline-start:.125rem; }
.auth-shell .field__control{ position:relative; display:flex; align-items:center; }
.auth-shell .field__icon{ position:absolute; inset-inline-start:.75rem; display:flex; color:var(--fg-muted); pointer-events:none; }
.auth-shell .input{
  width:100%; height:44px; padding-block:0; padding-inline:2.375rem .875rem;
  font-family:var(--font-body); font-size:.9375rem; color:var(--fg);
  background:var(--field-bg); border:1px solid var(--line-strong); border-radius:var(--radius);
  transition:border-color .16s ease, box-shadow .16s ease, background .16s ease;
}
.auth-shell .input::placeholder{ color:var(--fg-muted); }
.auth-shell .input:hover{ border-color:var(--fg-muted); }
.auth-shell .input:focus{ outline:none; border-color:var(--sand-dim); box-shadow:0 0 0 3px var(--ring); }
.auth-shell .field--has-action .input{ padding-inline-end:2.75rem; }
.auth-shell .reveal{
  position:absolute; inset-inline-end:.375rem; display:flex; align-items:center; justify-content:center;
  width:32px; height:32px; border:0; border-radius:8px; background:transparent; color:var(--fg-muted); cursor:pointer;
  transition:color .16s ease, background .16s ease;
}
.auth-shell .reveal:hover{ color:var(--fg); background:var(--surface-2); }
.auth-shell .reveal:focus-visible{ outline:2px solid var(--sand-dim); outline-offset:1px; }
.auth-shell .field--invalid .input{ border-color:var(--danger); }
.auth-shell .field__error{ font-size:.75rem; color:var(--danger); }
.auth-shell .alert{
  display:flex; gap:.625rem; align-items:flex-start; padding:.75rem .875rem; font-size:.8125rem; line-height:1.5;
  color:var(--danger); background:var(--danger-bg); border:1px solid var(--danger); border-radius:var(--radius);
}
.auth-shell .alert svg{ flex:none; margin-top:.0625rem; }
.auth-shell .btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.5rem;
  width:100%; height:48px; margin-top:.25rem;
  font-family:var(--font-body); font-size:.9375rem; font-weight:600;
  color:var(--action-fg); background:var(--action-bg); border:0; border-radius:var(--radius); cursor:pointer;
  box-shadow:0 1px 2px rgba(11,11,13,.18);
  transition:transform .18s var(--ease), box-shadow .18s var(--ease), opacity .16s ease, background .15s ease;
}
.auth-shell .btn:hover{ background:var(--action-hover); transform:translateY(-1px); box-shadow:0 10px 24px rgba(11,11,13,.22); }
.auth-shell .btn:active{ transform:translateY(0); }
.auth-shell .btn:focus-visible{ outline:2px solid var(--sand-dim); outline-offset:2px; }
.auth-shell .btn[disabled]{ opacity:.55; cursor:not-allowed; transform:none; box-shadow:none; }
.auth-shell[data-theme="dark"] .btn{ box-shadow:0 1px 2px rgba(0,0,0,.5); }
.auth-shell[data-theme="dark"] .btn:hover{ box-shadow:0 10px 24px rgba(0,0,0,.6); }
.auth-shell[dir="rtl"] .btn__arrow{ transform:scaleX(-1); }
/* Secondary (outline) button -- the app's own dev-only Initialize
   Database / Load Demo Data actions, kept out of the mockup's own
   vocabulary since it never had them, but built from the same tokens. */
.auth-shell .btn--outline{ background:transparent; border:1px solid var(--line-strong); color:var(--fg); box-shadow:none; }
.auth-shell .btn--outline:hover{ background:var(--surface-2); box-shadow:none; }
.auth-shell .icon-btn{
  display:inline-flex; align-items:center; justify-content:center; width:36px; height:36px;
  color:var(--fg-subtle); background:var(--surface); border:1px solid var(--line); border-radius:9px; cursor:pointer;
  transition:color .16s ease, border-color .16s ease;
}
.auth-shell .icon-btn:hover{ color:var(--fg); border-color:var(--line-strong); }
.auth-shell .icon-btn:focus-visible{ outline:2px solid var(--sand-dim); outline-offset:2px; }
.auth-shell[data-theme="dark"] .icon-sun{ display:block; }
.auth-shell[data-theme="dark"] .icon-moon{ display:none; }
.auth-shell .icon-sun{ display:none; }
@keyframes auth-rise{ from{ opacity:0; transform:translateY(12px); } to{ opacity:1; transform:none; } }
.auth-shell .stagger > *{ animation:auth-rise .55s var(--ease) both; }
.auth-shell .stagger > *:nth-child(1){ animation-delay:.08s; }
.auth-shell .stagger > *:nth-child(2){ animation-delay:.16s; }
.auth-shell .stagger > *:nth-child(3){ animation-delay:.24s; }
.auth-shell .stagger > *:nth-child(4){ animation-delay:.32s; }
.auth-shell .stagger > *:nth-child(5){ animation-delay:.40s; }
.auth-shell .stagger > *:nth-child(6){ animation-delay:.48s; }
.auth-shell .stagger > *:nth-child(7){ animation-delay:.56s; }
@media (prefers-reduced-motion:reduce){
  .auth-shell *, .auth-shell *::before, .auth-shell *::after{ animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important; }
  .auth-shell .btn:hover{ transform:none; }
}

/* ============================================================
   SIDEBAR -- main app nav rail. Source of truth: the Mawaridna
   sidebar prototype (approved 2026-09-10), wired into
   daaptech/templates/dt_sidebar.html (a new template -- the legacy
   daaptech/templates/sidebar.html is left untouched and unused,
   kept only as a rollback reference).

   Deliberately its OWN token family under .dt-sidebar, same
   discipline as .dt-app/.cf-app/.auth-shell: the sidebar wraps every
   page (it isn't opted into per-page like .dt-app), always renders
   as a dark rail regardless of the app's light/dark toggle -- same
   as the legacy .oh-sidebar it replaces -- so there's no body.dark
   branch to maintain here.

   Needs Inter loaded via <link> in the consuming page's <head> (see
   daaptech/templates/index.html) -- not this stylesheet's job to
   pull web fonts in for every page that loads it (same rule as
   .auth-shell above).

   --accent/--accent-soft are pinned to the style guide's own Standard
   dark palette (body.dark .dt-app up above -- #F3F4F6/rgba(243,244,246,.12))
   rather than the Mawaridna prototype's orange, so the "selected" look
   matches the rest of the app instead of introducing a one-off brand
   color. --bg is pure black (not the prototype's #131417) to match the
   legacy .oh-sidebar it replaces. */
.dt-sidebar{
  /* Pitch black at all times, in both app light and dark mode -- unlike
     .dt-navbar, this one does NOT follow body.dark (confirmed: Ahmad
     wants it permanently dark, same as the legacy .oh-sidebar it
     replaces). --accent-soft is a solid, clearly-visible gray (not a
     12%-opacity near-white wash) for the active-entry highlight -- that
     wash read as "barely there" / not visible against black, which was
     the actual bug being fixed here, not the background color. */
  --bg:#000000;
  --bg-elevated:#121212;
  --surface-hover:rgba(255,255,255,.06);
  --surface-active:rgba(255,255,255,.09);
  --border:rgba(255,255,255,.08);
  --border-strong:rgba(255,255,255,.14);
  --text-primary:#f2f2f1;
  --text-secondary:#98989d;
  --text-tertiary:#6b6c72;
  --accent:#F3F4F6;
  --accent-soft:hsl(0,0%,22%);
  --active-text:var(--text-primary);
  --radius:8px;
  --ease:cubic-bezier(.4,0,.2,1);

  width:100%;
  height:100vh;
  position:sticky;
  top:0;
  display:flex;
  flex-direction:column;
  overflow-x:hidden;
  background:var(--bg);
  color:var(--text-primary);
  font-family:'Inter', -apple-system, "Segoe UI", Roboto, sans-serif;
  z-index:40;
}
@media (prefers-reduced-motion: reduce){
  .dt-sidebar, .dt-sidebar *{ animation-duration:.001ms !important; transition-duration:.001ms !important; }
}

/* ---- header ----
   The collapse button is pulled out of flow (absolute, pinned to the
   right edge) so it doesn't compete with the logo for flex space --
   .dt-sidebar__header centering the logo and the button being flush
   right are two independent placements, not one flex row split by an
   auto margin. */
.dt-sidebar__header{
  position:relative;
  display:flex; align-items:center; justify-content:center;
  padding:16px; height:64px; flex-shrink:0;
}
.dt-sidebar__logo{
  /* targetLogo.png is a wide wordmark (2084x625, ~3.3:1), not a square
     icon -- size by height and let width flow naturally, or "contain"
     inside a forced square box shrinks it to an illegible sliver. */
  height:28px; width:auto; max-width:180px;
  object-fit:contain; flex-shrink:0;
  background:transparent;
  transition:opacity .15s var(--ease);
}
.dt-sidebar.is-collapsed .dt-sidebar__logo{ display:none; }
.dt-sidebar__collapse-btn{
  position:absolute; right:16px; top:50%; transform:translateY(-50%);
  width:28px; height:28px; flex-shrink:0;
  border:none; border-radius:7px; background:transparent; color:var(--text-tertiary);
  display:flex; align-items:center; justify-content:center; cursor:pointer;
  transition:background .15s var(--ease), color .15s var(--ease);
}
.dt-sidebar__collapse-btn:hover{ background:var(--surface-hover); color:var(--text-primary); }
.dt-sidebar__collapse-btn svg{ transition:transform .22s var(--ease); }
.dt-sidebar.is-collapsed .dt-sidebar__collapse-btn svg{ transform:rotate(180deg); }

/* ---- nav ---- */
.dt-sidebar__nav{
  flex:1; overflow-y:auto; overflow-x:hidden;
  padding:12px 10px;
  scrollbar-width:thin; scrollbar-color:var(--border-strong) transparent;
}
.dt-sidebar__nav::-webkit-scrollbar{ width:6px; }
.dt-sidebar__nav::-webkit-scrollbar-thumb{ background:var(--border-strong); border-radius:10px; }
.dt-sidebar__nav ul{ list-style:none; margin:0; padding:0; }

.dt-nav-group{ margin-bottom:4px; }
.dt-nav-group__label{
  font-size:11px; font-weight:600; color:var(--text-tertiary);
  padding:14px 10px 6px; white-space:nowrap; overflow:hidden;
  transition:opacity .15s var(--ease);
}
.dt-sidebar.is-collapsed .dt-nav-group__label{ opacity:0; height:0; padding-top:0; padding-bottom:6px; }

.dt-nav-item{ position:relative; margin-bottom:2px; }

.dt-nav-link{
  all:unset; box-sizing:border-box; text-decoration:none !important;
  display:flex; align-items:center; gap:11px; width:100%;
  padding:9px 10px; border-radius:var(--radius);
  color:var(--text-secondary) !important; font-size:13.5px; font-weight:500;
  cursor:pointer; white-space:nowrap; position:relative;
  transition:background .13s var(--ease), color .13s var(--ease);
}
/* !important above and on the states below, for two separate legacy
   rules in static/src/css/main.css and darkmode.css that both outrank a
   plain rule here since the Dashboard/submenu/flyout entries are real
   <a> tags:
   1. ".dark a{color:#cfcfcf !important}" flattened every sidebar link,
      active or not, to the same gray in dark mode, erasing exactly the
      active/inactive distinction this component exists to show. Light
      mode has no such rule, which is why only dark mode looked broken.
   2. "a:hover, a:active, a:focus, a:focus-within{text-decoration:
      underline}" re-added an underline specifically on :active/:focus/
      :focus-within (a plain, un-!important ":hover" override here was
      enough to beat "a:hover" on specificity alone, but not those three
      -- which is why the underline kept showing on whichever entry was
      the current page, not just on mouse hover). */
.dt-nav-link:hover{ background:var(--surface-hover); color:var(--text-primary) !important; }
.dt-nav-link:focus-visible{ outline:2px solid var(--accent); outline-offset:-1px; }
.dt-nav-link.is-active{ background:var(--accent-soft); color:var(--active-text) !important; }
.dt-nav-link.is-active::before{
  content:""; position:absolute; left:-10px; top:8px; bottom:8px; width:3px;
  background:var(--accent); border-radius:0 3px 3px 0;
}
.dt-sidebar.is-collapsed .dt-nav-link.is-active::before{ left:0; }

.dt-nav-link__icon{
  width:19px; height:19px; flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
}
.dt-nav-link__icon svg, .dt-nav-link__icon img{ width:19px; height:19px; }
/* Normalizes every per-app menu icon (arbitrary source colors) to solid
   white regardless of the source SVG/PNG's own colors -- the sidebar is
   permanently black, so this is unconditional, unlike the navbar logo. */
.dt-nav-link__icon img{ filter:brightness(0) invert(1); }
.dt-nav-link__text{ overflow:hidden; text-overflow:ellipsis; flex:1; opacity:1; transition:opacity .1s var(--ease); }
.dt-sidebar.is-collapsed .dt-nav-link__text{ opacity:0; width:0; }
.dt-nav-link__chevron{
  width:14px; height:14px; flex-shrink:0; color:var(--text-tertiary);
  transition:transform .18s var(--ease), opacity .1s var(--ease);
}
.dt-nav-item.is-open > .dt-nav-link .dt-nav-link__chevron{ transform:rotate(90deg); }
.dt-sidebar.is-collapsed .dt-nav-link__chevron{ opacity:0; width:0; }

/* ---- expanded-state submenu (accordion) ---- */
.dt-submenu{ list-style:none; margin:0; padding:0; max-height:0; overflow:hidden; transition:max-height .22s var(--ease); }
.dt-nav-item.is-open > .dt-submenu{ max-height:600px; }
.dt-sidebar.is-collapsed .dt-submenu{ display:none; }
.dt-submenu__link{
  all:unset; box-sizing:border-box; text-decoration:none !important; display:block; width:100%; cursor:pointer;
  padding:7px 10px 7px 40px; margin:1px 0; border-radius:var(--radius);
  font-size:13px; color:var(--text-secondary) !important; white-space:nowrap;
  transition:background .13s var(--ease), color .13s var(--ease);
}
.dt-submenu__link:hover{ background:var(--surface-hover); color:var(--text-primary) !important; }
.dt-submenu__link:focus-visible{ outline:2px solid var(--accent); outline-offset:-1px; }
.dt-submenu__link.is-active{ color:var(--active-text) !important; font-weight:600; }

/* ---- collapsed-state flyout submenu ---- */
.dt-flyout{
  display:none; position:absolute; left:calc(100% + 10px); top:-6px; min-width:208px;
  background:var(--bg-elevated); border:1px solid var(--border-strong); border-radius:10px;
  padding:6px; box-shadow:0 12px 32px rgba(0,0,0,.45); z-index:60;
}
.dt-flyout__title{
  padding:8px 10px 6px; font-size:12.5px; font-weight:600; color:var(--text-primary);
  border-bottom:1px solid var(--border); margin-bottom:4px; white-space:nowrap;
}
.dt-flyout__link{
  all:unset; box-sizing:border-box; text-decoration:none !important; display:block; width:100%; padding:7px 10px;
  border-radius:6px; font-size:13px; color:var(--text-secondary) !important; cursor:pointer; white-space:nowrap;
}
.dt-flyout__link:hover{ background:var(--surface-hover); color:var(--text-primary) !important; }
.dt-flyout__link.is-active{ color:var(--active-text) !important; font-weight:600; }
.dt-sidebar.is-collapsed .dt-nav-item.has-children:hover > .dt-flyout,
.dt-sidebar.is-collapsed .dt-nav-item.has-children:focus-within > .dt-flyout{ display:block; }

/* ---- tooltip for collapsed leaf items (no children) ---- */
.dt-tooltip{
  display:none; position:absolute; left:calc(100% + 10px); top:50%; transform:translateY(-50%);
  background:var(--bg-elevated); border:1px solid var(--border-strong); color:var(--text-primary);
  font-size:12.5px; font-weight:500; padding:6px 10px; border-radius:6px; white-space:nowrap;
  box-shadow:0 8px 20px rgba(0,0,0,.4); z-index:60;
}
.dt-sidebar.is-collapsed .dt-nav-item:not(.has-children):hover .dt-tooltip,
.dt-sidebar.is-collapsed .dt-nav-item:not(.has-children):focus-within .dt-tooltip{ display:block; }

/* ---- footer / user card ---- */
.dt-sidebar__footer{ border-top:1px solid var(--border); padding:10px; flex-shrink:0; }
.dt-user-card{
  display:flex; align-items:center; gap:10px; padding:8px; border-radius:var(--radius);
  cursor:pointer; transition:background .13s var(--ease);
}
.dt-user-card:hover{ background:var(--surface-hover); }
.dt-user-card__avatar{
  width:32px; height:32px; border-radius:7px; object-fit:cover;
  background:var(--surface-active); flex-shrink:0;
}
.dt-user-card__info{ overflow:hidden; white-space:nowrap; opacity:1; transition:opacity .12s var(--ease); line-height:1.2; }
.dt-sidebar.is-collapsed .dt-user-card__info{ opacity:0; width:0; }
.dt-user-card__name{ font-size:13px; font-weight:600; color:var(--text-primary); }
.dt-user-card__role{ font-size:11.5px; color:var(--text-tertiary); }

/* ---- shell: the #sidebar grid column this lives in ----
   .oh-wrapper-main is a 2-col CSS grid (sidebar | content), and its
   legacy --closed modifier (toggled by both Alpine in index.html and
   static/index/index.js off a 'sidebarOpen' localStorage key,
   independent of this component) resizes that grid to 90px -- sized
   for the legacy .oh-sidebar icon rail, not this one -- and, on
   mobile, sets #sidebar to display:none, which previously trapped a
   phone-width visitor inside the sidebar with no way back to the
   hamburger button (it lives in the navbar, which was hidden below
   the sidebar's own height in the single-column stack). This
   component now owns its own visibility end to end (.is-collapsed /
   .is-mobile-open below, driven by dt-sidebar.js) and no longer reads
   --closed at all -- both overrides below win on specificity alone
   (3 classes / 3 classes+id vs. the legacy rules' 1 class(+id)), so
   they hold regardless of source order or whether Alpine/index.js
   still flips --closed in the background. */
.oh-wrapper-main.dt-sidebar-shell{ grid-template-columns:264px auto; }
.oh-wrapper-main.dt-sidebar-shell.is-collapsed{ grid-template-columns:72px auto; }
.oh-wrapper-main.dt-sidebar-shell.oh-wrapper-main--closed #sidebar{ display:block; }
@media (max-width:767.98px){
  .oh-wrapper-main.dt-sidebar-shell,
  .oh-wrapper-main.dt-sidebar-shell.is-collapsed{ grid-template-columns:auto; }

  /* Off-canvas drawer: fixed (not sticky, not a grid item's own width)
     so it takes zero space in the document flow -- #sidebar's grid
     cell collapses to the height of nothing, and content starts right
     at the top instead of a phone-height column of nav sitting above
     it. Starts off-screen; .is-mobile-open (dt-sidebar.js, toggled by
     the existing navbar hamburger) slides it in over the content
     rather than pushing it down. */
  .dt-sidebar{
    position:fixed; top:0; left:0;
    width:280px; max-width:85vw; height:100vh;
    transform:translateX(-100%);
    transition:transform .24s var(--ease);
    box-shadow:0 0 40px rgba(0,0,0,.5);
    z-index:100;
  }
  .dt-sidebar.is-mobile-open{ transform:translateX(0); }
  /* The desktop icon-rail collapse button has no place on a touch drawer
     -- it isn't "close the sidebar" (that's the navbar hamburger /
     backdrop / Escape), it's "shrink to icons", which reads as the
     sidebar's contents randomly disappearing when tapped by someone
     expecting the former. Hidden entirely; dt-sidebar.js also stops
     applying a stored desktop collapsed state at this width, so the
     rest of these overrides are belt-and-suspenders for a sidebar that
     was already collapsed in a desktop session before the viewport
     (or window) shrank. */
  .dt-sidebar__collapse-btn{ display:none; }
  .dt-sidebar.is-collapsed{ width:280px; max-width:85vw; }
  .dt-sidebar.is-collapsed .dt-sidebar__logo{ display:block; opacity:1; width:auto; height:28px; }
  .dt-sidebar.is-collapsed .dt-nav-link__text,
  .dt-sidebar.is-collapsed .dt-nav-link__chevron,
  .dt-sidebar.is-collapsed .dt-nav-group__label,
  .dt-sidebar.is-collapsed .dt-user-card__info{ opacity:1; width:auto; height:auto; }
  .dt-sidebar.is-collapsed .dt-submenu{ display:block; }
}

/* ---- mobile backdrop ---- */
.dt-sidebar__backdrop{
  display:none;
  position:fixed; inset:0;
  background:rgba(0,0,0,.5);
  z-index:99;
}
@media (max-width:767.98px){
  .dt-sidebar.is-mobile-open ~ .dt-sidebar__backdrop{ display:block; }
}

/* ============================================================
   NAVBAR -- replaces the old .oh-navbar. Per Ahmad, the only four
   pieces of the old bar actually in use are the sidebar toggle (now
   mobile-only -- desktop collapsing lives in the sidebar header), the
   logo, breadcrumbs, and the profile/logout menu; everything else
   (notifications, language switcher, check-in/out widget, floating
   button) was dropped from daaptech/templates/index.html, not deleted
   -- those includes are still used elsewhere.

   Theme-aware, NOT permanently dark like .dt-sidebar: pitch black only
   reads right once the app itself is in dark mode (body.dark, the
   existing toggle in profile_section.html's dropdown) -- against the
   app's own light mode it just sat there as an out-of-place black
   stripe. Light (default) deliberately adds no color overrides at all:
   .oh-navbar__breadcrumb-link/.oh-navbar__icon/.oh-navbar__user-name
   already render correctly on white, since that's what they were
   originally themed for. Dark reuses the exact values
   daaptech/static/daaptech/css/darkmode.css already defines for
   ".dark .oh-navbar__*" (that file only themes the *old* .oh-navbar
   class, so .dt-navbar needs its own copy of the same values) --
   breadcrumbs_view.html and profile_section.html are otherwise reused
   completely unchanged (same hx-get/Alpine/logout behavior). */
.dt-navbar{
  position:sticky; top:0;
  height:64px;
  display:flex; align-items:center; gap:16px;
  background:#ffffff;
  padding:0 20px;
  z-index:30;
  transition:background .15s ease;
}
body.dark .dt-navbar{ background:#000000; }
.dt-navbar__toggle{
  display:none;
  width:36px; height:36px; flex-shrink:0;
  border:none; border-radius:8px; background:transparent; color:#5f6368;
  align-items:center; justify-content:center; cursor:pointer;
  transition:background .15s ease, color .15s ease;
}
.dt-navbar__toggle:hover{ background:rgba(0,0,0,.05); color:#111; }
body.dark .dt-navbar__toggle{ color:#adadad; }
body.dark .dt-navbar__toggle:hover{ background:rgba(255,255,255,.08); color:#f2f2f1; }
@media (max-width:767.98px){
  .dt-navbar__toggle{ display:flex; }
}
/* Centered independently of the toggle/breadcrumbs/profile either side
   of it, rather than flex-centered between them (which would shift with
   their widths -- e.g. disappear off-center the moment breadcrumbs are
   present). */
.dt-navbar__logo{
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  height:22px; width:auto;
  /* mawaridnaLogoFullnobg.png is itself a light/white mark on transparent
     -- unfiltered, that's invisible against this bar's white light-mode
     background. brightness(0) normalizes it to solid black regardless of
     source color (same technique as the sidebar's nav icons above); dark
     mode inverts that same normalized result to white. */
  filter:brightness(0);
}
body.dark .dt-navbar__logo{ filter:brightness(0) invert(1); }
.dt-navbar__breadcrumbs{ min-width:0; overflow:hidden; }
.dt-navbar__breadcrumbs .oh-navbar__breadcrumb{ padding-left:0; }
body.dark .dt-navbar__breadcrumbs .oh-navbar__breadcrumb-link{ color:#e5e5e5; }
body.dark .dt-navbar__breadcrumbs .oh-navbar__breadcrumb-link.active{ color:#cfcfcf; }
body.dark .dt-navbar__breadcrumbs .oh-navbar__breadcrumb-item::after{ filter:invert(1) brightness(.7); }
.dt-navbar__profile{ margin-left:auto; flex-shrink:0; }
body.dark .dt-navbar__profile .oh-navbar__user-name{ color:#dfdede; }
body.dark .dt-navbar__profile .oh-navbar__user-info::after{ filter:brightness(0) invert(1); }
body.dark .dt-navbar__profile .oh-navbar__user-info:hover{ background-color:#514d4d; }
