/* =====================================================================
   PRAXIS ADMIN — shared stylesheet for the Administration section.

   The admin section is a set of standalone pages (admin-users.html,
   admin-notifications.html, …). Each page carries the same shell
   (appbar + icon nav-rail + a labeled admin side-nav + page header +
   toolbar) and pulls ALL of its visual treatment from this one file so
   the ten screens read as a single, consistent section.

   Built in the Praxis / Mazlan design language (see praxis-core.css):
   --px-* layered slate surfaces w/ lit edges, 8/12/16 geometry, teal
   accent, light + dark via body[data-theme]. This file self-contains the
   base EHSQ palette + shell layout so an admin page only needs to link:
     praxis-core · praxis-appbar · praxis-navrail · praxis-pageheader ·
     praxis-create-new · praxis-module-selector · praxis-admin (this).
   ===================================================================== */

/* ============================================================ FONTS */
/* ==================================================== DS TOKENS (base
   EHSQ palette — identical vocabulary to record/search/workspace) */
/* Foundation tokens (--praxis-*) moved to praxis-tokens.css, the single
   source. This file had its own 67-token copy, which meant admin pages
   rendered a different radius scale and text-secondary than the rest of
   the app depending on load order. Link praxis-tokens.css before this. */
:root{

  --appbar-h:64px; --navrail-w:56px; --adminnav-w:260px;
  /* Was a dedicated amber (#fbe6c2 / rgba(245,196,90,.20)) — a few units per
     channel from --praxis-tone-warning-bg (--praxis-color-orange-10,
     #fdf2e6), so a selected row and a warning-toned row read as the same
     colour. teal-10 is already this system's selection fill (see the
     dropdown's aria-checked state); aliasing it here instead of carrying a
     second, near-identical selection colour resolves in both themes without
     a separate dark declaration. */
  --admin-row-selected:var(--praxis-color-teal-10);
}

/* ================================================================ BASE */
*{box-sizing:border-box;}
html,body{height:100%;}
body{margin:0;font-family:var(--praxis-type-font-sans);color:var(--praxis-color-text-primary);
  font-size:var(--praxis-type-size-base);line-height:1.5;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;}
button{font-family:inherit;cursor:pointer;color:inherit;}
a{color:var(--praxis-color-text-link);text-decoration:none;}
a:hover{text-decoration:underline;}
svg{display:block;}
.icon{width:22px;height:22px;fill:currentColor;flex-shrink:0;}
.icon--20{width:20px;height:20px;}.icon--18{width:18px;height:18px;}.icon--16{width:16px;height:16px;}
.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);}
.app{display:flex;flex-direction:column;height:100vh;overflow:hidden;}

/* ============================================================= APP BAR
   Container positioning only — fill/brand/search/right cluster come from
   praxis-appbar.css. */
.appbar{position:relative;height:var(--appbar-h);flex-shrink:0;display:flex;align-items:center;z-index:30;}
/* Page switcher (next to the logo) */
.appswitch{position:relative;}
.appswitch__trigger{display:inline-flex;align-items:center;gap:4px;height:32px;padding:0 8px 0 10px;border:0;background:transparent;color:inherit;font-family:inherit;font-size:.875rem;font-weight:600;border-radius:var(--praxis-radius-md);cursor:pointer;}
.appswitch__trigger:hover{background:rgba(127,127,127,.14);}
.appswitch__pop{position:absolute;top:calc(100% + 6px);left:0;min-width:200px;z-index:200;background:var(--praxis-color-surface-default);border:1px solid var(--praxis-color-border-default);border-radius:var(--praxis-radius-md);padding:6px;box-shadow:var(--praxis-elevation-4);}
.appswitch__pop[hidden]{display:none;}
.appswitch__item{display:block;padding:8px 10px;border-radius:var(--praxis-radius-sm);font-size:.875rem;font-weight:500;color:var(--praxis-color-text-primary);text-decoration:none;}
.appswitch__item:hover{background:var(--praxis-color-neutral-05);text-decoration:none;}
.appswitch__item--active{color:var(--praxis-color-text-link);font-weight:600;}
body[data-theme="dark"] .appswitch__item:hover{background:rgba(255,255,255,.06);}

/* =====================================================================
   Toggle switch (shared: profile appearance, admin toggles, filter On/Off)

   TWO MARKUP FORMS, ONE DEFINITION. Praxis shipped two contradictory ideas of
   what `.switch` means, and until 2026-08-18 only one of them was styled:

     WRAPPER form — canonical. `.switch` is the wrapper; the input is inside it.
       <span class="switch">
         <input type="checkbox">
         <span class="switch__track"></span><span class="switch__thumb"></span>
       </span>

     SIBLING form — what praxis-filters.js emits. `.switch` is ON the input and
     the track is its next sibling.
       <input type="checkbox" class="switch">
       <span class="switch__track"><span class="switch__thumb"></span></span>

   The sibling form rendered as a BARE BROWSER CHECKBOX between two labels: no
   sheet defined .switch__track or .switch__thumb, and `class="switch"` on the
   input also opts it out of the Praxis checkbox rules in praxis-core.css, which
   are keyed `input[type="checkbox"]:not(.switch):not(.switch *)`.

   WHY THE WRAPPER IS CANONICAL AND THE SIBLING FORM IS SUPPORTED ANYWAY
   The wrapper form works and real pages use it, and praxis-core.css is already
   committed to it — the `:not(.switch *)` clause in that exclusion only means
   anything if `.switch` can have descendants. So the wrapper wins.
   But praxis-filters.css reads `.onoff:has(.switch:checked)`, which only matches
   with the class on the input, so its sheet and its script agree with each other.
   Rewriting either would mean touching the JS and that `:has()` selector to fix a
   problem that CSS alone can close. So both forms are defined here, from one set
   of values, and they render identically.

   PART NAMES: `.switch__track` / `.switch__thumb` are canonical. The original
   `.track` / `.thumb` still work and are kept because consumers use them, but
   they are two of the most collision-prone class names it is possible to put in a
   shared stylesheet, so new markup should not use them.
   ===================================================================== */
