/* =========================================================================
   ZEISMO CRM — Component layer
   Consumes tokens.css only. Loaded LAST via the app_admin_head hook, so it
   settles the argument between Bootstrap 3, Tailwind and the legacy
   style.css without any of them being edited.

   Rule for this file: no hex values, no magic numbers. If something needs a
   value that is not a token, the token was missing and belongs in tokens.css.
   ========================================================================= */

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

body.app.admin,
body.app.admin .content,
#wrapper{
  background: var(--zs-surface);
  color: var(--zs-text-primary);
}

body.app.admin{
  font-family: var(--zs-font-ui);
  font-size: var(--zs-body-size);
  line-height: var(--zs-body-lh);
  font-weight: var(--zs-body-w);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Contextual alternates + tabular figures everywhere by default: a CRM is
     mostly numbers in columns, and proportional digits make them jitter. */
  font-feature-settings: 'cv05' 1, 'ss03' 1, 'tnum' 1;
}

body.app.admin h1, body.app.admin h2, body.app.admin h3,
body.app.admin h4, body.app.admin h5{
  font-family: var(--zs-font-ui);
  color: var(--zs-text-primary);
  margin-top: 0;
}
body.app.admin h1{ font-size:var(--zs-h1-size); line-height:var(--zs-h1-lh); letter-spacing:var(--zs-h1-ls); font-weight:var(--zs-h1-w); }
body.app.admin h2{ font-size:var(--zs-h2-size); line-height:var(--zs-h2-lh); letter-spacing:var(--zs-h2-ls); font-weight:var(--zs-h2-w); }
body.app.admin h3,
body.app.admin h4{ font-size:var(--zs-h3-size); line-height:var(--zs-h3-lh); letter-spacing:var(--zs-h3-ls); font-weight:var(--zs-h3-w); }

/* The one place the display face appears: a page's own title. Big enough that
   Calistoga reads as character rather than as noise. */
.zs-page-title{
  font-family: var(--zs-font-display);
  font-size: var(--zs-display-size);
  line-height: var(--zs-display-lh);
  letter-spacing: var(--zs-display-ls);
  font-weight: var(--zs-display-w);
  color: var(--zs-text-primary);
}

body.app.admin .text-muted,
body.app.admin .help-block{ color: var(--zs-text-secondary) !important; }
body.app.admin .bold,
body.app.admin strong,
body.app.admin b{ font-weight: 600; }
body.app.admin a{ color: var(--zs-accent); text-decoration: none;
  transition: color var(--zs-t-fast) var(--zs-ease); }
body.app.admin a:hover,
body.app.admin a:focus{ color: var(--zs-accent-hover); text-decoration: none; }
body.app.admin hr{ border-top:1px solid var(--zs-border); margin: var(--zs-s5) 0; }

/* Small caps label, used for column groups and section eyebrows. */
.zs-label{
  font-size: var(--zs-label-size); font-weight: var(--zs-label-w);
  letter-spacing: var(--zs-label-ls); text-transform: uppercase;
  color: var(--zs-text-tertiary); line-height: var(--zs-label-lh);
}

/* Any number, anywhere. */
.zs-num, body.app.admin td.zs-num, .zs-stat-value{
  font-family: var(--zs-font-data);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1, 'zero' 1;
  letter-spacing: var(--zs-data-ls);
}

/* ── Focus: one ring, on everything, always visible ────────────────────── */

body.app.admin :focus-visible{
  outline: 2px solid var(--zs-accent);
  outline-offset: 2px;
  border-radius: var(--zs-r-sm);
}
body.app.admin .btn:focus-visible,
body.app.admin .form-control:focus-visible,
body.app.admin a:focus-visible{ outline: 2px solid var(--zs-accent); outline-offset: 2px; }

/* ── Page entrance: one orchestrated fade, not per-element confetti ────── */

@keyframes zs-rise{ from{ opacity:0; transform: translateY(4px);} to{ opacity:1; transform:none;} }
/* Deliberately the FAST duration, not the slow one: this fires on every single
   navigation, and anything longer starts to read as latency rather than as
   polish. */
body.app.admin #wrapper > .content{ animation: zs-rise var(--zs-t-fast) var(--zs-ease) both; }
@media (prefers-reduced-motion: reduce){
  body.app.admin #wrapper > .content{ animation: none; }
}

/* ── Card (panel_s) ────────────────────────────────────────────────────── */

body.app.admin .panel_s,
body.app.admin .panel.panel-default{
  background: var(--zs-surface-raised);
  border: 1px solid var(--zs-border);
  border-radius: var(--zs-r-lg);
  box-shadow: var(--zs-e1);
  margin-bottom: var(--zs-s5);
}
body.app.admin .panel_s .panel-body,
body.app.admin .panel-body{ padding: var(--zs-s5); background: transparent; }
body.app.admin .panel_s .panel-heading{
  background: transparent;
  border-bottom: 1px solid var(--zs-border);
  border-radius: var(--zs-r-lg) var(--zs-r-lg) 0 0;
  padding: var(--zs-s4) var(--zs-s5);
  font-weight: 600;
  color: var(--zs-text-primary);
}
body.app.admin .panel-table-full{ padding: 0 !important; }
/*
 | .table-responsive carries margin: 0 -24px so a table sits flush inside a
 | panel that has 24px of padding. .panel-table-full removes that padding, so
 | the negative margin then hangs the table 24px off BOTH edges: the left of
 | every header and cell is clipped ("IVOICE #", "o entries found"), and the
 | 48px of phantom width is what produced a horizontal scrollbar on tables
 | that fit perfectly well. Where there is no padding to cancel, there is no
 | negative margin either.
 */
body.app.admin .panel-table-full > .dataTables_wrapper .table-responsive,
body.app.admin .panel-table-full .table-responsive{ margin-left: 0; margin-right: 0; }

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

body.app.admin .btn{
  font-family: var(--zs-font-ui);
  font-size: var(--zs-body-size);
  font-weight: 500;
  line-height: 1.2;
  padding: 9px var(--zs-s4);
  border-radius: var(--zs-r-md);
  border: 1px solid transparent;
  transition: background var(--zs-t-fast) var(--zs-ease),
              border-color var(--zs-t-fast) var(--zs-ease),
              color var(--zs-t-fast) var(--zs-ease),
              box-shadow var(--zs-t-fast) var(--zs-ease);
  box-shadow: none;
  text-shadow: none;
}
body.app.admin .btn:active{ transform: translateY(.5px); }

body.app.admin .btn-primary,
body.app.admin .btn-info{
  background: var(--zs-accent);
  border-color: var(--zs-accent);
  color: var(--zs-text-on-accent);
}
body.app.admin .btn-primary:hover, body.app.admin .btn-primary:focus,
body.app.admin .btn-info:hover, body.app.admin .btn-info:focus{
  background: var(--zs-accent-hover); border-color: var(--zs-accent-hover);
  color: var(--zs-text-on-accent);
}

body.app.admin .btn-default{
  background: var(--zs-surface-raised);
  border-color: var(--zs-border-strong);
  color: var(--zs-text-primary);
}
body.app.admin .btn-default:hover, body.app.admin .btn-default:focus{
  background: var(--zs-surface-hover); border-color: var(--zs-border-strong);
  color: var(--zs-text-primary);
}

/* Ghost: the quiet third button, for actions that sit next to a primary. */
body.app.admin .btn-link, body.app.admin .zs-btn-ghost{
  background: transparent; border-color: transparent; color: var(--zs-text-secondary);
}
body.app.admin .btn-link:hover, body.app.admin .zs-btn-ghost:hover{
  background: var(--zs-surface-hover); color: var(--zs-text-primary); text-decoration: none;
}

