﻿* { box-sizing: border-box; margin: 0; padding: 0; }
/* Scales every rem-based measurement app-wide, including third-party CSS
   this stylesheet can't reach directly - e.g. TomSelect's bundled theme
   (tom-select.bootstrap5.css, loaded after this file) sizes its controls
   entirely in rem (font-size: 0.875rem, min-height: calc(1.5em + 0.75rem +
   border)), so without this the client/description autocomplete would stay
   full-size while everything else shrank. Percentage (not a fixed px)
   so it still composes with a user's own browser accessibility font size. */
html { font-size: 80%; height: 100%; }
/* Exactly one scroll region for the tenant app shell (index.php): .content
   (below), never the page itself - body.app-shell is locked to the
   viewport so an inner element overflowing its own container can never
   ALSO add a second, outer scrollbar (it'll be clipped there instead,
   which is the signal something inside needs its own overflow handling,
   not a reason to let body scroll). Scoped to .app-shell specifically -
   this stylesheet is also shared by landing.php/admin.php, which are
   normal scrolling pages, not this single-scroll-region layout. */
/* Flex column, not a hardcoded "header is 44px" subtraction: header takes
   whatever height its own content needs (it can wrap to 2 lines at some
   desktop widths - .tabs already has flex-wrap for that) and .layout gets
   exactly whatever's left, so it can never push part of the page out of
   reach with nothing able to scroll to it. */