.switch{position:relative;display:inline-flex;align-items:center;width:34px;height:20px;flex-shrink:0;}
.switch input{position:absolute;opacity:0;width:100%;height:100%;margin:0;cursor:pointer;}
.switch .track,.switch .switch__track{position:absolute;inset:0;border-radius:999px;background:var(--praxis-color-neutral-30);transition:background var(--praxis-motion-fast);}
.switch .thumb,.switch .switch__thumb{position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--praxis-color-white);box-shadow:0 1px 2px rgba(16,36,58,.35);transition:transform var(--praxis-motion-fast);pointer-events:none;}
.switch input:checked + .track,.switch input:checked + .switch__track{background:var(--praxis-color-teal-60);}
.switch input:checked ~ .thumb,.switch input:checked ~ .switch__thumb{transform:translateX(14px);}
.switch input:focus-visible + .track,.switch input:focus-visible + .switch__track{outline:2px solid var(--praxis-color-border-focus);outline-offset:2px;}

/* Sibling form. `input.switch` matches ONLY this form — in the wrapper form the
   input carries no class — so these rules cannot reach the markup above.
   The input is collapsed rather than absolutely positioned because its parent
   (.onoff, a <label>) is not a positioned ancestor; the label makes the whole row
   clickable, which is the better target anyway. */
input.switch{width:0;height:0;opacity:0;margin:0;padding:0;border:0;flex:none;}
input.switch + .switch__track{position:relative;display:inline-block;width:34px;height:20px;flex-shrink:0;border-radius:999px;background:var(--praxis-color-neutral-30);transition:background var(--praxis-motion-fast);cursor:pointer;}
input.switch + .switch__track .switch__thumb{position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--praxis-color-white);box-shadow:0 1px 2px rgba(16,36,58,.35);transition:transform var(--praxis-motion-fast);pointer-events:none;}
input.switch:checked + .switch__track{background:var(--praxis-color-teal-60);}
input.switch:checked + .switch__track .switch__thumb{transform:translateX(14px);}
input.switch:focus-visible + .switch__track{outline:2px solid var(--praxis-color-border-focus);outline-offset:2px;}
/* Profile menu — shared component, see praxis-profile-menu.css */

/* ============================================================== LAYOUT */
.main{flex:1;display:flex;min-height:0;}
/* Nav-rail CONTAINER (contents styled by praxis-navrail.css) */
.praxis-navrail{display:flex;flex-direction:column;justify-content:space-between;width:var(--navrail-w);flex-shrink:0;
  background:var(--praxis-color-surface-default);border-right:1px solid var(--praxis-color-neutral-20);box-sizing:border-box;z-index:20;}
/* --ph-pad-x sits here rather than on .pageheader so the toolbar band and
   .admin-body / .rm-body inherit the same inset and everything below the
   header lines up against one number. */
.content{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0;--ph-pad-x:24px;}

/* Shared nav-rail popover material (Create New / Dashboards flyouts) */
.px-pop{position:absolute;z-index:200;background:var(--praxis-color-surface-default);border:1px solid var(--praxis-color-border-default);border-radius:12px;padding:6px;box-shadow:var(--praxis-elevation-4);}
.px-pop[hidden]{display:none;}
body[data-variant="praxis"] .px-pop{border:0;box-shadow:var(--px-overlay);}

/* ============================================================= TOOLBAR
   The band itself — height, inset, page fade and closing hairline — is the
   shared component in praxis-pageheader.css. Only the controls are local. */
.tbtn{display:inline-flex;align-items:center;gap:7px;height:40px;padding:0 14px;border:0;border-radius:10px;background:var(--px-tool);color:var(--praxis-color-text-primary);font-size:.875rem;font-weight:600;box-shadow:var(--px-tool-shadow);transition:box-shadow var(--praxis-motion-fast),background var(--praxis-motion-fast),color var(--praxis-motion-fast);}
.tbtn .icon{color:var(--praxis-color-text-secondary);}
.tbtn .material-symbols-rounded{font-size:20px;color:var(--praxis-color-text-secondary);}
.tbtn:hover{box-shadow:var(--px-tool-shadow-hover);color:var(--praxis-color-text-primary);}
/* .ws-item:hover and .praxis-navrail__link:hover both suppress the hover
   underline because Praxis anticipates either being rendered as <a href>
   (see .tbtn[aria-disabled="true"] below, added for the same reason) — this
   one didn't, so a .tbtn rendered as a link underlined on hover while every
   other anchor-capable component in the system did not. */