body.app.admin .btn-danger{ background: var(--zs-danger); border-color: var(--zs-danger); color:#fff; }
body.app.admin .btn-danger:hover, body.app.admin .btn-danger:focus{ filter: brightness(1.07); color:#fff; }
body.app.admin .btn-success{ background: var(--zs-success); border-color: var(--zs-success); color:#fff; }
body.app.admin .btn-success:hover{ filter: brightness(1.07); color:#fff; }
body.app.admin .btn-warning{ background: var(--zs-warning); border-color: var(--zs-warning); color:#fff; }

body.app.admin .btn-xs, body.app.admin .btn-sm{ padding: 5px 10px; font-size: var(--zs-caption-size); }
body.app.admin .btn-lg{ padding: 12px var(--zs-s5); font-size: var(--zs-h3-size); }
body.app.admin .btn[disabled], body.app.admin .btn.disabled{ opacity:.5; box-shadow:none; }

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

body.app.admin .form-group{ margin-bottom: var(--zs-s4); }
body.app.admin .form-group > label,
body.app.admin .form-group > .control-label{
  /* Block, so the label sits ABOVE its field. Bootstrap leaves labels
     inline-block, which reads as a caption floating beside the input. Scoped
     to a direct child of .form-group so checkbox and radio labels, which are
     legitimately inline next to their control, are left alone. */
  display: block;
  font-size: var(--zs-caption-size);
  font-weight: 600;
  color: var(--zs-text-secondary);
  letter-spacing: .005em;
  margin-bottom: var(--zs-s1);
}
body.app.admin .form-horizontal .form-group > .control-label{ display: inline-block; }
body.app.admin .checkbox label,
body.app.admin .radio label{ display: inline-block; font-weight: 400; color: var(--zs-text-primary); }
body.app.admin .form-control,
body.app.admin select.form-control,
body.app.admin textarea.form-control,
body.app.admin .bootstrap-select > .dropdown-toggle{
  background: var(--zs-surface-raised);
  border: 1px solid var(--zs-border-strong);
  border-radius: var(--zs-r-md);
  color: var(--zs-text-primary);
  font-family: var(--zs-font-ui);
  font-size: var(--zs-body-size);
  padding: 9px var(--zs-s3);
  height: auto;
  box-shadow: none;
  transition: border-color var(--zs-t-fast) var(--zs-ease),
              box-shadow var(--zs-t-fast) var(--zs-ease);
}
body.app.admin .form-control:focus,
body.app.admin .bootstrap-select.open > .dropdown-toggle{
  border-color: var(--zs-accent);
  box-shadow: 0 0 0 3px var(--zs-accent-ring);
  outline: none;
}
body.app.admin .form-control::placeholder{ color: var(--zs-text-tertiary); }
body.app.admin .form-control[readonly],
body.app.admin .form-control[disabled]{ background: var(--zs-surface-sunken); color: var(--zs-text-secondary); }

/* Numeric inputs get the data face so typed figures line up with the table. */
body.app.admin input[type=number].form-control,
body.app.admin input.zs-num{ font-family: var(--zs-font-data); font-variant-numeric: tabular-nums; }

body.app.admin .has-error .form-control{ border-color: var(--zs-danger); }
body.app.admin .has-error .form-control:focus{ box-shadow: 0 0 0 3px var(--zs-danger-soft); }
body.app.admin .has-error label,
body.app.admin label.error,
body.app.admin .text-danger{ color: var(--zs-danger) !important; }
body.app.admin label.error{
  font-weight: 500; font-size: var(--zs-caption-size); margin-top: var(--zs-s1); display:block;
}
body.app.admin .has-success .form-control{ border-color: var(--zs-success); }

body.app.admin input[type=checkbox], body.app.admin input[type=radio]{ accent-color: var(--zs-accent); }

/* ── Signature element: the signal dot ─────────────────────────────────────
   Every status, stage, priority and health indicator in ZEISMO CRM is a
   neutral chip with a small coloured dot. Colour lives in the dot; the chip
   and its text stay legible.

   Why: a CRM screen carries thirty of these at once. Solid coloured pills
   turn a table into a fruit bowl and force the eye to decode hue before it
   can read a word. A dot is enough to signal state at a glance, keeps the
   label at full contrast, and stays readable for colour-blind users because
   the word is always there. This is the one thing that should make a ZEISMO
   screenshot recognisable.                                                    */

body.app.admin .label,
body.app.admin .badge,
.zs-pill{
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px 3px 8px;
  border-radius: var(--zs-r-pill);
  background: var(--zs-neutral-soft);
  color: var(--zs-text-primary);
  font-family: var(--zs-font-ui);
  font-size: var(--zs-caption-size);
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: 0;
  text-shadow: none;
  border: 1px solid transparent;
  white-space: nowrap;
  vertical-align: baseline;
}
body.app.admin .label::before,
.zs-pill::before{
  content: ''; flex: none;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--zs-neutral);
}
/* Bootstrap's colour classes now tint only the dot and the chip's wash. */
body.app.admin .label-success,  .zs-pill-success  { background: var(--zs-success-soft); }
body.app.admin .label-success::before,  .zs-pill-success::before  { background: var(--zs-success); }
body.app.admin .label-danger,   .zs-pill-danger   { background: var(--zs-danger-soft); }
body.app.admin .label-danger::before,   .zs-pill-danger::before   { background: var(--zs-danger); }
body.app.admin .label-warning,  .zs-pill-warning  { background: var(--zs-warning-soft); }
body.app.admin .label-warning::before,  .zs-pill-warning::before  { background: var(--zs-warning); }
body.app.admin .label-info,     .zs-pill-info     { background: var(--zs-info-soft); }
body.app.admin .label-info::before,     .zs-pill-info::before     { background: var(--zs-info); }
body.app.admin .label-primary                     { background: var(--zs-accent-soft); }
body.app.admin .label-primary::before             { background: var(--zs-accent); }
body.app.admin .label-default                     { background: var(--zs-neutral-soft); }

/* A counter badge is a number, not a state: no dot, data face. */
body.app.admin .badge{
  padding: 2px 8px; font-family: var(--zs-font-data);
  font-variant-numeric: tabular-nums; font-size: var(--zs-caption-size);
}
body.app.admin .badge::before{ display: none; }

/* Priority as three bars: reads as magnitude, not as another colour to decode. */
.zs-priority{ display:inline-flex; align-items:flex-end; gap:2px; height:11px; vertical-align:-1px; }
.zs-priority i{ display:block; width:3px; border-radius:1px; background: var(--zs-border-strong); }
.zs-priority i:nth-child(1){ height:5px; } .zs-priority i:nth-child(2){ height:8px; } .zs-priority i:nth-child(3){ height:11px; }
.zs-priority[data-level="1"] i:nth-child(-n+1),
.zs-priority[data-level="2"] i:nth-child(-n+2),
.zs-priority[data-level="3"] i:nth-child(-n+3){ background: var(--zs-accent); }
.zs-priority[data-level="3"] i{ background: var(--zs-danger); }

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

body.app.admin table.table{
  background: var(--zs-surface-raised);
  color: var(--zs-text-primary);
  font-size: var(--zs-body-size);
  border-collapse: separate;
  border-spacing: 0;
  margin-bottom: 0;
  width: 100%;
}

/* Sticky header. Hairline separation only; no zebra striping anywhere. */
body.app.admin table.table > thead > tr > th{
  position: sticky; top: 0; z-index: 2;
  background: var(--zs-surface-raised);
  border-bottom: 1px solid var(--zs-border) !important;
  border-top: 0 !important;
  padding: var(--zs-s3) var(--zs-row-pad-x);
  font-size: var(--zs-label-size);
  font-weight: var(--zs-label-w);
  letter-spacing: var(--zs-label-ls);
  text-transform: uppercase;
  color: var(--zs-text-tertiary);
  white-space: nowrap;
  vertical-align: middle;
}
body.app.admin table.table > tbody > tr > td{
  border-top: 0 !important;
  border-bottom: 1px solid var(--zs-border);
  padding: var(--zs-row-pad-y) var(--zs-row-pad-x);
  vertical-align: middle;
  transition: background var(--zs-t-fast) var(--zs-ease);
}
body.app.admin table.table > tbody > tr:last-child > td{ border-bottom: 0; }
body.app.admin table.table > tbody > tr:hover > td{ background: var(--zs-surface-hover); }
body.app.admin table.table > tbody > tr.selected > td,
body.app.admin table.table > tbody > tr.active > td{ background: var(--zs-surface-selected); }
body.app.admin table.table-striped > tbody > tr:nth-of-type(odd) > td{ background: transparent; }
body.app.admin table.table-bordered,
body.app.admin table.table-bordered > tbody > tr > td,
body.app.admin table.table-bordered > thead > tr > th{ border-left:0 !important; border-right:0 !important; }

/* Numbers right-aligned in the data face. */
/* A FIGURE: right-aligned so digits line up down the column, and the
   header goes with it. zs-num-head is applied by ui.js to the header of
   any column it detects as numeric; without a rule here the cells were
   right-aligned under a left-aligned label, which is what made the module
   tables look like the columns had slipped. */
body.app.admin table.table td.zs-num,
body.app.admin table.table th.zs-num,
body.app.admin table.table th.zs-num-head,
body.app.admin table.table td.text-right,
body.app.admin table.table th.text-right{
  text-align: right;
  font-family: var(--zs-font-data);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1, 'zero' 1;
}

/* A CODE: an SKU, a barcode, a document number, a date. It wants the same
   tabular face so characters line up, but it is not a quantity and must
   NOT be right-aligned - a column of right-ranged SKUs reads as if it is
   detached from its heading. Separate class, because the distinction is
   about meaning and only the view knows which it has. */
body.app.admin table.table td.zs-code,
body.app.admin table.table th.zs-code,
.zs-code{
  font-family: var(--zs-font-data);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1, 'zero' 1;
  letter-spacing: var(--zs-data-ls);
}
body.app.admin table.table th.text-right{ font-family: var(--zs-font-ui); }

/* Row actions: present but quiet until the row is under the cursor. */
body.app.admin table.table .row-options,
body.app.admin table.table .zs-row-actions{
  opacity: 0; transition: opacity var(--zs-t-fast) var(--zs-ease);
}
body.app.admin table.table > tbody > tr:hover .row-options,
body.app.admin table.table > tbody > tr:hover .zs-row-actions,
body.app.admin table.table > tbody > tr:focus-within .row-options,
body.app.admin table.table > tbody > tr:focus-within .zs-row-actions{ opacity: 1; }

/* Avatar for people and company cells. */
.zs-avatar{
  width:26px; height:26px; border-radius:50%; flex:none;
  display:inline-grid; place-items:center;
  background: var(--zs-accent-soft); color: var(--zs-accent);
  font-size: var(--zs-caption-size); font-weight:600;
  object-fit: cover; vertical-align:middle;
}
.zs-cell-person{ display:inline-flex; align-items:center; gap: var(--zs-s2); }

/* ── DataTables chrome ─────────────────────────────────────────────────── */

body.app.admin .dataTables_wrapper{ background: var(--zs-surface-raised); border-radius: var(--zs-r-lg); }
body.app.admin .dataTables_wrapper .dataTables_filter input,
body.app.admin .dataTables_wrapper .dataTables_length select{
  background: var(--zs-surface-raised);
  border: 1px solid var(--zs-border-strong);
  border-radius: var(--zs-r-md);
  color: var(--zs-text-primary);
  padding: 7px var(--zs-s3);
  font-size: var(--zs-body-size);
}
body.app.admin .dataTables_wrapper .dataTables_filter input:focus{
  border-color: var(--zs-accent); box-shadow: 0 0 0 3px var(--zs-accent-ring); outline:none;
}
body.app.admin .dataTables_wrapper .dataTables_info,
body.app.admin .dataTables_wrapper .dataTables_length label,
body.app.admin .dataTables_wrapper .dataTables_filter label{
  color: var(--zs-text-secondary); font-size: var(--zs-caption-size);
}

/* Footer: info, per-page and pagination read as one strip. */
body.app.admin .dataTables_wrapper .row:last-child{
  border-top: 1px solid var(--zs-border);
  margin: 0; padding: var(--zs-s3) var(--zs-s4);
  align-items: center;
}
body.app.admin .pagination{
  margin: 0; padding-left: 0; list-style: none;
  display: inline-flex; align-items: center; gap: 0;
}
body.app.admin .pagination > li{ display: inline-block; list-style: none; }
body.app.admin .pagination > li > a,
body.app.admin .pagination > li > span{
  background: transparent;
  border: 1px solid var(--zs-border);
  color: var(--zs-text-secondary);
  margin-left: var(--zs-s1);
  border-radius: var(--zs-r-md) !important;
  padding: 6px 11px;
  font-size: var(--zs-caption-size);
  font-family: var(--zs-font-data);
  transition: background var(--zs-t-fast) var(--zs-ease), color var(--zs-t-fast) var(--zs-ease);
}
body.app.admin .pagination > li > a:hover{ background: var(--zs-surface-hover); color: var(--zs-text-primary); }
body.app.admin .pagination > .active > a,
body.app.admin .pagination > .active > span,
body.app.admin .pagination > .active > a:hover{
  background: var(--zs-accent); border-color: var(--zs-accent); color: var(--zs-text-on-accent);
}
body.app.admin .pagination > .disabled > a,
body.app.admin .pagination > .disabled > span{ opacity:.45; }

/* Sort indicators: a single caret that fills when active. */
body.app.admin table.table > thead > tr > th.sorting,
body.app.admin table.table > thead > tr > th.sorting_asc,
body.app.admin table.table > thead > tr > th.sorting_desc{
  cursor: pointer; position: relative; padding-right: var(--zs-s6);
  background-image: none !important;
}
body.app.admin table.table > thead > tr > th.sorting::after,
body.app.admin table.table > thead > tr > th.sorting_asc::after,
body.app.admin table.table > thead > tr > th.sorting_desc::after{
  content: ''; position: absolute; right: var(--zs-s3); top: 50%;
  width: 0; height: 0; margin-top: -2px;
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  transition: opacity var(--zs-t-fast) var(--zs-ease);
}
body.app.admin table.table > thead > tr > th.sorting::after{
  border-top: 5px solid var(--zs-text-tertiary); opacity: .35;
}
body.app.admin table.table > thead > tr > th.sorting_asc::after{
  border-bottom: 5px solid var(--zs-accent); margin-top: -4px; opacity: 1;
}
body.app.admin table.table > thead > tr > th.sorting_desc::after{
  border-top: 5px solid var(--zs-accent); opacity: 1;
}
body.app.admin table.table > thead > tr > th.sorting:hover::after{ opacity:.7; }

/* Bulk selection: a floating bar, so the action follows the selection. */
.zs-bulkbar{
  position: fixed; left: 50%; bottom: var(--zs-s6); transform: translateX(-50%) translateY(8px);
  z-index: 1040;
  display: flex; align-items: center; gap: var(--zs-s4);
  background: var(--zs-text-primary); color: var(--zs-surface-raised);
  padding: var(--zs-s3) var(--zs-s5);
  border-radius: var(--zs-r-pill);
  box-shadow: var(--zs-e3);
  opacity: 0; pointer-events: none;
  transition: opacity var(--zs-t-base) var(--zs-ease), transform var(--zs-t-base) var(--zs-ease);
}
.zs-bulkbar.is-visible{ opacity:1; transform: translateX(-50%); pointer-events:auto; }
.zs-bulkbar .zs-bulkbar-count{ font-family: var(--zs-font-data); font-weight:600; }

/* ── Empty state: never a spinner over a void ──────────────────────────── */

.zs-empty{
  padding: var(--zs-s12) var(--zs-s6);
  text-align: center; color: var(--zs-text-secondary);
}
.zs-empty-icon{
  width: 44px; height: 44px; margin: 0 auto var(--zs-s4);
  display: grid; place-items: center;
  border-radius: var(--zs-r-lg);
  background: var(--zs-surface-sunken); color: var(--zs-text-tertiary);
  font-size: 19px;
}
.zs-empty-title{
  font-size: var(--zs-h3-size); font-weight: 600;
  color: var(--zs-text-primary); margin-bottom: var(--zs-s1);
}
.zs-empty-text{ font-size: var(--zs-body-size); margin-bottom: var(--zs-s5); }
body.app.admin td.dataTables_empty{
  padding: var(--zs-s10) var(--zs-s4) !important;
  text-align:center; color: var(--zs-text-secondary);
}

/* Skeleton rows while a table loads. */
@keyframes zs-shimmer{ 0%{background-position:-420px 0} 100%{background-position:420px 0} }
.zs-skel{
  /* Inline by default means height is ignored and the skeleton is invisible. */
  display: block;
  height: 11px; max-width: 100%; border-radius: var(--zs-r-sm);
  background: var(--zs-surface-sunken);
  background-image: linear-gradient(90deg,
    var(--zs-surface-sunken) 0%, var(--zs-surface-hover) 45%, var(--zs-surface-sunken) 90%);
  background-size: 420px 100%;
  animation: zs-shimmer 1.25s linear infinite;
}
@media (prefers-reduced-motion: reduce){ .zs-skel{ animation: none; } }
body.app.admin table.dt-table-loading tbody tr td{ opacity: .5; }

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

body.app.admin #side-menu,
body.app.admin .navbar-default .sidebar,
body.app.admin .sidebar{
  background: var(--zs-surface-raised);
  border-right: 1px solid var(--zs-border);
}
body.app.admin #side-menu li > a{
  color: var(--zs-text-secondary);
  font-size: var(--zs-body-size);
  font-weight: 500;
  padding: 9px var(--zs-s4);
  margin: 1px var(--zs-s2);
  border-radius: var(--zs-r-md);
  border: 0;
  transition: background var(--zs-t-fast) var(--zs-ease), color var(--zs-t-fast) var(--zs-ease);
}
body.app.admin #side-menu li > a:hover,
body.app.admin #side-menu li > a:focus{
  background: var(--zs-surface-hover); color: var(--zs-text-primary);
}
/* Active state: tinted, accented, and marked with a rail so it survives
   being the only cue on a small screen. */
body.app.admin #side-menu li.active > a,
body.app.admin #side-menu li > a.active{
  background: var(--zs-accent-soft);
  color: var(--zs-accent);
  font-weight: 600;
  position: relative;
}
body.app.admin #side-menu li.active > a::before{
  content:''; position:absolute; left:0; top:50%; transform:translateY(-50%);
  width:3px; height:17px; border-radius:0 2px 2px 0; background: var(--zs-accent);
}
body.app.admin #side-menu li > a i{ color: currentColor; opacity:.85; }
body.app.admin #side-menu .nav-second-level li a{
  padding-left: var(--zs-s10); font-size: var(--zs-caption-size);
}

