/* ==========================================================
   limaPOS Licensing — Deep Navy admin theme
   Mirrors the desktop app's PyQt6 colour system so brand
   identity stays consistent across surfaces.
   ========================================================== */

/* Secret-field with show/hide toggle (used in admin Settings → M-Pesa).
   The reveal button sits inside the same flex row as the input. */
.field.secret-field {
  position: relative;
}
.field.secret-field input {
  padding-right: 70px;
}
.field.secret-field .reveal-btn {
  position: absolute;
  right: 8px;
  top: calc(50% + 6px);
  transform: translateY(-50%);
  background: #f1f5f9;
  border: 1px solid #cbd5e1;
  color: #1e293b;
  font-size: 11px;
  font-weight: 600;
  padding: 5px 10px;
  border-radius: 6px;
  cursor: pointer;
}
.field.secret-field .reveal-btn:hover {
  background: #e2e8f0;
}

:root {
  --brand-blue:     #3b82f6;
  --brand-blue-dk:  #1d4ed8;
  --blue-light:     #dbeafe;
  --deep-navy:      #1e3a5f;
  --deep-navy-dk:   #142640;
  /* Alias — many call sites reference var(--navy). Keep both in sync. */
  --navy:           #1e3a5f;
  --navy-dk:        #142640;
  --emerald:        #10b981;
  --emerald-dk:     #059669;
  --emerald-light:  #d1fae5;
  --emerald-text:   #065f46;
  --amber:          #f59e0b;
  --amber-light:    #fef3c7;
  --amber-text:     #92400e;
  --red:            #ef4444;
  --red-dk:         #dc2626;
  --red-light:      #fee2e2;
  --red-text:       #991b1b;
  --violet:         #8b5cf6;
  --violet-light:   #ede9fe;
  --violet-text:    #5b21b6;
  --card:           #ffffff;
  --surface:        #f8fafc;
  --border:         #e2e8f0;
  --text-primary:   #1e293b;
  --text-muted:     #64748b;
  --text-soft:      #94a3b8;

  /* ---- Previously-undefined tokens -------------------------------------
     These seven were referenced across 21 files but never declared, so every
     rule using them was invalid at computed-value time and silently dropped.
     Two consequences, both measured in the browser rather than assumed:

       border: 1px solid var(--border-soft)  ->  border-color fell back to
           currentColor, so borders took on the surrounding TEXT colour
           (a red-text element rendered a red border, not a grey one).
       color: var(--text-secondary)          ->  declaration dropped, so the
           element inherited body colour instead of rendering muted.

     Declaring them here fixes all 21 files at once. Values are picked to sit
     inside the existing slate palette and to match radii/shadows already in
     use, not invented fresh. */
  --border-soft:    #eef2f7;   /* between --border and white; also used as a fill */
  --text-secondary: #475569;   /* slate-600: between --text-primary and --text-muted */
  --danger:         #ef4444;   /* alias of --red, for border-color call sites */
  --danger-text:    #991b1b;   /* alias of --red-text */
  --r-md:           10px;      /* the most common radius in this file (7 uses) */
  --shadow-lg:      0 8px 24px rgba(15, 23, 42, 0.10);
  /* Accent-aware: app.php overrides this inline when a business sets a custom
     accent colour, so that override still wins over this default. */
  --blue-dark:      #1d4ed8;   /* = --brand-blue-dk */
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
               'Helvetica Neue', Arial, sans-serif;
  background: var(--surface);
  color: var(--text-primary);
  font-size: 14px;
  line-height: 1.45;
}
a { color: var(--brand-blue); text-decoration: none; }
a:hover { text-decoration: underline; }

/* --- App shell ----------------------------------------------- */
.app {
  display: grid;
  grid-template-columns: 220px 1fr;
  min-height: 100vh;
}
.sidebar {
  background: var(--deep-navy);
  color: rgba(255, 255, 255, 0.65);
  padding: 0;
}
.sidebar-logo {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 18px 18px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.sidebar-logo .dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--brand-blue);
}
.sidebar-logo .wordmark {
  display: flex; flex-direction: column;
}
.sidebar-logo .wordmark .title {
  color: #fff;
  font-weight: 800;
  font-size: 16px;
  letter-spacing: 0.2px;
}
.sidebar-logo .wordmark .subtitle {
  color: rgba(255, 255, 255, 0.45);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}

.sidebar nav {
  padding: 12px 8px;
  display: flex; flex-direction: column; gap: 2px;
}
.sidebar nav a {
  color: #cfd6e4;
  text-decoration: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  border-left: 3px solid transparent;
}
.sidebar nav a:hover { background: rgba(255, 255, 255, 0.06); color: #fff; }
.sidebar nav a.active {
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  border-left-color: var(--brand-blue);
}
.sidebar nav .nav-icon {
  width: 18px; height: 18px;
  display: inline-block;
  fill: none; stroke: currentColor;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
}

.content {
  display: flex; flex-direction: column;
  /* clip, NOT hidden. Both stop a wide table from scrolling the page
     sideways, but `hidden` makes this element a scroll container — and
     because it has no height of its own it never actually scrolls, so every
     `position: sticky` descendant anchored itself to a scrollport that never
     moved and simply scrolled away with the page. That is why the Settings
     section list (.set-nav) and its section headers (.set-head) never pinned,
     and why the Settings list then clipped its own rows mid-text: it was
     scrolling out of view while holding a fixed max-height. `clip` contains
     the overflow without creating a scroll container, so sticky works against
     the page as intended. */
  overflow-x: clip;
  /* A grid item's min-width is `auto`, i.e. "never narrower than my widest
     child". The topbar's title + greeting + date strip do not wrap, so on a
     phone this column refused to shrink below ~586px: the app laid itself out
     586px wide inside a 390px screen and `overflow-x: clip` above quietly cut
     the right-hand side off every page. Letting the column shrink is what
     makes the clip harmless — wide tables still scroll inside their own
     .table-wrap, which is the only thing the clip was ever meant to catch. */
  min-width: 0;
}
.content > .page { min-width: 0; }

.topbar {
  background: #fff;
  border-bottom: 1px solid var(--border);
  padding: 14px 28px;
  display: flex; align-items: center; gap: 16px;
}
.topbar h1 {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  color: var(--text-primary);
}
.topbar .grow { flex: 1; }
.topbar .user-pill {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 9999px;
  padding: 6px 14px;
  font-weight: 600;
  font-size: 12px;
  color: var(--text-muted);
}
.topbar .logout {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 14px;
  font-weight: 600;
  font-size: 12px;
  color: var(--text-primary);
  cursor: pointer;
}
.topbar .logout:hover { background: var(--surface); }

/* Owner support session (admin panel → Companies → Impersonate). Styling moved
   out of inline attributes so the desktop rule at the end of this file can pin
   it under the fixed topbar — inline styles cannot be overridden by a media
   query, and behind that header is exactly where this warning used to sit. */
.impersonation-banner {
  background: #6d28d9;
  color: #fff;
  padding: 10px 24px;
  font-size: 13px;
  font-weight: 600;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.impersonation-banner .end-session {
  margin-left: auto;
  background: #fff;
  color: #6d28d9;
  padding: 5px 12px;
  border-radius: 8px;
  text-decoration: none;
  font-weight: 700;
}

.page {
  padding: 24px 28px;
  display: flex; flex-direction: column; gap: 20px;
}

/* --- Cards / metric tiles ----------------------------------- */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 20px 22px;
}
.card-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: 0.2px;
  margin-bottom: 10px;
}
.card .muted {
  color: var(--text-muted);
  font-size: 12px;
  margin-top: 4px;
}