.tbtn:hover,.tbtn:focus-visible{text-decoration:none;}
.tbtn:active{background:var(--px-surface-2);}
.tbtn--icon{width:40px;padding:0;justify-content:center;}
.tbtn--primary{background:var(--px-primary-grad);color:var(--praxis-color-white);box-shadow:var(--px-primary-shadow);padding:0 18px;}
.tbtn--primary .icon,.tbtn--primary .material-symbols-rounded{color:var(--praxis-color-white);}
.tbtn--primary:hover{filter:brightness(1.05);color:var(--praxis-color-white);box-shadow:var(--px-primary-shadow);}
/* ghost variant — flat labelled action (used by Search Logs / Activity) */
.tbtn--ghost{background:transparent;box-shadow:none;}
/* Disabled had no APPEARANCE, only suppressed behaviour. praxis-core.css excludes
   :disabled and [aria-disabled="true"] from the hover wash and the press
   transform, so a disabled button stopped responding while looking identical to an
   enabled one at rest — indistinguishable in a screenshot, and worse than useless
   to a user deciding whether to click. Added 2026-08-18.

   Opacity rather than a flat grey so it works on every variant at once, including
   .tbtn--primary's gradient, which no single colour could stand in for.
   [aria-disabled] is covered too: a link styled as a button cannot take :disabled. */
.tbtn:disabled,.tbtn[aria-disabled="true"],
.admin-ghostbtn:disabled,.admin-ghostbtn[aria-disabled="true"]{
  opacity:.45;cursor:not-allowed;box-shadow:none;
}
.tbtn--ghost:hover{background:var(--px-hover);box-shadow:none;}

/* ===================================================================
   ADMIN SIDE-NAV — the labeled panel that lets the user jump between
   admin screens (replaces the old tile launcher). Sits between the icon
   rail and the page content.
   =================================================================== */
.adminnav{width:var(--adminnav-w);flex-shrink:0;display:flex;flex-direction:column;min-height:0;
  /* Solid page fill so the fixed dot-grid does not show through this nav panel at all. */
  background:var(--px-page);
  border-right:1px solid var(--praxis-color-border-default);z-index:15;}
.adminnav__head{padding:16px 18px 8px;}
.adminnav__title{margin:0;font-size: 1rem;font-weight:700;color:var(--praxis-color-text-primary);line-height:1.2;}
.adminnav__sub{display:block;margin-top:2px;font-size:.75rem;color:var(--praxis-color-text-secondary);}
.adminnav__filter{position:relative;margin:2px 14px 6px;}
.adminnav__filter .material-symbols-rounded{position:absolute;left:10px;top:50%;transform:translateY(-50%);font-size:18px;color:var(--praxis-color-text-secondary);pointer-events:none;}
.adminnav__filter input{width:100%;height:36px;padding:0 12px 0 34px;border:0;border-radius:var(--praxis-radius-md);background:var(--px-chip);color:var(--praxis-color-text-primary);font:inherit;font-size:.8125rem;}
.adminnav__filter input::placeholder{color:var(--praxis-color-text-secondary);}
.adminnav__filter input:focus{outline:2px solid var(--praxis-color-border-focus);outline-offset:1px;}
.adminnav__scroll{flex:1;overflow-y:auto;padding:12px 10px 18px;}
.adminnav__group{padding:14px 10px 4px;font-size:.6875rem;font-weight:800;letter-spacing:normal;color:var(--praxis-color-text-secondary);}
.adminnav__item{position:relative;display:flex;align-items:center;gap:12px;min-height:40px;padding:0 12px;border-radius:10px;
  color:var(--praxis-color-text-secondary);text-decoration:none;font-size:.875rem;font-weight:600;line-height:1.2;
  transition:background var(--praxis-motion-fast),color var(--praxis-motion-fast);}