/* ── Top bar ───────────────────────────────────────────────────────────── */

body.app.admin #header,
body.app.admin .navbar-default,
body.app.admin nav.navbar{
  background: var(--zs-surface-raised);
  border-bottom: 1px solid var(--zs-border);
  box-shadow: none;
}
body.app.admin .navbar-nav > li > a{
  color: var(--zs-text-secondary);
  font-size: var(--zs-body-size);
  transition: color var(--zs-t-fast) var(--zs-ease);
}
body.app.admin .navbar-nav > li > a:hover{ color: var(--zs-text-primary); }
body.app.admin #search input,
body.app.admin .top-search input{
  background: var(--zs-surface-sunken);
  border: 1px solid transparent;
  border-radius: var(--zs-r-md);
  color: var(--zs-text-primary);
}
body.app.admin #search input:focus{
  background: var(--zs-surface-raised);
  border-color: var(--zs-accent);
  box-shadow: 0 0 0 3px var(--zs-accent-ring);
}

/* ── Breadcrumbs ───────────────────────────────────────────────────────── */

body.app.admin .breadcrumb, .zs-breadcrumb{
  background: transparent; padding: 0; margin-bottom: var(--zs-s3);
  font-size: var(--zs-caption-size); color: var(--zs-text-tertiary);
}
body.app.admin .breadcrumb > li + li::before,
.zs-breadcrumb > li + li::before{ content:'/'; color: var(--zs-text-tertiary); padding: 0 var(--zs-s2); }
body.app.admin .breadcrumb > .active{ color: var(--zs-text-primary); font-weight:500; }