.metrics-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}
@media (max-width: 1100px) { .metrics-row { grid-template-columns: repeat(2, 1fr); } }
.metric {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 18px 20px;
  position: relative;
  overflow: hidden;
}
.metric .label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.6px;
  color: var(--text-muted);
  text-transform: uppercase;
}
.metric .value {
  margin-top: 6px;
  font-size: 24px;
  font-weight: 800;
  color: var(--text-primary);
}
.metric .delta {
  margin-top: 4px;
  font-size: 12px;
  color: var(--text-muted);
}
.metric .strip {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 4px;
  background: var(--brand-blue);
}
.metric.emerald .strip  { background: var(--emerald); }
.metric.amber   .strip  { background: var(--amber); }
.metric.red     .strip  { background: var(--red); }
.metric.violet  .strip  { background: var(--violet); }

/* --- Tables ------------------------------------------------- */
.table-card { padding: 0; overflow: hidden; }
.table-head {
  display: flex; align-items: center;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
}
.table-head .grow { flex: 1; }
.table-head h2 {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-primary);
}
table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
table.data thead th {
  text-align: left;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--surface);
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
}
table.data tbody td {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  color: var(--text-primary);
}
table.data tbody tr:last-child td { border-bottom: 0; }
table.data tbody tr:hover { background: #fafbfc; }
table.data td.right, table.data th.right { text-align: right; }
table.data td.center, table.data th.center { text-align: center; }
.empty {
  padding: 36px 24px;
  text-align: center;
  color: var(--text-muted);
  font-size: 13px;
}

/* --- Pills / badges ----------------------------------------- */
.pill {
  display: inline-block;
  padding: 3px 12px;
  border-radius: 9999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.2px;
}

/* --- Forms --------------------------------------------------- */
form .field {
  display: flex; flex-direction: column; gap: 6px;
  margin-bottom: 14px;
}
form .field label {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: 0.1px;
}
form .field input,
form .field select,
form .field textarea {
  font-family: inherit;
  font-size: 14px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
  color: var(--text-primary);
}
form .field input:focus,
form .field select:focus,
form .field textarea:focus {
  outline: none;
  border-color: var(--brand-blue);
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
}
form .field .hint {
  font-size: 11px;
  color: var(--text-muted);
}
form .row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
form .actions {
  display: flex; gap: 10px;
  justify-content: flex-end;
  margin-top: 14px;
}

/* --- Buttons ------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center; gap: 8px;
  padding: 9px 16px;
  border-radius: 8px;
  font-weight: 700;
  font-size: 13px;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background .12s ease, border-color .12s ease;
  text-decoration: none;
}
.btn.primary {
  background: var(--brand-blue);
  color: #fff;
}
.btn.primary:hover { background: var(--brand-blue-dk); text-decoration: none; }
.btn.secondary {
  background: var(--surface);
  color: var(--deep-navy);
  border-color: var(--border);
}
.btn.secondary:hover { background: var(--blue-light); }
.btn.ghost {
  background: transparent;
  color: var(--brand-blue);
  border-color: var(--brand-blue);
}
.btn.ghost:hover { background: var(--blue-light); }
.btn.danger {
  background: var(--red);
  color: #fff;
}
.btn.danger:hover { background: var(--red-dk); }
.btn.small { padding: 5px 10px; font-size: 12px; }

/* --- Filters strip ------------------------------------------ */
.filters {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
}
.filters label { font-size: 12px; color: var(--text-muted); font-weight: 700; }
.filters input[type="search"],
.filters select {
  font-family: inherit; font-size: 13px;
  padding: 7px 11px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
}

/* --- Flash messages ----------------------------------------- */
.flash {
  border-radius: 10px;
  padding: 12px 16px;
  font-weight: 600;
  font-size: 13px;
}
.flash.success { background: var(--emerald-light); color: var(--emerald-text); }
.flash.error   { background: var(--red-light);     color: var(--red-text); }
.flash.info    { background: var(--blue-light);    color: var(--brand-blue-dk); }
.flash.warn    { background: var(--amber-light);   color: var(--amber-text); }

/* --- Login page --------------------------------------------- */
.login-host {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background:
    linear-gradient(135deg, var(--deep-navy) 0%, var(--deep-navy-dk) 100%);
}
.login-card {
  width: 380px;
  background: #fff;
  border-radius: 16px;
  padding: 32px 28px;
  box-shadow: 0 10px 40px rgba(15, 23, 42, 0.25);
}
.login-card .brand {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 6px;
}
.login-card .brand .dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--brand-blue);
}
.login-card .brand .name {
  font-size: 18px;
  font-weight: 800;
  color: var(--deep-navy);
}
.login-card .sub {
  color: var(--text-muted);
  font-size: 13px;
  margin-bottom: 22px;
}

/* --- Layout helpers ----------------------------------------- */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.grid-3 { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 18px; }
@media (max-width: 980px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
  .app { grid-template-columns: 64px 1fr; }
  .sidebar nav a span.label { display: none; }
  .sidebar-logo .wordmark { display: none; }
}

/* --- Code blocks / monospace -------------------------------- */
code, pre {
  font-family: 'SF Mono', Consolas, Menlo, monospace;
  font-size: 12.5px;
}
.codebox {
  background: #0f172a;
  color: #cbd5e1;
  padding: 14px 16px;
  border-radius: 10px;
  overflow-x: auto;
}

/* --- Modal / dialog ------------------------------------------ */
.modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, 0.55);
  display: flex; align-items: center; justify-content: center;
  z-index: 50;
}
.modal {
  width: 520px; max-width: 92%;
  background: #fff;
  border-radius: 14px;
  padding: 22px 24px;
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.35);
}
.modal h3 {
  margin: 0 0 8px;
  font-size: 16px;
  font-weight: 800;
  color: var(--text-primary);
}

/* ==========================================================
   LimaPOS app compatibility layer.
   Maps the POS app component classes onto the licensing
   Deep Navy design tokens above, so every page adopts the
   licensing look without rewriting JS-generated markup.
   ========================================================== */