body.app-shell { height: 100%; overflow: hidden; display: flex; flex-direction: column; }
body.app-shell > header { flex-shrink: 0; }
body.app-shell > .layout { flex: 1 1 auto; min-height: 0; }
body { font-family: "Roboto", "Segoe UI", Calibri, Arial, sans-serif; font-size: 10px; background: #f3f4f6; color: #1f2937; }
:root {
  --green: #217346; --green-d: #1a5c38; --green-l: #e6f0ea; --border: #d4d4d4; --hdr: #f7f7f7;
  /* Text */
  --text: #1f2937; --text-muted: #6b7280; --text-faint: #9ca3af;
  /* Status color ramps - each already used consistently across badges/
     warnings/etc, just as raw hex repeated in many places rather than a
     named token. Declaring them here doesn't change any existing color,
     only gives the recurring ramps a single source of truth. */
  --red: #dc2626; --red-d: #b91c1c; --red-l: #fee2e2; --red-l2: #fef2f2; --red-border: #fecaca; --red-text: #991b1b;
  --amber: #d97706; --amber-d: #92400e; --amber-l: #fef3c7; --amber-border: #fde68a;
  --blue: #2563eb; --blue-d: #1d4ed8; --blue-l: #dbeafe; --blue-border: #bfdbfe; --blue-text: #1e40af;
  --emerald: #059669; --emerald-d: #065f46; --emerald-l: #d1fae5; --emerald-l2: #a7f3d0;
  --purple: #7c3aed; --purple-d: #6b21a8; --purple-l: #f3e8ff;
  /* Spacing/radius/shadow scale - used going forward for new/edited rules;
     not retrofitted across the whole file (a much larger, separate pass). */
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 20px; --space-6: 24px;
  --radius-sm: 4px; --radius-md: 8px; --radius-lg: 12px;
  --shadow-sm: 0 1px 3px rgba(0,0,0,.06); --shadow-md: 0 6px 20px rgba(0,0,0,.08);
}
header { background: var(--green); color: #fff; padding: 6px 13px; display: flex; align-items: center; gap: 13px; box-shadow: 0 2px 4px rgba(0,0,0,.15); }
/* Defaults to white (this header's own background is normally dark green) -
   filter turns any solid-color image white (brightness(0) blackens every
   opaque pixel, invert(1) flips to white). App.applyBranding() adds
   .on-light-bg (removing the filter, showing the logo's natural green/
   gradient) if this org's custom brand color ever lands light instead. */
.header-logo { height: 22px; width: auto; flex-shrink: 0; filter: brightness(0) invert(1); }
.header-logo.on-light-bg { filter: none; }
header .tabs { display: flex; gap: 5px; margin-left: auto; align-items: center; max-width: 76%; flex-wrap: wrap; justify-content: flex-end; }
header .tabs button, header .tabs .nav-logout-btn { background: transparent; color: #fff; border: none; padding: 5px 8px; cursor: pointer; border-radius: 4px 4px 0 0; font-size: 10px; min-width: 59px; white-space: nowrap; }
header .tabs button.active { background: #fff; color: var(--green); box-shadow: inset 0 -3px 0 rgba(0,0,0,0.03); }
header .tabs button:hover, header .tabs .nav-logout-btn:hover { background: rgba(255,255,255,.12); }
header .tabs button.active:hover { background: #fff; }
/* Log out is a plain anchor (a real navigation, not an internal view
   switch like every other .tabs button), styled identically - display:
   inline-block since anchors don't take padding/width like buttons by
   default, text-decoration:none to drop the link underline. */
header .tabs .nav-logout-btn { display: inline-block; text-decoration: none; text-align: center; }

/* Grouped nav dropdowns (Contacts/Finance) - plain CSS+JS, same pattern as
   the existing .autocomplete/.client-typeahead custom dropdowns. */
header .tabs .nav-dropdown { position: relative; }
header .tabs .nav-dropdown-toggle.active-group { background: rgba(255,255,255,.22); }
.nav-badge { display: inline-block; background: #dc2626; color: #fff; font-size: 8px; font-weight: 700; border-radius: 999px; padding: 1px 5px; margin-left: 2px; vertical-align: middle; }
header .tabs button.nav-locked, header .tabs .nav-dropdown-menu button.nav-locked { opacity: .6; }
.doc-followup-badge { display: inline-block; background: #fef3c7; color: #92400e; border: 1px solid #fde68a; font-size: 8px; font-weight: 700; border-radius: 3px; padding: 1px 5px; margin-left: 6px; cursor: pointer; }
.doc-followup-badge:hover { background: #fde68a; }
header .tabs .nav-dropdown-menu {
  display: none; position: absolute; top: 100%; left: 0; margin-top: 4px; min-width: 120px;
  background: #fff; border: 1px solid var(--border); border-radius: 6px;
  box-shadow: 0 4px 14px rgba(0,0,0,.15); flex-direction: column; padding: 3px; z-index: 60;
}
header .tabs .nav-dropdown.open .nav-dropdown-menu { display: flex; }
header .tabs .nav-dropdown-menu button {
  color: #1f2937; background: transparent; text-align: left; min-width: 0; width: 100%;
  border-radius: 4px; padding: 6px 8px;
}
header .tabs .nav-dropdown-menu button:hover { background: var(--green-l); }
header .tabs .nav-dropdown-menu button.active { background: var(--green-l); color: var(--green); font-weight: 600; }
header .tabs .nav-settings-btn { margin-left: 10px; }

/* Make tabs compact on small screens */
@media (max-width: 900px) {
  header .tabs { max-width: 60%; }
  header .tabs button { padding: 6px 8px; font-size: 12px; min-width: 64px; }
}
.layout { display: flex; position: relative; }
.sidebar { width: 208px; background: var(--hdr); box-shadow: 1px 0 3px rgba(0,0,0,.05); overflow-y: auto; padding: 6px; flex-shrink: 0; }
.sidebar::-webkit-scrollbar { width: 8px; }
.sidebar::-webkit-scrollbar-track { background: transparent; }
.sidebar::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 4px; }
.sidebar::-webkit-scrollbar-thumb:hover { background: #b0b6c0; }
/* Toggle for the folders sidebar (Archive/Clients/Suppliers/Employees) - a
   prominent half-circle "tab" handle (flat left edge, rounded right edge)
   with a › glyph, indicating the panel it opens slides in from the left
   edge toward the right. Fixed to the middle of the left screen edge
   (not tucked inline into the header, where it was barely noticeable) so
   it's always visible regardless of scroll position. Off-canvas backdrop
   is inert/hidden above the mobile breakpoint, where the sidebar is always
   visible inline as before. */
.sidebar-toggle-btn {
  display: none; background: var(--green-d); border: none; color: #fff;
  font-size: 22px; line-height: 1; cursor: pointer;
  position: fixed; left: 0; top: 50%; transform: translateY(-50%); z-index: 95;
  width: 34px; height: 68px; padding: 0;
  border-radius: 0 999px 999px 0;
  align-items: center; justify-content: center;
  box-shadow: 2px 0 10px rgba(0,0,0,.3);
}
.sidebar-toggle-btn:active { transform: translateY(-50%) scale(.96); }
.sidebar-toggle-btn:hover { background: var(--green); }
.sidebar-backdrop { display: none; }
/* Separate burger toggle for the main nav (.tabs) - opens it as a
   right-hand off-canvas panel on mobile (see the ≤860px media query below).
   Hidden entirely above that breakpoint, where .tabs renders inline as
   always. */
/* margin-left:auto pins this to the header's right edge on its own -
   previously relied on .tabs (margin-left:auto, in normal flow) pushing
   everything after it rightward, but .tabs is position:fixed on mobile now
   (removed from flow entirely), so this must push itself. */
.nav-toggle-btn { display: none; background: transparent; border: none; color: #fff; font-size: 18px; line-height: 1; padding: 4px 8px; cursor: pointer; border-radius: 4px; margin-left: auto; }
.nav-toggle-btn:hover { background: rgba(255,255,255,.15); }
.nav-backdrop { display: none; }
.nav-panel-close { display: none; }
/* Quotes/Invoices row actions: a fixed full-height panel that slides in
   from the right edge over the page (same slide mechanic as the mobile
   off-canvas sidebar above, mirrored to the right and active at every
   width, not just mobile) instead of cramming buttons into the list's
   Actions column. */
.doc-actions-panel {
  position: fixed; top: 44px; right: 0; bottom: 0; z-index: 80;
  width: 260px; max-width: 85vw; background: #fff;
  transform: translateX(100%); transition: transform .22s ease;
  box-shadow: -2px 0 12px rgba(0,0,0,.15);
  display: flex; flex-direction: column;
}
.doc-actions-panel.open { transform: translateX(0); }
.doc-actions-panel-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; padding: 12px; background: var(--green-l); border-bottom: 1px solid var(--border); }
.doc-actions-panel-details { min-width: 0; }
.doc-actions-panel-number { font-size: 14px; font-weight: 700; color: var(--green-d); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.doc-actions-panel-meta { margin-top: 4px; font-size: 10px; color: #4b5563; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.doc-actions-panel-total { font-weight: 600; color: #1f2937; }
.doc-actions-panel-close {
  flex-shrink: 0; width: 22px; height: 22px; border: none; border-radius: 50%;
  background: #dc2626; color: #fff; font-size: 15px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center; transition: background .12s ease;
}
.doc-actions-panel-close:hover { background: #b91c1c; }
.doc-actions-panel-body { display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; overflow-y: auto; }
.doc-actions-panel-body button { width: 100%; text-align: left; }
.delivery-panel-actions { display: flex; flex-direction: column; gap: 6px; }
/* Suppliers Payable's per-supplier group header, inside one wide table
   cell (colspan) - a flex-wrap row instead of raw inline text+buttons so
   the name/total/buttons stack cleanly on a narrow screen instead of
   running into each other. */
.supplier-payable-group-header { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.supplier-payable-group-header .spacer { flex: 1; }
/* Everything the table's Contact Person/Project/Issue Date/Approval
   columns hold when they're hidden from the table on a phone (see
   .col-doc-extra below) - shown here instead so nothing is actually lost,
   just moved out of a cramped row into this already-open panel. */
.doc-actions-panel-details-list { border-bottom: 1px solid var(--border); padding-bottom: 10px; margin-bottom: 4px; display: flex; flex-direction: column; gap: 6px; }
.doc-detail-row { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; font-size: 11px; }
.doc-detail-label { color: #6b7280; font-weight: 600; flex-shrink: 0; }
.doc-actions-backdrop {
  display: block; position: fixed; top: 44px; left: 0; right: 0; bottom: 0;
  background: rgba(0,0,0,.3); z-index: 70; opacity: 0; pointer-events: none; transition: opacity .22s ease;
}
.doc-actions-backdrop.open { opacity: 1; pointer-events: auto; }
/* Negative margin cancels the sidebar's own 8px padding so the logo spans
   the pane's full width edge-to-edge, without changing that padding for
   every other sidebar section (folder/client/supplier/employee trees),
   which still rely on it for their own inset. */
.sidebar-logo { margin: -6px -6px 6px; padding: 11px 10px; text-align: center; font-size: 13px; font-weight: 700; color: var(--green-d); background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.05); box-sizing: border-box; }
.sidebar-logo img { width: 100%; height: auto; display: block; }
.sidebar h3 { font-size: 10px; text-transform: uppercase; letter-spacing: .04em; color: #9ca3af; padding: 6px 6px 3px; }
.sidebar-section { margin-bottom: 4px; }
.sidebar-section-header { font-size: 10px; text-transform: uppercase; letter-spacing: .04em; color: #9ca3af; padding: 6px 6px 3px; cursor: pointer; user-select: none; display: flex; align-items: center; gap: 3px; transition: color .12s ease; }
.sidebar-section-header:hover { color: var(--green); }
.sidebar-tree { margin-bottom: 8px; }
.tree-node { padding: 4px 6px 4px 4px; margin: 0 2px; cursor: pointer; border-radius: 6px; border-left: 2px solid transparent; display: flex; align-items: center; gap: 3px; font-size: 10px; transition: background .12s ease, border-color .12s ease; }
.tree-node:hover { background: #fff; }
.tree-node.active { background: #fff; border-left-color: var(--green); font-weight: 600; color: var(--green-d); box-shadow: 0 1px 2px rgba(0,0,0,.04); }
.tree-node .caret { width: 11px; font-size: 8px; }
.tree-node span:last-of-type { flex: 1; overflow: hidden; text-overflow: ellipsis; }
.tree-download { margin-left: auto; border: none; background: transparent; color: #6b7280; cursor: pointer; font-size: 10px; padding: 2px 3px; border-radius: 3px; flex-shrink: 0; transition: background .12s ease, color .12s ease; }
.tree-download:hover { background: var(--green-l); color: var(--green); }
.tree-children { margin-left: 14px; }
.main { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
/* Safety-net default for any <button> that ISN'T inside .toolbar/
   .doc-actions-panel-body/table.data td (the only contexts the rules below
   actually style) - without this, a button anywhere else (the Pricing
   page's whole card layout, plan-status action buttons, etc.) rendered as
   a bare, unstyled native browser button. Those more specific selectors
   below still win where they apply (same specificity, declared later, or
   simply more specific via the descendant combinator). */
button {
  font-family: inherit; font-size: 10px; padding: 4px 8px;
  border: 1px solid var(--border); background: #fff; color: var(--green);
  border-radius: 4px; cursor: pointer; transition: background .12s ease;
}
button:hover { background: var(--green-l); }
button:disabled, button:disabled:hover { cursor: not-allowed; opacity: .5; background: #fff; color: #9ca3af; border-color: var(--border); }
button.danger { background: var(--red); color: #fff; border-color: var(--red-d); }
button.danger:hover { background: var(--red-d); }
button.mini { padding: 2px 8px; font-size: 9px; border-radius: var(--radius-sm); }
/* Icon-only action buttons (row delete/edit) - square, centered icon, no
   text label, replacing bare words like "Delete"/"Edit" in dense tables
   and side panels where a full-width text button wastes space. */
button.icon-btn { display: inline-flex; align-items: center; justify-content: center; padding: 4px; width: 26px; height: 26px; }
button.icon-btn.mini { width: 22px; height: 22px; padding: 2px; }
button.icon-btn .app-icon { display: block; }
/* Same gap as the button fix above, for the same reason: at least 8 near-
   identical input/select/textarea rules exist scoped to specific
   containers (.toolbar, .modal .form-row, .settings-section-body
   .form-row, .pay-modal-info .form-row, etc.) - anything outside all of
   them fell back to a bare, unstyled native control. Those more specific
   rules still win where they apply. Excludes checkbox/radio/range/color/
   file (already have their own correct native look, e.g. .checkbox-label
   input[type=checkbox] below - border/padding/background on those would
   visually break the native control in most browsers, not fix anything). */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]), select, textarea {
  font-family: inherit; font-size: 10px; padding: 4px 6px;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: #fff; color: var(--text);
}
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):focus, select:focus, textarea:focus { outline: none; border-color: var(--green); box-shadow: 0 0 0 2px rgba(33,115,70,.12); }
.toolbar { background: #fff; border-bottom: 1px solid var(--border); padding: 5px 10px; display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.toolbar button, .toolbar select, .toolbar input, .doc-actions-panel-body button, table.data td button { font-size: 10px; padding: 4px 8px; border: 1px solid var(--border); background: #fff; border-radius: 4px; cursor: pointer; }
.toolbar button, .doc-actions-panel-body button, table.data td button { background: var(--green); color: #fff; border-color: var(--green-d); }
.toolbar button:hover, .doc-actions-panel-body button:hover, table.data td button:hover { background: var(--green-d); }
.toolbar button.secondary, .doc-actions-panel-body button.secondary, table.data td button.secondary { background: #fff; color: var(--green); }
.toolbar button.secondary:hover, .doc-actions-panel-body button.secondary:hover, table.data td button.secondary:hover { background: var(--green-l); }
.toolbar button.danger, .doc-actions-panel-body button.danger, table.data td button.danger { background: #dc2626; border-color: #b91c1c; }
table.data td button + button { margin-left: 4px; }
.toolbar button.report-subtab.active { background: var(--green); color: #fff; border-color: var(--green-d); font-weight: 600; }
/* Dashboard > Overview's 1M/3M/6M/12M range picker, inline in the panel's
   own <h2> next to the title rather than a separate toolbar row. */
.dash-range-picker { float: right; display: inline-flex; gap: 4px; }
.dash-range-picker button.dash-range-btn { font-size: 10px; padding: 3px 8px; border: 1px solid var(--border); background: #fff; color: #374151; border-radius: 4px; cursor: pointer; font-weight: 400; }
.dash-range-picker button.dash-range-btn:hover { background: var(--green-l); }
.dash-range-picker button.dash-range-btn.active { background: var(--green); color: #fff; border-color: var(--green-d); font-weight: 600; }
.toolbar button:disabled, .toolbar button:disabled:hover { cursor: not-allowed; opacity: 0.45; background: #fff; color: #9ca3af; border-color: var(--border); }
.toolbar .spacer { flex: 1; }
/* Document editor's "Actions" dropdown - all the export/compare/AI buttons
   that used to spill across the whole toolbar row, tucked into one menu.
   Same open/outside-click-close interaction as the header's .nav-dropdown,
   kept as its own class since this toolbar re-renders per document (see
   bindDocEditor's namespaced document-click listener). */
.toolbar-dropdown { position: relative; }
.toolbar-dropdown-menu {
  display: none; position: absolute; top: 100%; left: 0; margin-top: 4px; min-width: 200px;
  background: #fff; border: 1px solid var(--border); border-radius: 6px;
  box-shadow: 0 4px 14px rgba(0,0,0,.15); flex-direction: column; padding: 4px; z-index: 60;
}
.toolbar-dropdown.open .toolbar-dropdown-menu { display: flex; }
.toolbar-dropdown-menu button {
  background: transparent !important; color: #1f2937 !important; border: none !important;
  text-align: left; width: 100%; border-radius: 4px; padding: 7px 10px !important; font-size: 11px !important;
}
.toolbar-dropdown-menu button:hover { background: var(--green-l) !important; }
.content { flex: 1; overflow: auto; background: #fff; }
table.grid { width: 100%; border-collapse: collapse; font-size: 10px; }
table.grid th, table.grid td { border: 1px solid var(--border); padding: 2px 3px; height: 18px; }
table.grid th { background: var(--hdr); font-weight: 600; position: sticky; top: 0; z-index: 2; }
table.grid td { background: #fff; }
table.grid td.editing { padding: 0; }
table.grid input, table.grid select { width: 100%; height: 18px; border: none; padding: 0 3px; font-size: 10px; font-family: inherit; background: #fff; }
table.grid input:focus, table.grid select:focus { outline: 2px solid var(--green); background: #fffbe6; }
table.grid tr.selected td { background: #e6f0ea; }
.row-num { width: 29px; text-align: center; background: var(--hdr) !important; color: #6b7280; font-size: 9px; }
.col-desc { min-width: 224px; }
.col-num { width: 72px; text-align: right; }
.col-unit { width: 56px; }
.col-qty { width: 56px; }
.col-sku { width: 96px; }
.col-total { width: 88px; text-align: right; }
.col-action { width: 32px; text-align: center; }
.qt-grid .col-num { width: 80px; }
.qt-grid .col-qty { width: 56px; }
.qt-grid .col-total { width: 96px; }
.qt-grid .col-action { width: 32px; text-align: center; }
/* Drag-and-drop row reordering (Line Items/Labour/Consumables/Time Entries) */
.row-drag-handle { width: 18px; text-align: center; cursor: grab; color: #9ca3af; user-select: none; }
.row-drag-handle:active { cursor: grabbing; }
.doc-items-body tr.dragging-row { opacity: 0.4; }
.doc-items-body tr.drop-above { box-shadow: inset 0 2px 0 0 var(--green); }
.doc-items-body tr.drop-below { box-shadow: inset 0 -2px 0 0 var(--green); }
.totals { width: 256px; margin-left: auto; padding: 10px; }
.totals table { width: 100%; }
.totals td { padding: 3px 6px; }
.totals .grand { font-size: 13px; font-weight: 700; border-top: 2px solid var(--green); }
.doc-header { padding: 13px; border-bottom: 1px solid var(--border); display: flex; gap: 19px; flex-wrap: wrap; }
.doc-header .field { display: flex; flex-direction: column; gap: 2px; }
.doc-header label { font-size: 9px; text-transform: uppercase; color: #6b7280; }
.doc-header input, .doc-header select { padding: 3px 6px; border: 1px solid var(--border); border-radius: 4px; font-size: 10px; min-width: 160px; }
.doc-header .doc-num { font-size: 16px; font-weight: 700; color: var(--green); }
.dropzone { border: 2px dashed var(--border); border-radius: 8px; padding: 26px; text-align: center; color: #6b7280; margin: 13px; transition: all .2s; cursor: pointer; }
.dropzone.dragover { border-color: var(--green); background: var(--green-l); color: var(--green); }
.dropzone .icon { font-size: 29px; margin-bottom: 8px; }
/* Real card look (background/border/radius/shadow) instead of bare
   padding - previously every .panel-wrapped section (most list views'
   tables, dashboard blocks, etc.) had NO visual boundary against the page
   at all, one of the flattest/most "internal tool" things about the
   current look. */
.panel { padding: 13px; background: #fff; border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); }
.panel h2 { font-size: 13px; margin-bottom: 12px; color: var(--green); }
table.data { width: 100%; border-collapse: collapse; font-size: 10px; }
table.data th, table.data td { border: 1px solid var(--border); padding: 5px 6px; text-align: left; }
table.data th { background: var(--hdr); }
table.data tr:hover td { background: var(--green-l); }
table.data tr.row-outstanding td { background: #fef2f2; }
table.data tr.row-outstanding:hover td { background: #fee2e2; }
table.data tr.doc-row { cursor: pointer; }
table.data tr.doc-row.selected td { background: var(--green); color: #fff; }
table.data tr.contact-row, table.data tr.employee-row { cursor: pointer; }
table.data tr.contact-row.selected td, table.data tr.employee-row.selected td { background: var(--green); color: #fff; }
table.data tr.emp-row, table.data tr.payroll-txn-row { cursor: pointer; }
table.data tr.emp-row.selected td, table.data tr.payroll-txn-row.selected td { background: var(--green); color: #fff; }
table.data tr.expense-row, table.data tr.ledger-row, table.data tr.price-row { cursor: pointer; }
table.data tr.expense-row.selected td, table.data tr.ledger-row.selected td, table.data tr.price-row.selected td { background: var(--green); color: #fff; }
/* Suppliers Payable: click a row (not a button) to open the delivery
   checklist side panel for that invoice - see #deliveryPanel in index.php,
   which reuses the .doc-actions-panel family's CSS. */
table.data tr.supplier-payable-row { cursor: pointer; }
/* Inline SVG icons (App.icon() in app.js) - vertical-align nudges them to
   sit on the text baseline instead of the box's own baseline (the default
   for inline SVG sits noticeably low next to text). */
.app-icon { vertical-align: -2px; flex-shrink: 0; }
/* Small solid status dot (e.g. "blocked") - replaces the 🔴 emoji used for
   this in real HTML contexts (native <option> text elsewhere can't render
   an icon at all, so those keep the emoji - a real technical constraint,
   not a design choice). */
.status-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--red); vertical-align: 1px; }
/* Shared "nothing here yet" moment - an icon + short message, used
   consistently instead of the same ad-hoc bare gray text repeated
   (and worded slightly differently) per view. */
.empty-state { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 32px 16px; color: var(--text-faint); text-align: center; }
.empty-state .app-icon { width: 32px; height: 32px; opacity: .6; }
.empty-state-msg { font-size: 11px; }
.badge { display: inline-block; padding: 2px 6px; border-radius: 10px; font-size: 9px; font-weight: 600; }
.badge.draft { background: #e5e7eb; color: #374151; }
.badge.sent { background: var(--blue-l); color: var(--blue-text); }
.badge.accepted { background: var(--emerald-l); color: var(--emerald-d); }
.badge.paid { background: var(--emerald-l2); color: #064e3b; }
.badge.archived { background: var(--purple-l); color: var(--purple-d); }
.badge.rejected { background: var(--red-l); color: var(--red-text); }
.badge.partially_paid { background: var(--amber-l); color: var(--amber-d); }
.badge.deposit_paid { background: var(--amber-l); color: var(--amber-d); }
.badge.proforma-sent { background: var(--blue-l); color: var(--blue-text); }
.badge.materials-ordered { background: var(--amber-l); color: var(--amber-d); }
.badge.materials-arrived { background: var(--emerald-l); color: var(--emerald-d); }
.badge.project-completed { background: var(--purple-l); color: var(--purple-d); }
.badge.invoice-requested { background: var(--emerald-l); color: var(--emerald-d); }
.badge.procured { background: var(--emerald-l); color: var(--emerald-d); }
/* Suppliers Payable: paid 48+ hours ago with materials still not delivered.
   Its own class rather than reusing .badge.rejected - same red, but a
   "chase this up" warning is a completely different fact from a rejection,
   and conflating them makes either one's styling impossible to change
   later without silently restyling the other. */
.badge.delivery-overdue { background: var(--red-l); color: var(--red-text); }
.doc-status-select { border: none; cursor: pointer; font-family: inherit; }
.doc-status-select:focus { outline: 2px solid var(--green); }
.no-contact-warn { color: #b91c1c; font-weight: 600; font-size: 9px; }
.stale-warn { color: #b45309; font-weight: 600; font-size: 9px; }
table.data tr.row-blocked td { background: #fef2f2; }
table.data tr.row-blocked:hover td { background: #fee2e2; }
.client-blocked-badge {
  display: inline-block;
  padding: 2px 6px;
  border-radius: 10px;
  font-size: 9px;
  font-weight: 700;
  background: var(--red-l);
  color: var(--red-text);
}
tr.price-stale-row .item-desc { border-left: 3px solid #f59e0b; }

/* ===== Schedule (shared org-wide day planner) ===== */
.schedule-layout { display: flex; gap: 13px; align-items: flex-start; padding: 0 13px 13px; }
.schedule-calendar-col { flex: 1; min-width: 0; margin: 0; }
.schedule-side-panel { width: 272px; flex-shrink: 0; background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 13px; position: sticky; top: 16px; }
.schedule-stat-grid.stat-grid { grid-template-columns: repeat(2, 1fr); gap: 6px; margin-bottom: 0; }
.schedule-task-list { max-height: 384px; overflow-y: auto; }
.schedule-task-row { display: flex; align-items: center; gap: 6px; padding: 6px 3px; border-bottom: 1px solid var(--border); }
.schedule-task-row:last-child { border-bottom: none; }
.schedule-task-row.dragging-row { opacity: 0.4; }
.schedule-task-row.drop-above { box-shadow: inset 0 2px 0 0 var(--green); }
.schedule-task-row.drop-below { box-shadow: inset 0 -2px 0 0 var(--green); }
.schedule-task-body { flex: 1; min-width: 0; }
.schedule-task-title { font-size: 10px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.schedule-task-meta { font-size: 9px; color: #6b7280; }
.schedule-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; background: var(--border); border: 1px solid var(--border); }
.schedule-dow { background: var(--hdr); padding: 5px; text-align: center; font-size: 9px; font-weight: 700; color: #6b7280; text-transform: uppercase; }
/* Fixed height (not min-height) so every cell - empty or full, any row -
   is exactly the same size regardless of content. Safe to clip overflow:
   entries are already capped to 3 + a "+N more" line (renderSchedule), each
   single-line/ellipsis-truncated, so content never actually needs more than
   this height in the first place. */
.schedule-grid.schedule-grid-week .schedule-cell { height: 176px; }
.schedule-cell { background: #fff; height: 72px; overflow: hidden; padding: 3px; cursor: pointer; }
.schedule-cell:hover { background: var(--green-l); }
.schedule-cell-empty { background: #fafafa; cursor: default; }
.schedule-cell-empty:hover { background: #fafafa; }
.schedule-today { box-shadow: inset 0 0 0 2px var(--green); }
.schedule-daynum { font-size: 10px; font-weight: 700; color: #374151; margin-bottom: 2px; }
.schedule-entry { font-size: 9px; background: var(--green-l); color: var(--green-d); border-radius: 3px; padding: 1px 3px; margin-bottom: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.schedule-entry .schedule-emp { color: #6b7280; }
.schedule-more { font-size: 8px; color: #9ca3af; }
/* Overdue (still open, past its date) = red; done = green - on both the
   calendar's mini entry chips and the day modal's full entry cards. Done
   wins over overdue (a completed task isn't "overdue" anymore). */
.schedule-entry.overdue { background: #fee2e2; color: #991b1b; }
.schedule-entry.overdue .schedule-emp { color: #991b1b; }
.schedule-entry.completed { background: #d1fae5; color: #065f46; }
.schedule-entry.completed .schedule-emp { color: #065f46; }

.schedule-modal-section-title { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: #9ca3af; margin: 0 0 6px; }
.schedule-day-item { border: 1px solid var(--border); border-left: 4px solid var(--border); border-radius: 6px; padding: 8px 10px; margin-bottom: 10px; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.04); }
.schedule-day-item.overdue { border-left-color: #dc2626; background: #fef2f2; }
.schedule-day-item.completed { border-left-color: #16a34a; background: #f0fdf4; }
.schedule-day-item-row { display: flex; gap: 8px; align-items: flex-start; }
.schedule-day-item-time { flex: 0 0 auto; font-size: 9px; font-weight: 700; color: var(--green-d); background: var(--green-l); border-radius: 4px; padding: 2px 6px; white-space: nowrap; }
.schedule-day-item-body { flex: 1; min-width: 0; }
.schedule-day-item-title { font-weight: 600; font-size: 10px; }
.schedule-day-item-title .badge { margin-left: 6px; vertical-align: 1px; }
.schedule-day-item-emp { font-size: 10px; color: #6b7280; margin-top: 2px; }
.schedule-day-item-notes { font-size: 10px; color: #6b7280; margin-top: 4px; font-style: italic; }
.schedule-day-item-actions { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 10px; padding-top: 8px; border-top: 1px solid #f3f4f6; flex-wrap: wrap; }
.schedule-day-item-buttons { display: flex; gap: 5px; }
.schedule-day-item-buttons button { padding: 3px 8px; font-size: 10px; }
.buy-from-btn { display: block; width: 100%; text-align: left; background: none; border: 1px dashed var(--border); border-radius: 4px; padding: 2px 5px; cursor: pointer; font-size: 10px; }
.buy-from-btn:hover { background: var(--green-l); }
.buy-from-btn.selected { border: 1px solid var(--green); background: var(--green-l); font-weight: 600; }
.buy-from-btn b { display: block; }
/* Member role: financial views and delete actions are owner/admin-only
   (enforced server-side too, in every api/*.php file - this is just UX). */
body.role-member .danger:not(.remove-item),
body.role-member button[data-view="bookkeeping"],
body.role-member button[data-view="payroll"],
body.role-member button[data-view="reports"],
body.role-member button[data-view="settings"] { display: none !important; }
.modal-bg { position: fixed; inset: 0; background: rgba(0,0,0,.4); display: none; align-items: center; justify-content: center; z-index: 100; }
.modal-bg.show { display: flex; }
/* The document editor's floating Save button uses an inline z-index:999
   (app.js) so it stays above the editor's own scrolling content/sticky
   headers - but that also put it above this modal's z-index:100, so it
   stayed visible and clickable over ANY open modal (Compare Supplier
   Prices included), causing exactly the wrong Save button to get clicked.
   Hides it specifically while a modal is open, without touching its
   z-index (which the editor still needs for its own stacking). */
body:has(.modal-bg.show) #saveDocBtnBottom { display: none; }
.modal { background: #fff; border-radius: 8px; padding: 16px; min-width: 320px; max-width: 90vw; max-height: 90vh; overflow: auto; box-shadow: 0 8px 24px rgba(0,0,0,.2); }
.modal h2 { margin-bottom: 12px; color: var(--green); }
.modal .form-row { margin-bottom: 10px; }
.modal .form-row label { display: block; font-size: 10px; color: #6b7280; margin-bottom: 2px; }
.modal .form-row input:not([type="checkbox"]):not([type="radio"]), .modal .form-row select, .modal .form-row textarea { width: 100%; padding: 5px 6px; border: 1px solid var(--border); border-radius: 4px; font-size: 10px; }
.modal .form-row .form-section-label { display: block; font-size: 10px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--text-faint); border-top: 1px solid var(--border); padding-top: 12px; margin: 4px 0 10px; }
.modal .form-row .form-hint { color: var(--text-muted); font-size: 11px; margin: 4px 0 8px; line-height: 1.4; }
/* Same small helper-text treatment, usable outside a modal too (e.g. the
   Settings page's AI Integration section) - kept as its own unscoped rule
   rather than widening the .modal-scoped one above, since a plain settings
   page form-row has different spacing/label rules already. */
.form-hint { color: var(--text-muted); font-size: 11px; margin: 4px 0 0; line-height: 1.4; }
.modal .actions { display: flex; gap: 6px; justify-content: flex-end; margin-top: 16px; }
/* Every modal button was falling back to the bare, unstyled browser
   default (no color/radius/hover) - this was the single biggest reason
   any modal with more than one or two buttons read as dated/cluttered. */
.modal button { font-size: 10px; padding: 5px 11px; border: 1px solid var(--green-d); border-radius: 4px; cursor: pointer; background: var(--green); color: #fff; }
.modal button:hover { background: var(--green-d); }
.modal button.secondary { background: #fff; color: var(--green); border-color: var(--border); }
.modal button.secondary:hover { background: var(--green-l); }
.modal button.danger { background: #dc2626; border-color: #b91c1c; color: #fff; }
.modal button.danger:hover { background: #b91c1c; }
.markup-preview { background: var(--green-l); border: 1px solid var(--border); border-radius: 6px; padding: 6px 8px; font-size: 10px; margin-top: 4px; }
.markup-preview b { color: var(--green-d); }
.toast { position: fixed; bottom: 20px; right: 20px; background: #1f2937; color: #fff; padding: 8px 13px; border-radius: 6px; z-index: 200; opacity: 0; transition: opacity .3s; }
.toast.show { opacity: 1; }
.toast.error { background: #dc2626; }
.toast.success { background: var(--green); }
.fs-widget { position: fixed; bottom: 16px; left: 16px; display: flex; flex-direction: column; gap: 5px; z-index: 90; }
.fs-btn { background: #fff; color: var(--green-d); border: 1px solid var(--border); border-radius: 20px; padding: 6px 13px; font-size: 10px; font-weight: 600; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,.15); position: relative; }
.fs-btn:hover { background: var(--green-l); }
.fs-btn .nav-badge { position: absolute; top: -6px; right: -6px; margin-left: 0; }
/* Mobile-only duplicate of the two buttons above, living inside the
   slide-out nav panel instead - hidden here (desktop default) and swapped
   with .fs-widget by the mobile media query below, so exactly one copy is
   ever visible. */
.nav-fs-actions { display: none; }
.import-progress { min-width: 352px; max-width: 448px; }
.import-progress-meta { display: flex; justify-content: space-between; gap: 10px; margin-bottom: 10px; font-size: 10px; color: #6b7280; }
.import-progress-bar { position: relative; height: 11px; border-radius: 999px; background: #e5e7eb; overflow: hidden; margin: 8px 0 6px; }
.import-progress-bar > span { display: block; height: 100%; width: 0; background: linear-gradient(90deg, var(--green), #34d399); border-radius: inherit; transition: width .2s ease; }
.import-progress-text { font-size: 10px; color: #374151; margin-bottom: 10px; }
.import-progress-stats { display: flex; gap: 13px; flex-wrap: wrap; margin-top: 12px; }
.import-progress-stat { background: #f9fafb; border: 1px solid var(--border); border-radius: 6px; padding: 6px 8px; min-width: 96px; }
.import-progress-stat strong { display: block; font-size: 14px; color: var(--green); }
.import-progress-stat span { font-size: 9px; text-transform: uppercase; letter-spacing: .04em; color: #6b7280; }
.autocomplete { position: absolute; background: #fff; border: 1px solid var(--border); max-height: 160px; overflow-y: auto; z-index: 50; box-shadow: 0 4px 8px rgba(0,0,0,.1); }
.autocomplete div { padding: 5px 8px; cursor: pointer; font-size: 10px; }
.autocomplete div:hover, .autocomplete div.active { background: var(--green-l); }
.client-typeahead { position: absolute; background: #fff; border: 1px solid var(--border); max-height: 240px; overflow-y: auto; z-index: 2000; box-shadow: 0 8px 24px rgba(0,0,0,.15); border-radius: 8px; }
.client-typeahead .ct-opt { padding: 8px 10px; cursor: pointer; font-size: 10px; border-bottom: 1px solid #f3f4f6; }
.client-typeahead .ct-opt.ct-new { font-weight: 700; color: #064e3b; background: #f0fdf4; }
.client-typeahead .ct-opt:hover, .client-typeahead .ct-opt.active { background: #ecfdf5; }

/* Prominent primary button - deliberately its own blue accent (not the
   office-green button family) since it's the document editor's single
   floating Save action; standing apart from the rest of the UI is the
   point, not a bug. */
.primary { background: linear-gradient(180deg,var(--blue),var(--blue-d)); color: #fff; border: none; padding: 10px 14px; border-radius: 10px; font-size: 12px; font-weight: 800; box-shadow: 0 8px 24px rgba(37,99,235,0.18); cursor: pointer; }
.primary:hover { background: linear-gradient(180deg,var(--blue-d),var(--blue-text)); }
.hidden { display: none !important; }
.view-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: 4px; overflow: hidden; }
.view-toggle button { border: none; background: #fff; color: #374151; padding: 4px 10px; cursor: pointer; font-size: 10px; }
.view-toggle button:hover { background: var(--green-l); }
.view-toggle button.active { background: var(--green); color: #fff; }

/* Quote Template - matches Smart Steel Solutions xlsx format */
.quote-template { padding: 16px 120px; max-width: 100%; margin: 0 auto; }
.qt-header { display: flex; justify-content: space-between; align-items: flex-start; padding-bottom: 12px; border-bottom: 2px solid var(--green); margin-bottom: 16px; }
.qt-company-info { display: flex; flex-direction: column; gap: 3px; }
.qt-logo { font-size: 18px; font-weight: 700; color: var(--green); }
.qt-logo img { max-height: 48px; max-width: 208px; display: block; }
header h1 img#appLogoImg { max-height: 26px; max-width: 160px; display: block; }
.branding-upload { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.branding-preview { max-height: 38px; max-width: 144px; border: 1px solid var(--border); border-radius: 4px; padding: 2px; background: #fff; }
.branding-upload input[type="color"] { width: 32px; height: 24px; padding: 2px; border: 1px solid var(--border); border-radius: 4px; cursor: pointer; vertical-align: middle; }
.brand-swatch { width: 29px; height: 22px; border: 1px solid var(--border); border-radius: 4px; margin: 0 auto 2px; }
#paymentTermsPreview { background: #f3f4f6; border: 1px solid var(--border); border-radius: 4px; padding: 6px 8px; font-size: 10px; color: #374151; margin-top: 6px; }
.qt-company-details { display: flex; flex-wrap: wrap; gap: 6px; font-size: 9px; color: #6b7280; }
.qt-company-details span { background: #f3f4f6; padding: 2px 6px; border-radius: 3px; }
.qt-title { font-size: 22px; font-weight: 700; color: var(--green); letter-spacing: 2px; }
.qt-info-row { display: flex; gap: 32px; margin-bottom: 16px; }
.qt-left { flex: 1; background: #f9fafb; border: 1px solid var(--border); border-radius: 6px; padding: 10px; }
.qt-right { flex: 1; background: #f9fafb; border: 1px solid var(--border); border-radius: 6px; padding: 10px; }
.qt-label { font-size: 9px; font-weight: 700; text-transform: uppercase; color: #6b7280; margin-bottom: 6px; letter-spacing: 0.5px; }
.qt-left > div, .qt-right > div { margin-bottom: 6px; font-size: 10px; display: flex; align-items: center; justify-content: space-between; }
.qt-left > div:last-child, .qt-right > div:last-child { margin-bottom: 0; }
.qt-left > div > span:first-child, .qt-right > div > span:first-child { white-space: nowrap; margin-right: 8px; }
.qt-plain-row { flex: 1; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 22px; background: var(--green-l); border: 1px solid var(--border); border-radius: 6px; padding: 10px 13px; }
.qt-plain-row > div { font-size: 10px; display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.qt-plain-row > div > span:first-child { font-size: 9px; font-weight: 700; text-transform: uppercase; color: #6b7280; letter-spacing: 0.5px; white-space: nowrap; }
.qt-val { font-weight: 600; color: #1f2937; }
.qt-val.qt-num { color: var(--green); font-size: 13px; }
.qt-input { border: 1px solid var(--border); border-radius: 4px; padding: 3px 6px; font-size: 10px; font-family: inherit; background: #fff; transition: border-color .2s; }
.qt-input:focus { outline: none; border-color: var(--green); box-shadow: 0 0 0 2px rgba(33,115,70,.1); }
.contact-hover-wrap { position: relative; display: inline-block; cursor: pointer; border-bottom: 1px dotted #9ca3af; }
/* No margin between the name and the popup - a gap here is a dead zone
   the pointer has to cross that belongs to neither element, dropping
   :hover (and the popup) before a click on a row inside can ever land.
   The visual gap is padding-top instead, which IS part of this box, so
   hover/click never breaks while crossing it. */
.contact-tooltip { display: none; position: absolute; left: 0; top: 100%; padding-top: 6px; z-index: 50; }
.contact-tooltip-inner { background: #1f2937; color: #fff; border-radius: 6px; padding: 5px; font-size: 10px; white-space: nowrap; box-shadow: 0 4px 12px rgba(0,0,0,.25); }
/* Hover shows it for a quick glance; .open (toggled by clicking the name)
   pins it open regardless of mouse movement, so there's always a reliable
   way to reach the copy rows even if a hover path ever gets interrupted. */
.contact-hover-wrap:hover .contact-tooltip, .contact-hover-wrap.open .contact-tooltip { display: block; }
.contact-tooltip-row { display: flex; align-items: center; gap: 5px; padding: 3px 5px; border-radius: 4px; cursor: pointer; }
.contact-tooltip-row:hover { background: rgba(255,255,255,.12); }
.contact-tooltip-label { color: #9ca3af; }
.contact-tooltip-val { font-weight: 600; }
.contact-tooltip-empty { color: #9ca3af; font-weight: 400; font-style: italic; }
.qt-grid { margin-bottom: 12px; }
.qt-grid th { background: var(--green) !important; color: #fff !important; font-size: 10px; text-transform: uppercase; }
.qt-grid .col-desc { min-width: 280px; }
.qt-grid .col-num { width: 80px; }
.qt-grid .col-qty { width: 56px; }
.qt-grid .col-supplier { width: 80px; font-size: 8px; color: #6b7280; text-align: left; }
.qt-grid .col-total { width: 88px; text-align: right; }
.qt-totals { width: 272px; margin-left: auto; padding: 6px 10px; border: 1px solid var(--border); border-radius: 6px; }
.qt-totals table { width: 100%; border-collapse: collapse; }
.qt-totals td { padding: 3px 6px; font-size: 10px; border: none; }
.qt-totals .grand { font-size: 14px; font-weight: 700; border-top: 2px solid var(--green); padding-top: 6px; }
.qt-footer { display: flex; gap: 32px; margin-top: 20px; }
.qt-banking { flex: 1; border: 1px solid var(--border); border-radius: 6px; padding: 10px; }
.qt-terms { flex: 1; border: 1px solid var(--border); border-radius: 6px; padding: 10px; }
.qt-validity { margin-top: 12px; padding: 6px 10px; background: #fffbeb; border: 1px solid #fde68a; border-radius: 4px; font-size: 10px; color: #92400e; }

/* ===== Document Sections (Line Items / Labor / Consumables) ===== */
.doc-section { margin-bottom: 16px; border: 1px solid var(--border); border-radius: 6px; overflow: visible; position: relative; }
/* The section containing a focused input must rise above sections below it so the autocomplete dropdown is visible */
.doc-section:focus-within { z-index: 1000; }
.doc-section-header { display: flex; justify-content: space-between; align-items: center; padding: 6px 10px; background: var(--green-l); border-bottom: 1px solid var(--border); }
.doc-section-title { font-weight: 700; font-size: 10px; color: var(--green-d); text-transform: uppercase; letter-spacing: 0.5px; }
.doc-section-subtotal { font-weight: 600; font-size: 10px; color: var(--green-d); }
.doc-section.labour .doc-section-header { background: #dbeafe; border-bottom-color: #bfdbfe; }
.doc-section.labour .doc-section-title, .doc-section.labour .doc-section-subtotal { color: #1e40af; }
.doc-section.consumables .doc-section-header { background: #fef3c7; border-bottom-color: #fde68a; }
.doc-section.consumables .doc-section-title, .doc-section.consumables .doc-section-subtotal { color: #92400e; }
.doc-section.travel .doc-section-header { background: #e0f2fe; border-bottom-color: #bae6fd; }
.doc-section.travel .doc-section-title, .doc-section.travel .doc-section-subtotal { color: #075985; }
.doc-section.other .doc-section-header { background: #ede9fe; border-bottom-color: #ddd6fe; }
.doc-section.other .doc-section-title, .doc-section.other .doc-section-subtotal { color: #5b21b6; }
/* After Invoice Request: red accent (matching the same fixed colour the
   XLSX/PDF export gives this section's title bar) wrapped around its own
   material/labour/consumable/other mini-sections, so it reads as visually
   distinct from the invoice's original scope above it. */
.doc-section-group-air { margin: 6px 0 16px; padding: 10px; border: 1px solid var(--red-border); border-radius: var(--radius-md); background: var(--red-l2); }
.doc-section-group-air-title { font-weight: 700; font-size: 12px; color: var(--red-text); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px; }
.doc-section-group-air-hint { font-size: 11px; color: var(--red-text); margin-bottom: 10px; }
.doc-section-group-air .doc-section:last-child { margin-bottom: 0; }
.doc-section-footer { padding: 6px 10px; border-top: 1px solid var(--border); }
.doc-section .qt-grid { margin-bottom: 0; }
.doc-section .qt-grid th { position: relative !important; z-index: 1 !important; }
.doc-section .qt-grid td { position: relative; }
.doc-section .qt-grid .autocomplete { z-index: 99999 !important; position: absolute !important; }
.doc-section .qt-grid .col-desc { position: relative; overflow: visible; }
.doc-section .qt-grid .col-desc .autocomplete { top: 100%; left: 0; min-width: 304px; }

/* ===== Autocomplete dropdown (material line items) ===== */
.doc-section .qt-grid .col-desc .autocomplete { max-height: 224px; }
.ac-opt { padding: 6px 8px; font-size: 10px; cursor: pointer; line-height: 1.3; border-bottom: 1px solid #f3f4f6; text-align: left; }
.ac-opt:last-child { border-bottom: none; }
.ac-opt:hover { background: var(--green-l); }
.ac-opt .ac-sku { color: #6b7280; font-size: 8px; }
.ac-opt .ac-price { color: var(--green); font-weight: 700; float: right; }
/* Fixed two-column layout - cheapest always left, most expensive always
   right, same position every time regardless of which (if either) side has
   data, so the two are easy to scan/compare at a glance while still typing. */
.ac-opt .ac-supplier-prices { padding: 0; margin-top: 5px; display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.ac-price-col { min-width: 0; }
.ac-price-col-label { font-size: 7px; color: #9ca3af; text-transform: uppercase; letter-spacing: .03em; margin-bottom: 2px; }
.ac-price-tag { display: block; width: 100%; padding: 2px 5px; border-radius: 4px; font-size: 9px; border: 1px dashed var(--border); cursor: pointer; box-sizing: border-box; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ac-price-tag:hover { background: var(--green-l); }
.ac-price-tag b { display: block; font-size: 10px; }
.ac-price-tag.ac-cheapest { border-color: var(--green); color: var(--green); }
.ac-price-tag.ac-most-expensive { border-color: #b45309; color: #b45309; }
.ac-price-tag-empty { display: block; color: #bbb; font-size: 9px; padding: 2px 5px; }

/* ===== Bank Balances ===== */
.bank-accounts-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; padding: 0 13px 13px; }
.bank-account-card { margin: 0; }
.bank-account-card.bank-account-main { border: 1px solid #6366f1; }
.bank-account-card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.bank-account-balance { font-size: 21px; font-weight: 700; }
.badge-main { font-size: 8px; font-weight: 700; color: #fff; background: #6366f1; border-radius: 4px; padding: 2px 5px; vertical-align: middle; }

/* ===== Supplier comparison columns (material line items) ===== */
.qt-grid th.col-supplier { font-size: 8px; }
.col-supplier { font-size: 9px; text-align: left; }
.cheap-sup, .exp-sup { font-size: 9px; text-align: left; line-height: 1.35; white-space: normal; min-width: 88px; }
.cheap-sup b, .exp-sup b { display: block; font-weight: 700; font-size: 10px; }
.cheap-sup { color: #047857; }
.cheap-sup b { color: #059669; }
.exp-sup { color: #b91c1c; }
.exp-sup b { color: #dc2626; }

/* ===== Compare Mode (side-by-side quote options) ===== */
.compare-diff-banner { padding: 6px 13px; background: var(--green-l); border-bottom: 1px solid var(--border); font-size: 10px; color: var(--green-d); }
.compare-wrap { display: flex; gap: 13px; padding: 13px; align-items: flex-start; }
.compare-pane { flex: 1; min-width: 0; background: #fff; border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden; box-shadow: var(--shadow-sm); }
.compare-pane-header { padding: 6px 10px; background: var(--green-l); border-bottom: 1px solid var(--border); font-size: 10px; display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.compare-pane-toolbar { padding: 6px 10px; display: flex; gap: 5px; flex-wrap: wrap; border-bottom: 1px solid var(--border); }
.compare-pane-toolbar button { font-size: 10px; padding: 3px 6px; border: 1px solid var(--border); background: #fff; border-radius: 4px; cursor: pointer; }
.compare-pane-toolbar button.secondary { color: var(--green); }
.compare-pane-toolbar button.danger { background: #dc2626; color: #fff; border-color: #b91c1c; }
.compare-pane-toolbar button:not(.secondary):not(.danger) { background: var(--green); color: #fff; border-color: var(--green-d); }
.compare-pane .qt-grid { margin: 0 10px 10px; width: calc(100% - 24px); }
.compare-pane .qt-grid td, .compare-pane .qt-grid th { padding: 3px 5px; font-size: 10px; }
.compare-pane .qt-grid td { position: relative; }
.compare-pane .qt-grid .col-desc { position: relative; overflow: visible; min-width: 0; }
.compare-pane .qt-grid .col-desc .autocomplete { top: 100%; left: 0; min-width: 240px; max-height: 192px; z-index: 999; position: absolute; }
.compare-pane .qt-grid tr.selected td { background: var(--green-l); }
.compare-totals { margin: 0 10px 10px; width: auto; }
.compare-totals .num { text-align: right; }

/* ===== Payments Tab ===== */
.pay-summary { display: flex; gap: 10px; padding: 10px 13px; flex-wrap: wrap; }
.pay-card { flex: 1; min-width: 144px; background: #fff; border: 1px solid var(--border); border-radius: var(--radius-md); padding: 10px 13px; box-shadow: var(--shadow-sm); }
.pay-card-label { font-size: 9px; text-transform: uppercase; color: #6b7280; margin-bottom: 4px; }
.pay-card-value { font-size: 16px; font-weight: 700; color: #1f2937; }
.pay-overdue td { background: #fef2f2 !important; }
.pay-overdue:hover td { background: #fee2e2 !important; }
.pay-actions { white-space: nowrap; }
.pay-actions button { margin: 2px 2px; padding: 2px 6px; font-size: 9px; border: 1px solid var(--border); border-radius: 4px; cursor: pointer; }
.pay-actions .pay-view, .pay-actions .pay-history { background: #fff; color: var(--green); border-color: var(--green); }
.pay-actions .pay-view:hover, .pay-actions .pay-history:hover { background: var(--green-l); }
.pay-actions .pay-partial { background: #2563eb; color: #fff; border-color: #1d4ed8; }
.pay-actions .pay-partial:hover { background: #1d4ed8; }
.pay-actions .pay-full { background: #059669; color: #fff; border-color: #047857; }
.pay-actions .pay-full:hover { background: #047857; }
.pay-balance-display { font-size: 14px; font-weight: 700; color: #dc2626; padding: 5px 6px; background: #fef2f2; border: 1px solid #fecaca; border-radius: 4px; }
.pay-modal-info .form-row input, .pay-modal-info .form-row select, .pay-modal-info .form-row textarea { width: 100%; padding: 5px 6px; border: 1px solid var(--border); border-radius: 4px; font-size: 10px; }
.pay-preview { margin-top: 8px; }
.pay-history-list table { width: 100%; }
.pay-history-list tfoot td { border-top: 2px solid var(--green); padding: 6px; }

/* ===== Client Debt Banner & Outstanding Badges ===== */
.client-debt-banner {
  background: #fef2f2;
  border: 2px solid #fecaca;
  border-left: 4px solid #dc2626;
  border-radius: 6px;
  padding: 8px 13px;
  margin: 6px 13px 0;
  color: #7f1d1d;
  font-size: 10px;
  font-weight: 500;
  animation: pulse 2s infinite;
}
.client-debt-banner b { color: #dc2626; }
.client-debt-banner button { background: #fff; color: var(--green); border-color: var(--green); }
.client-debt-banner button:hover { background: var(--green-l); }
@keyframes pulse { 0%, 100% { border-color: #fecaca; } 50% { border-color: #fca5a5; } }

.pay-badge-owed {
  display: inline-block;
  padding: 2px 6px;
  border-radius: 10px;
  font-size: 9px;
  font-weight: 700;
  background: var(--red-l);
  color: var(--red-text);
  border: 1px solid var(--red-border);
}

/* Prominent Payments tab badge */
header .tabs button[data-view="payments"].has-outstanding {
  background: #dc2626 !important;
  color: #fff !important;
  border-color: #b91c1c !important;
  animation: tab-pulse 1.5s infinite;
}
header .tabs button[data-view="payments"].has-outstanding:hover {
  background: #b91c1c !important;
}
@keyframes tab-pulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(220,38,38,0.4); } 50% { box-shadow: 0 0 0 6px rgba(220,38,38,0); } }

/* ===== Settings Tab ===== */
.settings-wrap { max-width: 640px; margin: 0 auto; padding: 16px; }
.settings-section { background: #fff; border: 1px solid var(--border); border-radius: var(--radius-md); margin-bottom: 16px; overflow: hidden; box-shadow: var(--shadow-sm); }
.settings-section-header { background: var(--green-l); padding: 10px 13px; font-size: 11px; font-weight: 700; color: var(--green-d); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 6px; }
.settings-section-body { padding: 13px; }
/* Collapsible (closed by default, see showSettings()) - scoped to
   .settings-wrap specifically, not the bare .settings-section-header class,
   which the AI Quote Draft's "Suggested Suppliers" panel also reuses for
   matching style only, elsewhere, where it must stay a plain static header. */
.settings-wrap .settings-section-header { cursor: pointer; user-select: none; }
.settings-wrap .settings-section-header::after {
  content: '\25B8'; margin-left: auto; font-size: 12px; line-height: 1;
  transition: transform .2s ease; flex-shrink: 0;
}
.settings-wrap .settings-section.expanded > .settings-section-header::after { transform: rotate(90deg); }
.settings-section-body .form-row { margin-bottom: 12px; }
.settings-section-body .form-row label { display: block; font-size: 10px; color: #6b7280; margin-bottom: 4px; font-weight: 600; }
.settings-section-body .form-row input,
.settings-section-body .form-row select,
.settings-section-body .form-row textarea { width: 100%; padding: 6px 8px; border: 1px solid var(--border); border-radius: 4px; font-size: 10px; font-family: inherit; transition: border-color .2s, box-shadow .2s; }
.settings-section-body .form-row input:focus,
.settings-section-body .form-row select:focus,
.settings-section-body .form-row textarea:focus { outline: none; border-color: var(--green); box-shadow: 0 0 0 3px rgba(33,115,70,.12); }
.settings-section-body .form-row textarea { min-height: 48px; resize: vertical; }
.settings-save-bar { position: sticky; bottom: 0; background: #fff; border-top: 1px solid var(--border); padding: 10px 13px; display: flex; justify-content: flex-end; gap: 6px; }
.settings-save-bar button { background: var(--green); color: #fff; border: 1px solid var(--green-d); border-radius: 4px; padding: 6px 19px; font-size: 11px; font-weight: 600; cursor: pointer; transition: background .2s; }
.settings-save-bar button:hover { background: var(--green-d); }
.settings-layout { display: flex; gap: 16px; align-items: flex-start; padding: 16px; }
.settings-layout .settings-wrap { flex: 1 1 480px; max-width: 640px; margin: 0; padding: 0; min-width: 0; }
.settings-preview-pane { flex: 1 1 420px; min-width: 272px; position: sticky; top: 12px; }
.settings-preview-card { background: #fff; border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,.06); overflow: hidden; }
.settings-preview-card-header { background: var(--green-l); padding: 8px 11px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 8px; }
.settings-preview-card-header h3 { flex: 1; font-size: 10px; margin: 0; color: var(--green-d); }
.settings-preview-card-header select { font-size: 10px; padding: 3px 6px; border: 1px solid var(--border); border-radius: 4px; }
.settings-preview-body { padding: 11px; max-height: calc(100vh - 170px); overflow: auto; background: #f3f4f6; }
.settings-preview-body .quote-template { padding: 11px; max-width: 100%; font-size: 10px; background: #fff; box-shadow: 0 1px 4px rgba(0,0,0,.08); }
.settings-preview-body .qt-title { font-size: 16px; }
.settings-preview-body .qt-logo { font-size: 13px; }
.settings-preview-body .qt-grid th, .settings-preview-body .qt-grid td { font-size: 9px; padding: 3px 5px; }
.settings-preview-doc-image { width: 100%; display: block; margin-bottom: 10px; border-radius: 4px; }
.settings-preview-doc-image-placeholder { padding: 8px; text-align: center; color: #9ca3af; font-size: 9px; border: 1px dashed var(--border); border-radius: 4px; margin-bottom: 10px; background: #fff; }
@media (max-width: 1100px) {
  .settings-layout { flex-direction: column; }
  .settings-preview-pane { position: static; width: 100%; }
}
.settings-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.settings-grid .form-row { margin-bottom: 0; }
.checkbox-label { display: flex !important; align-items: center; gap: 6px; font-weight: 400 !important; color: #1f2937 !important; cursor: pointer; padding: 6px 8px; border: 1px solid var(--border); border-radius: 4px; background: #fff; }
.checkbox-label input[type="checkbox"] { width: 13px; height: 13px; accent-color: var(--green); cursor: pointer; }
@media (max-width: 600px) { .settings-grid { grid-template-columns: 1fr; } }

/* ===== Payroll ===== */
.payroll-employee-badge { display: inline-block; padding: 2px 6px; border-radius: 10px; font-size: 9px; font-weight: 700; background: var(--blue-l); color: var(--blue-text); border: 1px solid var(--blue-border); }
.payroll-entry-source { font-size: 9px; color: #6b7280; }
.payroll-entry-source.document { color: #059669; }
.payroll-entry-source.custom { color: #2563eb; }
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; padding: 10px 13px; }
.stat-card { background: #fff; border: 1px solid var(--border); border-radius: var(--radius-md); padding: 10px 13px; box-shadow: var(--shadow-sm); }
.stat-label { font-size: 9px; text-transform: uppercase; color: #6b7280; margin-bottom: 4px; }
.stat-value { font-size: 16px; font-weight: 700; color: #1f2937; }
.stat-value.red, .emp-bal.red, .emp-status.red, .bank-account-balance.red { color: #dc2626; }
.stat-value.green, .emp-bal.green, .emp-status.green, .bank-account-balance.green { color: #059669; }
/* Quotes/Invoices pages' merged Current/This Month/All Time cards - one
   metric per card, all forced into a single row (not left to wrap into an
   unbalanced split, e.g. 4-then-1) via an inline grid-template-columns set
   by the JS to match that page's actual card count (5 for Quotes, 4 for
   Invoices - a fixed CSS column count here would leave a gap on whichever
   page doesn't match it). Each card's scopes stack as their own line
   (label left, value right) rather than cramming side-by-side mini-columns
   into one card. */
.stat-multi-col { margin-top: 6px; }
.stat-multi-item { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; padding: 3px 0; border-top: 1px solid #f3f4f6; }
.stat-multi-item:first-child { border-top: none; }
.stat-multi-tag { font-size: 9px; text-transform: uppercase; color: #9ca3af; letter-spacing: .03em; white-space: nowrap; }
.stat-multi-val { font-size: 14px; font-weight: 700; color: #1f2937; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stat-multi-val.red { color: #dc2626; }
/* Dashboard > Financial Health Index */
.health-score-row { display: flex; gap: 20px; align-items: center; padding: 10px 13px; flex-wrap: wrap; }
.health-score-circle { width: 68px; height: 68px; border-radius: 50%; border: 4px solid; display: flex; align-items: center; justify-content: center; font-size: 22px; font-weight: 700; flex-shrink: 0; }
.health-score-detail { min-width: 0; }
.health-grade { font-size: 15px; font-weight: 700; margin-bottom: 6px; }
.health-factors { display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: 11px; color: #6b7280; }
.health-factor-score { font-weight: 700; color: #374151; }
.health-recommendations-wrap { padding: 0 13px 13px; font-size: 12px; }
.health-recommendations { margin: 6px 0 0; padding-left: 18px; color: #374151; }
.health-recommendations li { margin-bottom: 4px; }
.stat-group-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: #9ca3af; }
/* Filters row sits directly below the action-buttons .toolbar, in its own
   slightly muted bar - a visual break between "do something" (New/Refresh/
   Merge) and "narrow the list" (status/sort/search) instead of both mixed
   into one crowded line. */
.toolbar.filter-bar { background: #fafafa; }

.cycle-toggle { display: inline-flex; gap: 3px; padding: 3px; background: var(--hdr); border-radius: 8px; }
.cycle-toggle button { border: none; border-radius: 6px; background: transparent; }
.cycle-toggle button.active { background: var(--green); color: #fff; border-color: var(--green-d); box-shadow: 0 1px 3px rgba(0,0,0,.15); }
.pricing-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; padding: 4px 13px 13px; align-items: stretch; }
/* .panel's own padding (13px) is overridden here with more generous
   spacing, and a real card look (background/border/radius/shadow) added -
   previously a plain tier had NONE of those, only the current plan got a
   border, so every other card had no visual definition against the page
   background at all. */
.pricing-card {
  display: flex; flex-direction: column; position: relative;
  background: #fff; border: 1px solid var(--border); border-radius: 12px;
  padding: 22px 20px; box-shadow: 0 1px 3px rgba(0,0,0,.05);
  transition: box-shadow .15s ease, transform .15s ease;
}
.pricing-card:hover { box-shadow: 0 6px 20px rgba(0,0,0,.08); transform: translateY(-2px); }
.pricing-card h3 { font-size: 15px; margin-bottom: 2px; }
.pricing-card.pricing-current { border: 2px solid var(--green); box-shadow: 0 6px 20px rgba(33,115,70,.12); }
.pricing-card.pricing-current::before {
  content: 'Current Plan'; position: absolute; top: -11px; left: 20px;
  background: var(--green); color: #fff; font-size: 9px; font-weight: 700;
  letter-spacing: .03em; text-transform: uppercase; padding: 3px 10px; border-radius: 999px;
}
.pricing-price { font-size: 26px; font-weight: 700; margin: 6px 0 14px; color: var(--green-d); }
.pricing-features { list-style: none; padding: 0; margin: 0 0 18px; flex: 1; font-size: 11px; color: #374151; }
.pricing-features li { padding: 6px 0; border-bottom: 1px solid var(--border); padding-left: 20px; position: relative; }
.pricing-features li::before { content: '✓'; position: absolute; left: 0; color: var(--green); font-weight: 700; }
.pricing-features li:last-child { border-bottom: none; }
/* The actual call-to-action button on each card had NO styling at all
   before this (not inside .toolbar/.doc-actions-panel-body/table.data td,
   the only selectors that gave a button this app's real look) - it
   rendered as a bare, unstyled native browser button. */
.choose-plan-btn {
  width: 100%; padding: 11px 16px; font-size: 12px; font-weight: 700;
  background: var(--green); color: #fff; border: 1px solid var(--green-d);
  border-radius: 8px; cursor: pointer; transition: background .12s ease, box-shadow .12s ease;
}
.choose-plan-btn:hover { background: var(--green-d); box-shadow: 0 2px 8px rgba(33,115,70,.25); }
.pricing-card button:disabled, .pricing-card button:disabled:hover {
  cursor: not-allowed; opacity: .5; background: #fff; color: #9ca3af; border-color: var(--border); box-shadow: none;
}
.dash-alert { margin: 0 13px 13px; padding: 8px 11px; background: #fef2f2; border: 1px solid #fecaca; color: #b91c1c; border-radius: 6px; cursor: pointer; font-weight: 600; }
.dash-alert:hover { background: #fee2e2; }
.dash-client-row { cursor: pointer; }
.dash-client-row:hover td { background: var(--green-l); }
.dash-chart-row { display: flex; gap: 13px; padding: 3px 13px 13px; flex-wrap: wrap; }
/* Explicit height (not left to Chart.js's default aspect-ratio-from-width
   sizing) so these stay readable at any width - paired with
   maintainAspectRatio:false on these specific charts in renderDashboard. */
.dash-chart-col { flex: 2 1 320px; min-width: 224px; position: relative; height: 260px; }
.dash-chart-col-small { flex: 1 1 220px; max-width: 256px; position: relative; height: 260px; }
/* Reports tab's own charts (reportChart1/2) - identical reasoning: an
   explicit height so App.tuneChart's maintainAspectRatio:false actually
   keeps these readable instead of shrinking to match a narrow phone's
   width. */
.report-chart-panel { position: relative; height: 260px; }
.dash-panel-toggle { cursor: pointer; user-select: none; display: flex; align-items: center; gap: 6px; }
.dash-panel-arrow { font-size: 9px; color: #6b7280; display: inline-block; transition: transform .15s; }
.dash-panel-toggle.collapsed .dash-panel-arrow { transform: rotate(-90deg); }
.dash-panel-toggle.collapsed { margin-bottom: 0; }
/* ---------- Dashboard: Next Step widget ---------- */
/* Stepper: connected circular badges (mockup style), horizontally
   scrollable instead of wrapping since the stage count is dynamic
   (3-10 depending on what's actually stuck) and a wrapped multi-row
   pill grid loses the "connected steps" read the mockup had. */
.next-step-stepper { display: flex; gap: 18px; overflow-x: auto; padding: 4px 2px 14px; margin-bottom: 2px; -webkit-overflow-scrolling: touch; }
.next-step-stage { display: flex; flex-direction: column; align-items: center; gap: 6px; flex: 0 0 auto; width: 78px; cursor: pointer; user-select: none; position: relative; }
.next-step-stage:not(:last-child)::after { content: ''; position: absolute; top: 18px; left: calc(50% + 19px); width: calc(100% - 19px); height: 2px; background: var(--border); z-index: 0; }
.next-step-stage-circle { position: relative; width: 38px; height: 38px; border-radius: 50%; background: #fff; border: 2px solid var(--border); display: flex; align-items: center; justify-content: center; color: #9ca3af; z-index: 1; }
.next-step-stage:hover .next-step-stage-circle { border-color: var(--green); color: var(--green-d); }
.next-step-stage.active .next-step-stage-circle { background: var(--green); border-color: var(--green-d); color: #fff; box-shadow: 0 0 0 4px var(--green-l); }
.next-step-stage-count { position: absolute; top: -6px; right: -6px; background: var(--red); color: #fff; font-size: 9px; font-weight: 700; border-radius: 999px; min-width: 16px; height: 16px; padding: 0 3px; display: flex; align-items: center; justify-content: center; border: 2px solid #fff; }
.next-step-stage-label { font-size: 10.5px; font-weight: 600; color: #6b7280; text-align: center; line-height: 1.25; }
.next-step-stage.active .next-step-stage-label { color: var(--green-d); }
/* Housekeeping's stepper button reads as a different, lower-key category
   (FYI, not "stuck work") - dashed grey ring instead of solid, grey count
   bubble instead of red-alert, grey (not green) fill when active. */
.next-step-stage-housekeeping .next-step-stage-circle { border-style: dashed; }
.next-step-stage-housekeeping .next-step-stage-count { background: #9ca3af; }
.next-step-stage-housekeeping.active .next-step-stage-circle { background: #6b7280; border-color: #4b5563; border-style: solid; color: #fff; box-shadow: 0 0 0 4px #eee; }
.next-step-stage-housekeeping.active .next-step-stage-label { color: #4b5563; }
.next-step-list { display: flex; flex-direction: column; gap: 6px; }
.next-step-row { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border: 1px solid var(--border); border-radius: var(--radius-md); cursor: pointer; background: #fff; }
.next-step-row:hover { border-color: var(--green); box-shadow: 0 1px 3px rgba(0,0,0,.08); }
.next-step-row-badge { flex-shrink: 0; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
.next-step-row-body { flex: 1; min-width: 0; }
.next-step-row-title { font-size: 13px; font-weight: 600; color: #1f2937; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.next-step-row-sub { font-size: 11px; color: #6b7280; margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Per-stage urgency colour, shared by the row's icon badge and its
   action button (and mirrored on the matching stepper circle when
   active) so the same job always reads the same colour everywhere. */
.next-step-badge-blue { background: var(--blue-l); color: var(--blue-text); }
.next-step-badge-purple { background: var(--purple-l); color: var(--purple-d); }
.next-step-badge-amber { background: var(--amber-l); color: var(--amber-d); }
.next-step-badge-green { background: var(--green-l); color: var(--green-d); }
.next-step-badge-red { background: var(--red-l); color: var(--red-text); }
.next-step-row-btn { flex-shrink: 0; white-space: nowrap; color: #fff; border: 1px solid transparent; border-radius: 999px; padding: 5px 13px; font-size: 11px; font-weight: 700; cursor: pointer; }
.next-step-row-btn:hover { opacity: .88; }
.next-step-btn-blue { background: var(--blue); border-color: var(--blue-d); }
.next-step-btn-purple { background: var(--purple); border-color: var(--purple-d); }
.next-step-btn-amber { background: var(--amber); border-color: var(--amber-d); }
.next-step-btn-green { background: var(--green); border-color: var(--green-d); }
.next-step-btn-red { background: var(--red); border-color: var(--red-d); }
/* Housekeeping: visually secondary - smaller, muted grey regardless of
   the row's own colour key. Hidden by default via an INLINE style from
   nextStepRowHtml (not a display:none here) - jQuery's show()/hide() only
   restores the stylesheet's own display:flex when the element's own
   style.display was literally "none"; a CSS-class display:none instead
   makes jQuery fall back to the tag's generic default ("block"), which
   would silently break this row's flex layout the first time the "Also
   worth a look" button reveals it. It only ever becomes visible when that
   stepper button is active (bindNextStepsPanel toggles it like any other
   stage filter) - previously this was an always-visible block under every
   process row, which just meant a lot of scrolling to get past it. */
.next-step-row-housekeeping { padding: 7px 10px; background: #fafafa; }
.next-step-row-housekeeping .next-step-row-title { font-size: 12px; font-weight: 500; color: #4b5563; }
.next-step-row-housekeeping .next-step-row-badge { background: #ececec; color: #9ca3af; width: 28px; height: 28px; }
.next-step-row-housekeeping .next-step-row-btn { background: #9ca3af; border-color: #6b7280; font-size: 10px; padding: 4px 11px; }
.emp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 10px; padding: 3px; }
.emp-card { border: 1px solid var(--border); border-radius: var(--radius-md); padding: 10px 11px; background: #fff; box-shadow: var(--shadow-sm); }
.emp-name { font-weight: 700; font-size: 11px; }
.emp-bal { font-size: 14px; font-weight: 700; margin: 5px 0 2px; }
.emp-status { font-size: 8px; font-weight: 800; letter-spacing: 0.5px; }
.emp-meta { font-size: 9px; color: #6b7280; margin: 5px 0; }
.emp-actions button { font-size: 9px; padding: 2px 6px; border: 1px solid var(--border); border-radius: 4px; cursor: pointer; margin: 2px 2px 0 0; }
.payroll-source { display: inline-block; padding: 2px 6px; border-radius: 10px; font-size: 9px; font-weight: 700; }
.payroll-source.document { background: var(--emerald-l); color: var(--emerald-d); border: 1px solid var(--emerald-l2); }
.payroll-source.custom { background: var(--blue-l); color: var(--blue-text); border: 1px solid var(--blue-border); }
.payroll-source.advance { background: var(--red-l); color: var(--red-text); border: 1px solid var(--red-border); }
.payroll-status { display: inline-block; padding: 2px 6px; border-radius: 10px; font-size: 9px; font-weight: 700; }
.payroll-status.paid { background: var(--emerald-l); color: var(--emerald-d); border: 1px solid var(--emerald-l2); }
.payroll-status.partial { background: var(--amber-l); color: var(--amber-d); border: 1px solid var(--amber-border); }
.payroll-status.outstanding { background: var(--red-l); color: var(--red-text); border: 1px solid var(--red-border); }
.payroll-red-tag { display: inline-block; padding: 1px 5px; border-radius: 8px; font-size: 7px; font-weight: 800; background: var(--red); color: #fff; vertical-align: middle; }
.pay-partial, .pay-full { font-size: 9px; padding: 2px 6px; border-radius: 4px; border: 1px solid; cursor: pointer; margin: 2px; }
.pay-partial { background: #2563eb; color: #fff; border-color: #1d4ed8; }
.pay-partial:hover { background: #1d4ed8; }
.pay-full { background: #059669; color: #fff; border-color: #047857; }
.pay-full:hover { background: #047857; }
.pay-history-row td { background: #f9fafb; }


/* ===== Loader ===== */
.app-loader { position: fixed; inset: 0; background: rgba(255,255,255,.85); display: none; align-items: center; justify-content: center; flex-direction: column; gap: 13px; z-index: 10000; }
.app-loader.show { display: flex; }
.app-loader-spinner { width: 38px; height: 38px; border: 4px solid var(--green-l); border-top-color: var(--green); border-radius: 50%; animation: app-spin 0.8s linear infinite; }
.app-loader-msg { font-size: 11px; color: var(--green-d); font-weight: 600; }
@keyframes app-spin { to { transform: rotate(360deg); } }

/* ===== Payments Filters ===== */
.pay-filters { display: flex; gap: 6px; padding: 6px 13px; flex-wrap: wrap; align-items: center; background: #fff; border-bottom: 1px solid var(--border); }
.pay-filters label { font-size: 9px; color: #6b7280; font-weight: 600; }
.pay-filters select, .pay-filters input { font-size: 10px; padding: 3px 6px; border: 1px solid var(--border); border-radius: 4px; background: #fff; }
.pay-filters .pay-date-presets { display: flex; gap: 3px; flex-wrap: wrap; }
.pay-filters .pay-date-presets button { font-size: 9px; padding: 2px 6px; border: 1px solid var(--border); border-radius: 4px; background: #fff; color: var(--green); cursor: pointer; }
.pay-filters .pay-date-presets button.active { background: var(--green); color: #fff; border-color: var(--green-d); }
.pay-filters .pay-date-presets button:hover { background: var(--green-l); }
.pay-filters .pay-date-presets button.active:hover { background: var(--green-d); }

/* ===== Mobile Responsive Shell =====
   Everything below is additive - it only activates under the breakpoint
   and never changes the desktop (>860px) appearance of anything above. */
@media (max-width: 860px) {
  .sidebar-toggle-btn { display: flex; }
  .nav-toggle-btn { display: inline-block; }

  /* Any .stat-grid given an inline grid-template-columns to force N equal
     columns in one desktop row (Reports/Dashboard/Finances/person-stats
     cards) reverts back to auto-fit here instead of literally squeezing N
     columns into a phone screen - !important since it's overriding an
     inline style, same reason .merged-stat-grid below needs it too (which,
     styling denser multi-row cards, keeps its own stronger 1-column-only
     override - declared further down, so it still wins for its own
     elements despite equal selector specificity). */
  .stat-grid { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)) !important; }

  /* Dashboard > Financial Health Index: the factor list's desktop
     flex-wrap ("Profit Margin 25/25  Net Profit 25/25" then a ragged
     second/third row) reads fine at desktop widths but wraps unevenly at
     phone width, splitting label/score pairs into an inconsistent 1-2
     column mess. One factor per line instead (label left, score right),
     same list pattern used everywhere else in this pass. The score
     circle stacks above its own detail instead of trying to share a row
     with it once there's no room to sit side by side. */
  .health-score-row { flex-direction: column; align-items: flex-start; gap: 10px; }
  .health-factors { flex-direction: column; gap: 4px; }
  .health-factor { display: flex; justify-content: space-between; gap: 8px; }

  /* Dashboard > Next Step: the stepper already scrolls horizontally
     (same on desktop) so it just needs its circles to shrink a touch;
     rows go from icon+title+sub+button in one line to title/sub
     wrapping onto their own line since there's no room for four items
     side by side at phone width. */
  .next-step-stage { width: 62px; gap: 4px; }
  .next-step-stage:not(:last-child)::after { top: 15px; left: calc(50% + 16px); }
  .next-step-stage-circle { width: 32px; height: 32px; }
  .next-step-stage-label { font-size: 9.5px; }
  .next-step-row { flex-wrap: wrap; }
  .next-step-row-title, .next-step-row-sub { white-space: normal; }
  .next-step-row-btn { font-size: 10px; padding: 4px 11px; margin-left: 42px; }

  /* Sidebar becomes an off-canvas panel, hidden by default and slid in
     over the content (not pushed alongside it) so .main can use the full
     viewport width without any layout jump when toggled. */
  .layout { overflow: hidden; }
  .sidebar {
    position: fixed; top: 44px; left: 0; bottom: 0; z-index: 80;
    width: 82vw; max-width: 300px;
    transform: translateX(-100%);
    transition: transform .22s ease;
    box-shadow: 2px 0 12px rgba(0,0,0,.15);
  }
  .layout.sidebar-open .sidebar { transform: translateX(0); }
  .sidebar-backdrop {
    display: block; position: fixed; top: 44px; left: 0; right: 0; bottom: 0;
    background: rgba(0,0,0,.4); z-index: 70;
    opacity: 0; pointer-events: none; transition: opacity .22s ease;
  }
  .layout.sidebar-open .sidebar-backdrop { opacity: 1; pointer-events: auto; }
  .main { width: 100%; }

  /* Main nav (.tabs) becomes a right-hand off-canvas panel, same slide
     mechanic as the folders sidebar above but mirrored to the right edge
     and triggered by its own burger/backdrop/close-X (#navToggleBtn/
     #navBackdrop/#navPanelCloseBtn) so the two panels never fight each
     other. Nav items stack vertically instead of the desktop's inline row. */
  header .tabs {
    position: fixed; top: 44px; right: 0; bottom: 0; z-index: 85;
    width: 82vw; max-width: min(300px, 92vw);
    background: var(--green);
    flex-direction: column; align-items: stretch; justify-content: flex-start;
    flex-wrap: nowrap; gap: 2px; margin-left: 0;
    padding: 10px; overflow-y: auto; -webkit-overflow-scrolling: touch;
    transform: translateX(100%);
    transition: transform .22s ease;
    box-shadow: -2px 0 12px rgba(0,0,0,.15);
  }
  body.nav-open header .tabs { transform: translateX(0); }
  .nav-backdrop {
    display: block; position: fixed; top: 44px; left: 0; right: 0; bottom: 0;
    background: rgba(0,0,0,.4); z-index: 75;
    opacity: 0; pointer-events: none; transition: opacity .22s ease;
  }
  body.nav-open .nav-backdrop { opacity: 1; pointer-events: auto; }
  .nav-panel-close {
    display: block; align-self: flex-end; background: rgba(255,255,255,.15);
    color: #fff; border: none; border-radius: 4px; width: 32px; height: 32px;
    font-size: 20px; line-height: 1; cursor: pointer; margin-bottom: 6px;
  }
  .nav-panel-close:hover { background: rgba(255,255,255,.28); }
  header .tabs button, header .tabs .nav-logout-btn { width: 100%; text-align: left; font-size: 14px; padding: 10px 12px; min-width: 0; border-radius: 4px; }
  header .tabs .nav-logout-btn { margin-top: 8px; border-top: 1px solid rgba(255,255,255,.2); padding-top: 14px; }

  /* Support/Feedback: the fixed bottom-left .fs-widget sat on top of page
     content on a phone with nowhere to move it out of the way - swapped
     here for the nav-panel copy instead, pinned to the bottom of the
     (flex-column) off-canvas list via margin-top:auto so it reads as the
     last item, closest to the bottom of the window, not floating over the
     page underneath. */
  .fs-widget { display: none; }
  .nav-fs-actions {
    display: flex; flex-direction: column; gap: 2px;
    margin-top: auto; padding-top: 10px;
    border-top: 1px solid rgba(255,255,255,.2);
  }
  .nav-fs-actions .fs-btn {
    background: transparent; color: #fff; border: none; box-shadow: none;
    border-radius: 4px; width: 100%; text-align: left; font-size: 14px; padding: 10px 12px;
    display: flex; align-items: center; gap: 8px;
  }
  .nav-fs-actions .fs-btn:hover { background: rgba(255,255,255,.12); }
  header .tabs .nav-settings-btn { margin-left: 0; }
  /* Sub-menus (Quotes/Invoices, Contacts, Finances) expand inline in the
     vertical stack (accordion-style) instead of floating as an absolutely-
     positioned overlay - a floating dropdown makes no sense inside an
     already-narrow off-canvas panel. */
  header .tabs .nav-dropdown-menu {
    position: static; margin-top: 0; margin-left: 14px; box-shadow: none;
    background: rgba(0,0,0,.15); border: none;
  }
  header .tabs .nav-dropdown-menu button { color: #fff; }
  header .tabs .nav-dropdown-menu button:hover,
  header .tabs .nav-dropdown-menu button.active { background: rgba(255,255,255,.18); color: #fff; }

  /* Tables: default to SHRINKING/WRAPPING to actually fit the phone screen,
     not a forced-wide table you have to scroll sideways to read - that
     forced-640px approach (this rule's previous version) was the bug: it
     made even a plain 2-column table (e.g. the Contacts Overview "Top 5"
     list) wider than the viewport for no real reason. Applies site-wide to
     every plain list/data table (documents list, contacts, payments,
     payroll, prices, dashboard tables, etc.) without needing to touch each
     app.js render function individually.
     The ONE deliberate exception is the quote/invoice line-item editor
     grid (.grid/.qt-grid) - real <input> controls per cell (qty/price/
     description), not just text, genuinely can't reflow into a phone
     width without a much larger editor redesign, so it keeps real
     horizontal scrolling instead. */
  .content .panel, .content > table.data, .doc-section { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .content .panel table.data, .content .panel table.grid { font-size: 9px; }
  .content .panel table.data th, .content .panel table.data td {
    padding: 4px 5px; white-space: normal; word-break: break-word;
  }
  .content .panel table.grid, .doc-section .qt-grid { min-width: 560px; }

  /* Quotes/Invoices list: only the essentials stay in the table row
     (Number, Client, Total, Outstanding, Status) - Contact Person, Project,
     Issue Date and Approval move into the row's already-existing slide-over
     panel instead (see the detail rows built in showDocuments's row-click
     handler), and the status cell's secondary badges (Pro Forma sent,
     Materials, Project Completed, Service Fee, Follow-up nudge) move there
     too rather than stacking up inside an already-cramped cell. */
  .doc-list-table .col-doc-extra, .doc-list-table .doc-status-extra { display: none; }
  /* The status <select> has no CSS width at all normally - a browser sizes
     a native select to fit its WIDEST option text (e.g. "Partially_paid"),
     which was dominating the row and squeezing Number/Client/Total/
     Outstanding into whatever was left. Pinned to a small fixed width
     instead (the badge coloring/font still make the current status clear
     even clipped) so those columns actually get the room they need. */
  .doc-list-table select.doc-status-select { width: 62px; max-width: 62px; font-size: 8px; padding: 3px 2px; }

  /* Clients/Suppliers/Employees lists: same idea - only Name stays in the
     row, everything else (Contact Person/Email/Phone/Tax#/Specialization/
     ID Number) moves into the row-click panel (see the detail rows built
     in showContacts/showEmployees) - action buttons live in that panel
     only already, never inline in the row on any screen size. */
  .contact-list-table .col-contact-extra { display: none; }

  /* Payroll's Employees/Transactions tables - same idea again (see the
     detail rows built in showPayroll's row-click handlers). */
  .emp-table .col-payroll-extra, .payroll-txn-table .col-payroll-extra { display: none; }

  /* Expenses, Bookkeeping's ledger, Prices, and Suppliers Payable - same
     idea again (see the detail rows built in each view's own row-click
     handler in app.js). */
  .expenses-table .col-expense-extra, .expense-invoices-table .col-expense-extra { display: none; }
  .ledger-table .col-ledger-extra { display: none; }
  .price-list-table .col-price-extra { display: none; }
  .supplier-payable-table .col-payable-extra { display: none; }

  /* Schedule: the 272px-wide side panel sitting BESIDE the 7-column
     calendar was squeezing that grid down to a sliver on a phone (~15px
     per day cell, showing nothing) - stack the side panel below instead,
     full width, and give it back a normal static position (sticky/top:16px
     only made sense next to the grid, not above/below it). Cells shrink a
     bit further too so a full week fits without their own overflow. */
  .schedule-layout { flex-direction: column; }
  .schedule-side-panel { width: 100%; position: static; top: auto; }
  .schedule-cell { height: 58px; padding: 2px; }
  .schedule-grid.schedule-grid-week .schedule-cell { height: 140px; }
  .schedule-daynum { font-size: 9px; margin-bottom: 1px; }
  .schedule-entry { font-size: 8px; padding: 1px 2px; }
  .schedule-dow { padding: 3px; font-size: 8px; }

  /* Quotes/Invoices merged stat-card grid: each card holds several
     side-by-side values (Current/This Month/All Time) instead of 1 - the
     desktop inline column count (set by the JS, one column per card) left
     no room for that on a phone (values truncated, columns pushed
     off-screen), so this overrides back to full-width, 1 card per row,
     same as the shared .stat-grid default. Scoped to this one grid, not
     the shared .stat-grid rule itself, so every other page's stat cards
     keep their own layout untouched. !important because the desktop
     column count above is an inline style, which otherwise wins over a
     plain class rule regardless of media query. */
  .merged-stat-grid { grid-template-columns: 1fr !important; }

  /* Toolbars (New/Refresh/filters/search, above every list view) stack as
     full-width rows instead of wrapping into a ragged, unevenly-indented
     mess - several of these carry an inline margin-left meant only for a
     single-line desktop layout, hence !important to actually override that
     on a phone. */
  .toolbar { flex-direction: column; align-items: stretch; }
  .toolbar > * { margin-left: 0 !important; width: 100% !important; box-sizing: border-box; }
  .toolbar .spacer { display: none; }

  /* Schedule's Prev/Month+Year/Next: wrapped in their own row (a single
     .toolbar child) specifically so they're exempt from the ".toolbar > *"
     full-width stacking above and can stay side by side, with Today/view
     toggle/filters still stacking normally below them. */
  .sched-nav-row { display: flex; flex-direction: row; align-items: center; justify-content: center; gap: 8px; }
  .sched-nav-row button { width: auto; flex: 0 0 auto; }

  /* Dashboard charts: Chart.js's default aspect-ratio sizing shrinks the
     height right along with the width on a narrow phone, to the point of
     being unreadable - these get an explicit, generous height instead (see
     the matching maintainAspectRatio:false added in renderDashboard) and
     each takes the FULL row width (never side-by-side, and never a narrow
     box left-aligned with empty space beside it - the doughnut chart's
     previous complaint on mobile). */
  .dash-chart-row { flex-direction: column; }
  .dash-chart-col, .dash-chart-col-small {
    flex-basis: 100%; width: 100%; max-width: 100%; min-width: 0;
    height: 300px;
  }
  .report-chart-panel { height: 300px; }

  /* Comfortable tap targets - only bumped where the desktop sizing (built
     for a mouse) would otherwise be too small/cramped to tap reliably. */
  .toolbar button, .toolbar select, .toolbar input,
  .pay-actions button, .emp-actions button, .schedule-day-item-buttons button,
  .view-toggle button, .cycle-toggle button { min-height: 36px; }
  .row-drag-handle, .col-action, td.col-action { min-width: 30px; }

  /* iOS Safari zooms the page on focusing any input under 16px - this
     keeps the visual size the same elsewhere while avoiding that. */
  input, select, textarea { font-size: 16px; }
  table.grid input, table.grid select { font-size: 13px; } /* dense grids stay compact; not prone to the zoom issue since they're not the primary mobile entry point yet */

  /* Modal: max-width already prevents overflow, but min-width alone could
     still exceed a narrow phone's viewport - cap it relative to the
     viewport instead of a fixed pixel floor. */
  .modal { min-width: min(400px, 92vw); width: 92vw; padding: 16px; }
  .modal .actions { flex-wrap: wrap; }

  .quote-template { padding: 16px; }
  .qt-info-row, .qt-footer { flex-direction: column; gap: 12px; }
  .totals, .qt-totals { width: 100%; }
}

/* TomSelect (client/description-autocomplete dropdowns) - the bundled
   tom-select.bootstrap5.css theme styles these off Bootstrap CSS variables
   (--bs-body-bg etc.) that don't exist here since this app doesn't load
   Bootstrap itself, so those backgrounds silently resolved to transparent -
   the "translucent dropdown" look. Explicit solid overrides using this
   app's own colors instead of relying on those undefined variables. */
.ts-control, .ts-wrapper.single .ts-control, .ts-wrapper.single.input-active .ts-control {
  background: #fff;
  border-color: var(--border);
}
.ts-wrapper.focus .ts-control { border-color: var(--green); box-shadow: 0 0 0 2px rgba(33,115,70,.1); }
.ts-dropdown, .ts-dropdown .ts-dropdown-content, .ts-dropdown-content {
  background: #fff;
}
.ts-dropdown {
  border-color: var(--border);
  box-shadow: 0 4px 12px rgba(0,0,0,.08);
}
.ts-dropdown .option { background: #fff; color: #1f2937; }
.ts-dropdown .option.active { background: var(--green-l); color: var(--green-d); }
.ts-dropdown .optgroup-header { background: var(--hdr); }