/* ── Dropdowns, modals, drawers ────────────────────────────────────────── */

body.app.admin .dropdown-menu{
  background: var(--zs-surface-raised);
  border: 1px solid var(--zs-border);
  border-radius: var(--zs-r-lg);
  box-shadow: var(--zs-e3);
  padding: var(--zs-s1);
  font-size: var(--zs-body-size);
}
body.app.admin .dropdown-menu > li > a{
  color: var(--zs-text-primary); border-radius: var(--zs-r-sm);
  padding: 7px var(--zs-s3);
  transition: background var(--zs-t-fast) var(--zs-ease);
}
body.app.admin .dropdown-menu > li > a:hover,
body.app.admin .dropdown-menu > li > a:focus{ background: var(--zs-surface-hover); color: var(--zs-text-primary); }
body.app.admin .dropdown-menu .divider{ background: var(--zs-border); margin: var(--zs-s1) 0; }

body.app.admin .modal-content{
  background: var(--zs-surface-raised);
  border: 1px solid var(--zs-border);
  border-radius: var(--zs-r-xl);
  box-shadow: var(--zs-e3);
}
body.app.admin .modal-header{
  border-bottom: 1px solid var(--zs-border);
  padding: var(--zs-s5);
}
body.app.admin .modal-title{ font-size: var(--zs-h2-size); font-weight: var(--zs-h2-w); letter-spacing: var(--zs-h2-ls); }
body.app.admin .modal-body{ padding: var(--zs-s5); }
body.app.admin .modal-footer{
  border-top: 1px solid var(--zs-border);
  padding: var(--zs-s4) var(--zs-s5);
  background: var(--zs-surface);
  border-radius: 0 0 var(--zs-r-xl) var(--zs-r-xl);
}
body.app.admin .modal-backdrop.in{ opacity:.42; background: var(--zs-ink); }

/* ── Tabs ──────────────────────────────────────────────────────────────── */

body.app.admin .nav-tabs{ border-bottom: 1px solid var(--zs-border); }
body.app.admin .nav-tabs > li > a{
  border: 0; border-bottom: 2px solid transparent;
  border-radius: 0; margin-right: var(--zs-s5); padding: var(--zs-s3) 0;
  color: var(--zs-text-secondary); font-weight: 500; font-size: var(--zs-body-size);
  background: transparent;
  transition: color var(--zs-t-fast) var(--zs-ease), border-color var(--zs-t-fast) var(--zs-ease);
}
body.app.admin .nav-tabs > li > a:hover{ background: transparent; color: var(--zs-text-primary); border-bottom-color: var(--zs-border-strong); }
body.app.admin .nav-tabs > li.active > a,
body.app.admin .nav-tabs > li.active > a:hover,
body.app.admin .nav-tabs > li.active > a:focus{
  background: transparent; border: 0; border-bottom: 2px solid var(--zs-accent);
  color: var(--zs-accent); font-weight: 600;
}

/* ── Alerts and toasts ─────────────────────────────────────────────────── */

body.app.admin .alert{
  border-radius: var(--zs-r-md);
  border: 1px solid transparent;
  padding: var(--zs-s3) var(--zs-s4);
  font-size: var(--zs-body-size);
  box-shadow: none;
}
body.app.admin .alert-success{ background: var(--zs-success-soft); border-color: var(--zs-success); color: var(--zs-success); }
body.app.admin .alert-danger { background: var(--zs-danger-soft);  border-color: var(--zs-danger);  color: var(--zs-danger); }
body.app.admin .alert-warning{ background: var(--zs-warning-soft); border-color: var(--zs-warning); color: var(--zs-warning); }
body.app.admin .alert-info   { background: var(--zs-info-soft);    border-color: var(--zs-info);    color: var(--zs-info); }

body.app.admin .alert-zeismo-success,
body.app.admin .alert-zeismo-danger,
body.app.admin .alert-zeismo-warning,
body.app.admin #main-alerts .alert{ border-radius: var(--zs-r-md); box-shadow: var(--zs-e2); }

/* ── Stat widgets ──────────────────────────────────────────────────────────
   One big tabular number, a small quiet label, and a trend that whispers.  */

.zs-stat{
  background: var(--zs-surface-raised);
  border: 1px solid var(--zs-border);
  border-radius: var(--zs-r-lg);
  box-shadow: var(--zs-e1);
  padding: var(--zs-s5);
}
.zs-stat-label{
  font-size: var(--zs-label-size); font-weight: var(--zs-label-w);
  letter-spacing: var(--zs-label-ls); text-transform: uppercase;
  color: var(--zs-text-tertiary); margin-bottom: var(--zs-s2);
}
.zs-stat-value{
  font-size: 28px; font-weight: 600; line-height: 1.1;
  color: var(--zs-text-primary);
}
.zs-stat-value .zs-stat-unit{ font-size: 15px; color: var(--zs-text-tertiary); font-weight: 500; }
.zs-stat-trend{
  display:inline-flex; align-items:center; gap:4px;
  margin-top: var(--zs-s2);
  font-size: var(--zs-caption-size); font-family: var(--zs-font-data);
  color: var(--zs-text-secondary);
}
.zs-stat-trend.is-up{ color: var(--zs-success); }
.zs-stat-trend.is-down{ color: var(--zs-danger); }