/* Buttons (app uses .btn-primary etc; licensing uses .btn.primary) */
.btn-primary  { background: var(--brand-blue); color:#fff; }
.btn-primary:hover  { background: var(--brand-blue-dk); text-decoration:none; }
.btn-success  { background: var(--emerald); color:#fff; }
.btn-success:hover  { background: var(--emerald-dk); }
.btn-danger   { background: var(--red); color:#fff; }
.btn-danger:hover   { background: var(--red-dk); }
.btn-secondary { background: var(--surface); color: var(--deep-navy); border-color: var(--border); }
.btn-secondary:hover { background: var(--blue-light); }
.btn-ghost { background: transparent; color: var(--brand-blue); border-color: var(--brand-blue); }
.btn-ghost:hover { background: var(--blue-light); }
.btn-sm { padding: 5px 10px; font-size: 12px; }
.btn-lg { padding: 13px 20px; font-size: 15px; }
.btn-block { display: flex; width: 100%; justify-content: center; }
.btn-icon { padding: 0; width: 40px; height: 40px; justify-content: center; border-radius: 9999px; }
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn-google { background:#fff; border:1px solid var(--border); color:var(--text-primary); font-weight:600; }
.btn-google:hover { background: var(--surface); }
.auth-divider { display:flex; align-items:center; gap:12px; margin:16px 0; color:var(--text-muted); font-size:12px; }
.auth-divider::before, .auth-divider::after { content:""; flex:1; height:1px; background:var(--border); }

/* Cards — licensing .card has padding; the app pairs .card with .card-body,
   so neutralise .card padding and let body/header provide it. */
.card { padding: 0; }
.card.card-body { padding: 20px 22px; }
.card-body { padding: 20px 22px; }
.card-header { padding: 16px 20px; border-bottom: 1px solid var(--border); font-weight: 700; font-size: 15px; }
.card-pad { padding: 20px 22px; }
.card-clickable { cursor: pointer; transition: box-shadow .15s, transform .15s; }
.card-clickable:hover { box-shadow: 0 4px 12px rgba(15,23,42,.10); transform: translateY(-2px); }

/* Stat cards → licensing .metric look */
.stat-card { padding: 18px 20px; display:flex; flex-direction:column; gap:6px; }
.stat-label { font-size:11px; font-weight:700; letter-spacing:.6px; color:var(--text-muted); text-transform:uppercase; }
.stat-value { font-size:26px; font-weight:800; color:var(--text-primary); }
.stat-delta { font-size:12px; color:var(--text-muted); }
.stat-delta.up { color: var(--emerald-text); } .stat-delta.down { color: var(--red-text); }

/* Tables (app uses .table-wrap + table.table) → licensing table.data look */
.table-wrap { overflow-x: auto; }
table.table { width:100%; border-collapse:collapse; font-size:13px; }
table.table thead th { text-align:left; font-weight:700; font-size:11px; letter-spacing:.4px; text-transform:uppercase; color:var(--text-muted); background:var(--surface); padding:12px 18px; border-bottom:1px solid var(--border); white-space:nowrap; }
table.table thead th.sortable { cursor:pointer; user-select:none; }
table.table tbody td { padding:14px 18px; border-bottom:1px solid var(--border); }
/* Totals rows line up with the body (they had no padding of their own). */
table.table tfoot td { padding:14px 18px; }
table.table tbody tr:hover { background:#fafbfc; }
table.table .num, table.table th.num { text-align:right; }

/* Badges → licensing pill look */
.badge { display:inline-block; padding:3px 12px; border-radius:9999px; font-size:11px; font-weight:700; white-space:nowrap; }
.badge-blue   { background: var(--blue-light);    color: var(--brand-blue-dk); }
.badge-green  { background: var(--emerald-light); color: var(--emerald-text); }
.badge-amber  { background: var(--amber-light);   color: var(--amber-text); }
.badge-red    { background: var(--red-light);     color: var(--red-text); }
.badge-violet { background: var(--violet-light);  color: var(--violet-text); }
.badge-grey   { background: var(--surface);       color: var(--text-muted); }
.pill.blue{background:var(--blue-light);color:var(--brand-blue-dk);} .pill.green{background:var(--emerald-light);color:var(--emerald-text);}
.pill.amber{background:var(--amber-light);color:var(--amber-text);} .pill.red{background:var(--red-light);color:var(--red-text);}

/* Alerts → licensing flash look */
.alert { display:flex; align-items:flex-start; gap:12px; padding:12px 16px; border-radius:10px; font-weight:600; font-size:13px; margin-bottom:16px; }
.alert-success { background: var(--emerald-light); color: var(--emerald-text); }
.alert-error   { background: var(--red-light);     color: var(--red-text); }
.alert-warning { background: var(--amber-light);   color: var(--amber-text); }
.alert-info    { background: var(--blue-light);    color: var(--brand-blue-dk); }
.alert-close { margin-left:auto; cursor:pointer; background:none; border:none; font-size:18px; color:inherit; opacity:.6; }
.alert-close:hover { opacity:1; }

/* Inputs (app uses .input/.select/.textarea/.label/.field outside a form) */
.field { display:flex; flex-direction:column; gap:6px; margin-bottom:14px; }
.label { font-size:12px; font-weight:700; color:var(--text-primary); }
.input, .select, .textarea { width:100%; font-family:inherit; font-size:14px; padding:9px 12px; border:1px solid var(--border); border-radius:8px; background:#fff; color:var(--text-primary); }
.input:focus, .select:focus, .textarea:focus { outline:none; border-color:var(--brand-blue); box-shadow:0 0 0 3px rgba(59,130,246,.15); }
.textarea { min-height:90px; resize:vertical; }
.field-error { font-size:11px; color: var(--red-text); }
.check { display:inline-flex; align-items:center; gap:8px; cursor:pointer; }
.toggle { position:relative; display:inline-block; width:44px; height:24px; }
.toggle input { opacity:0; width:0; height:0; }
.toggle .slider { position:absolute; inset:0; cursor:pointer; background:var(--border); border-radius:9999px; transition:background .15s; }
.toggle .slider::before { content:""; position:absolute; height:18px; width:18px; left:3px; top:3px; background:#fff; border-radius:50%; transition:transform .15s; }
.toggle input:checked + .slider { background: var(--brand-blue); }
.toggle input:checked + .slider::before { transform: translateX(20px); }

/* Modals — app keeps modals in the DOM and toggles .open */
.modal-backdrop { position:fixed; inset:0; background:rgba(15,23,42,.55); display:none; align-items:center; justify-content:center; padding:16px; z-index:1000; }
.modal-backdrop.open { display:flex; }
.modal-header { display:flex; align-items:center; border-bottom:1px solid var(--border); padding-bottom:12px; margin-bottom:14px; }
.modal-header h3 { margin:0; }
.modal-footer { display:flex; gap:10px; justify-content:flex-end; border-top:1px solid var(--border); padding-top:14px; margin-top:16px; }
.modal-full { width: 1000px; max-width: 94%; }

/* Grids + utilities */
.grid { display:grid; gap:18px; }
.grid-2 { grid-template-columns: repeat(2,1fr); }
.grid-3 { grid-template-columns: repeat(3,1fr); }
.grid-4 { grid-template-columns: repeat(4,1fr); }
@media (max-width:1024px){ .grid-4,.grid-3 { grid-template-columns: repeat(2,1fr); } }
@media (max-width:768px){ .grid-2,.grid-3,.grid-4 { grid-template-columns: 1fr; } }
.flex{display:flex;} .items-center{align-items:center;} .between{justify-content:space-between;}
.gap-2{gap:8px;} .gap-3{gap:12px;} .gap-4{gap:16px;}
.mt-4{margin-top:16px;} .mb-4{margin-bottom:16px;}
.hidden{display:none!important;} .spacer{flex:1;} .text-muted{color:var(--text-soft);}

/* Loading + empty + pagination */
.spinner { display:inline-block; width:20px; height:20px; border:2.5px solid var(--blue-light); border-top-color:var(--brand-blue); border-radius:50%; animation:spin .7s linear infinite; }
.spinner-lg { width:36px; height:36px; border-width:4px; }
@keyframes spin { to { transform: rotate(360deg); } }
.skeleton { background:linear-gradient(90deg,#eef2f7 25%,#e2e8f0 37%,#eef2f7 63%); background-size:400% 100%; animation:shimmer 1.4s ease infinite; border-radius:6px; height:14px; }
.skeleton-block { height:16px; margin:10px 0; } .skeleton-stat { height:30px; width:60%; margin-top:6px; }
.sk-row td { padding:12px 18px; } .sk-row .skeleton { height:14px; }
@keyframes shimmer { 0%{background-position:100% 0;} 100%{background-position:0 0;} }
.progress { height:8px; background:var(--surface); border-radius:9999px; overflow:hidden; }
.progress>span { display:block; height:100%; background:var(--brand-blue); }
.empty-state { text-align:center; padding:48px 24px; border:1.5px dashed var(--border); border-radius:12px; background:var(--surface); }
.empty-state .empty-icon{ font-size:40px; opacity:.5; } .empty-state .empty-title{ font-size:16px; font-weight:700; margin:8px 0; } .empty-state .empty-msg{ color:var(--text-muted); margin-bottom:16px; }
.pagination { display:flex; align-items:center; gap:8px; justify-content:flex-end; padding:12px 0; }
.breadcrumbs { display:flex; gap:8px; font-size:12px; color:var(--text-soft); margin-bottom:16px; }

/* Mobile sidebar drawer (licensing collapses to 64px on desktop; the app
   adds an off-canvas drawer on small screens). */
.sidebar-toggle { display:none; background:none; border:none; font-size:22px; cursor:pointer; color:var(--text-primary); }
.sidebar-scrim { display:none; }
@media (max-width:768px){
  .app { grid-template-columns: 1fr; }
  .sidebar { position:fixed; inset:0 auto 0 0; width:220px; z-index:40; transform:translateX(-100%); transition:transform .2s; }
  .sidebar.open { transform:none; }
  .sidebar-toggle { display:inline-flex; }
  .sidebar.open ~ .sidebar-scrim { display:block; position:fixed; inset:0; background:rgba(15,23,42,.4); z-index:35; }
}

/* ==========================================================
   LimaPOS — premium polish layer (fonts, sidebar, depth).
   Loaded last so it refines the licensing theme + bridge.
   ========================================================== */

/* --- Typography: modern geometric sans ------------------------ */
body, input, select, textarea, button {
  font-family: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont,
               "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
h1, h2, h3, .sidebar-logo .title, .topbar h1, .card-title, .stat-value {
  letter-spacing: -0.02em;
}
.topbar h1 { font-weight: 800; }

/* --- Sidebar: richer navy, icon chips, accent active --------- */
.sidebar {
  background: linear-gradient(185deg, #1f3e66 0%, #16293f 100%);
  box-shadow: 1px 0 0 rgba(0,0,0,.25);
}
.sidebar-logo { padding: 20px 18px; }
.sidebar-logo .dot {
  width: 30px; height: 30px; border-radius: 9px; background: var(--brand-blue);
  box-shadow: 0 4px 12px rgba(59,130,246,.45);
  position: relative;
}
.sidebar-logo .dot::after {
  content: "L"; position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 800; font-size: 16px;
}
/* Uploaded business logo — same footprint as the dot; white backing so
   transparent PNGs/SVGs stay legible on the navy sidebar. */
.sidebar-logo .biz-logo {
  width: 30px; height: 30px; border-radius: 9px; object-fit: cover;
  background: #fff; flex-shrink: 0;
  box-shadow: 0 4px 12px rgba(0,0,0,.35);
}
.sidebar-logo .wordmark .title { font-size: 17px; }
.sidebar nav { padding: 14px 12px; gap: 4px; }
.sidebar nav a {
  padding: 10px 12px; border-radius: 11px; border-left: none;
  color: #aeb9cf; font-weight: 600; position: relative;
  transition: background .15s, color .15s, transform .15s;
}
.sidebar nav a .nav-icon {
  width: 20px; height: 20px; opacity: .8;
  flex: 0 0 20px; transition: opacity .15s, color .15s;
}
.sidebar nav a:hover {
  background: rgba(255,255,255,.07); color: #fff; transform: translateX(2px);
}
.sidebar nav a:hover .nav-icon { opacity: 1; }
.sidebar nav a.active {
  background: linear-gradient(90deg, rgba(59,130,246,.30), rgba(59,130,246,.06));
  color: #fff;
  box-shadow: inset 0 0 0 1px rgba(59,130,246,.35);
}
.sidebar nav a.active::before {
  content: ""; position: absolute; left: -12px; top: 9px; bottom: 9px;
  width: 3px; border-radius: 0 3px 3px 0; background: var(--brand-blue);
}
.sidebar nav a.active .nav-icon { opacity: 1; color: #fff; }

/* --- Topbar: subtle lift -------------------------------------- */
.topbar { box-shadow: 0 1px 2px rgba(15,23,42,.05); }
.user-pill { background: var(--blue-light); color: var(--brand-blue-dk); border: none; }
.logout { font-weight: 700; transition: background .15s, border-color .15s; }

/* --- Cards & buttons: depth + motion ------------------------- */
.card { box-shadow: 0 1px 3px rgba(15,23,42,.06); border-radius: 14px; }
.btn { transition: transform .12s ease, box-shadow .15s ease, background .12s ease; border-radius: 10px; }
.btn-primary:hover { box-shadow: 0 6px 16px rgba(59,130,246,.32); transform: translateY(-1px); }
.btn-success:hover { box-shadow: 0 6px 16px rgba(16,185,129,.32); transform: translateY(-1px); }
.btn-lg { border-radius: 12px; }

/* --- Stat cards: colored icon chip + hover ------------------- */
.stat-card { box-shadow: 0 1px 3px rgba(15,23,42,.06); transition: transform .15s, box-shadow .15s; border-radius: 14px; }
.stat-card:hover { transform: translateY(-3px); box-shadow: 0 12px 28px rgba(15,23,42,.10); }
.stat-icon {
  width: 38px; height: 38px; border-radius: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 18px; margin-bottom: 4px;
  background: var(--blue-light); color: var(--brand-blue-dk);
}
.stat-icon.green { background: var(--emerald-light); color: var(--emerald-text); }
.stat-icon.amber { background: var(--amber-light); color: var(--amber-text); }
.stat-icon.violet { background: var(--violet-light); color: var(--violet-text); }

/* --- Inputs: a touch softer --------------------------------- */
.input, .select, .textarea { border-radius: 10px; }
.btn-block { border-radius: 10px; }

/* ==========================================================
   LimaPOS — dashboard modernization (§3) + type scale (§4)
   ========================================================== */

/* Type scale per limapos_dashboard_fix_prompt §4. PJS retained for premium feel. */
body, input, select, textarea, button { font-size: 14px; line-height: 1.5; }
.topbar h1 { font-size: 20px; font-weight: 600; letter-spacing: -.01em; }
h3, .card-title { font-size: 16px; font-weight: 600; color: var(--navy); margin: 0; }
.stat-label { font-size: 13px; font-weight: 500; color: var(--text-secondary); text-transform: none; letter-spacing: 0; }
.stat-value { font-size: 32px; font-weight: 700; letter-spacing: -.02em; color: var(--navy); line-height: 1.1; }
.text-muted, .muted { color: var(--text-muted); font-size: 12px; }
.card-sub { font-size: 12px; font-weight: 400; color: var(--text-muted); }
.sidebar nav a { font-size: 14px; font-weight: 500; min-height: 44px; }

/* Stat card refinement (§3). */
.stat-card {
  padding: 24px; gap: 6px; display: flex; flex-direction: column;
  box-shadow: 0 1px 4px rgba(15,23,42,.08); border: none;
}
.stat-card .stat-icon { margin-bottom: 6px; }
.stat-trend { font-size: 12px; color: var(--text-muted); font-weight: 500; margin-top: 4px; }
.stat-trend.up { color: var(--emerald-text); }
.stat-trend.down { color: var(--red-text, #b91c1c); }
.skeleton-stat { height: 32px; width: 60%; border-radius: 6px; }

/* Pill switcher (Top Products By Revenue | By Units). */
.pill-switch {
  display: inline-flex; background: var(--blue-light); border-radius: 999px;
  padding: 3px; gap: 2px;
}
.pill-switch button {
  border: none; background: transparent; padding: 6px 14px; border-radius: 999px;
  font-size: 12px; font-weight: 600; color: var(--text-secondary); cursor: pointer;
  transition: background .15s, color .15s;
}
.pill-switch button:hover { color: var(--brand-blue-dk); }
.pill-switch button.active {
  background: #fff; color: var(--brand-blue-dk);
  box-shadow: 0 1px 3px rgba(15,23,42,.10);
}

/* Uppercase muted column headers (§3). */
table.table thead th.col-h, table.data thead th.col-h {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-muted); padding-top: 10px; padding-bottom: 10px;
}

/* Accent links (View all → / Manage →). */
.link-accent {
  color: var(--brand-blue); font-weight: 600; font-size: 13px; text-decoration: none;
  transition: color .15s, transform .15s; display: inline-flex; gap: 4px; align-items: center;
}
.link-accent:hover { color: var(--brand-blue-dk); }
.link-accent:hover span { transform: translateX(2px); }
.link-accent span { transition: transform .15s; display: inline-block; }

/* Topbar: date strip + user avatar (§3). Layout-wide but minimal. */
.topbar-date {
  font-size: 12px; color: var(--text-muted); font-weight: 500;
  padding-right: 14px; border-right: 1px solid var(--border-soft); margin-right: 4px;
}
.user-pill {
  display: inline-flex; align-items: center; gap: 8px; padding: 5px 12px 5px 5px;
  background: var(--blue-light); border-radius: 999px; font-size: 13px; font-weight: 600;
  color: var(--brand-blue-dk);
}
.user-pill .avatar {
  width: 28px; height: 28px; border-radius: 50%; background: var(--brand-blue); color: #fff;
  display: inline-flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700;
}
.user-pill .urole { color: var(--text-muted); font-weight: 500; font-size: 12px; }
.logout.icon-only {
  width: 36px; height: 36px; padding: 0; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--border-soft);
}
.logout.icon-only:hover { background: var(--blue-light); border-color: var(--brand-blue); color: var(--brand-blue-dk); }

/* ==========================================================
   LimaPOS — final harmonization (sidebar/topbar fixes)
   Lands last so it wins the cascade against earlier blocks.
   ========================================================== */

/* ---- 1. Topbar user-pill: specificity bump --------------------
   The licensing block defines `.topbar .user-pill { background:
   var(--surface); border:1px solid var(--border); ...}`. That
   selector outranks `.user-pill` alone, which is why my avatar
   pill never showed. Re-declare at matching specificity. */
.topbar .user-pill {
  background: var(--blue-light);
  color: var(--brand-blue-dk);
  border: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 12px 5px 5px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
}
.topbar .user-pill .avatar {
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--brand-blue); color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700;
}
.topbar .user-pill .urole { color: var(--text-muted); font-weight: 500; font-size: 12px; }

/* Topbar icon-only sign-out (same matching). */
.topbar .logout.icon-only {
  width: 36px; height: 36px; padding: 0; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--border-soft);
}
.topbar .logout.icon-only:hover {
  background: var(--blue-light); border-color: var(--brand-blue);
  color: var(--brand-blue-dk);
}

/* ---- 2. Sidebar/breakpoint harmonization ----------------------
   The licensing CSS collapsed the sidebar to a 64px icon-rail at
   `<=980px`, but the drawer-mode bridge only kicked in at <=900px.
   Between 901-980px the two fought (icon-rail markup + drawer
   transforms). Re-tune so:
     - desktop (>=992px) keeps the full 220px shell
     - tablet/phone (<=991px) uses ONE drawer mode (bridge style)
   The hamburger toggle (`.sidebar-toggle`) is wired by JS and stays
   visible whenever the drawer is in play. */
@media (max-width: 991px) {
  .app { grid-template-columns: 1fr; }
  .sidebar { position: fixed; top: 0; left: 0; bottom: 0; width: 240px;
             z-index: 40; transform: translateX(-100%); transition: transform .2s ease; }
  .sidebar.open { transform: translateX(0); }
  .sidebar nav a span.label { display: inline; }
  .sidebar-logo .wordmark { display: flex; }
  .sidebar-toggle { display: inline-flex; }
}
@media (min-width: 992px) {
  .app { grid-template-columns: 220px 1fr; }
  .sidebar { position: static; transform: none; width: auto; }
  .sidebar-toggle { display: none; }
}

/* ---- 3. Sidebar polish safety net -----------------------------
   Higher-specificity restatement of the active state so nothing
   above can clobber the gradient + accent bar. */
.app .sidebar nav a {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 11px; border-left: none;
  color: #cbd5e1; font-weight: 500; font-size: 14px;
  min-height: 44px; position: relative;
}
.app .sidebar nav a .nav-icon { width: 20px; height: 20px; flex: 0 0 20px; color: #cbd5e1; opacity: 1; }
/* The bridge's global `.label { color: var(--text-primary) }` (form-input
   label styling) was painting these nav labels in dark navy on the dark
   navy sidebar — invisible. Re-paint the sidebar label specifically. */
.app .sidebar nav a .label { color: #cbd5e1; font-size: 14px; font-weight: 500; }
.app .sidebar nav a:hover { background: rgba(255,255,255,.08); color: #fff; }
.app .sidebar nav a:hover .nav-icon { color: #fff; }
.app .sidebar nav a:hover .label { color: #fff; }
.app .sidebar nav a.active {
  background: linear-gradient(90deg, rgba(59,130,246,.30), rgba(59,130,246,.06));
  color: #fff;
  box-shadow: inset 0 0 0 1px rgba(59,130,246,.35);
}
.app .sidebar nav a.active .nav-icon { color: #fff; opacity: 1; }
.app .sidebar nav a.active .label { color: #fff; }
.app .sidebar nav a.active::before {
  content: ""; position: absolute; left: -12px; top: 9px; bottom: 9px;
  width: 3px; border-radius: 0 3px 3px 0; background: var(--brand-blue);
}

/* ==========================================================
   Round 2 §8 — Modal viewport-fit (applies app-wide).
   Lands last so it wins the cascade against the older two
   .modal definitions in this file.
   ========================================================== */

/* Backdrop allows scrolling on tiny viewports where even the
   capped modal is too tall. Padding gives the modal breathing room. */
.modal-backdrop {
  padding: 16px;
  overflow-y: auto;
}

/* Modal becomes a flex column with a hard height cap. Body scrolls
   internally; header + footer stay anchored. The legacy padding on
   .modal is reset so each child section can own its own padding. */
.modal {
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 0;
}

.modal-header {
  padding: 18px 22px 12px;
  margin-bottom: 0;
  flex-shrink: 0;
  border-bottom: 1px solid var(--border-soft);
}
.modal-body {
  padding: 16px 22px;
  flex: 1 1 auto;
  overflow-y: auto;
}
/* When a modal has no explicit .modal-body wrapper, .modal still has
   max-height + overflow:hidden. Without a scrollable child the content
   would clip — fall back to scrolling on the modal itself. */
.modal:not(:has(.modal-body)) {
  overflow-y: auto;
  padding: 18px 22px;
}
.modal-footer {
  padding: 14px 22px 18px;
  margin-top: 0;
  flex-shrink: 0;
  border-top: 1px solid var(--border-soft);
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

/* Size variants. */
.modal-lg   { width: 760px;  max-width: 96vw; }
.modal-full { width: 1000px; max-width: 96vw; }

/* Mobile / small-tablet — full-width with a tight margin. */
@media (max-width: 768px) {
  .modal-backdrop { padding: 8px; }
  .modal,
  .modal-lg,
  .modal-full       { width: 100%; max-width: 100%; max-height: 96vh; }
  .modal-header     { padding: 14px 16px 10px; }
  .modal-body       { padding: 12px 16px; }
  .modal-footer     { padding: 12px 16px 14px; flex-wrap: wrap; }
}

/* POS receipt modal isn't a .modal — it's a separate .receipt-card.
   Bring it under the same 90vh cap so the rule is uniform. */
.receipt-card { max-height: 90vh !important; }
@media (max-width: 768px) {
  .receipt-backdrop { padding: 8px; }
  .receipt-card { max-width: 100%; }
}

/* ==========================================================
   UI Improvements §1 — Fixed sidebar (collapsible) + fixed topbar.
   Lands last; wins the cascade against the grid layout above.
   Desktop (≥992px) uses position:fixed sidebar + margin-left content;
   below 992px the existing drawer mode in this file takes over.
   ========================================================== */

@media (min-width: 992px) {
  /* The .app wrapper used to be a CSS grid (220px 1fr). With a fixed
     sidebar the grid is no longer doing layout work; let the content
     flow normally with a margin instead. */
  .app { display: block; }

  .sidebar {
    position: fixed;
    top: 0; left: 0;
    height: 100vh;
    width: 220px;
    transition: width .25s ease;
    overflow: hidden;        /* no scrollbar — content adapts to viewport */
    z-index: 1000;
    display: flex;
    flex-direction: column;
  }
  /* Sidebar nav. Items take a fixed compact size (~42px) regardless of
     how many entries the plan includes — so Pro (11 items) and Starter
     (6 items) both render with the same per-row rhythm. Any leftover
     vertical space collapses naturally at the end of the column, putting
     a clean dark gap before the collapse button. On short viewports the
     items can shrink down to 36px so the bottom item (Branches) stays
     visible even on 720p laptops with the full Pro nav. */
  .app .sidebar nav { flex: 1 1 auto; min-height: 0; overflow: hidden;
                       padding: 10px 12px; gap: 2px;
                       display: flex; flex-direction: column;
                       justify-content: flex-start; }
  .app .sidebar nav a { flex: 0 1 auto; height: 42px; min-height: 36px;
                         padding: 0 12px; align-items: center; }
  .app .sidebar-logo { padding: 14px 18px; }

  .sidebar.collapsed { width: 64px; }
  .sidebar.collapsed .sidebar-logo .wordmark { display: none; }
  .sidebar.collapsed .sidebar-logo { justify-content: center; padding: 18px 0; }
  .sidebar.collapsed nav a .label { display: none; }
  .sidebar.collapsed nav a { justify-content: center; padding: 10px 0; }
  .sidebar.collapsed nav a.active::before { left: 0; }
  .sidebar.collapsed .sidebar-collapse-btn .label { display: none; }
  .sidebar.collapsed .sidebar-collapse-btn .sb-chev { transform: rotate(180deg); }

  /* Toggle button — sits flush at the bottom of the sidebar and uses the
     same horizontal rhythm as the nav items above it (matching padding /
     border-radius / hover treatment). Icon-only — no text label. */
  .sidebar-collapse-btn {
    flex-shrink: 0;
    display: flex; align-items: center; justify-content: flex-end;
    margin: 4px 12px 12px;
    padding: 8px 12px;
    background: transparent; border: none;
    color: #cbd5e1;
    border-radius: 11px; cursor: pointer;
    transition: background .15s, color .15s;
  }
  .sidebar-collapse-btn:hover { background: rgba(255,255,255,.08); color: #fff; }
  .sidebar.collapsed .sidebar-collapse-btn { justify-content: center; margin: 4px 8px 12px; padding: 8px 0; }

  /* Content sits to the right of the fixed sidebar. The width tracks
     the sidebar via a sibling selector so it slides in/out smoothly. */
  .content {
    margin-left: 220px;
    transition: margin-left .25s ease;
    min-height: 100vh;
    /* Reserve the fixed topbar's height ONCE, here, rather than on .page.
       The topbar is out of flow, so whatever comes first inside .content was
       being painted underneath it — and between the header and .page sit the
       banners: the owner-impersonation warning (with its "End owner session"
       button), the subscription read-only notice and the two-factor prompt.
       Each of those was invisible behind the header until this padding
       existed. 65px = the topbar's 64px min-height + its 1px bottom border. */
    padding-top: 65px;
  }
  .sidebar.collapsed ~ .content { margin-left: 64px; }

  /* Top bar — fixed full width minus the sidebar. */
  .topbar {
    position: fixed;
    top: 0;
    left: 220px;
    right: 0;
    min-height: 64px;
    z-index: 999;
    background: #fff;
    transition: left .25s ease;
  }
  .sidebar.collapsed ~ .content .topbar { left: 64px; }

  /* The topbar clearance now lives on .content (above), so .page keeps the
     ordinary page padding from the base rule — it no longer has to
     compensate for the header on its own, which is what left every banner
     stacked underneath it. */

  /* No position:sticky on .impersonation-banner, deliberately. It was tried so
     the exit button would follow the admin down the page, but .content sets
     overflow-x: hidden, which makes overflow-y compute to auto — so .content
     becomes a scroll container that never actually scrolls. A sticky child
     anchors to THAT scrollport: it gained a permanent 65px downward offset
     (leaving a white gap under the header and covering the notice below it)
     and never stuck to anything. Pinning it would mean restructuring the
     scroll container, which is not worth it for a banner that sits at the top
     of the page anyway. */
}

/* Below 992px: the existing drawer mode handles everything — no fixed
   topbar, no margin-left on content. Hide the desktop-only collapse btn. */
@media (max-width: 991px) {
  .sidebar-collapse-btn { display: none; }
}

/* ==========================================================
   UI Improvements §2 — Topbar greeting (avatar + 2-line text).
   Sits between the page title and the date strip on the left
   side of the fixed top bar.
   ========================================================== */

.topbar-title {
  font-size: 16px;
  font-weight: 700;
  color: var(--text-secondary);
  margin: 0;
  padding-right: 14px;
  border-right: 1px solid var(--border-soft);
  white-space: nowrap;
}

.greeting {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 6px;
  max-width: 360px;
  overflow: hidden;
}
.greet-avatar {
  width: 36px; height: 36px;
  flex-shrink: 0;
  border-radius: 50%;
  color: #fff;
  font-weight: 700;
  font-size: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Blue → indigo gradient instead of flat colour. The PHP-generated
     hash colour is still set via inline `style="background:…"`; we
     override it here with the gradient unconditionally. */
  background: linear-gradient(135deg, #3b82f6 0%, #4f46e5 100%) !important;
  box-shadow: 0 2px 4px rgba(59,130,246,.30);
}
.greet-text {
  min-width: 0;
  line-height: 1.3;
}
.greet-line {
  font-size: 13px;
  color: var(--text-primary);
  font-weight: 400;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: flex;
  align-items: center;
  gap: 4px;
}
.greet-line strong { color: var(--brand-blue); font-weight: 700; }
.greet-wave {
  display: inline-flex;
  align-items: center;
  /* Small idle wave so the emoji feels alive without being distracting. */
  animation: greet-wave 4s ease-in-out infinite;
  transform-origin: 70% 70%;
  line-height: 1;
}
@keyframes greet-wave {
  0%, 90%, 100% { transform: rotate(0deg); }
  92% { transform: rotate(14deg); }
  94% { transform: rotate(-8deg); }
  96% { transform: rotate(12deg); }
  98% { transform: rotate(-4deg); }
}
.greet-meta {
  font-size: 11px;
  color: #94a3b8;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Equal whitespace around the · separator inside the subtitle. The PHP
   template renders "Role · Branch" with a single space on each side; we
   slightly expand that visually with letter-spacing on the middle dot. */
.greet-meta .greet-sep { padding: 0 6px; opacity: .7; }

/* Narrower viewports — drop the title (page is in the URL anyway), then
   the greeting subtitle, then the whole greeting if it still overflows. */
@media (max-width: 1100px) {
  .topbar-title { display: none; }
}
@media (max-width: 768px) {
  .greet-meta { display: none; }
  .greeting { max-width: 200px; }
}
@media (max-width: 540px) {
  .greeting { display: none; }
}

/* Sidebar plan chip — shown under the brand block. Links to billing. */
.plan-chip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 4px 12px 14px;
  padding: 8px 12px;
  border-radius: 10px;
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.08);
  color: #cbd5e1;
  font-size: 12px;
  text-decoration: none;
  transition: background .12s;
}
.plan-chip:hover { background: rgba(255,255,255,.10); }
.plan-chip .pc-name { color: #fff; font-weight: 700; letter-spacing: -.01em; }
.plan-chip .pc-meta { color: #94a3b8; font-size: 11px; font-weight: 600; }
.plan-chip.trial { background: rgba(16,185,129,.14); border-color: rgba(16,185,129,.30); }
.plan-chip.trial .pc-meta { color: #6ee7b7; }
.plan-chip.warn  { background: rgba(245,158,11,.14); border-color: rgba(245,158,11,.30); }
.plan-chip.warn .pc-meta  { color: #fcd34d; }

/* ---------------------------------------------------------------------------
   Contextual help ("?" dots) and the consultant callout.
   Additive only — no existing selector is touched. A help dot sits beside a
   label or heading; clicking it opens a small popover with plain-language
   guidance. Purely presentational: the popover is positioned by the shared
   handler in limapos.js.
   --------------------------------------------------------------------------- */
.help-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  margin-left: 6px;
  padding: 0;
  flex: none;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  cursor: help;
  vertical-align: middle;
  transition: background .12s, color .12s, border-color .12s;
}
.help-dot:hover,
.help-dot[aria-expanded="true"] {
  background: var(--blue-light);
  border-color: var(--brand-blue);
  color: var(--brand-blue-dk);
}
.help-dot:focus-visible { outline: 2px solid var(--brand-blue); outline-offset: 2px; }

.help-pop {
  position: absolute;
  z-index: 1200;
  max-width: 320px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  color: var(--text-primary);
  font-size: 12.5px;
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: normal;
  text-transform: none;
  text-align: left;
  box-shadow: 0 8px 24px rgba(15, 23, 42, .14);
}
.help-pop strong { color: var(--text-primary); }
.help-pop .help-eg {
  display: block;
  margin-top: 6px;
  color: var(--text-muted);
  font-size: 11.5px;
}

/* Consultant callout — deliberately quiet: a card, not a banner, so it reads
   as an offer rather than an upsell interrupting the work. */
.consult-card {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-top: 18px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
}
.consult-card .cc-icon {
  flex: none;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  background: var(--blue-light);
  color: var(--brand-blue-dk);
}
.consult-card h4 { margin: 0 0 2px; font-size: 13.5px; color: var(--text-primary); }
.consult-card p  { margin: 0; font-size: 12.5px; color: var(--text-muted); line-height: 1.55; }
.consult-card .cc-actions { margin-top: 10px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.consult-card .cc-paid {
  font-size: 11px;
  font-weight: 600;
  color: var(--amber-text);
  background: var(--amber-light);
  border-radius: 999px;
  padding: 2px 8px;
}

/* ── Public header CTA ──────────────────────────────────────────────────────
   The "Start free trial" button in the top nav, and the quiet Login beside it.
   These lived only in landing.php's own <style>, so the Resources hub and the
   article page — which share this stylesheet and the same .nav-links markup —
   rendered a smaller, flatter button with a different label. Moved here so the
   three public pages cannot drift apart again. */
.nav-links > a.btn-primary { background: var(--brand-blue-dk); color: #fff; font-weight: 700; }
/* Sized as a real primary action: it was .btn-sm (about 33px tall), which made
   the page's most important action its smallest button. The arrow is the hover
   cue, because the stock hover colour is the same blue it already sits on. */
.nav-links > .nav-cta { padding: 10px 16px 10px 18px; min-height: 40px; gap: 7px;
  border-radius: 10px; letter-spacing: -.005em;
  box-shadow: 0 1px 2px rgba(15, 23, 42, .12), inset 0 1px 0 rgba(255, 255, 255, .14); }
.nav-links > .nav-cta:hover { box-shadow: 0 10px 22px -8px rgba(29, 78, 216, .6); }
.nav-cta .arr { display: inline-block; transition: transform .16s ease; }
.nav-cta:hover .arr, .nav-cta:focus-visible .arr { transform: translateX(3px); }
/* On desktop, Login becomes a quiet text link so it stops competing with the
   CTA as a second outlined box. The mobile sheet keeps it a button. */
@media (min-width: 1025px) {
  .nav-links > .nav-login { background: none; border-color: transparent;
    color: var(--text-secondary); padding: 10px 2px; min-height: 40px; }
  .nav-links > .nav-login:hover { color: var(--navy); background: none; box-shadow: none; }
}

/* Read-only branch shown in a form when there is nothing to choose — a
   single-branch business, or a branch-locked admin/cashier
   (views/partials/branch_ui.php). Looks like a quiet, settled field. */
.branch-fixed { padding: 9px 12px; border: 1px solid var(--border-soft); border-radius: 8px;
  background: var(--surface); color: var(--text-secondary); font-size: 14px; line-height: 1.4; }
/* A business with one branch: per-branch columns say the same thing on every
   row, so they are dropped (the layout adds .branch-single to <body>). */
.branch-single .col-branch { display: none !important; }
/* A single-branch business: a read-only branch field says nothing, so it is
   hidden together with the field it sits in (its "Branch" label). */
.branch-fixed.branch-only { display: none; }
.field:has(> .branch-fixed.branch-only) { display: none; }

/* ── Page toolbar ────────────────────────────────────────────────────────
   One pattern for list pages (Inventory, Sales, Customers, Reports): filters
   on the left, actions on the right. Each group wraps as a unit, so a narrow
   screen never strands one button on a line of its own. Controls are a
   compact 34px so the bar stays a bar, not a form. */
.toolbar { display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: center; padding: 12px 14px; }
.toolbar.bare { padding: 0; background: none; border: 0; box-shadow: none; }
.tb-filters { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; flex: 1 1 480px; min-width: 0; }
.tb-actions { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; justify-content: flex-end; margin-left: auto; align-self: flex-start; }
.toolbar .input, .toolbar .select { height: 34px; padding: 6px 11px; font-size: 13px; }
.toolbar .select { width: auto; min-width: 130px; max-width: 190px; padding-right: 28px; }
.toolbar input[type=date] { width: auto; max-width: 150px; }
.tb-label { font-size: 12px; font-weight: 600; color: var(--text-muted); }
.tb-search { position: relative; flex: 1 1 200px; max-width: 300px; }
.tb-search svg { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--text-muted); pointer-events: none; }
.toolbar .tb-search .input { width: 100%; padding-left: 32px; }
.tb-actions .btn { height: 34px; display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.tb-sep { width: 1px; height: 20px; background: var(--border); margin: 0 4px; }
/* A toggle filter: a chip rather than a loose checkbox. */
.tb-chip { display: inline-flex; align-items: center; gap: 6px; height: 34px; padding: 0 12px; border: 1px solid var(--border);
  border-radius: 999px; font-size: 13px; color: var(--text-secondary); cursor: pointer; white-space: nowrap; user-select: none; }
.tb-chip input { margin: 0; accent-color: var(--brand-blue); }
.tb-chip:has(input:checked) { background: var(--blue-light); border-color: var(--brand-blue); color: var(--brand-blue-dk); font-weight: 600; }
/* A small menu (Export ▾ → CSV / PDF): a <details>, so it opens with no
   script; limapos.js closes it on a pick, an outside click or Esc. */
.tb-menu { position: relative; }
.tb-menu > summary { list-style: none; cursor: pointer; }
.tb-menu > summary::-webkit-details-marker { display: none; }
.tb-menu-pop { position: absolute; right: 0; top: calc(100% + 4px); z-index: 40; min-width: 200px; padding: 4px;
  background: var(--card, #fff); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 8px 24px rgba(15,23,42,.12); }
.tb-menu-pop a { display: block; padding: 7px 10px; border-radius: 6px; font-size: 13px; font-weight: 600; color: var(--text-primary); text-decoration: none; cursor: pointer; }
.tb-menu-pop a:hover, .tb-menu-pop a:focus-visible { background: var(--surface); outline: none; }
.tb-menu-pop small { display: block; color: var(--text-muted); font-size: 11px; font-weight: 400; }

/* ── KPI cards ───────────────────────────────────────────────────────────
   Headline figures in the Monthly performance format, used everywhere a page
   leads with numbers (Dashboard, Sales, Reports, Inventory, Accounting):
   separate cards, a small colour square naming what the figure is (blue =
   revenue/sales, orange = costs, green = profit/completed …), an uppercase
   label, one bold figure and a quiet line of context. Cells may be links. */
.kpi-strip { display: grid; gap: 14px; grid-template-columns: repeat(var(--kpi-cols, 4), minmax(0, 1fr)); }
.kpi { display: block; min-width: 0; padding: 14px 16px; color: inherit; text-decoration: none;
  background: var(--card); border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 1px 3px rgba(15,23,42,.06); }
a.kpi { transition: border-color .12s, box-shadow .12s; }
a.kpi:hover { border-color: #cbd5e1; box-shadow: 0 4px 12px rgba(15,23,42,.08); }
.kpi-label { display: flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 700; color: var(--text-secondary);
  text-transform: uppercase; letter-spacing: .04em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kpi-value { display: block; font-size: 22px; font-weight: 800; color: var(--navy); margin-top: 6px;
  font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kpi-value.neg { color: var(--red-text); }
.kpi-sub { display: block; font-size: 12px; color: var(--text-muted); margin-top: 4px; line-height: 1.45; }
.kpi-sub b.up { color: var(--emerald-text); font-weight: 700; } .kpi-sub b.down { color: var(--red-text); font-weight: 700; }
/* The colour square (same palette as the Monthly performance chart). */
.kpi-dot { width: 10px; height: 10px; border-radius: 3px; flex: none; display: inline-block; background: #94a3b8; }
.kpi-dot.blue { background: #2a78d6; } .kpi-dot.orange { background: #eb6834; } .kpi-dot.green { background: #1baf7a; }
.kpi-dot.amber { background: var(--amber); } .kpi-dot.red { background: var(--red); } .kpi-dot.violet { background: var(--violet); }
.kpi-dot[hidden] { display: none; }
.kpi-est { font-size: 10px; font-weight: 600; color: var(--text-muted); text-transform: none; letter-spacing: 0;
  padding: 0 5px; border: 1px dashed var(--border); border-radius: 4px; }
@media (max-width: 900px) { .kpi-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .kpi-strip { grid-template-columns: 1fr; } }

/* ==========================================================
   Menu (hamburger) button — 2026-10-05.
   One button opens / collapses the sidebar on every width (it
   replaced the chevron at the foot of the sidebar).
   ========================================================== */
.sidebar-toggle {
  display: inline-flex !important; align-items: center; justify-content: center; flex: none;
  width: 44px; height: 44px; padding: 0; margin-right: 4px;
  background: transparent; border: 1px solid transparent; border-radius: 11px;
  color: var(--text-primary, #1e293b); cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.sidebar-toggle:hover { background: var(--blue-light, #dbeafe); color: var(--brand-blue-dk, #1d4ed8); }
.sidebar-toggle:focus-visible { outline: 3px solid color-mix(in srgb, var(--brand-blue, #3b82f6) 45%, transparent); outline-offset: 2px; }
.sidebar-toggle[aria-expanded="true"] { color: var(--brand-blue-dk, #1d4ed8); }
.sidebar-collapse-btn { display: none !important; }   /* retired control */
/* Collapsed (icon-only) sidebar: the plan chip shows its name only — its
   "28d left" text used to be cut off at the edge of the 64px rail. */
@media (min-width: 992px) {
  .sidebar.collapsed .plan-chip { justify-content: center; padding-left: 0; padding-right: 0; margin-left: 8px; margin-right: 8px; }
  .sidebar.collapsed .plan-chip .pc-meta { display: none; }
}

/* ---- "Working on it" pill (reports and accounts) ---------------------------
   Shown by LimaPOS.working() while a report or statement is being prepared,
   so a long period never looks frozen. Bottom centre, above page content and
   modals (a register can load inside one); announced politely to screen readers (role=status). */
.lp-working {
  position: fixed; left: 50%; bottom: 22px; z-index: 1900;
  transform: translate(-50%, 16px); opacity: 0; pointer-events: none;
  display: flex; align-items: center; gap: 10px; max-width: min(92vw, 560px);
  padding: 10px 16px; border-radius: 999px;
  background: #0f172a; color: #f8fafc; font-size: 13.5px; line-height: 1.35;
  box-shadow: 0 8px 24px rgba(15, 23, 42, .25);
  transition: opacity .18s ease, transform .18s ease;
}
.lp-working.on { opacity: 1; transform: translate(-50%, 0); }
.lp-working-spin {
  flex: none; width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid rgba(248, 250, 252, .35); border-top-color: #f8fafc;
  animation: lp-working-spin .8s linear infinite;
}
@keyframes lp-working-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .lp-working { transition: none; }
  .lp-working-spin { animation-duration: 2.4s; }
}
@media print { .lp-working { display: none !important; } }