.adminnav__item:hover{background:var(--px-hover);color:var(--praxis-color-text-primary);text-decoration:none;}
.adminnav__item:focus-visible{outline:2px solid var(--praxis-color-border-focus);outline-offset:-2px;}
.adminnav__item .material-symbols-rounded{font-size:20px;flex-shrink:0;}
.adminnav__item--active{background:var(--praxis-color-teal-10);color:var(--praxis-color-teal-80);}
.adminnav__item--active:hover{background:var(--praxis-color-teal-10);color:var(--praxis-color-teal-80);}
.adminnav__item--active::before{content:"";position:absolute;left:4px;top:9px;bottom:9px;width:3px;border-radius:2px;background:var(--praxis-color-teal-60);}
body[data-theme="dark"] .adminnav__item--active{background:rgba(41,210,215,.14);color:#5CE0E5;}
body[data-theme="dark"] .adminnav__item--active::before{background:#29D2D7;}
.adminnav__badge{margin-left:auto;font-size: 0.6875rem;font-weight:800;letter-spacing:.05em;padding:2px 6px;border-radius:5px;background:var(--praxis-color-pink-50);color:var(--praxis-color-white);}

/* ===================================================================
   ADMIN BODY — the scrolling content region below the toolbar.
   =================================================================== */
.admin-body{flex:1;min-height:0;overflow-y:auto;padding:var(--px-toolbar-gutter,16px) var(--ph-pad-x,24px) 32px;
  display:flex;flex-direction:column;gap:18px;}
/* two-column split (Users, Reporting Authorities, Components) */
.admin-cols{display:grid;gap:18px;align-items:start;}
.admin-cols--2{grid-template-columns:1fr 1fr;}
.admin-cols--aside{grid-template-columns:minmax(280px,340px) 1fr;}  /* narrow left + wide right */
.admin-cols--main{grid-template-columns:1fr minmax(320px,420px);}  /* wide left + narrow right */

/* ---- Card ---- */
.admin-card{background:var(--px-surface);border-radius:var(--praxis-radius-md);box-shadow:var(--praxis-card);padding:20px 22px;}
.admin-card--flush{padding:16px 18px;}
.admin-card__title{margin:0 0 16px;font-size:1rem;font-weight:700;color:var(--praxis-color-text-primary);
  display:flex;align-items:center;gap:8px;}
.admin-card__hint{margin-left:6px;width:16px;height:16px;border-radius:50%;background:var(--praxis-color-neutral-15);
  color:var(--praxis-color-text-secondary);font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;}
.admin-subhead{margin:6px 0 14px;font-size: 0.875rem;font-weight:700;color:var(--praxis-color-text-primary);}

/* ---- Fields (flat label + underlined control) ---- */
.admin-grid{display:grid;gap:18px 34px;}
.admin-grid--2{grid-template-columns:repeat(2,minmax(0,1fr));}
.admin-grid--3{grid-template-columns:repeat(3,minmax(0,1fr));}
.admin-grid--4{grid-template-columns:repeat(4,minmax(0,1fr));}
.admin-grid--6{grid-template-columns:repeat(6,minmax(0,1fr));}
.admin-field{position:relative;display:flex;flex-direction:column;gap:5px;min-width:0;}
.admin-field__label{font-size:.8125rem;font-weight:600;color:var(--praxis-color-text-secondary);}
.admin-field__label .req{color:var(--praxis-color-red-60);margin-left:2px;}
/* ---- Fields: the same treatment as the record fields (.rfield__control in
   praxis-rfield.css) — no border, --px-field fill carrying the affordance,
   chevron and trailing icons inset 12px. Was an underline on a transparent
   background, which read as a different control system to the record pages'.
   Height stays 34px rather than the record pages' 40: admin screens run
   several fields to a row inside fixed grids, and the shared thing is the
   treatment, not the density. ---- */
.admin-field__control{height:34px;width:100%;border:0;border-radius:var(--praxis-radius-md);
  background-color:var(--px-field);font:inherit;font-size:.875rem;
  color:var(--praxis-color-text-primary);padding:0 12px;
  transition:background-color var(--praxis-motion-fast),box-shadow var(--praxis-motion-fast);}
/* text-disabled measured 2.73:1 against this fill — under 1.4.3. text-secondary
   is the lightest token that clears 4.5:1; weight does the rest of the work of
   separating a placeholder from a real value. */
.admin-field__control::placeholder{color:var(--praxis-color-text-secondary);font-weight:500;opacity:1;}
.admin-field__control:hover:not(:disabled){background-color:var(--px-field-hover);}
/* No resting border, so focus draws an inset ring — inside the box, so nothing
   reflows in a grid of fields when one takes focus. */
.admin-field__control:focus{outline:none;
  box-shadow:inset 0 0 0 1px var(--praxis-color-interactive-default),
             0 0 0 3px color-mix(in srgb, var(--praxis-color-interactive-default) 22%, transparent);}
/* Chevron drawn by CSS on every select, so it cannot go missing. The old
   .admin-field__caret span was only on some selects, leaving the rest with no
   arrow at all under appearance:none — and praxis-lucide.js rewrites
   material-symbols spans into SVGs it sizes via an injected
   `svg.material-symbols-rounded` rule, which outranks a plain class selector,
   so the span could not be reliably hidden from here either. Removed from
   build-admin.py and profile.html instead. */
select.admin-field__control{appearance:none;-webkit-appearance:none;padding-right:34px;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%235D6977'%3E%3Cpath d='M7 10l5 5 5-5z'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;background-size:20px 20px;}
body[data-theme="dark"] select.admin-field__control{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%239AA7B4'%3E%3Cpath d='M7 10l5 5 5-5z'/%3E%3C/svg%3E");}
/* Date, time and datetime-local carry native indicators on the same edge. */
.admin-field__control::-webkit-calendar-picker-indicator{margin-right:2px;}
/* A read-only value is not a field, so it takes no fill and no underline —
   an underlined value next to unbordered inputs read as the editable one. */
.admin-field__value{height:34px;display:flex;align-items:center;font-size:.875rem;font-weight:600;color:var(--praxis-color-text-primary);}
/* inline label + toggle/value row */
/* Label and control sit together. This was space-between with a flex:1 label,
   which pinned the toggle to the far right of whatever the row happened to be
   — across a full-width card that left a label and its switch a metre apart
   with nothing in between, and no way to tell which label a switch belonged to
   in a stack of them. */
.admin-field--row{flex-direction:row;align-items:center;justify-content:flex-start;gap:12px;}
.admin-field--row .admin-field__label{flex:0 1 auto;}

/* ---- Tabs (underline strip) ---- */
.admin-tabs{display:flex;gap:2px;flex-wrap:wrap;border-bottom:1px solid var(--praxis-color-border-default);margin-bottom:18px;}
.admin-tab{appearance:none;border:0;background:transparent;font:inherit;font-size:.8125rem;font-weight:700;letter-spacing:.02em;color:var(--praxis-color-text-secondary);padding:10px 14px;border-bottom:2px solid transparent;margin-bottom:-1px;cursor:pointer;}
.admin-tab:hover{color:var(--praxis-color-text-primary);}
.admin-tab--active{color:var(--praxis-color-teal-70);border-bottom-color:var(--praxis-color-teal-60);}
body[data-theme="dark"] .admin-tab--active{color:#5CE0E5;border-bottom-color:#29D2D7;}

/* ---- Data table ---- */
.admin-tabletools{display:flex;align-items:center;gap:6px;padding:0 0 12px;flex-wrap:wrap;}
.admin-ghostbtn{display:inline-flex;align-items:center;gap:8px;height:34px;padding:0 12px;border:0;background:transparent;
  color:var(--praxis-color-text-secondary);font:inherit;font-size:.8125rem;font-weight:700;border-radius:8px;}
.admin-ghostbtn:hover{background:var(--px-hover);color:var(--praxis-color-text-primary);}
.admin-ghostbtn .material-symbols-rounded{font-size:18px;}
.admin-ghostbtn--accent{color:var(--praxis-color-teal-70);}
.admin-ghostbtn--accent .material-symbols-rounded{color:var(--praxis-color-teal-60);}
.admin-table-wrap{border:1px solid var(--praxis-color-border-default);border-radius:var(--praxis-radius-sm);overflow:hidden;background:var(--px-surface);}
.admin-table-scroll{max-height:440px;overflow:auto;}
.admin-table{width:100%;border-collapse:collapse;font-size:.875rem;}
.admin-table thead th{position:sticky;top:0;z-index:1;text-align:left;font-weight:700;font-size:.75rem;letter-spacing:.02em;
  color:var(--praxis-color-text-secondary);padding:11px 14px;background:var(--px-surface-2);
  border-bottom:1px solid var(--praxis-color-border-default);white-space:nowrap;}
.admin-table thead th .req{color:var(--praxis-color-red-60);}
.admin-table tbody td{padding:12px 14px;border-bottom:1px solid var(--praxis-color-border-default);
  color:var(--praxis-color-text-primary);vertical-align:top;}
.admin-table tbody tr:last-child td{border-bottom:0;}
.admin-table tbody tr:hover{background:var(--px-hover);}
.admin-table__row--selected,.admin-table__row--selected:hover{background:var(--admin-row-selected);}
/* The rule above is (0,1,0)/(0,2,0) — the zebra stripe below is (0,2,2) in
   light — so a selected row on an even index rendered the stripe, not the
   selection, and a selected row looked identical to an unselected one on
   every other row. Prefixing the wrap ancestor reaches (0,3,2), which beats
   the light zebra rule unconditionally regardless of sheet order. */
.admin-table-wrap .admin-table tbody tr.admin-table__row--selected,
.admin-table-wrap .admin-table tbody tr.admin-table__row--selected:hover{
  background:var(--admin-row-selected);
}
/* The dark zebra rule is a type-selector heavier — body[data-theme="dark"]
   .admin-table tbody tr:nth-child(even) is (0,3,3) — so the (0,3,2) rule
   above still loses on an even row in dark mode specifically (verified in a
   browser: an even selected row rendered the zebra tint, not the selection
   colour). Same fix as dark-mode row hover: add body[data-theme="dark"] to
   the wrap-ancestor selector to reach (0,4,3), which beats it
   unconditionally. */
body[data-theme="dark"] .admin-table-wrap .admin-table tbody tr.admin-table__row--selected,
body[data-theme="dark"] .admin-table-wrap .admin-table tbody tr.admin-table__row--selected:hover{
  background:var(--admin-row-selected);
}
.admin-table__empty td{padding:22px 14px;text-align:center;color:var(--praxis-color-text-secondary);}
.admin-table__num{text-align:right;font-variant-numeric:tabular-nums;}
.admin-link{color:var(--praxis-color-text-link);font-weight:600;cursor:pointer;}
.admin-rowx{border:0;background:transparent;color:var(--praxis-color-text-secondary);width:30px;height:30px;border-radius:7px;display:inline-flex;align-items:center;justify-content:center;}
.admin-rowx:hover{background:var(--px-hover);color:var(--praxis-color-red-60);}
.admin-rowx .material-symbols-rounded{font-size:18px;}
.admin-check{width:16px;height:16px;accent-color:var(--praxis-color-teal-60);cursor:pointer;}
/* status pills (Users grid, etc.)

   WCAG 1.4.3 — the label is 12px/700, which is not large text (large starts at
   18.66px bold), so it needs 4.5:1. Two of the three variants were built from
   palette rungs rather than the audited --praxis-tone-* pairs and measured
   short: --ok was green-60 on green-10 at 3.81:1 and --lock was red-60 on
   red-10 at 3.88:1. Both now take the tone pair, which is one rung darker on
   the ink and the same tint behind it — 4.99:1 and 5.08:1. --off was already
   4.89:1 and is left where it is rather than moved for symmetry.

   --info and --warning were added 2026-08-25: the reference site needed an
   amber and a blue pill and both were missing, so its own pages were reaching
   for .admin-pill--warning and getting the bare shape with no colour. */
.admin-pill{display:inline-flex;align-items:center;height:22px;padding:0 9px;border-radius:999px;font-size:.75rem;font-weight:700;white-space:nowrap;}
.admin-pill--ok{background:var(--praxis-tone-success-bg);color:var(--praxis-tone-success-fg);}
.admin-pill--off{background:var(--praxis-color-neutral-10);color:var(--praxis-color-text-secondary);}
.admin-pill--lock{background:var(--praxis-tone-danger-bg);color:var(--praxis-tone-danger-fg);}
.admin-pill--info{background:var(--praxis-tone-info-bg);color:var(--praxis-tone-info-fg);}
.admin-pill--warning{background:var(--praxis-tone-warning-bg);color:var(--praxis-tone-warning-fg);}
body[data-theme="dark"] .admin-pill--ok{background:rgba(9,139,83,.16);color:#4cd08a;}
body[data-theme="dark"] .admin-pill--off{background:rgba(255,255,255,.08);color:var(--praxis-color-text-secondary);}
body[data-theme="dark"] .admin-pill--lock{background:rgba(226,45,56,.18);color:#f28b91;}
/* The two overrides above now restate what the tone tokens already resolve to
   in dark, and they are kept rather than deleted: praxis-core.css remaps the
   tone pairs under body[data-variant="praxis"][data-theme="dark"], so on a dark
   page that is NOT the Praxis variant the pill would keep its light tint. Same
   reason --info and --warning get none: nothing outside the Praxis variant uses
   them yet. */
/* card header with a right-aligned count/meta */
.admin-card__meta{margin-left:auto;font-size:.8125rem;font-weight:600;color:var(--praxis-color-text-secondary);}
.admin-table-scroll--tall{max-height:560px;}

/* ---- Tinted panel (Details / setting groups / logon options) ---- */
.admin-panel{background:var(--px-surface-2);border-radius:var(--praxis-radius-md);padding:18px 20px;}
.admin-panel__title{margin:0 0 14px;font-size: 0.875rem;font-weight:700;color:var(--praxis-color-text-primary);}

/* ---- Preferences: settings card grid ---- */
.admin-settings-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;}
.admin-setting-card{background:var(--px-surface-2);border-radius:var(--praxis-radius-md);padding:16px 18px;display:flex;flex-direction:column;}
.admin-setting-card__title{margin:0 0 6px;font-size: 0.875rem;font-weight:700;color:var(--praxis-color-text-primary);}
.admin-setting-row{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:38px;
  padding:6px 0;border-bottom:1px solid var(--praxis-color-border-default);}
.admin-setting-row:last-child{border-bottom:0;}
.admin-setting-row__label{font-size:.8125rem;font-weight:600;color:var(--praxis-color-text-secondary);}
.admin-setting-row__value{font-size:.875rem;font-weight:600;color:var(--praxis-color-text-primary);text-align:right;}
.admin-setting-row__value--muted{color:var(--praxis-color-text-disabled);font-weight:500;}

/* ---- Performance: drill-down stat buttons ---- */
.admin-drill{display:flex;flex-wrap:wrap;align-items:flex-start;gap:24px;}
.admin-drill__date{min-width:120px;}
.admin-drill__date .admin-field__label{margin-bottom:4px;}
.admin-drill__stats{flex:1;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:16px;}
.admin-stat{display:flex;flex-direction:column;align-items:center;gap:10px;text-align:center;}
/* Light tool button, not a filled slate slab: these are navigation into a
   report, not primary actions, and a column of dark blocks dominated the page. */
.admin-stat__btn{width:100%;height:40px;min-height:40px;border:0;border-radius:10px;padding:0 14px;
  background:var(--px-surface);color:var(--praxis-color-text-primary);
  font:inherit;font-weight:600;font-size: 0.875rem;line-height:1.2;
  box-shadow:var(--px-tool-shadow);
  display:flex;align-items:center;justify-content:center;text-align:center;
  transition:background var(--praxis-motion-fast),box-shadow var(--praxis-motion-fast),transform 150ms var(--praxis-ease-default);}
.admin-stat__btn:hover{background:var(--px-surface);box-shadow:var(--px-tool-shadow-hover);}
.admin-stat__btn:active{transform:scale(.97);}
body[data-theme="dark"] .admin-stat__btn{background:var(--px-surface-2);color:var(--praxis-color-text-primary);box-shadow:var(--px-tool-shadow);}
.admin-stat__metric{font-size:.8125rem;color:var(--praxis-color-text-secondary);}
.admin-stat__metric b{color:var(--praxis-color-text-primary);font-weight:700;}

/* ---- Info banner (Components) ---- */
.admin-banner{display:flex;gap:12px;align-items:flex-start;background:var(--praxis-color-blue-10);
  border-radius:var(--praxis-radius-md);padding:14px 16px;color:var(--praxis-color-text-primary);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--praxis-color-blue-60) 22%, transparent);}
.admin-banner .material-symbols-rounded{color:var(--praxis-color-blue-60);font-size:22px;flex-shrink:0;}
.admin-banner__body{flex:1;min-width:0;}
.admin-banner__title{font-weight:700;margin-bottom:2px;}
.admin-banner__text{font-size:.875rem;color:var(--praxis-color-text-secondary);line-height:1.5;}
.admin-banner__close{border:0;background:transparent;color:var(--praxis-color-text-secondary);width:30px;height:30px;border-radius:7px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;}
.admin-banner__close:hover{background:rgba(16,36,58,.06);color:var(--praxis-color-text-primary);}
body[data-theme="dark"] .admin-banner{background:rgba(71,102,235,.14);}

/* ---- Components: menus list + preview ---- */
.admin-menulist{display:flex;flex-direction:column;}
.admin-menulist__label{font-size:.8125rem;font-weight:700;color:var(--praxis-color-text-secondary);padding:4px 4px 8px;}
.admin-menurow{display:flex;align-items:center;gap:10px;padding:12px 6px;border-bottom:1px solid var(--praxis-color-border-default);}
.admin-menurow__name{flex:1;font-size:.875rem;font-weight:600;color:var(--praxis-color-text-primary);}
.admin-menurow__act{border:0;background:transparent;color:var(--praxis-color-text-secondary);width:30px;height:30px;border-radius:7px;display:inline-flex;align-items:center;justify-content:center;}
.admin-menurow__act:hover{background:var(--px-hover);color:var(--praxis-color-text-primary);}
.admin-menurow__act .material-symbols-rounded{font-size:18px;}
.admin-addmenu{display:inline-flex;align-items:center;gap:10px;margin-top:14px;border:0;background:transparent;color:var(--praxis-color-teal-70);font:inherit;font-size:.875rem;font-weight:700;padding:6px 4px;}
.admin-addmenu .material-symbols-rounded{color:var(--praxis-color-teal-60);font-size:22px;}
.admin-preview__label{font-size:.8125rem;font-weight:700;color:var(--praxis-color-text-secondary);margin-bottom:12px;}
.admin-cngroup{margin-bottom:18px;}
.admin-cngroup__title{margin:0 0 8px;font-size: 1rem;font-weight:700;color:var(--praxis-color-text-primary);}
.admin-cngrid{display:grid;grid-template-columns:1fr 1fr;gap:10px;background:var(--px-surface-2);border-radius:10px;padding:12px;}
.admin-cnbtn{display:flex;align-items:center;justify-content:space-between;gap:10px;background:var(--px-surface);border-radius:8px;
  padding:11px 14px;box-shadow:var(--px-tool-shadow);font-size:.875rem;font-weight:600;color:var(--praxis-color-text-primary);}
.admin-cnbtn .material-symbols-rounded{color:var(--praxis-color-teal-60);font-size:20px;}

/* ---- Search Logs: helper note + color legend ---- */
.admin-note{font-size:.875rem;color:var(--praxis-color-text-secondary);line-height:1.6;font-style:italic;}
.admin-note .lg-tm{color:var(--praxis-color-blue-60);font-style:normal;font-weight:700;}
.admin-note .lg-jv{color:var(--praxis-color-green-60);font-style:normal;font-weight:700;}
.admin-note .lg-cs{color:var(--praxis-color-pink-60);font-style:normal;font-weight:700;}
.admin-note .lg-err{color:var(--praxis-color-red-60);font-style:normal;font-weight:800;}

/* ===================================================================
   GLOBAL CHROME OVERLAYS — the shared app-header / nav-rail popovers that
   work on every page: nav-rail popover rows (px-menu), the Dashboards
   popout (ws-pop), search suggestions (ss-pop), and the Mazlan drawer
   (mz-*). Create New (cn-*) and the module selector (msel-*) get their CSS
   from praxis-create-new.css / praxis-module-selector.css. Ported from the
   record page so behaviour + look match app-wide.
   =================================================================== */

/* Mazlan four-dot brand mark (app-header pill + drawer greeting) */
.mazlan-mark{position:relative;display:inline-block;width:20px;height:20px;flex-shrink:0;vertical-align:middle;}
.mazlan-mark--sm{width:16px;height:16px;}
.mazlan-mark>span{position:absolute;width:25%;height:25%;border-radius:50%;display:block;}
.mazlan-mark>span:nth-child(1){left:12.5%;top:12.5%;background:#2F4051;}
.mazlan-mark>span:nth-child(2){right:12.5%;top:12.5%;background:#E30072;}
.mazlan-mark>span:nth-child(3){left:12.5%;bottom:12.5%;background:#5CC9D0;}
.mazlan-mark>span:nth-child(4){right:12.5%;bottom:12.5%;background:var(--praxis-color-teal-60);}
body[data-theme="dark"] .mazlan-mark>span:nth-child(1){background:#d1d5db;}

/* generic overlay rows (used by the Dashboards popout) */
.px-menu__head{padding:8px 10px 4px;font-size:.6875rem;font-weight:700;letter-spacing:normal;color:var(--praxis-color-text-secondary);}
.px-menu__item{display:flex;align-items:center;gap:10px;width:100%;padding:8px 10px;border:0;background:transparent;
  border-radius:8px;cursor:pointer;text-align:left;font-family:inherit;font-size:.875rem;font-weight:500;
  color:var(--praxis-color-text-primary);text-decoration:none;}
.px-menu__item:hover{background:var(--px-hover);text-decoration:none;}
.px-menu__sep{height:1px;background:var(--praxis-color-border-default);margin:6px 4px;}

/* ---- Dashboards / workspaces popout ---- */
.ws-pop{top:0;left:calc(100% + 8px);width:300px;max-height:70vh;overflow-y:auto;}
body[data-variant="praxis"] .ws-pop{
  background:color-mix(in srgb, var(--px-surface) 60%, transparent);
  -webkit-backdrop-filter:saturate(1.35) blur(16px);backdrop-filter:saturate(1.35) blur(16px);
  box-shadow:var(--px-overlay), inset 0 .5px 0 var(--px-edge);
  border-radius:14px;padding:10px;transform-origin:top left;}
body[data-variant="praxis"] .ws-pop .px-menu__head{
  font-size:16px;font-weight:700;letter-spacing:0;text-transform:none;color:var(--praxis-color-text-primary);padding:6px 8px 12px;}
.ws-item{display:flex;align-items:center;gap:12px;width:100%;padding:8px 10px;border:0;background:transparent;
  border-radius:10px;cursor:pointer;text-align:left;font-family:inherit;color:var(--praxis-color-text-primary);text-decoration:none;}
.ws-item:hover{background:var(--px-hover);text-decoration:none;}
.ws-item:focus-visible{outline:2px solid var(--praxis-color-teal-50);outline-offset:-2px;}
.ws-item__icon{width:34px;height:34px;flex-shrink:0;border-radius:9px;display:flex;align-items:center;justify-content:center;
  background:var(--praxis-color-neutral-10);color:var(--praxis-color-text-secondary);}
.ws-item__icon .icon{width:19px;height:19px;}
.ws-item--home .ws-item__icon{background:var(--praxis-color-teal-10);color:var(--praxis-color-teal-80);}
.ws-item--new .ws-item__icon{background:transparent;color:var(--praxis-color-interactive-default);}
body[data-variant="praxis"] .ws-pop .ws-item:not(.ws-item--home):not(.ws-item--new) .ws-item__icon{
  background:var(--px-surface);box-shadow:var(--px-tool-shadow);color:var(--praxis-color-text-secondary);}
.ws-item__text{display:flex;flex-direction:column;min-width:0;flex:1;}
.ws-item__name{font-size:.875rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.ws-item__sub{font-size:.75rem;color:var(--praxis-color-text-secondary);}

/* ---- Search suggestions ---- */
.ss-pop{position:absolute;top:calc(100% + 8px);left:0;right:0;z-index:210;padding:6px;
  background:var(--praxis-color-surface-default);border:1px solid var(--praxis-color-border-default);border-radius:12px;
  box-shadow:var(--praxis-elevation-4);max-height:60vh;overflow-y:auto;}
.ss-pop[hidden]{display:none;}
body[data-variant="praxis"] .ss-pop{border:0;box-shadow:var(--px-overlay);}
body[data-variant="praxis"][data-theme="dark"] .ss-pop{background:rgba(26,32,45,.94);
  -webkit-backdrop-filter:saturate(1.3) blur(16px);backdrop-filter:saturate(1.3) blur(16px);}
.ss-sec__head{padding:8px 10px 4px;font-size:.6875rem;font-weight:700;letter-spacing:normal;color:var(--praxis-color-text-secondary);}
.ss-row{display:flex;align-items:center;gap:10px;width:100%;padding:8px 10px;border:0;background:transparent;
  border-radius:8px;cursor:pointer;text-align:left;font-family:inherit;font-size:.875rem;font-weight:500;color:var(--praxis-color-text-primary);}
.ss-row:hover{background:var(--px-hover);}
.ss-row .icon{width:18px;height:18px;color:var(--praxis-color-text-secondary);flex-shrink:0;}
.ss-row mark{background:transparent;color:var(--praxis-color-interactive-default);font-weight:700;}
.ss-row[hidden]{display:none;}

/* ===================================================================
   RESPONSIVE — mirrors the app-wide 1024 / 768 / 480 cascade.
   =================================================================== */
@media (max-width:1024px){
  .admin-settings-grid{grid-template-columns:repeat(2,minmax(0,1fr));}
  .admin-drill__stats{grid-template-columns:repeat(3,minmax(0,1fr));}
  .admin-cols--2,.admin-cols--aside,.admin-cols--main{grid-template-columns:1fr;}
  .admin-grid--4,.admin-grid--6{grid-template-columns:repeat(2,minmax(0,1fr));}
}
@media (max-width:768px){
  :root{--adminnav-w:224px;}
  .admin-grid--2,.admin-grid--3{grid-template-columns:1fr;}
  .admin-settings-grid{grid-template-columns:1fr;}
  .admin-drill__stats{grid-template-columns:repeat(2,minmax(0,1fr));}
}
@media (max-width:640px){
  /* Collapse the labeled side-nav to an icon-only rail on small screens */
  .adminnav{width:60px;}
  .adminnav__head,.adminnav__filter,.adminnav__group span,.adminnav__item span:not(.material-symbols-rounded),.adminnav__badge{display:none;}
  .adminnav__group{padding:10px 0 2px;text-align:center;}
  .adminnav__item{justify-content:center;padding:0;}
  .adminnav__scroll{padding:6px 8px;}
}
@media (max-width:480px){
  .admin-grid--4,.admin-grid--6,.admin-drill__stats{grid-template-columns:1fr;}
  .appswitch{display:none;}
}


/* ---------------------------------------------------------------------
   Admin tables — same treatment as the search table: the header carries no
   fill (the rule and the weight do the work) and the body is zebra striped.
   --------------------------------------------------------------------- */
.admin-table thead th{ background:var(--px-surface); }
.admin-table tbody tr:nth-child(even){ background:var(--px-hover-btn); }
body[data-theme="dark"] .admin-table thead th{ background:var(--px-surface); }
body[data-theme="dark"] .admin-table tbody tr:nth-child(even){ background:rgba(255,255,255,.035); }
/* Row hover never showed on an even row in dark mode, at any colour. The rule
   above is (0,3,3) — one type-selector heavier than the base
   `.admin-table tbody tr:hover` (0,2,2) can ever reach, dark mode or not — so
   hover always lost on an even row regardless of what a consumer set it to.
   This rule ties the zebra rule's own (0,3,3) and wins the tie by coming
   later in this same sheet, the same fix already applied above for the
   nth-child/selected-row collision, just against hover instead of selection.
   --px-hover-btn (10% white in dark) rather than a dark remap of whatever
   colour hover uses in light: it is the token every other interactive
   surface in this theme already hovers to, so nothing new needs defining.
   Found building a real product on this checkout — see
   CHANGELOG.md's Beakon-reskin findings. */
body[data-theme="dark"] .admin-table tbody tr:hover{ background:var(--px-hover-btn); }


/* ---- Workspace flyout ------------------------------------------------- */
.ws-pop{ max-height:min(70vh,560px); overflow-y:auto; }
.ws-item__badge{
  margin-left:auto; flex-shrink:0; padding:3px 9px; border-radius:999px;
  font-size:.6875rem; font-weight:700;
  background:var(--praxis-color-teal-10); color:var(--praxis-color-teal-80);
}
body[data-theme="dark"] .ws-item__badge{ background:rgba(41,210,215,.16); color:var(--praxis-color-text-link); }
/* The current workspace read as a white block in dark — --praxis-color-teal-10
   is a light tint that isn't remapped. Pink, matching how selection is marked
   elsewhere in the app. */
body[data-theme="dark"] .ws-item--home .ws-item__icon{
  background:rgba(227,0,114,.18); color:#ff5aa8;
}
body[data-theme="dark"] .ws-item--home{ background:rgba(227,0,114,.10); }
body[data-theme="dark"] .ws-item--home .ws-item__badge{
  background:rgba(227,0,114,.18); color:#ff5aa8;
}