/* The legacy dashboard tiles inherit the same treatment. */
body.app.admin .widget .panel_s .panel-body h4,
body.app.admin ._total{
  font-family: var(--zs-font-data); font-variant-numeric: tabular-nums; font-weight: 600;
}

/* ── Wells, list groups, misc surfaces ─────────────────────────────────── */

body.app.admin .well{
  background: var(--zs-surface-sunken); border: 1px solid var(--zs-border);
  border-radius: var(--zs-r-md); box-shadow: none;
}
body.app.admin .list-group-item{
  background: var(--zs-surface-raised); border-color: var(--zs-border); color: var(--zs-text-primary);
}
body.app.admin .progress{ background: var(--zs-surface-sunken); border-radius: var(--zs-r-pill); box-shadow:none; height: 6px; }
body.app.admin .progress-bar{ background: var(--zs-accent); box-shadow:none; }
body.app.admin code, body.app.admin pre{
  font-family: var(--zs-font-data); font-size: var(--zs-caption-size);
  background: var(--zs-surface-sunken); border: 1px solid var(--zs-border);
  border-radius: var(--zs-r-sm); color: var(--zs-text-primary);
}
body.app.admin .tooltip-inner{
  background: var(--zs-text-primary); color: var(--zs-surface-raised);
  border-radius: var(--zs-r-md); font-size: var(--zs-caption-size);
  padding: 6px 10px; box-shadow: var(--zs-e2);
}

/* Nothing in the product may scroll the page sideways. Wide content scrolls
   inside its own container instead. */
body.app.admin{ overflow-x: hidden; }
body.app.admin .table-responsive,
body.app.admin .dataTables_wrapper{ overflow-x: auto; -webkit-overflow-scrolling: touch; }


/* ═══════════════════════════════════════════════════════════════════════
   TOOLBAR REFINEMENT (2026 pass)
   The top bar is the one piece of chrome on every screen. It should read as a
   single calm strip: one row, even rhythm, nothing competing for attention.
   ═══════════════════════════════════════════════════════════════════════ */

body.app.admin #header{
  height: 60px;
  display: flex; align-items: center;
  padding: 0 var(--zs-s4);
  gap: var(--zs-s2);
  background: var(--zs-surface-raised);
  border-bottom: 1px solid var(--zs-border);
  position: sticky; top: 0; z-index: 1030;
}

/* The company name is a wordmark, not a headline: sized down and weighted so
   it identifies without dominating the row. */
body.app.admin #header .logo,
body.app.admin #header a.navbar-brand{
  font-size: 15px !important; font-weight: 700 !important;
  letter-spacing: -0.01em; color: var(--zs-accent) !important;
  text-transform: none;
  display: inline-flex; align-items: center;
  max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Every icon control in the bar shares one 34px hit target, so the row has an
   even rhythm instead of icons at mixed sizes and offsets. */
body.app.admin #header .navbar-nav > li > a,
body.app.admin #header .zs-theme-toggle,
body.app.admin #header .hide-menu{
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; height: 34px; padding: 0 8px; margin: 0 1px;
  border-radius: var(--zs-r-md);
  color: var(--zs-text-secondary);
  transition: background var(--zs-t-fast) var(--zs-ease),
              color var(--zs-t-fast) var(--zs-ease);
}
body.app.admin #header .navbar-nav > li > a:hover,
body.app.admin #header .zs-theme-toggle:hover,
body.app.admin #header .hide-menu:hover{
  background: var(--zs-surface-hover); color: var(--zs-text-primary);
}
/* The bar's inner chain (nav > div > div > ul) is block-level and 57px tall
   inside a 60px strip, which left the quick-add sitting at the top rather than
   on the centre line. Every level is made a centred flex row so one rule
   settles the whole chain instead of nudging individual items. */
body.app.admin #header > nav{
  display: flex !important; align-items: center !important;
  flex: 1 1 auto; min-width: 0; height: 100%; margin: 0 !important;
}
/* Height and centring only. Forcing width here made each nested wrapper span
   the full bar, which stacked the siblings past the right edge and pushed the
   search and icons off-screen. Let their own widths stand. */
body.app.admin #header nav > div,
body.app.admin #header nav > div > div{
  display: flex !important; align-items: center !important;
  min-width: 0; height: 100%; margin: 0 !important;
}
body.app.admin #header nav > div{ flex: 1 1 auto; }
body.app.admin #header .navbar-nav{
  display: flex !important; align-items: center !important;
  height: 100%; margin: 0 !important; padding: 0 !important;
}
body.app.admin #header .navbar-nav > li{
  float: none !important; display: inline-flex !important;
  align-items: center; height: 100%;
}

/* ── Search: the centrepiece of the bar ──────────────────────────────────
   A soft filled field that lifts to a raised surface with an accent ring on
   focus. Filled-at-rest reads as "type here" far better than an outline, and
   the lift on focus gives the interaction somewhere to go.                  */

body.app.admin #top_search{
  flex: 1 1 auto; max-width: 520px;
  margin: 0 var(--zs-s3) !important;
}
body.app.admin #search_input,
body.app.admin #top_search input[type="search"]{
  width: 100%; height: 38px;
  padding: 0 var(--zs-s4) 0 38px;
  border-radius: var(--zs-r-pill);
  background: var(--zs-surface-sunken) !important;
  border: 1px solid transparent !important;
  color: var(--zs-text-primary) !important;
  font-family: var(--zs-font-ui); font-size: var(--zs-body-size);
  box-shadow: none;
  transition: background var(--zs-t-base) var(--zs-ease),
              border-color var(--zs-t-base) var(--zs-ease),
              box-shadow var(--zs-t-base) var(--zs-ease);
}
body.app.admin #search_input::placeholder{ color: var(--zs-text-tertiary); }
body.app.admin #search_input:hover{ background: var(--zs-surface-hover) !important; }
body.app.admin #search_input:focus{
  background: var(--zs-surface-raised) !important;
  border-color: var(--zs-accent) !important;
  box-shadow: 0 0 0 3px var(--zs-accent-ring);
  outline: none;
}
body.app.admin #top_search_button{
  left: 12px !important; right: auto !important; top: 50% !important;
  transform: translateY(-50%); pointer-events: none;
}
body.app.admin #top_search_button button{
  padding: 0 !important; color: var(--zs-text-tertiary) !important;
  background: transparent !important; line-height: 0;
}
body.app.admin #top_search:focus-within #top_search_button button{ color: var(--zs-accent) !important; }

/* Every direct child of the bar centres on one line. The markup carries
   Tailwind margins (tw-mt-*) tuned for the old 70px bar, which pushed the
   quick-add button above the strip; those are neutralised here. */
body.app.admin #header > *,
body.app.admin #header .navbar-nav > li{
  margin-top: 0 !important; margin-bottom: 0 !important;
  align-self: center;
}

/* Any element in the bar carrying a negative top margin from the old 70px
   layout. `-tw-mt-1` on the quick-add's <li> was lifting it out of the strip. */
body.app.admin #header li.icon,
body.app.admin #header .-tw-mt-1,
body.app.admin #header .tw-mt-4,
body.app.admin #header .tw-mt-2{
  margin-top: 0 !important;
  display: inline-flex; align-items: center; align-self: center;
}

/* The quick-add "+" circle: sized to match the other controls. */
body.app.admin #header a[data-toggle="dropdown"] > span.tw-rounded-full{
  width: 32px !important; height: 32px !important;
  background: var(--zs-accent) !important;
}

body.app.admin #header a.quick-actions-toggle,
body.app.admin #header .quick-actions-toggle{
  width: 34px; height: 34px; padding: 0 !important; margin: 0 2px !important;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--zs-r-md) !important;
  background: var(--zs-accent) !important;
  color: #fff !important;
  align-self: center;
}
body.app.admin #header a.quick-actions-toggle:hover{ background: var(--zs-accent-hover) !important; }

/* The search wrapper is a flex row so the field sits centred at its own
   height instead of stretching the strip. */
body.app.admin #top_search{
  display: flex !important; align-items: center;
  height: 38px; align-self: center;
}

/* ── Forms (2026 pass) ───────────────────────────────────────────────────
   Fields were floating at full width with loose vertical rhythm. Tightened:
   a comfortable max measure, consistent gaps, and a required marker that
   reads as a marker rather than as an error.                                */

body.app.admin .panel_s .panel-body > .form-group,
body.app.admin form .form-group{ margin-bottom: var(--zs-s4); }

/* A text field the width of a monitor is hard to scan and looks unfinished.
   Capped to a comfortable measure; full-width elements opt back in. */
body.app.admin .panel-body input.form-control:not([type="hidden"]),
body.app.admin .panel-body select.form-control{
  max-width: 620px;
}
body.app.admin .panel-body textarea.form-control{ max-width: 820px; }
body.app.admin .form-control.tw-w-full,
body.app.admin .input-group .form-control{ max-width: none; }

/* The red asterisk on every label read like a validation error. It is a
   marker: quieter, and after the word where it belongs. */
body.app.admin .form-group label .text-danger,
body.app.admin label > .text-danger{
  color: var(--zs-text-tertiary) !important;
  font-weight: 400;
}

body.app.admin .panel-footer{
  background: var(--zs-surface);
  border-top: 1px solid var(--zs-border);
  padding: var(--zs-s4) var(--zs-s5);
  border-radius: 0 0 var(--zs-r-lg) var(--zs-r-lg);
}

/* Bootstrap-select and input groups matched to the field styling. */
body.app.admin .bootstrap-select > .dropdown-toggle{
  height: 38px; display: inline-flex; align-items: center;
  border-radius: var(--zs-r-md);
}
body.app.admin .input-group-addon{
  background: var(--zs-surface-sunken);
  border-color: var(--zs-border-strong);
  color: var(--zs-text-secondary);
  border-radius: var(--zs-r-md);
}

/* ── Tables (2026 pass) ──────────────────────────────────────────────────
   Column headers get a sunken strip so the header reads as a distinct band,
   and the first column carries slightly more weight as the row's subject.   */

body.app.admin table.table > thead > tr > th{
  background: var(--zs-surface-sunken);
  border-bottom: 1px solid var(--zs-border) !important;
  font-size: 10.5px;
}
body.app.admin table.table > thead > tr > th:first-child{ border-radius: var(--zs-r-md) 0 0 0; }
body.app.admin table.table > thead > tr > th:last-child{ border-radius: 0 var(--zs-r-md) 0 0; }

/* The row's subject: the first text column reads as the thing, the rest as
   its attributes. */
body.app.admin table.table > tbody > tr > td:first-child,
body.app.admin table.table > tbody > tr > td:nth-child(2){
  font-weight: 500;
}
body.app.admin table.table > tbody > tr{
  transition: background var(--zs-t-fast) var(--zs-ease);
}
body.app.admin table.table > tbody > tr:hover{ background: var(--zs-surface-hover); }

/* Tabs above a form/table read as a segmented control rather than as links. */
body.app.admin .nav-tabs{
  border-bottom: 1px solid var(--zs-border);
  padding: 0 var(--zs-s5);
  background: transparent;
}

/* ── Responsive: tables become card lists on a phone ───────────────────── */

@media (max-width: 767px){
  body.app.admin .panel_s .panel-body{ padding: var(--zs-s4); }

  body.app.admin table.table.zs-stack,
  body.app.admin table.table.zs-stack thead,
  body.app.admin table.table.zs-stack tbody,
  body.app.admin table.table.zs-stack tr,
  body.app.admin table.table.zs-stack td{ display: block; width: 100%; }

  body.app.admin table.table.zs-stack thead{
    position: absolute; width:1px; height:1px; overflow:hidden; clip: rect(0 0 0 0);
  }
  body.app.admin table.table.zs-stack > tbody > tr{
    border: 1px solid var(--zs-border);
    border-radius: var(--zs-r-lg);
    margin-bottom: var(--zs-s3);
    padding: var(--zs-s2) 0;
    background: var(--zs-surface-raised);
  }
  body.app.admin table.table.zs-stack > tbody > tr > td{
    border-bottom: 0;
    display: flex; justify-content: space-between; gap: var(--zs-s4);
    padding: 7px var(--zs-s4);
    text-align: right;
  }
  /* The header text is carried onto each cell so a stacked row still reads. */
  body.app.admin table.table.zs-stack > tbody > tr > td[data-label]::before{
    content: attr(data-label);
    flex: none; text-align: left;
    font-size: var(--zs-label-size); font-weight: var(--zs-label-w);
    letter-spacing: var(--zs-label-ls); text-transform: uppercase;
    color: var(--zs-text-tertiary);
  }
  /* A cell with no column name (the select checkbox, the row-actions column)
     has nothing to caption, so it sits left instead of leaving a labelled gap. */
  body.app.admin table.table.zs-stack > tbody > tr > td:not([data-label]){
    justify-content: flex-start; text-align: left;
  }
  /* An empty cell in a stacked row is just dead height. */
  body.app.admin table.table.zs-stack > tbody > tr > td:empty{ display: none; }
  /* Row actions are hover-revealed on desktop; on a touch screen there is no
     hover, so they are always visible once the row is a card. */
  body.app.admin table.table.zs-stack .row-options,
  body.app.admin table.table.zs-stack .zs-row-actions{ opacity: 1; }
  .zs-bulkbar{ left: var(--zs-s3); right: var(--zs-s3); transform:none; border-radius: var(--zs-r-lg); }
  .zs-bulkbar.is-visible{ transform:none; }

  /* ── Topbar on a phone ───────────────────────────────────────────────
     The core header carries `tw-hidden md:tw-flex` on #logo, so below
     768px the product showed no brand at all: a hamburger, then a row of
     icons. Put the mark back, and keep it from crowding the controls. */
  body.app.admin #header #logo{
    display: flex !important;
    height: 48px;
    max-width: 42vw;          /* never squeezes the controls off-screen */
    overflow: hidden;
  }
  body.app.admin #header #logo img{
    height: 26px !important;
    width: auto !important;
    max-width: 100%;
    object-fit: contain;
  }
  /* The text fallback (a workspace with no uploaded logo) has no natural
     limit, so a long company name would push the icon row away. */
  body.app.admin #header #logo .logo-text{
    font-size: 15px !important;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
  }

  /* The control cluster is ul.navbar-right, and at 390px it ran 16px past
     the viewport - which is what made the whole page scroll sideways. It
     scrolls within itself now instead of pushing the document wider. */
  body.app.admin #header ul.navbar-nav.navbar-right{
    display: flex;
    flex-wrap: nowrap;
    max-width: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  body.app.admin #header ul.navbar-nav.navbar-right::-webkit-scrollbar{ display: none; }
  body.app.admin #header ul.navbar-nav.navbar-right > li{ flex: 0 0 auto; }
  /* Belt and braces: nothing in the header may widen the document. */
  body.app.admin #header,
  body.app.admin #header nav{ max-width: 100vw; overflow-x: clip; }

  /* The plan chip states status; on a phone the bolt and the tier name are
     enough, and the padding is what was eating the width. */
  body.app.admin .zs-plan-chip{
    height: 28px; padding: 0 8px; margin: 0 3px; font-size: 12px;
  }
}

@media (max-width: 420px){
  /* At this width the tier name is the first thing worth losing: the chip
     still reads as "plan" and still opens quota and upgrade. */
  body.app.admin .zs-plan-chip .zs-plan-chip-label{ display: none; }
  body.app.admin .zs-plan-chip{ padding: 0 7px; }
  body.app.admin #header #logo{ max-width: 34vw; }
}

@media (max-width: 380px){
  body.app.admin{ font-size: 13px; }
  body.app.admin .panel_s .panel-body{ padding: var(--zs-s3); }
  .zs-stat-value{ font-size: 24px; }
}

/* ── Plan chip (topbar) ─────────────────────────────────────────────────
   The tenant's current plan, one click from quota and upgrade. A soft chip,
   not a filled button: it states status, it does not shout an action. Sized
   to sit level with the icon row.                                            */
body.app.admin .zs-plan-chip-host{ display: inline-flex; align-items: center; }
body.app.admin .zs-plan-chip{
  display: inline-flex; align-items: center; gap: 5px;
  height: 30px; padding: 0 12px; margin: 0 6px;
  border-radius: var(--zs-r-pill);
  background: var(--zs-accent-soft);
  color: var(--zs-accent);
  border: 1px solid transparent;
  font-family: var(--zs-font-ui);
  font-size: 12.5px; font-weight: 600; line-height: 1;
  white-space: nowrap;
  transition: background var(--zs-t-fast) var(--zs-ease),
              border-color var(--zs-t-fast) var(--zs-ease);
}
body.app.admin .zs-plan-chip:hover,
body.app.admin .zs-plan-chip:focus{
  background: var(--zs-accent-soft);
  border-color: var(--zs-accent);
  color: var(--zs-accent);
  text-decoration: none;
}
body.app.admin .zs-plan-chip svg{ flex: none; opacity: .9; }

/* ── Scrollbars ──────────────────────────────────────────────────────────
   The default horizontal scrollbar under a wide table is a thick grey slab
   that reads as a broken UI element, and it sits there permanently even on a
   table with nothing to scroll to. Thin, low-contrast, and it uses the
   surface tokens so it disappears into the card until it is needed.         */

body.app.admin *{
  scrollbar-width: thin;                                  /* Firefox */
  scrollbar-color: var(--zs-border-strong) transparent;
}
body.app.admin *::-webkit-scrollbar{ width: 9px; height: 9px; }
body.app.admin *::-webkit-scrollbar-track{ background: transparent; }
body.app.admin *::-webkit-scrollbar-thumb{
  background: var(--zs-border-strong);
  border-radius: var(--zs-r-pill);
  border: 2px solid transparent;
  background-clip: content-box;
}
body.app.admin *::-webkit-scrollbar-thumb:hover{ background-clip: padding-box; }
body.app.admin *::-webkit-scrollbar-corner{ background: transparent; }

/* A table only scrolls when it genuinely overflows, and the bar is not
   reserved as permanent furniture underneath it. */
body.app.admin .table-responsive{
  overflow-x: auto;
  overscroll-behavior-x: contain;
}
/* Left visible: a clipping wrapper is what hid the first column, and the
   inner container already scrolls when the table is truly wider. */
body.app.admin .dataTables_wrapper{ overflow-x: visible; }
body.app.admin .dataTables_scrollBody{ overflow-x: auto !important; }
/* DataTables draws a second, always-visible bar in its own scroll head/foot
   even when the table fits; that is the slab in the screenshot. */
body.app.admin .dataTables_scrollHead,
body.app.admin .dataTables_scrollFoot{ overflow: hidden !important; }

/* ── Demo banner offset ───────────────────────────────────────────────────
   The sidebar's own first item carries a hard-coded Tailwind offset
   (tw-mt-[57px]) meant to clear the fixed top bar. The demo banner adds its
   own height above that bar, and without this the sidebar profile card
   slides in underneath it. ui.js measures the real banner height into
   --zs-note-h; this just adds it on top of the sidebar's existing offset. */
body.zs-demo-body .sidebar > *:first-child{
  margin-top: calc(57px + var(--zs-note-h, 33px)) !important;
}

/* ── Announcement card ──────────────────────────────────────────────────
   Replaces the stock Bootstrap alert (thin border, cramped header, a raw
   "From: 1" with no name resolution). A quiet icon tile, a real header row,
   and message copy that reads like a note from a person, not a system
   warning.                                                                  */

body.app.admin .zs-announce{
  display: flex; gap: var(--zs-s4);
  background: var(--zs-surface-raised);
  border: 1px solid var(--zs-border);
  border-left: 3px solid var(--zs-accent);
  border-radius: var(--zs-r-lg);
  box-shadow: var(--zs-e1);
  padding: var(--zs-s5);
  margin-bottom: var(--zs-s5);
}
body.app.admin .zs-announce-icon{
  flex: none; width: 38px; height: 38px; border-radius: var(--zs-r-md);
  background: var(--zs-accent-soft); color: var(--zs-accent);
  display: grid; place-items: center; font-size: 15px;
}
body.app.admin .zs-announce-body{ flex: 1; min-width: 0; }
body.app.admin .zs-announce-head{
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--zs-s1) var(--zs-s3);
  margin-bottom: var(--zs-s2);
}
body.app.admin .zs-announce-tag{
  font-size: var(--zs-label-size); font-weight: var(--zs-label-w);
  letter-spacing: var(--zs-label-ls); text-transform: uppercase;
  color: var(--zs-accent);
}
body.app.admin .zs-announce-from,
body.app.admin .zs-announce-date{
  font-size: var(--zs-caption-size); color: var(--zs-text-tertiary);
}
body.app.admin .zs-announce-from::before{ content: '·'; margin-inline-end: var(--zs-s3); color: var(--zs-border-strong); }
body.app.admin .zs-announce-date::before{ content: '·'; margin-inline-end: var(--zs-s3); color: var(--zs-border-strong); }
body.app.admin .zs-announce-actions{ margin-inline-start: auto; display: flex; gap: var(--zs-s2); }
body.app.admin .zs-announce-actions a{
  color: var(--zs-text-tertiary); width: 26px; height: 26px; border-radius: var(--zs-r-sm);
  display: grid; place-items: center; transition: background var(--zs-t-fast) var(--zs-ease), color var(--zs-t-fast) var(--zs-ease);
}
body.app.admin .zs-announce-actions a:hover{ background: var(--zs-surface-hover); color: var(--zs-text-primary); }
body.app.admin .zs-announce-title{
  font-size: var(--zs-h3-size); font-weight: 600; color: var(--zs-text-primary);
  margin: 0 0 var(--zs-s1);
}
body.app.admin .zs-announce-message{
  font-size: var(--zs-body-size); line-height: var(--zs-body-lh); color: var(--zs-text-secondary);
}
body.app.admin .zs-announce-message p{ margin: 0 0 var(--zs-s2); }

/* ── Theme toggle control ──────────────────────────────────────────────── */

.zs-theme-toggle{
  background: transparent; border: 0; cursor: pointer;
  color: var(--zs-text-secondary);
  padding: var(--zs-s2); margin: 6px var(--zs-s1) 0;
  border-radius: var(--zs-r-md); line-height: 0;
  transition: background var(--zs-t-fast) var(--zs-ease), color var(--zs-t-fast) var(--zs-ease);
}
.zs-theme-toggle:hover{ background: var(--zs-surface-hover); color: var(--zs-text-primary); }
.zs-theme-toggle svg{ width:17px; height:17px; }
:root[data-zs-theme="dark"] .zs-theme-toggle .zs-icon-moon,
:root:not([data-zs-theme="dark"]) .zs-theme-toggle .zs-icon-sun{ display:none; }
@media (prefers-color-scheme: dark){
  :root:not([data-zs-theme="light"]):not([data-zs-theme="dark"]) .zs-theme-toggle .zs-icon-moon{ display:none; }
  :root:not([data-zs-theme="light"]):not([data-zs-theme="dark"]) .zs-theme-toggle .zs-icon-sun{ display:inline; }
}

/* ── Dark-mode reconciliation for things that hard-code white ──────────── */

:root[data-zs-theme="dark"] body.app.admin,
:root[data-zs-theme="dark"] body.app.admin .content,
:root[data-zs-theme="dark"] #wrapper{ background: var(--zs-surface); }
:root[data-zs-theme="dark"] body.app.admin .panel_s,
:root[data-zs-theme="dark"] body.app.admin table.table,
:root[data-zs-theme="dark"] body.app.admin table.table > thead > tr > th{ background: var(--zs-surface-raised); }
:root[data-zs-theme="dark"] body.app.admin img.zs-invert-on-dark{ filter: invert(1) hue-rotate(180deg); }

/* ── Tailwind literals that survive into dark mode ───────────────────────
   `tw-bg-white`, `tw-bg-neutral-*` and friends are compiled hex values sitting
   in the markup of 261 views, so no amount of restyling a component class
   reaches them. Only the ones that paint a visible surface are re-pointed,
   and only under dark mode, because in light they are already right.        */

:root[data-zs-theme="dark"] body.app.admin .tw-bg-white,
:root[data-zs-theme="dark"] body.app.admin .\!tw-bg-white,
:root[data-zs-theme="dark"] body.app.admin .tw-bg-neutral-50,
:root[data-zs-theme="dark"] body.app.admin .tw-bg-neutral-100,
:root[data-zs-theme="dark"] body.app.admin .tw-bg-gray-50,
:root[data-zs-theme="dark"] body.app.admin .tw-bg-gray-100{
  background-color: var(--zs-surface-raised) !important;
}
:root[data-zs-theme="dark"] body.app.admin .tw-text-neutral-700,
:root[data-zs-theme="dark"] body.app.admin .tw-text-neutral-800,
:root[data-zs-theme="dark"] body.app.admin .tw-text-neutral-900{
  color: var(--zs-text-primary) !important;
}
:root[data-zs-theme="dark"] body.app.admin .tw-text-neutral-400,
:root[data-zs-theme="dark"] body.app.admin .tw-text-neutral-500,
:root[data-zs-theme="dark"] body.app.admin .tw-text-neutral-600{
  color: var(--zs-text-secondary) !important;
}
:root[data-zs-theme="dark"] body.app.admin .tw-border-neutral-200,
:root[data-zs-theme="dark"] body.app.admin .tw-border-neutral-300,
:root[data-zs-theme="dark"] body.app.admin .tw-border-solid{
  border-color: var(--zs-border) !important;
}
/* The topbar search sits on a filled input rather than a card. */
:root[data-zs-theme="dark"] body.app.admin #header input[type="text"],
:root[data-zs-theme="dark"] body.app.admin #header input:not([type="checkbox"]):not([type="radio"]){
  background-color: var(--zs-surface-sunken) !important;
  color: var(--zs-text-primary) !important;
}
/* Anything still painting pure white inside the app in dark mode is a bug in
   waiting; this catches the long tail without hunting each one down. */
:root[data-zs-theme="dark"] body.app.admin [style*="background:#fff"],
:root[data-zs-theme="dark"] body.app.admin [style*="background: #fff"],
:root[data-zs-theme="dark"] body.app.admin [style*="background-color:#fff"]{
  background-color: var(--zs-surface-raised) !important;
}

/* ═══════════════════════════════════════════════════════════════════════
   AUTHENTICATION (2026 pass)
   Split layout: a branded panel that states what the product is, beside a
   focused form. Delivered entirely through CSS on the existing markup, so no
   view file changes and the sign-in logic is untouched.

   Scoped to body.login_admin so it cannot leak into the app.
   ═══════════════════════════════════════════════════════════════════════ */

body.login_admin{
  background: var(--zs-surface) !important;
  font-family: var(--zs-font-ui);
  color: var(--zs-text-primary);
  min-height: 100vh;
  margin: 0;
}

/* The brand panel used to be a body::before pinned with position:fixed to
   the left edge. It is now the real <aside id="zs-authside"> element that
   the auth hook injects, because a fixed pseudo-element cannot take part in
   the grid: in Arabic and Urdu the grid mirrored the form to the left while
   the pseudo-panel stayed pinned left, so the page rendered TWO panels with
   the heading stranded on top of one of them. The aside mirrors correctly
   and can hold a headline, bullets and a footer, which a pseudo-element
   could never do. Its own styles live with the hook that emits it. */

/* The form column is a grid cell; it only needs its width and its stacking. */
body.login_admin .authentication-form-wrapper{
  position: relative; z-index: 2;
  width: min(440px, calc(100% - 2 * var(--zs-s5)));
  margin: 0 auto !important;
  padding-top: 0 !important;
}

body.login_admin .company-logo{ margin-bottom: var(--zs-s5); }
body.login_admin .company-logo img{ max-height: 44px; width: auto; }

body.login_admin .authentication-form-wrapper h1{
  font-size: 26px !important; font-weight: 600 !important;
  letter-spacing: -0.012em; color: var(--zs-text-primary) !important;
  margin-bottom: var(--zs-s1) !important;
}
body.login_admin .authentication-form-wrapper p{ color: var(--zs-text-secondary) !important; }
/* Headline and lede read better ranged left beside a form. */
body.login_admin .authentication-form-wrapper .text-center{ text-align: start !important; }

/* The card: the form is the page, so it carries no heavy container. */
body.login_admin .authentication-form-wrapper > div:nth-of-type(3),
body.login_admin .tw-bg-white{
  background: var(--zs-surface-raised) !important;
  border: 1px solid var(--zs-border) !important;
  border-radius: var(--zs-r-xl) !important;
  box-shadow: var(--zs-e2) !important;
  padding: var(--zs-s6) !important;
  margin: 0 !important;
}

body.login_admin .form-control{
  height: 44px; font-size: 14.5px;
  border-radius: var(--zs-r-md);
  background: var(--zs-surface-raised);
  border: 1px solid var(--zs-border-strong);
  max-width: none;
}
body.login_admin .form-control:focus{
  border-color: var(--zs-accent);
  box-shadow: 0 0 0 3px var(--zs-accent-ring);
}
body.login_admin .control-label{
  font-size: var(--zs-caption-size); font-weight: 600;
  color: var(--zs-text-secondary);
}

body.login_admin .btn-primary,
body.login_admin button[type="submit"]{
  width: 100%; height: 46px;
  border-radius: var(--zs-r-md);
  background: var(--zs-accent); border-color: var(--zs-accent);
  color: var(--zs-text-on-accent);
  font-weight: 600; font-size: 14.5px;
  transition: background var(--zs-t-fast) var(--zs-ease);
}
body.login_admin .btn-primary:hover{ background: var(--zs-accent-hover); }

/* One column on tablet and phone: the brand panel is the first thing to go. */
@media (max-width: 900px){
  body.login_admin .authentication-form-wrapper{
    margin: 0 auto !important;
    padding: var(--zs-s8) var(--zs-s4) !important;
  }
  body.login_admin .authentication-form-wrapper .text-center{ text-align: center !important; }
}

/* ── RTL (Arabic, Urdu) ──────────────────────────────────────────────────
   The overlay was written LTR-first with a handful of physical properties.
   Rather than rewrite every rule in logical properties (and risk the 415
   views that assume Bootstrap 3's LTR grid), the specific asymmetries are
   mirrored here under [dir=rtl]. Phone and email inputs stay LTR: an RTL
   rendering of +966501234567 is unreadable.                                */

[dir="rtl"] body.app.admin #side-menu li.active > a::before{
  left: auto; right: 0; border-radius: 2px 0 0 2px;
}
[dir="rtl"] body.app.admin #side-menu .nav-second-level li a{
  padding-left: 0; padding-right: var(--zs-s10);
}
[dir="rtl"] body.app.admin table.table > thead > tr > th.sorting::after,
[dir="rtl"] body.app.admin table.table > thead > tr > th.sorting_asc::after,
[dir="rtl"] body.app.admin table.table > thead > tr > th.sorting_desc::after{
  right: auto; left: var(--zs-s3);
}
[dir="rtl"] body.app.admin table.table > thead > tr > th.sorting,
[dir="rtl"] body.app.admin table.table > thead > tr > th.sorting_asc,
[dir="rtl"] body.app.admin table.table > thead > tr > th.sorting_desc{
  padding-right: var(--zs-row-pad-x); padding-left: var(--zs-s6);
}
[dir="rtl"] body.app.admin .pagination > li > a,
[dir="rtl"] body.app.admin .pagination > li > span{
  margin-left: 0; margin-right: var(--zs-s1);
}
[dir="rtl"] body.app.admin .label,
[dir="rtl"] .zs-pill{ padding: 3px 8px 3px 10px; }
[dir="rtl"] .zs-plan-chip{ direction: ltr; } /* the plan name reads fine; the bolt stays left */
/* Numbers, phones, emails: always LTR islands inside RTL text. */
[dir="rtl"] body.app.admin input[type="email"],
[dir="rtl"] body.app.admin input[type="tel"],
[dir="rtl"] body.app.admin input[type="number"],
[dir="rtl"] body.app.admin .zs-num,
[dir="rtl"] body.app.admin td.zs-num,
[dir="rtl"] body.app.admin .zs-code,
[dir="rtl"] body.app.admin td.zs-code{ direction: ltr; unicode-bidi: isolate; }
[dir="rtl"] body.app.admin td.zs-num,
[dir="rtl"] body.app.admin th.zs-num,
[dir="rtl"] body.app.admin th.zs-num-head{ text-align: left; }
/* A code follows the table's own direction, so it stays under its heading. */
[dir="rtl"] body.app.admin td.zs-code{ text-align: right; }
