/* Apple-inspired design language: system font stack (SF Pro on Apple
   devices, Segoe UI Variable on Windows), neutral #f5f5f7 canvas,
   near-black text, hairline borders, pill buttons, one blue accent. */

:root {
  /* ---- brand + primary actions ---- */
  --accent: #2563eb;                    /* primary blue */
  --accent-hover: #1d4ed8;
  --accent-soft: rgba(37, 99, 235, 0.10);
  --accent-ring: rgba(37, 99, 235, 0.18);
  --gold: #c8a165;                      /* Meiyi brand gold, kept for the logo */

  /* ---- surfaces ---- */
  --bg: #f6f7f9;                        /* app canvas */
  --card-bg: #ffffff;
  --surface-2: #fafbfc;                 /* table headers, inset panels */
  --border: #e5e8ed;                    /* hairline */
  --border-strong: #d6dae1;
  --border-faint: rgba(15, 23, 41, 0.06);

  /* ---- type ---- */
  --text: #0f1729;                      /* headings / primary */
  --text-2: #344054;                    /* body */
  --muted: #667085;                     /* secondary */
  --muted-2: #98a2b3;                   /* tertiary / placeholders */

  /* ---- status ---- */
  --danger: #d92d20;
  --danger-soft: rgba(217, 45, 32, 0.10);
  --success: #099250;
  --success-soft: rgba(9, 146, 80, 0.10);
  --warn: #b54708;
  --warn-soft: rgba(181, 71, 8, 0.10);

  /* ---- sidebar (dark) ---- */
  --sidebar-bg: #111725;
  --sidebar-bg-2: #171e2e;
  --sidebar-text: rgba(255, 255, 255, 0.72);
  --sidebar-text-strong: #ffffff;
  --sidebar-border: rgba(255, 255, 255, 0.08);
  --sidebar-w: 250px;

  /* the dark chrome token is still referenced by older rules (dropdowns,
     overlays) - keep it pointing at the sidebar tone so they stay coherent */
  --chrome: rgba(17, 23, 37, 0.92);

  /* ---- shape + depth ---- */
  --r-sm: 8px;
  --r: 12px;
  --r-lg: 16px;
  --shadow-xs: 0 1px 2px rgba(16, 24, 40, 0.05);
  --shadow-sm: 0 1px 3px rgba(16, 24, 40, 0.08), 0 1px 2px rgba(16, 24, 40, 0.04);
  --shadow: 0 4px 12px rgba(16, 24, 40, 0.07), 0 1px 3px rgba(16, 24, 40, 0.05);
  --shadow-lg: 0 12px 32px rgba(16, 24, 40, 0.12), 0 2px 8px rgba(16, 24, 40, 0.06);

  --topbar-h: 60px;                     /* sticky table headers pin below it */
  --content-w: 1180px;                  /* the centred content column */
  --settings-w: 940px;                  /* settings cards and anything under them */
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display",
    "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text-2);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  letter-spacing: -0.006em;
  font-size: 14.5px;
  line-height: 1.55;
}

/* ---------- icon tiles (iOS Settings-style glyph pucks) ---------- */

.icon-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  flex-shrink: 0;
  color: #fff;
  background-color: var(--tile-color, var(--accent));
  background-image: linear-gradient(160deg, rgba(255, 255, 255, 0.32), rgba(255, 255, 255, 0) 55%);
  box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.12);
}

.icon-tile svg {
  width: 19px;
  height: 19px;
}

.icon-tile.lg {
  width: 44px;
  height: 44px;
  border-radius: 12px;
}

.icon-tile.lg svg {
  width: 24px;
  height: 24px;
}

/* Form controls don't inherit the page font by default (browsers give them
   their own UI font) - force them to match everything else on the page. */
input, select, textarea, button {
  font: inherit;
  letter-spacing: inherit;
}

/* Every <select> in the app gets the same minimal chevron instead of each
   browser/OS's own native arrow - the one part of the native control that
   visibly clashed with the rest of the (otherwise fully custom-styled)
   Apple-esque form chrome. Box styling itself (border/radius/padding/
   background-color) stays with .pdf-input and the handful of other
   select-specific rules below - this just standardises the affordance. */
select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  cursor: pointer;
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 11px 8px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1.5 2L6 6.5L10.5 2' stroke='%2386868B' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

select::-ms-expand {
  display: none;
}

/* ---------- app shell: fixed sidebar + slim top bar ---------- */

.app-shell {
  display: flex;
  min-height: 100vh;
}

.app-main {
  flex: 1;
  min-width: 0;                 /* lets wide tables scroll instead of pushing */
  display: flex;
  flex-direction: column;
}

/* signed out (login, public share): no nav is rendered, so drop the sidebar
   and let the page use the full width */
.app-shell:not(:has(#site-nav)) .sidebar { display: none; }

/* ---------- sidebar ---------- */

.sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  position: sticky;
  top: 0;
  align-self: flex-start;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--sidebar-bg);
  border-right: 1px solid var(--sidebar-border);
  z-index: 200;
}

.sidebar-brand {
  padding: 18px 18px 14px;
  border-bottom: 1px solid var(--sidebar-border);
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  font-weight: 600;
  font-size: 0.9rem;
  line-height: 1.3;
  letter-spacing: -0.015em;
  color: var(--sidebar-text-strong);
  text-decoration: none;
}

/* The PNG is used as a mask and filled with a brushed-gold gradient, so the
   mark reads as metal against the dark sidebar rather than a flat knock-out. */
.brand-logo {
  width: 30px;
  aspect-ratio: 340 / 310;      /* the PNG's own proportions */
  flex-shrink: 0;
  display: inline-block;
  background: linear-gradient(115deg,
    #b8935c 0%, #dfc189 26%, #f4e0b4 50%, #cda765 74%, #e6cb95 100%);
  -webkit-mask: url("logo_no_word.png") no-repeat center / contain;
  mask: url("logo_no_word.png") no-repeat center / contain;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.35));
  transition: filter 0.2s;
}

a.brand:hover .brand-logo { filter: drop-shadow(0 1px 5px rgba(244, 224, 180, 0.5)); }

.brand span:not(.brand-logo) {
  display: block;
  width: 100%;
  font-weight: 450;
  font-size: 0.74rem;
  letter-spacing: 0.02em;
  color: var(--muted-2);
  margin-left: 40px;
  margin-top: -2px;
}

/* ---------- sidebar nav ---------- */

#site-nav::-webkit-scrollbar { width: 6px; }
#site-nav::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.14);
  border-radius: 3px;
}
#site-nav::-webkit-scrollbar-track { background: transparent; }

#site-nav {
  flex: 1;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.18) transparent;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 14px 10px 18px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* every direct link in the rail */
#site-nav > a,
.nav-group-btn {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 12px;
  border-radius: var(--r-sm);
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--sidebar-text);
  text-decoration: none;
  background: none;
  border: none;
  font-family: inherit;
  text-align: left;
  width: 100%;
  cursor: pointer;
  transition: background 0.14s, color 0.14s;
}

#site-nav > a:hover,
.nav-group-btn:hover {
  background: rgba(255, 255, 255, 0.06);
  color: var(--sidebar-text-strong);
}

#site-nav > a.active {
  background: var(--accent);
  color: #fff;
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}

/* ---------- grouped sections (Quotes, Tasks, Inventory, Reports) ----------
   In the rail these read as always-open labelled sections rather than
   hover dropdowns, so nothing is hidden behind a hover on a touch device. */
.nav-group {
  display: block;
  margin-top: 8px;
}

.nav-group-btn {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted-2);
  padding: 7px 12px 5px;
  cursor: default;
}

.nav-group-btn:hover {
  background: none;
  color: var(--muted-2);
}

.nav-group.active .nav-group-btn { color: rgba(255, 255, 255, 0.62); }

.nav-caret { display: none; }        /* nothing to open - the section is flat */

.nav-menu {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.nav-menu a {
  display: block;
  padding: 8px 12px 8px 22px;
  border-radius: var(--r-sm);
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--sidebar-text);
  text-decoration: none;
  position: relative;
  transition: background 0.14s, color 0.14s;
}

.nav-menu a::before {
  content: "";
  position: absolute;
  left: 10px;
  top: 50%;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.4;
  transform: translateY(-50%);
}

.nav-menu a:hover {
  background: rgba(255, 255, 255, 0.06);
  color: var(--sidebar-text-strong);
}

.nav-menu a.active {
  background: var(--accent);
  color: #fff;
  font-weight: 600;
}

.nav-menu a.active::before { opacity: 0.85; }

/* account + sign out pinned to the bottom of the rail */
#site-nav > a.nav-user {
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px solid var(--sidebar-border);
  border-radius: 0;
  color: var(--sidebar-text-strong);
  font-weight: 600;
}

#site-nav > a.nav-user::before {
  content: "";
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  border-radius: 50%;
  background: linear-gradient(140deg, var(--accent), #7c3aed);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16);
}

#site-nav > a.nav-user:hover,
#site-nav > a.nav-user.active {
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
}

/* ---------- top bar ---------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 150;
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  gap: 14px;
  padding-block: 0;
  padding-inline: max(26px, calc((100% - var(--content-w)) / 2 + 26px));
  background: rgba(255, 255, 255, 0.86);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--border);
  color: var(--text);
}

.topbar-title {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

/* Bar order at every width: the page title fills the left, then the bell,
   then the menu button hard right. On desktop the hamburger is hidden, which
   leaves [title ......... bell] - exactly where the bell belongs there. */
.topbar .topbar-title { order: 1; margin-right: auto; min-width: 0; }
.topbar .reminder-wrap { order: 2; margin-left: 0; flex-shrink: 0; }
.topbar .nav-toggle { order: 3; flex-shrink: 0; }

/* hamburger - hidden on desktop, shown when the rail collapses off-canvas */
.nav-toggle {
  display: none;
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text);
  font-size: 1.15rem;
  line-height: 1;
  padding: 6px 10px;
  cursor: pointer;
  transition: background 0.14s, border-color 0.14s;
}

.nav-toggle:hover { background: var(--surface-2); border-color: var(--border-strong); }

/* ---------- tablet / phone: rail slides in over the page ---------- */

@media (max-width: 1024px) {
  .sidebar {
    position: fixed;
    right: 0;
    left: auto;
    top: 0;
    transform: translateX(100%);
    transition: transform 0.24s ease;
    box-shadow: var(--shadow-lg);
  }

  /* the existing hamburger toggles .nav-open on #site-nav - :has() lets the
     rail react to it, so no JavaScript change was needed */
  .sidebar:has(#site-nav.nav-open) { transform: translateX(0); }

  .nav-toggle { display: inline-flex; align-items: center; }
}

/* ---------- admin: team job status page ---------- */

.jobstat-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
  margin: 8px 0 20px;
}

.jobstat-tile {
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-top: 3px solid var(--border);
  border-radius: 12px;
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}

.jobstat-bad { border-top-color: var(--danger); }
.jobstat-bad .jobstat-value { color: var(--danger); }
.jobstat-warn { border-top-color: #d9730d; }
.jobstat-warn .jobstat-value { color: #d9730d; }
.jobstat-good { border-top-color: #1c8a3c; }
.jobstat-good .jobstat-value { color: #1c8a3c; }

/* money figures are longer - let them shrink a touch so they don't wrap */
.jobstat-money {
  font-size: 1.5rem;
}

/* per-row collection progress under the Collected figure */
.collect-bar {
  display: block;
  height: 5px;
  margin-top: 5px;
  border-radius: 980px;
  background: #e8e8ed;
  overflow: hidden;
}

.collect-bar-fill {
  display: block;
  height: 100%;
  background: #1c8a3c;
  border-radius: 980px;
}

.collect-badge-open {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 980px;
  background: #fff1e6;
  color: #b8560a;
  white-space: nowrap;
}

.jobstat-value {
  font-size: 1.9rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.jobstat-label {
  font-size: 0.82rem;
  color: var(--muted);
}

.jobstat-list {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border-faint);
  border-radius: 14px;
  overflow: hidden;
  background: var(--card-bg);
}

.jobstat-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border-faint);
  border-left: 3px solid transparent;
  text-decoration: none;
  color: var(--text);
}

.jobstat-item-overdue { border-left-color: #e30000; }
.jobstat-item-today { border-left-color: #d9730d; }
.jobstat-item-upcoming { border-left-color: #1c8a3c; }

/* colour the My Tasks section headings to match the traffic-light groups */
.section-overdue { color: var(--danger); }
.section-today { color: #d9730d; }
.section-upcoming { color: #1c8a3c; }

.jobstat-item:last-child { border-bottom: none; }
.jobstat-item:hover { background: var(--bg); }

.jobstat-item-main {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  flex: 1;
}

.jobstat-item-title {
  font-weight: 500;
  overflow-wrap: anywhere;
}

.jobstat-item-client {
  color: var(--accent);
  font-weight: 600;
}

.jobstat-item-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 0.8rem;
  color: var(--muted);
}

.jobstat-pic {
  font-weight: 600;
  color: var(--text);
}

.jobstat-item-chevron {
  color: var(--muted);
  font-size: 1.3rem;
  flex-shrink: 0;
}

/* ---------- reminders bell + dropdown ---------- */

.reminder-wrap {
  position: relative;
  display: flex;
}

.reminder-bell {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  padding: 6px;
  border-radius: var(--r-sm);
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s, background 0.15s;
}

.reminder-bell:hover {
  color: var(--text);
  background: var(--surface-2);
}

.reminder-badge {
  position: absolute;
  top: 1px;
  right: 0;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  box-sizing: border-box;
  border-radius: 980px;
  background: var(--accent);
  color: #fff;
  font-size: 0.62rem;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}

.reminder-badge-overdue {
  background: var(--danger);
}

/* only-upcoming state: a quiet dot, no number, so the bell still signals
   "there's something" without shouting "act now" */
.reminder-dot {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
}

.reminder-panel {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  width: 340px;
  max-width: 88vw;
  max-height: 74vh;
  overflow-y: auto;
  background: var(--card-bg);
  color: var(--text);
  border: 1px solid var(--border-faint);
  border-radius: 14px;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.22);
  padding: 6px;
  z-index: 200;
}

.reminder-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 10px 6px;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.reminder-head-count {
  min-width: 20px;
  padding: 1px 7px;
  border-radius: 980px;
  background: var(--bg);
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 600;
  text-align: center;
}

.reminder-empty {
  margin: 0;
  padding: 12px 10px 16px;
  color: var(--muted);
  font-size: 0.88rem;
}

.reminder-group {
  padding: 10px 10px 4px;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}

/* traffic-light urgency, each obviously distinct from the grey/black task
   text: red = past due, amber = act today, green = still upcoming */
.reminder-group-overdue {
  color: var(--danger);
}

.reminder-group-today {
  color: #d9730d;
}

.reminder-group-upcoming {
  color: #1c8a3c;
}

/* a matching colour tab down the left of each item, so the group is still
   clear once you've scrolled past its heading */
.reminder-item {
  border-left: 3px solid transparent;
}

.reminder-item-overdue { border-left-color: #e30000; }
.reminder-item-today { border-left-color: #d9730d; }
.reminder-item-upcoming { border-left-color: #1c8a3c; }

.reminder-item {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 9px 10px;
  border-radius: 10px;
  text-decoration: none;
  color: var(--text);
}

.reminder-item:hover {
  background: var(--bg);
}

.reminder-item-title {
  font-size: 0.88rem;
  font-weight: 500;
  line-height: 1.25;
}

/* the client this task is for - so you know who it's about without
   opening it */
.reminder-item-client {
  font-size: 0.8rem;
  color: var(--text);
}

.reminder-item-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 0.75rem;
  color: var(--muted);
}

.reminder-footer-row {
  display: flex;
  margin-top: 4px;
  border-top: 1px solid var(--border-faint);
}

.reminder-footer {
  flex: 1;
  padding: 11px 10px;
  text-align: center;
  color: var(--accent);
  text-decoration: none;
  font-size: 0.85rem;
  font-weight: 500;
}

.reminder-footer + .reminder-footer {
  border-left: 1px solid var(--border-faint);
}

.reminder-footer:hover {
  text-decoration: underline;
}

.container {
  max-width: 860px;
  margin: 0 auto;
  padding: 40px 22px 110px;
}

h1 {
  margin: 0 0 6px;
  font-size: 2.1rem;
  font-weight: 700;
  letter-spacing: -0.025em;
  /* the blue-violet gradient headline treatment, applied to every page title */
  background: linear-gradient(92deg, #0a84ff 5%, #5e5ce6 55%, #bf5af2 95%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  width: fit-content;
}

.hint {
  color: var(--muted);
  margin-top: 0;
  margin-bottom: 28px;
  font-size: 0.95rem;
  line-height: 1.5;
}

/* ---------- landing hero (logo + company name) ---------- */

.hero {
  text-align: center;
  padding: 48px 0 30px;
}

@keyframes hero-rise {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Satin metallic finish, fully static: the logo PNG is used as a stencil
   (mask) and filled with a gentle gold gradient - a soft tonal shift
   around the brand gold, no bright specular highlights. */
.hero-logo {
  width: 128px;
  aspect-ratio: 340 / 310;   /* the PNG's own proportions */
  display: inline-block;
  margin-bottom: 18px;
  background: linear-gradient(115deg,
    #a5824e 0%, #c8a165 30%, #d4b078 52%, #b78e56 78%, #c8a165 100%);
  -webkit-mask: url("logo_no_word.png") no-repeat center / contain;
  mask: url("logo_no_word.png") no-repeat center / contain;
  animation: hero-rise 0.7s ease-out both;
  filter: drop-shadow(0 4px 10px rgba(122, 92, 48, 0.22));
}

.hero-company {
  margin: 0 auto 8px;   /* auto sides keep the fit-content h1 centered */
  font-size: 2.5rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  /* the landing page's company name stays black - override the gradient
     headline treatment that every other h1 gets */
  background: none;
  color: var(--text);
  animation: hero-rise 0.7s ease-out 0.12s both;
}

.hero-sub {
  color: var(--muted);
  font-size: 1.05rem;
  margin: 0;
  animation: hero-rise 0.7s ease-out 0.22s both;
}

.hero-card {
  max-width: 580px;
  margin: 0 auto;
  animation: hero-rise 0.7s ease-out 0.32s both;
}

.client-bar .save-btn {
  margin-top: 0;
}

/* Stacked client details form on the landing page (name / phone / address) */
.client-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  padding: 22px;
  text-align: left;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}

.client-form .field-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.client-form label {
  font-weight: 600;
  font-size: 0.85rem;
}

.client-form input {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 0.95rem;
  background: #fff;
}

/* ...but not a tickbox. Stretched to the field width it pushed its own
   label onto the next line, so every permission read as a stray box above
   the words it belonged to. */
.client-form input[type="checkbox"] {
  width: auto;
  padding: 0;
  border-radius: 3px;
}

.perm-checklist .pdf-check {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-right: 0;
}

.client-form select {
  width: 100%;
  padding: 10px 34px 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 0.95rem;
  background-color: #fff;
}

.client-form .save-btn {
  margin-top: 4px;
  align-self: flex-end;
}

@media (prefers-reduced-motion: reduce) {
  .hero-logo, .hero-company, .hero-sub, .hero-card {
    animation: none;
  }
  .hero-logo:hover {
    transform: none;
  }
}

/* ---------- flash messages ---------- */

.flash-stack {
  margin-bottom: 20px;
}

.flash {
  padding: 12px 16px;
  border-radius: 12px;
  margin-bottom: 8px;
  font-size: 0.9rem;
}

.flash-success {
  background: #e8f4ea;
  color: #1a7f37;
}

.flash-error {
  background: #fdecec;
  color: var(--danger);
}

/* ---------- choose-a-space page ---------- */

/* 200px left a card with ~156px of usable width for an icon, a space name
   and a price - so the two ran into each other. Wide enough for all three
   now, and it still drops to one column on a phone. */
.space-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
  gap: 14px;
}

.space-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  padding: 22px;
  text-decoration: none;
  color: var(--text);
  font-weight: 600;
  font-size: 1.02rem;
  letter-spacing: -0.015em;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
  transition: box-shadow 0.2s, transform 0.2s;
}

.space-card:hover {
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
  transform: translateY(-1px);
}

.space-arrow {
  color: var(--accent);
}

.space-card.completed {
  border-color: rgba(0, 113, 227, 0.35);
  background: #f5f9ff;
}

.space-card-left {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

/* ---------- choose-property page ---------- */

.property-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);   /* always two columns */
  gap: 18px;
  max-width: 620px;
  margin: 0 auto;
}

.property-card {
  aspect-ratio: 1 / 1;   /* big square tiles */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 20px;
  text-decoration: none;
  color: var(--text);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
  transition: box-shadow 0.2s, transform 0.2s;
}

.property-card:hover {
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.09);
  transform: translateY(-2px);
}

.property-card.selected {
  border-color: rgba(0, 113, 227, 0.45);
  background: #f5f9ff;
}

.property-card .icon-tile.lg {
  width: 76px;
  height: 76px;
  border-radius: 20px;
}

.property-card .icon-tile.lg svg {
  width: 42px;
  height: 42px;
}

.property-name {
  font-weight: 600;
  font-size: 1.08rem;
  letter-spacing: -0.015em;
  text-align: center;
  padding: 0 10px;
}

/* The price sits beside the space name in a narrow card. Without nowrap it
   broke mid-figure ("RM 6,220." / "94") and the pieces landed on top of the
   name; without flex-shrink: 0 it gave up its width to a long name instead
   of letting that name wrap. */
.space-status {
  color: var(--accent);
  font-size: 0.82rem;
  font-weight: 600;
  flex-shrink: 0;
  white-space: nowrap;
  margin-left: 10px;
  font-variant-numeric: tabular-nums;
}

/* the name is what gives way - it wraps rather than pushing the price out */
.space-name {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* ---------- an add-on's price per cabinet unit ---------- */

/* Which cabinets offer this add-on: a plain tick list, nothing else. It
   shares a cell with nothing now, so it can stay narrow and scannable. */
.addon-units {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 170px;
}

.addon-unit-name {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 0.85rem;
  cursor: pointer;
  padding: 1px 0;
}

/* a cabinet this add-on is not offered on: still listed, so it can be
   ticked on, but visibly not in play */
.addon-unit-off { opacity: 0.5; }

/* The per-cabinet price exceptions, folded away. Most add-ons cost the same
   everywhere, and leaving a box per cabinet per material on show turned this
   column into a wall of inputs all reading "same". */
.addon-overrides {
  margin-top: 8px;
  border-top: 1px solid var(--border-faint);
  padding-top: 7px;
}

.addon-overrides > summary {
  cursor: pointer;
  font-size: 0.78rem;
  color: var(--muted);
  list-style-position: inside;
}
.addon-overrides > summary:hover { color: var(--accent); }
.addon-overrides .hint { margin: 6px 0 8px; font-size: 0.72rem; }

.addon-override-flag {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 7px;
  border-radius: 980px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 0.66rem;
  font-weight: 650;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

/* cabinet name, then its box per material, one line each. A grid with an
   auto-fit track count cannot know how many materials there are and collapsed
   to a column per box; the rows are flex instead, wrapped by the name. */
.addon-override-grid {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.addon-override-unit {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.8rem;
  color: var(--muted);
  white-space: nowrap;
}

.addon-override-unit > span:first-child {
  width: 130px;
  flex: 0 0 auto;
}

/* the material names, once, sitting exactly over the boxes below - one
   width token for both, so a change to the box cannot leave the label
   floating over the wrong column */
.addon-overrides { --addon-box-w: 88px; }

.addon-override-head {
  font-size: 0.68rem;
  line-height: 1.2;
  margin-bottom: -2px;
}

.addon-override-col {
  width: var(--addon-box-w);
  flex: 0 0 auto;
}

/* material name above its box, not beside it: side by side each of these was
   ~200px wide, so two of them plus the cabinet name overflowed the column */
.addon-unit-price {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}

.addon-unit-price .hint { margin: 0; font-size: 0.68rem; line-height: 1.2; }

/* Narrower than a normal price box - these sit inside a table cell, and a
   blank one means "same as the add-on's own price". Qualified with
   .admin-table so it outranks that table's own 120px input rule, which is
   defined later in this file and was quietly winning. */
.admin-table .addon-overrides input[type="number"] {
  width: var(--addon-box-w);
  flex: 0 0 auto;
  padding: 5px 8px;
  font-size: 0.82rem;
}

/* ---------- dropdowns ----------
 *
 * A native <select> drops a list drawn by the operating system, which no
 * stylesheet can reach - so on Windows every dropdown in the app opened into
 * a grey OS list with none of its spacing, radius or colour. static/select.js
 * puts a real listbox in front of each one; the select itself stays in the
 * DOM and stays what submits.
 */
.custom-select {
  position: relative;
  display: inline-block;
  max-width: 100%;
}

/* the hidden real select still holds the value and still submits */
.custom-select .cs-native {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  margin: 0;
}

/* the closed control, matching the field look every input already uses */
.cs-button {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--text);
  font-family: inherit;
  font-size: 0.875rem;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s, box-shadow 0.15s;
}

.cs-button:hover:not(:disabled) { border-color: var(--accent); }
.cs-button:focus-visible,
.custom-select.cs-open .cs-button {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.cs-button:disabled { opacity: 0.6; cursor: not-allowed; background: var(--surface-2); }

.cs-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* an unmade choice reads quieter than a made one */
.cs-placeholder .cs-label { color: var(--muted); }

.cs-caret {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-right: 1.6px solid var(--muted);
  border-bottom: 1.6px solid var(--muted);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 0.15s;
}
.custom-select.cs-open .cs-caret {
  transform: rotate(-135deg) translate(-2px, -2px);
}

.cs-list {
  position: absolute;
  z-index: 400;
  left: 0;
  top: calc(100% + 5px);
  min-width: 100%;
  max-height: 264px;
  overflow-y: auto;
  padding: 5px;
  background: var(--card-bg, #fff);
  border: 1px solid var(--border);
  border-radius: var(--r-md, 12px);
  box-shadow: 0 12px 32px rgba(16, 24, 40, 0.14);
}

/* flipped above the control when there is no room beneath it */
.custom-select.cs-up .cs-list {
  top: auto;
  bottom: calc(100% + 5px);
}

.cs-option {
  padding: 8px 11px;
  border-radius: 8px;
  font-size: 0.875rem;
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cs-option:hover,
.cs-option.cs-active { background: var(--surface-2); }

.cs-option.cs-selected {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

/* an <optgroup> heading */
.cs-group {
  padding: 8px 11px 4px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---------- pre-delivery checklist ---------- */

.chk-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 34px;
  margin: 14px 0 6px;
  font-size: 0.92rem;
}

.chk-meta-label {
  display: block;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 2px;
}

.chk-date-input { padding: 5px 9px; font-size: 0.85rem; }

/* the printed stand-in for a field that is only a field on screen */
.chk-print-only { display: none; }

/* a blank to write the date on once it is printed */
.chk-write-line {
  display: inline-block;
  min-width: 150px;
  border-bottom: 1px solid var(--border-strong);
}

.chk-progress {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 12px 0 4px;
}

.chk-space { margin-top: 26px; }
.chk-space .space-room-badge { margin-left: 6px; }

.chk-table .chk-qty-col { width: 78px; text-align: center; }
.chk-table .chk-tick-col { width: 104px; text-align: center; }

/* the item's material or which cabinet it belongs to, quieter than its name */
.chk-detail {
  display: block;
  font-size: 0.78rem;
  color: var(--muted);
}

.chk-table input[type="checkbox"] {
  width: 17px;
  height: 17px;
  accent-color: var(--accent);
  cursor: pointer;
}

.chk-name-input { width: 100%; min-width: 190px; }
.chk-qty-input { width: 64px; text-align: center; }

/* two ways to add a row - off the list, or straight into an empty box */
.chk-add-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
}

.chk-add-way {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.chk-add-or {
  font-size: 0.8rem;
  color: var(--muted);
  padding: 0 2px;
}

.chk-add-note { margin-top: 8px; }

/* who the job passed through - each line signed with that account's own
   signature, so it can be done from whatever is to hand on the floor */
.chk-signoff {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
  gap: 26px;
  margin-top: 40px;
  page-break-inside: avoid;
}

.chk-sign { display: flex; flex-direction: column; }

.chk-sign-role {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

/* the signature sits ON the line, the way a written one does */
.chk-sign-mark {
  font-size: 1.6rem;
  height: 42px;
  display: flex;
  align-items: flex-end;
  padding-bottom: 2px;
  overflow: hidden;
}

.chk-sign-line {
  border-bottom: 1px solid var(--border-strong);
}

.chk-sign:not(.chk-sign-done) .chk-sign-line { height: 42px; }

.chk-sign-hint {
  margin-top: 4px;
  font-size: 0.65rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Naming one line's type on this quotation, beside the picker that chooses
   it. Empty means "call it whatever the catalogue calls it", which is what
   the placeholder shows - so a row that has not been renamed still reads as
   its type, in grey, and nothing has to be opened to find out. */
/* The Type picker has to show a type name in full - "Table (with drawer)"
   truncated to "Table (wit..." tells nobody which one is chosen - so both
   columns are given a width rather than left to the fixed layout to divide
   evenly. Positional, so it also lands on whatever sits second in the
   read-only breakdown - see the print block, which sizes that table's
   columns for paper. */
.rows-table th:nth-child(2):not(.variant-label-col) { width: 250px; }
.variant-label-col { width: 130px; }
.variant-label-cell { white-space: nowrap; }
.rows-table select.variant-select { max-width: 100%; }

.variant-label-input {
  width: 100%;
  max-width: 170px;
  padding: 7px 10px;
  border: 1px dashed var(--border);
  border-radius: 10px;
  font-family: inherit;
  font-size: 0.88rem;
  background: #fff;
  color: var(--text);
}
.variant-label-input::placeholder { color: var(--muted); font-style: italic; }
.variant-label-input:hover { border-color: var(--border-strong); }
.variant-label-input:focus {
  outline: none;
  border-style: solid;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* The cabinet's name on this quotation, typed straight into the heading.
   It has to READ as the heading it replaced - borderless until reached for -
   or every card looks like a form field. */
.unit-name-input {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 22rem;
  margin: -4px 0 -4px -8px;
  padding: 4px 8px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  font-family: inherit;
  font-size: 1.02rem;
  font-weight: 650;
  letter-spacing: -0.01em;
  color: var(--text);
  text-overflow: ellipsis;
}
.unit-name-input:hover {
  border-color: var(--border);
  background: #fff;
}
.unit-name-input:focus {
  outline: none;
  border-color: var(--accent);
  background: #fff;
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.chk-sign-btn { margin-top: 8px; align-self: flex-start; }
.chk-sign-note { margin-top: 4px; font-size: 0.7rem; }

/* setting an account's signature from the Accounts page */
.acct-sig-form {
  display: flex;
  align-items: center;
  gap: 6px;
}
.acct-sig-form input { width: 130px; }
.acct-sig-preview { display: block; font-size: 1.15rem; margin-top: 2px; }
.chk-sign-done .chk-sign-role { color: var(--ok, #1c8a3c); }

/* client and delivery details - the driver's half of the sheet */
.chk-client {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 34px;
  margin: 4px 0 10px;
  padding: 12px 16px;
  background: var(--surface-2);
  border-radius: var(--r-md, 12px);
  font-size: 0.92rem;
}

.chk-client-block { min-width: 0; }
.chk-client-wide { flex: 1 1 320px; }

@media (max-width: 640px) {
  /* Filling this in on a phone. The generic card layout gives every cell its
     own line, which turns one cabinet into four and a kitchen into a very
     long scroll - so the item takes the top line and Qty, Processed and
     Packed share the one beneath it, with targets sized for a thumb. */
  .chk-meta, .chk-client { gap: 10px 18px; }
  .chk-client-block { flex: 1 1 100%; }

  /* these have to outrank .admin-table:has(td[data-label]) td, which is
     (0,2,2) and defined later in this file - hence both class names and the
     attribute, rather than relying on source order */
  .admin-table.chk-table:has(td[data-label]) tbody tr {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 14px;
  }
  .admin-table.chk-table tbody td[data-label] {
    width: auto;
    padding: 3px 0;
    flex: 0 0 auto;
  }
  .admin-table.chk-table tbody td[data-label="Item"] {
    flex: 1 1 100%;
    justify-content: flex-start;
    font-weight: 600;
  }
  .admin-table.chk-table tbody td[data-label="Item"]::before { display: none; }
  .admin-table.chk-table tbody td[data-label="Processed"],
  .admin-table.chk-table tbody td[data-label="Packed"] { gap: 7px; }
  .chk-table input[type="checkbox"] { width: 24px; height: 24px; }
  .chk-table .chk-tick-col { width: auto; }
  .chk-detail { display: inline; margin-left: 6px; font-weight: 400; }

  /* the write-in rows keep their box on its own line - typed, not tapped */
  .admin-table.chk-table#chk-extras tbody td[data-label="Item"] { flex: 1 1 100%; }
  .chk-name-input { min-width: 0; }

  .chk-add-bar { gap: 8px; }
  .chk-add-way { flex: 1 1 100%; }
  .chk-add-way .custom-select, .chk-add-way .cs-button { width: 100%; }
  .chk-add-or { display: none; }
  .chk-signoff { gap: 20px; }
}

@media print {
  /* an unticked box has to print as an empty square somebody can pen a tick
     into - browsers render an unchecked box as nothing at all otherwise */
  .chk-table input[type="checkbox"] {
    -webkit-appearance: none;
    appearance: none;
    width: 13px;
    height: 13px;
    border: 1px solid #777;
    border-radius: 2px;
    position: relative;
  }
  .chk-table input[type="checkbox"]:checked::after {
    content: "\2713";
    position: absolute;
    inset: -3px 0 0 1px;
    font-size: 13px;
    line-height: 1;
  }
  /* the write-in boxes print as ruled boxes, not form fields */
  .chk-name-input, .chk-qty-input {
    border: none;
    padding: 0;
    background: none;
    font-size: inherit;
  }
  .chk-table { page-break-inside: auto; }
  .chk-table tr { page-break-inside: avoid; }
  .chk-space { page-break-after: avoid; }
}

/* ---------- renaming a space ---------- */

.space-title-row {
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
}

.space-title-row h1 { margin-bottom: 0; }

.space-rename summary {
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--accent);
  list-style: none;
}

.space-rename summary::-webkit-details-marker { display: none; }
.space-rename summary:hover { text-decoration: underline; }

.space-rename-form {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 10px;
  padding: 14px;
  background: var(--surface-2);
  border: 1px solid var(--border-faint);
  border-radius: var(--r);
}

.space-rename-form label {
  display: block;
  margin: 0 0 4px;
}

.space-rename-form .pdf-input { min-width: 220px; }

@media (max-width: 640px) {
  .space-rename-form { flex-direction: column; align-items: stretch; }
  .space-rename-form .pdf-input { min-width: 0; }
}

.add-space-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 14px;
}

.add-space-form {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  padding: 16px 18px;
  flex-wrap: wrap;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}

.add-space-label {
  font-weight: 600;
  font-size: 0.92rem;
  flex: 1;
}

.add-space-form input[type="text"] {
  /* large flex-basis forces the input (and the + Add button after it) onto
     their own line below the icon + room name */
  flex: 1 1 60%;
  min-width: 120px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 0.9rem;
  background: #fff;
}

.back-link {
  display: inline-block;
  color: var(--accent);
  text-decoration: none;
  font-size: 0.88rem;
  margin-bottom: 14px;
}

.back-link:hover {
  text-decoration: underline;
}

/* ---------- inputs (shared focus treatment) ---------- */

input[type="text"]:focus,
input[type="number"]:focus,
select:focus {
  outline: none;
  border-color: var(--accent) !important;
  box-shadow: 0 0 0 3.5px var(--accent-soft);
}

/* ---------- quote page ---------- */

.client-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  padding: 16px 18px;
  margin-bottom: 20px;
  flex-wrap: wrap;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}

.client-bar label {
  font-weight: 600;
  font-size: 0.9rem;
}

.client-bar input[type="text"] {
  flex: 1 1 220px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 0.95rem;
  background: #fff;
}

#save-quote-btn {
  background: var(--accent);
  color: #fff;
  border: none;
  padding: 10px 22px;
  border-radius: 980px;
  font-size: 0.9rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s;
}

#save-quote-btn:hover {
  background: var(--accent-hover);
}

#save-quote-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

.save-status {
  font-size: 0.85rem;
}

.save-status.success {
  color: #1a7f37;
}

.save-status.error {
  color: var(--danger);
}

.save-panel {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 18px 0;
}

.next-step-panel {
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  padding: 22px;
  margin-bottom: 100px;
  text-align: center;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}

.next-step-heading {
  margin: 0 0 14px;
  font-weight: 600;
  letter-spacing: -0.015em;
}

.next-step-panel .save-btn {
  margin: 0 6px;
  display: inline-block;
  text-decoration: none;
}

.secondary-btn {
  background: #fff !important;
  color: var(--accent) !important;
  border: 1px solid var(--accent) !important;
}

.secondary-btn:hover {
  background: var(--accent-soft) !important;
}

.space-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-top: 34px;
  margin-bottom: 14px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
  font-size: 1.25rem;
  letter-spacing: -0.02em;
}

.space-heading-edit {
  font-size: 0.8rem;
  font-weight: 400;
  color: var(--accent);
  text-decoration: none;
}

.space-heading-edit:hover {
  text-decoration: underline;
}

.space-room-badge {
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  background: #e8e8ed;
  padding: 3px 9px;
  border-radius: 980px;
  vertical-align: middle;
  margin-left: 8px;
}

.space-subtotal {
  margin-bottom: 6px;
}

/* ---------- unit cards (folder view) ---------- */

.unit-card {
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  padding: 18px 22px;
  margin-bottom: 14px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
  transition: box-shadow 0.2s;
}

.unit-card:hover {
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.06);
}

/* Folder-style cards: the header is always visible and clickable; the body
   (inputs, add-ons, subtotal) only shows once the card is expanded. */
.unit-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
}

/* Only the Quote form's headers (which carry a caret) are clickable -
   the read-only quote detail page reuses .unit-header without one. */
.unit-header:has(.unit-caret) {
  cursor: pointer;
  user-select: none;
}

.unit-card.collapsed .unit-header {
  margin-bottom: 0;
}

.unit-header:has(.unit-caret):hover h2 {
  color: var(--accent);
}

.unit-caret {
  color: var(--muted);
  font-size: 0.8rem;
  transition: transform 0.2s, color 0.2s;
}

.unit-card:not(.collapsed) .unit-caret {
  transform: rotate(90deg);
  color: var(--accent);
}

.unit-header h2 {
  margin: 0;
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  flex: 1;
  transition: color 0.15s;
}

.unit-header-subtotal {
  color: var(--muted);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}

.unit-header-subtotal.has-value {
  color: var(--text);
  font-weight: 600;
}

/* ---------- Putting the spaces in order ----------
   The order they sit in here is the order the quotation reads and prints
   in. A row drags by its handle on a desktop; the arrows do the same move
   and are what work on a touch screen. */

/* one per line while ordering: up and down mean something in a column, and
   very little in a grid that wraps */
.space-order-form .space-grid {
  grid-template-columns: 1fr;
  gap: 10px;
}

.space-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.space-row > .space-card {
  flex: 1;
  min-width: 0;
  padding: 14px 18px;
}

.space-drag {
  flex-shrink: 0;
  width: 28px;
  height: 34px;
  padding: 0;
  border: none;
  background: none;
  color: var(--muted-2);
  font-size: 0.95rem;
  letter-spacing: -3px;
  cursor: grab;
  touch-action: none;
}

.space-drag:active { cursor: grabbing; }

.space-moves {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}

.space-order-form > .save-btn {
  margin-top: 12px;
}

.space-row.arrange-dragging > .space-card {
  opacity: 0.5;
  border-color: var(--accent);
}

.arrange-move {
  width: 28px;
  height: 28px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card-bg);
  color: var(--muted);
  font-size: 0.6rem;
  line-height: 1;
  cursor: pointer;
}

.arrange-move:hover {
  color: var(--accent);
  border-color: var(--accent);
}

/* "Copy" on a row of the saved-quotes list: one dialog, aimed at whichever
   quotation's button was pressed. */
.copy-dialog {
  width: min(560px, calc(100vw - 32px));
  padding: 22px 24px 18px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  background: var(--card-bg);
  color: var(--text);
  box-shadow: 0 18px 48px rgba(16, 24, 40, 0.18);
}

.copy-dialog::backdrop {
  background: rgba(16, 24, 40, 0.38);
}

.copy-dialog-title {
  margin-top: 0;
}

/* in a dialog the fields have one column to work with, so they stack and
   fill it rather than sitting side by side as they do on the wide page */
.copy-dialog .client-edit-form {
  align-items: stretch;
}

.copy-dialog .client-edit-field {
  width: 100%;
}

/* (0,3,0), because the page's own .client-edit-form .pdf-input pins these
   to 200px and that is the right width beside a heading, not in a column */
.copy-dialog .client-edit-field .pdf-input {
  width: 100%;
}

/* Adding and removing a copy of a cabinet: a space can hold two of the same
   one - a kitchen run and its island - each with its own rows. Quiet until
   pointed at, so the header still reads as a name and a total. */
.unit-copy-btn,
.unit-remove-btn {
  flex-shrink: 0;
  padding: 3px 9px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--card-bg);
  color: var(--muted);
  font-family: inherit;
  font-size: 0.72rem;
  font-weight: 600;
  cursor: pointer;
  transition: color 0.12s, border-color 0.12s, background 0.12s;
}

/* ---------- Standard Sizes ----------
   The workshop's own dimensions, read by everyone and edited by
   administration on the same page. */

.standards-group {
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--card-bg);
  padding: 14px 18px 16px;
  margin-bottom: 16px;
}

.standards-group-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 10px;
}

.standards-group-name {
  flex: 1;
  min-width: 0;
  max-width: 320px;
  font-weight: 650;
}

.standards-form .admin-table .pdf-input {
  width: 100%;
  min-width: 90px;
}

.standards-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-top: 4px;
}

/* ---------- the shape a piece is measured as ----------
   A partition against a staircase is a trapezium, not a rectangle, so the
   row says which it is and draws it: the little figure is there so the two
   heights and the run are not guessed at from three unlabelled boxes. */

.shape-col { width: 150px; }
.height-b-col { width: 132px; }

.shape-cell select {
  width: 100%;
  max-width: 140px;
}

/* the drawing above its formula, both centred under the picker - side by
   side the letters on the shape ran into the sum and the whole thing read
   as clutter */
.shape-figure {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  margin-top: 8px;
  padding: 6px 4px 4px;
  border-radius: 10px;
  background: var(--surface-2);
}

.shape-figure svg {
  width: 96px;
  height: 75px;
  flex-shrink: 0;
  overflow: visible;
}

/* Which letter of the drawing a box is. It sits on the box, not on the
   column heading, because the letters belong to the shape and two rows in
   one table can be different shapes - a rectangle's width is w, and the
   same box on a trapezium is h. */
.measure-cell {
  white-space: nowrap;
}

.dim-letter {
  display: inline-block;
  min-width: 15px;
  margin-left: 6px;
  padding: 0 4px;
  border-radius: 5px;
  background: var(--accent-soft);
  color: var(--accent);
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  font-size: 0.82rem;
  text-align: center;
  text-transform: none;
  letter-spacing: 0;
}

.dim-letter:empty { display: none; }

.height-b-cell.shape-off .dim-letter { display: none; }

.shape-figure polygon,
.shape-figure rect {
  fill: var(--accent-soft);
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linejoin: round;
}

.shape-letter {
  fill: var(--text-2);
  font-size: 15px;
  font-style: italic;
  font-family: Georgia, "Times New Roman", serif;
}

.shape-formula {
  font-size: 0.74rem;
  color: var(--text-2);
  font-style: italic;
  line-height: 1.25;
  white-space: nowrap;
}

/* on the quotation itself, where the two heights print as "2400 / 1200" */
.shape-tag {
  display: inline-block;
  margin-left: 6px;
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted-2);
}

/* the second height only exists on a trapezium - the cell stays so the
   columns line up, with a dash where the box would be */
.height-b-cell .shape-na { display: none; color: var(--muted-2); }
.height-b-cell.shape-off input { display: none; }
.height-b-cell.shape-off .shape-na { display: inline; }

@media (max-width: 640px) {
  .shape-figure { margin-top: 6px; }
}

/* A cabinet's place in its space, which is the order it prints in. The
   handle drags on a desktop; the arrows do the same move and are what work
   on a touch screen. */
.unit-drag {
  flex-shrink: 0;
  color: var(--muted-2);
  font-size: 0.9rem;
  letter-spacing: -3px;
  cursor: grab;
  touch-action: none;
}

.unit-drag:active { cursor: grabbing; }

.unit-moves {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}

.unit-card.unit-dragging {
  opacity: 0.5;
  border-color: var(--accent);
}

/* the plus sits at the head of the row, in front of the cabinet it adds
   another of - a round button the width of one character, so a column of
   them lines up down the left edge of the space */
.unit-copy-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  font-size: 1rem;
  line-height: 1;
}

.unit-copy-btn:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-soft);
}

.unit-remove-btn:hover {
  color: var(--danger);
  border-color: var(--danger);
  background: var(--danger-soft);
}

.unit-card.collapsed .unit-body {
  display: none;
}

.unit-meta {
  color: var(--muted);
  font-size: 0.85rem;
  margin-bottom: 14px;
  line-height: 1.5;
}

/* ---------- entry tables ---------- */

.rows-table {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  margin-bottom: 10px;
}

.breakdown-table {
  margin-bottom: 26px;
}

.breakdown-table:last-of-type {
  margin-bottom: 10px;
}

.addon-name-heading {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--muted);
  margin: 14px 0 6px;
}

.rows-table th {
  text-align: left;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--muted);
  padding: 6px;
  border-bottom: 1px solid var(--border-faint);
}

.rows-table td {
  padding: 7px 6px;
  border-bottom: 1px solid var(--border-faint);
}

.rows-table input[type="number"] {
  width: 80px;
  padding: 8px 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  font-size: 0.875rem;
  background: #fff;
}

.rows-table input[type="text"].name-input {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 0.92rem;
  background: #fff;
}

/* Custom items: name gets the room, the size cell holds whichever of
   W/H/Qty the chosen formula needs (the others are display:none'd) */
/* The Item column absorbs the spare width - every other column holds
   fixed-size inputs, so without this the name box stays at its minimum and a
   name like "Dismantle old kitchen cabinet" gets cut off. The width goes on
   the HEADER cell: .rows-table is table-layout fixed, which sizes every
   column from the first row and ignores widths set on body cells. */
.custom-table thead th:nth-child(2) { width: 34%; }
.custom-table .custom-name-input { min-width: 180px; }
.custom-table .custom-size-cell { white-space: nowrap; }
.custom-table .custom-size-cell input { width: 80px; }
.custom-table .custom-size-cell input + input { margin-left: 6px; }
.custom-table .custom-price-input { width: 96px; }

.rows-table select.variant-select,
.rows-table select.custom-mode-select,
.rows-table select.material-select,
.addon-table select.material-select {
  padding: 7px 30px 7px 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 0.92rem;
  max-width: 160px;
  background-color: #fff;
}

.rows-table .length-ft,
.rows-table .line-total,
.addon-table .line-total {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.rows-table th.line-total,
.rows-table td.line-total,
.addon-table th.line-total,
.addon-table td.line-total {
  text-align: right;
  /* 120px is the baseline, not a cap: a five-figure amount broke after the
     "RM" and set the currency on its own line above the number. The column
     takes the width its longest amount needs instead. */
  width: 120px;
  white-space: nowrap;
}

.rows-table th.row-action,
.rows-table td.row-action,
.addon-table th.row-action,
.addon-table td.row-action {
  width: 34px;
}

.rows-table th.row-dup,
.rows-table td.row-dup,
.addon-table th.row-dup,
.addon-table td.row-dup {
  width: 30px;
}

.remove-row-btn {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  padding: 4px 8px;
  transition: color 0.15s;
}

.remove-row-btn:hover {
  color: var(--danger);
}

.dup-row-btn {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  font-size: 1.1rem;
  font-weight: 600;
  line-height: 1;
  padding: 4px 6px;
  transition: color 0.15s;
}

.dup-row-btn:hover {
  color: var(--accent);
}

.add-row-btn {
  background: #f5f5f7;
  border: none;
  color: var(--accent);
  padding: 8px 16px;
  border-radius: 980px;
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 500;
  transition: background 0.15s;
}

.add-row-btn:hover {
  background: #e8e8ed;
}

.unit-subtotal {
  text-align: right;
  margin-top: 12px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* ---------- add-on sections ---------- */

.addon-section {
  border-top: 1px solid var(--border-faint);
  margin-top: 14px;
  padding-top: 14px;
}

.addon-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 8px;
  font-weight: 600;
  font-size: 0.92rem;
  letter-spacing: -0.01em;
}

.addon-meta {
  color: var(--muted);
  font-weight: 400;
  font-size: 0.82rem;
}

.addon-table {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  margin-bottom: 10px;
}

.addon-table th {
  text-align: left;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--muted);
  padding: 6px;
  border-bottom: 1px solid var(--border-faint);
}

.addon-table td {
  padding: 7px 6px;
  border-bottom: 1px solid var(--border-faint);
}

.addon-table input[type="number"] {
  width: 80px;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 0.92rem;
  background: #fff;
}

.addon-table select.type-select {
  padding: 7px 30px 7px 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 0.92rem;
  max-width: 140px;
  background-color: #fff;
}

/* ---------- totals ---------- */

.grand-total-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  /* above the sticky table headers (z-index 2), below the topbar (100) -
     without this the share-links header row paints over the bar */
  z-index: 50;
  background: var(--chrome);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  color: #fff;
  padding: 16px 28px;
  display: flex;
  justify-content: space-between;
  max-width: 900px;
  margin: 0 auto;
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  border-radius: 16px 16px 0 0;
}

.grand-total-bar.static {
  position: static;
  border-radius: 16px;
  margin-top: 12px;
}

.section-heading {
  margin-top: 34px;
  margin-bottom: 12px;
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  scroll-margin-top: calc(var(--topbar-h) + 12px);  /* jump links land below the sticky bar */
}

/* smaller heading inside a section - e.g. each pricing mode's add-on table
   under the one "Add-ons" heading, instead of five same-weight headings */
.subsection-heading {
  margin-top: 22px;
  margin-bottom: 10px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.01em;
}

/* the Price List's jump links - one room's page is several screens long */
.admin-jump-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 14px;
  margin: 12px 0 4px;
  font-size: 0.85rem;
}
.admin-jump-bar a {
  color: var(--accent);
  text-decoration: none;
  font-weight: 550;
}
.admin-jump-bar a:hover { text-decoration: underline; }

/* ---------- admin page ---------- */

.admin-room-tabs {
  display: inline-flex;
  gap: 4px;
  margin-bottom: 22px;
  background: #e8e8ed;
  border-radius: 980px;
  padding: 4px;
}

.admin-room-tabs a {
  padding: 7px 18px;
  border-radius: 980px;
  text-decoration: none;
  font-size: 0.88rem;
  color: var(--text);
  transition: background 0.15s, color 0.15s;
}

.admin-room-tabs a.active {
  color: #fff;
  background: var(--accent);
}

.admin-room-tabs a:hover:not(.active) {
  background: rgba(255, 255, 255, 0.7);
}

/* Saved Quotes as stacked cards - a mobile-only alternative to the table
   below it (see the max-width media query), so every field and action
   is visible without scrolling sideways to reach it. */
.quote-cards {
  display: none;
}

/* Data-heavy pages (Saved Quotes, Order Management) get a wider reading
   column than the 860px used for forms and the quotation itself, so their
   tables fit instead of spilling out past .container - the container stays
   centred either way, but an overflowing table drags the page's visual
   centre to the right. */
body.wide-page .container {
  max-width: 1680px;
}

/* Shared column helpers for the list tables: a figure or a timestamp
   broken across lines is harder to scan than a slightly wider column. */
.admin-table .col-money {
  text-align: right;
  white-space: nowrap;
}

.admin-table .col-nowrap {
  white-space: nowrap;
}

/* ---------- search / filter / sort toolbar above a list table ---------- */

.table-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}

/* Magnifier drawn the same way the select chevron is (inline SVG on the
   background, same #86868B stroke), so the two controls read as a set.
   The selector carries [type="search"] on purpose: the shared
   input[type="search"].pdf-input rule sets the padding and lives later
   in this file, so anything of equal or lower specificity loses to it
   and the text lands on top of the icon. */
.table-tools .tools-search {
  flex: 1 1 280px;
  max-width: 380px;
}

.table-tools input[type="search"].tools-search {
  padding-left: 34px;
  background-repeat: no-repeat;
  background-position: left 11px center;
  background-size: 15px 15px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Ccircle cx='7' cy='7' r='4.5' stroke='%2386868B' stroke-width='1.6'/%3E%3Cpath d='M10.6 10.6L14 14' stroke='%2386868B' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
}

.table-tools .tools-count {
  margin-left: auto;
  white-space: nowrap;
}

/* rows and cards are re-shown by clearing [hidden], but the mobile
   layouts set display explicitly on both, which would win - so say it */
tr[hidden],
.quote-card[hidden] {
  display: none !important;
}

.admin-table th.is-sortable {
  cursor: pointer;
  user-select: none;
  padding-right: 24px;
  position: sticky;   /* re-stated: the sticky header rule still applies */
  transition: color 0.15s;
}

.admin-table th.is-sortable:hover {
  color: var(--text);
}

.admin-table th.is-sortable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-radius: 8px;
}

/* A stroked chevron, matching the one on every select rather than a
   filled triangle. It lives in the padding reserved above, so turning
   sorting on never changes a column's width. Unsorted columns show it
   faintly on hover only, so 5 arrows don't compete with the data. */
.admin-table th.is-sortable::after {
  content: "";
  position: absolute;
  right: 9px;
  top: 50%;
  width: 6px;
  height: 6px;
  margin-top: -5px;
  border-right: 1.5px solid var(--muted);
  border-bottom: 1.5px solid var(--muted);
  transform: rotate(45deg);
  opacity: 0;
  transition: opacity 0.15s, border-color 0.15s;
}

.admin-table th.is-sortable:hover::after {
  opacity: 0.45;
}

.admin-table th.is-sortable[data-dir]::after {
  opacity: 1;
  border-color: var(--accent);
}

.admin-table th.is-sortable[data-dir="asc"]::after {
  margin-top: -2px;
  transform: rotate(225deg);
}

@media (max-width: 640px) {
  .table-tools .tools-search,
  .table-tools .pdf-input {
    flex: 1 1 100%;
    max-width: none;
  }

  .table-tools .tools-count {
    margin-left: 0;
  }
}

/* ...and below that width the table scrolls inside its own box rather
   than overflowing, so the page never goes off-centre at any size. The
   max-height makes this the scroll container in both directions, which
   is what lets the header row stay pinned on a long list. */
.table-scroll {
  overflow: auto;
  max-height: 78vh;
  -webkit-overflow-scrolling: touch;
}

/* the quotation an order came from - present for traceability, but the
   MTC order number is the identity that matters on the shop floor, so it
   sits under the order number rather than taking a column of its own */
.source-quote {
  display: block;
  color: var(--muted);
  font-size: 0.75rem;
}

/* ---------- Order Management: fit every column on screen ----------
   13 columns compete for width here, so this table is tuned to fit
   rather than scroll: tighter cells, no wrapping mid-figure, and phase
   columns sized for a status pill instead of their full heading. */
.orders-table th,
.orders-table td {
  padding: 10px 10px;
}

.orders-table .col-money {
  text-align: right;
  white-space: nowrap;
}

.orders-table .col-phase {
  text-align: center;
  width: 1%;
  white-space: nowrap;
}

/* phase columns are sized by their status pill, not their heading - let
   the heading wrap onto a second line so it isn't what sets the width,
   and trim the cell/pill padding so five of them still fit on a laptop */
.orders-table th.col-phase {
  white-space: normal;
}

.orders-table .col-phase {
  padding-left: 6px;
  padding-right: 6px;
}

.orders-table .col-phase .calendar-status-badge {
  padding-left: 8px;
  padding-right: 8px;
}

.orders-table .quotation-id {
  white-space: nowrap;
}

/* an unscheduled phase reads as an empty slot, not a sentence - the full
   wording is on the cell's tooltip */
.phase-none {
  color: var(--border);
}

.orders-table .row-actions {
  white-space: nowrap;
  text-align: right;
}

.admin-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}

/* Corners are rounded per-cell rather than with overflow:hidden on the
   table, because an overflow ancestor clips a sticky header out of
   existence - and the header row stays put while you scroll (below). */
.admin-table thead tr:first-child th:first-child { border-top-left-radius: 16px; }
.admin-table thead tr:first-child th:last-child { border-top-right-radius: 16px; }
.admin-table tbody tr:last-child td:first-child { border-bottom-left-radius: 16px; }
.admin-table tbody tr:last-child td:last-child { border-bottom-right-radius: 16px; }

.admin-table th, .admin-table td {
  padding: 13px 16px;
  text-align: left;
  border-bottom: 1px solid var(--border-faint);
}

.admin-table tr:last-child td {
  border-bottom: none;
}

.admin-table th {
  /* stays visible under the top bar while the rows scroll past, so it's
     always clear which column a value belongs to */
  position: sticky;
  top: var(--topbar-h);
  z-index: 2;
  background: #fafafa;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--muted);
}

/* a header cell has no bottom border of its own once it's floating over
   the rows - draw the divider with a shadow so it can't be scrolled off */
.admin-table th {
  box-shadow: inset 0 -1px 0 var(--border-faint);
}

/* Inside a scrolling box the header pins to the box, not the page.

   Every ancestor with a non-visible overflow becomes the scrollport for a
   sticky descendant, so `top: var(--topbar-h)` stops meaning "sit under the
   page's top bar" and starts meaning "sit 60px down inside this box" - which
   pushes the header out of its own row and over the first line of data. Any
   wrapper given an overflow must be listed here. */
.table-scroll .admin-table th,
.dash-chart-card .admin-table th {
  top: 0;
}

/* Price-list cells. These predate the design system and kept their own
   border colour, radius and font, so a price box on the Price List looked
   subtly unlike the identical box on every other page. */
.admin-table input[type="number"] {
  width: 120px;
  padding: 8px 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  font-size: 0.875rem;
  background: #fff;
}

.admin-table .material-group-th {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 700;
  text-align: center;
  border-bottom: 1px solid var(--border-faint);
}

/* price columns stay a fixed width regardless of how many there are, so
   a table with just one material column doesn't stretch to fill the
   whole row - the name/type column absorbs any remaining space instead */
.admin-table .price-col {
  width: 160px;
}

/* Settings hub (/admin): Apple Settings-style section list */

.settings-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-width: 640px;
}

.settings-card {
  display: flex;
  align-items: center;
  gap: 18px;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 18px;
  padding: 22px 24px;
  text-decoration: none;
  color: var(--text);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
  transition: box-shadow 0.2s, transform 0.2s;
}

.settings-card:hover {
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
  transform: translateY(-1px);
}

.settings-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.settings-title {
  font-weight: 600;
  font-size: 1.08rem;
  letter-spacing: -0.015em;
}

.settings-desc {
  color: var(--muted);
  font-size: 0.88rem;
}

.settings-chevron {
  color: var(--muted);
  font-size: 0.9rem;
}

/* Admin configuration section (create/delete spaces, units, add-ons) */

.config-divider {
  margin-top: 48px;
  padding-top: 22px;
  border-top: 1px solid var(--border);
  font-size: 1.3rem;
}

.variant-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

.config-remove-row {
  display: flex;
  gap: 28px;
  flex-wrap: wrap;
  align-items: center;
}

.config-remove {
  display: flex;
  gap: 10px;
  align-items: center;
}

.admin-reset-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: #fdecec;
  border-radius: 16px;
  padding: 14px 18px;
  margin-bottom: 24px;
  flex-wrap: wrap;
}

.admin-reset-bar .hint {
  margin: 0;
  color: var(--danger);
  font-size: 0.88rem;
}

.admin-save-default-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: #eaf4ff;
  border-radius: 16px;
  padding: 14px 18px;
  margin-bottom: 24px;
  flex-wrap: wrap;
}

.admin-save-default-bar .hint {
  margin: 0;
  font-size: 0.88rem;
}

.save-default-form {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}

.save-default-form .pdf-input {
  width: 160px;
}

.danger-btn {
  background: #fff;
  color: var(--danger);
  border: 1px solid rgba(227, 0, 0, 0.4);
  padding: 8px 18px;
  border-radius: 980px;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s;
}

.danger-btn:hover {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
}

.admin-number-input {
  width: 120px;
  padding: 8px 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  font-size: 0.875rem;
  background: #fff;
}

/* ---------- misc ---------- */

/* Letterhead (composed from Admin > Quotation PDF settings). Hidden on
   screen; shown when printing, and inside the Admin preview panel. */
.print-letterhead {
  display: none;
  align-items: center;
  gap: 16px;
}

.pdf-preview .print-letterhead {
  display: flex;
}

.print-letterhead.lh-logo-right {
  flex-direction: row-reverse;
}

.print-letterhead.lh-logo-top {
  flex-direction: column;
  gap: 8px;
}

.print-letterhead .lh-logo {
  flex-shrink: 0;
}

.print-letterhead .lh-text {
  flex: 1;
  min-width: 0;
  line-height: 1.35;
}

.lh-align-left .lh-text { text-align: left; }
.lh-align-center .lh-text { text-align: center; }
.lh-align-right .lh-text { text-align: right; }

/* bottom letterhead row: left part pinned to the left edge, right part to
   the right edge, on one shared line (H/P ... | ... Tel/Fax). Not scoped to
   one letterhead: the printed document builds the same block, and without
   this the two phone numbers ran into each other mid-line. */
.lh-split {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 24px;
  text-align: left;
}

/* neither half wraps or runs into the other, however narrow the block
   gets - they are two phone numbers, not a sentence */
.lh-split > span { white-space: nowrap; }

/* centered title under the letterhead (e.g. "Quotation") - print/preview only */
.pdf-title {
  display: none;
  text-align: center;
  letter-spacing: 0.06em;
}

.pdf-preview .pdf-title {
  display: block;
  margin: 10px 0 4px;
}

/* Admin > Quotation PDF editor */
.pdf-preview {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 22px;
  margin-bottom: 18px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
  color: #000;
}

.pdf-input.pdf-wide,
textarea.pdf-input {
  width: 100%;
  max-width: 520px;
}

/* One canonical field look, applied to every typed control that carries
   .pdf-input. Listed per type on purpose: checkbox/file inputs also use
   the class but must keep their native affordance. Any new input type
   used with this class must be added here, or it silently falls back to
   the browser's default chrome and stops matching everything else. */
textarea.pdf-input,
input[type="text"].pdf-input,
input[type="number"].pdf-input,
input[type="password"].pdf-input,
input[type="date"].pdf-input,
input[type="time"].pdf-input,
input[type="search"].pdf-input,
input[type="email"].pdf-input,
input[type="tel"].pdf-input,
select.pdf-input {
  appearance: none;
  -webkit-appearance: none;
  padding: 8px 11px;
  /* the design system's field look, not this block's older one: it carries
     (0,1,2) specificity and so decides how every .pdf-input renders, and
     while it kept its own border colour, radius and font size, text fields
     came out a different height and roundness from the selects beside them */
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  font-size: 0.875rem;
  background-color: #fff;
  color: var(--text);
  transition: border-color 0.15s, box-shadow 0.15s;
}

textarea.pdf-input:focus,
input[type="text"].pdf-input:focus,
input[type="number"].pdf-input:focus,
input[type="password"].pdf-input:focus,
input[type="date"].pdf-input:focus,
input[type="time"].pdf-input:focus,
input[type="search"].pdf-input:focus,
input[type="email"].pdf-input:focus,
input[type="tel"].pdf-input:focus,
select.pdf-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* the native magnifier/clear chrome would sit on top of our own */
input[type="search"].pdf-input::-webkit-search-decoration,
input[type="search"].pdf-input::-webkit-search-cancel-button {
  -webkit-appearance: none;
}

input.pdf-input::placeholder,
textarea.pdf-input::placeholder {
  color: var(--muted);
}

select.pdf-input {
  padding-right: 32px;
}

.pdf-check {
  margin-right: 18px;
  font-size: 0.92rem;
}

.perm-checklist {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 480px;
}

.perm-details summary {
  cursor: pointer;
  color: var(--accent);
  font-size: 0.9rem;
}

.perm-details .perm-edit-form {
  margin-top: 12px;
  padding: 12px 14px;
  background: var(--bg);
  border-radius: 12px;
}

.materials-per-product {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
  gap: 10px;
  max-width: 900px;
  margin-bottom: 24px;
}

.materials-control {
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 12px;
  padding: 12px 16px;
}

.materials-control-body {
  margin-top: 12px;
}

.materials-control-list {
  list-style: none;
  margin: 0 0 10px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.materials-control-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-size: 0.9rem;
}

.materials-add-form {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 8px;
}

.pdf-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 20px;
}

.pdf-bar .save-btn {
  margin-top: 0;
  flex-shrink: 0;
  white-space: nowrap;
}

.pdf-bar .pdf-hint {
  margin: 0;
  font-size: 0.85rem;
}

.client-contact {
  margin: 2px 0 4px;
  color: var(--text);
  font-size: 0.95rem;
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}

/* let a long phone/address break within its own span instead of forcing
   the row wider than the screen */
.client-contact > span {
  min-width: 0;
  overflow-wrap: anywhere;
}

.client-contact .contact-sep {
  color: var(--muted);
}

.quotation-id {
  font-variant-numeric: tabular-nums;
  font-family: "SF Mono", ui-monospace, "Cascadia Code", Consolas, monospace;
  letter-spacing: 0.02em;
}

.row-actions {
  white-space: nowrap;
}

.inline-form {
  display: inline;
}

.link-danger-btn {
  background: none;
  border: none;
  padding: 0;
  color: var(--danger);
  text-decoration: none;
  cursor: pointer;
  font-size: inherit;
  font-family: inherit;
}

/* a button that reads as a link - for in-place actions that sit inline
   with real links, like revealing the customer-details editor */
.link-btn {
  background: none;
  border: none;
  padding: 0;
  color: var(--accent);
  cursor: pointer;
  font-size: inherit;
  font-family: inherit;
}

.link-btn:hover {
  text-decoration: underline;
}

/* ---------- editing the customer on a saved quote ---------- */

.client-edit-box {
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  padding: 18px 22px 14px;
  margin-bottom: 20px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}

.client-edit-box .section-heading {
  margin-top: 0;
}

.client-edit-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
}

.client-edit-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.client-edit-field label {
  font-size: 0.82rem;
  color: var(--muted);
}

.client-edit-field .pdf-input {
  width: 200px;
}

.client-edit-wide .pdf-input {
  width: 320px;
}

.client-edit-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

@media (max-width: 700px) {
  .client-edit-form {
    align-items: stretch;
  }

  .client-edit-field {
    width: 100%;
  }

  .client-edit-field .pdf-input,
  .client-edit-wide .pdf-input {
    width: 100%;
  }
}

.link-danger-btn:hover {
  text-decoration: underline;
}

.save-btn {
  margin-top: 18px;
  background: var(--accent);
  color: #fff;
  border: none;
  padding: 11px 24px;
  border-radius: 980px;
  font-size: 0.92rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s;
}

.save-btn:hover {
  background: var(--accent-hover);
}

/* ---------- quote footer (terms + signatures) ---------- */

.quote-footer {
  margin-top: 26px;
  font-size: 0.95rem;
  line-height: 1.5;
}

.qf-block {
  margin-bottom: 14px;
}

.qf-bold {
  font-weight: 700;
}

/* Grid, not flex: the two signature columns each stack label -> space ->
   line (-> controls), and labels can wrap to a different number of lines
   on each side (e.g. a short "Yours faithfully" next to a longer "I
   accept the above as confirmed order" that wraps on narrow phones).
   "display: contents" un-wraps each .sig-box so its children become grid
   items directly, letting the grid size every row (label/space/line/
   controls) to the taller of the two sides - so the signature space and
   underline always land at the same height on both sides, regardless of
   how many lines either label needs on a given screen. */
.sig-row {
  display: grid;
  grid-template-columns: minmax(0, 320px) minmax(0, 320px);
  column-gap: 48px;
  margin-top: 30px;
}

.sig-box-owner,
.sig-box-customer {
  display: contents;
}

.sig-box-owner .sig-label { grid-column: 1; grid-row: 1; }
.sig-box-customer .sig-label { grid-column: 2; grid-row: 1; }
.sig-box-owner .sig-space { grid-column: 1; grid-row: 2; }
.sig-box-customer .sig-space { grid-column: 2; grid-row: 2; }
.sig-box-owner .sig-line { grid-column: 1; grid-row: 3; }
.sig-box-customer .sig-line { grid-column: 2; grid-row: 3; }
.sig-box-owner .sig-controls { grid-column: 1; grid-row: 4; }
.sig-box-customer .sig-controls { grid-column: 2; grid-row: 4; }

.sig-label {
  margin-bottom: 4px;
}

.sig-space {
  height: 58px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.sig-img {
  max-height: 54px;
  max-width: 100%;
}

.sig-line {
  border-top: 1.5px solid var(--text);
  margin-top: 2px;
}

.sig-controls {
  margin-top: 8px;
}

/* typed, cursive-font signatures (Account page + printed "Yours faithfully" line) */
.sig-font-preview {
  font-family: 'Lobster', cursive;
  color: var(--text);
  line-height: 1;
}

.quote-sig-typed {
  font-size: 2rem;
}

.sig-preview-box {
  min-height: 48px;
  margin-bottom: 6px;
}

.account-sig-preview {
  display: inline-block;
  font-size: 2.6rem;
}

/* "Share with customer" box on the quote detail page */
.share-box {
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  padding: 18px 20px;
  margin-bottom: 28px;
}

.share-box .section-heading {
  margin-top: 0;
}

.share-link-input {
  width: 100%;
  min-width: 220px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.82rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 10px;
  background: var(--bg);
  color: var(--text);
}

.share-create-form {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 14px;
}

.share-create-form label {
  font-size: 0.9rem;
  color: var(--muted);
}


/* ---------- dashboard: light "console" theme ----------
   Scoped to .dash-root, sitting on the app's normal light background -
   professional/data-console in structure (uppercase labels, color-coded
   stat accents, bordered panels) but using the app's normal system font
   and light Apple-style palette throughout, for readability and
   consistency. Font sizes throughout are deliberately a notch larger
   than a typical dashboard for legibility. */

body.dash-page .container {
  max-width: 1180px;
}

.dash-root {
  --dash-good: #1c8a3c;
  --dash-warn: #b8790a;
  margin-bottom: 40px;
}

.dash-root .back-link {
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.dash-console-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 12px;
  margin: 4px 0 10px;
}

.dash-eyebrow {
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 6px;
}

.dash-title {
  margin: 0;
  font-size: 2.3rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.dash-status {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.82rem;
  letter-spacing: 0.03em;
  color: var(--muted);
  padding: 8px 16px;
  border: 1px solid var(--border-faint);
  border-radius: 980px;
  background: var(--card-bg);
  white-space: nowrap;
}

.dash-status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--dash-good);
  box-shadow: 0 0 6px 1px rgba(28, 138, 60, 0.5);
  animation: dash-pulse 2s ease-in-out infinite;
}

@keyframes dash-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
  .dash-status-dot { animation: none; }
}

.dash-panel-label {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 30px 0 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border-faint);
}

.dash-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
  margin-bottom: 10px;
}

@media (max-width: 480px) {
  .dash-stats {
    grid-template-columns: 1fr;
  }
}

.dash-stat {
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-top: 3px solid var(--accent);
  border-radius: 10px;
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}

.dash-stat--good { border-top-color: var(--dash-good); }
.dash-stat--good .dash-stat-value { color: var(--dash-good); }

.dash-stat--bad { border-top-color: var(--danger); }
.dash-stat--bad .dash-stat-value { color: var(--danger); }

.dash-stat--warn { border-top-color: var(--dash-warn); }
.dash-stat--warn .dash-stat-value { color: var(--dash-warn); }

.dash-stat-value {
  display: block;
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  white-space: nowrap;
}

.dash-stat-label {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}

.dash-chart-card {
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-top: 3px solid var(--accent-soft);
  border-radius: 10px;
  padding: 20px 24px 24px;
  margin-bottom: 20px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}

.dash-root .section-heading {
  margin: 0 0 18px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-faint);
  font-size: 0.92rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--accent);
}

.dash-chart {
  width: 100%;
  height: auto;
  overflow: visible;
}

.dash-axis {
  stroke: var(--border);
  stroke-width: 1;
}

.dash-axis-label {
  font-size: 14px;
  fill: var(--muted);
}

.dash-bar-primary {
  fill: var(--accent);
}

.dash-bar-closed {
  fill: var(--dash-good);
}

.dash-bar-lost {
  fill: var(--danger);
}

/* p90 sits behind the median bar as a lighter "how bad does it get" track */
.dash-bar-p90 {
  fill: var(--accent);
  opacity: 0.22;
}

/* projected, not earned - hollow so it can't be misread as actual revenue */
.dash-bar-forecast {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.5;
  stroke-dasharray: 4 3;
}

.dash-col-forecast {
  fill: var(--muted);
}

.dash-trend-line {
  fill: none;
  stroke: var(--dash-warn);
  stroke-width: 2;
  stroke-dasharray: 5 4;
  stroke-linejoin: round;
}

.dash-dot-p90 {
  background: var(--accent);
  opacity: 0.3;
}

.dash-step {
  fill: var(--dash-warn);
  font-weight: 600;
}

/* sample size shown next to any median - a segment figure means nothing
   without the number of jobs behind it, especially on small slices */
.dash-sample {
  fill: var(--muted);
  font-weight: 400;
}

.dash-sample-text {
  color: var(--muted);
  font-size: 0.85em;
}

.dash-good-text {
  color: var(--dash-good);
  font-weight: 600;
}

/* ---------- daily action board (admin only) ---------- */

.today-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 6px 0 20px;
}
.today-pill {
  font-size: 0.78rem;
  font-weight: 600;
  padding: 4px 12px;
  border-radius: 980px;
  white-space: nowrap;
}
.today-pill-critical    { background: rgba(227, 0, 0, 0.10); color: var(--danger); }
.today-pill-today       { background: #fff4de; color: #b8790a; }
.today-pill-warn        { background: rgba(184, 121, 10, 0.10); color: var(--dash-warn); }
.today-pill-opportunity { background: var(--accent-soft); color: var(--accent); }

.today-list { list-style: none; margin: 0 0 26px; padding: 0; display: flex;
              flex-direction: column; gap: 10px; }

.today-item {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 16px 18px;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-left: 4px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}
.today-critical    { border-left-color: var(--danger); }
.today-today       { border-left-color: #b8790a; }
.today-warn        { border-left-color: var(--dash-warn); }
.today-opportunity { border-left-color: var(--accent); }

.today-rank {
  flex: none;
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--bg);
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.today-body { flex: 1; min-width: 0; }
.today-head { display: flex; flex-wrap: wrap; align-items: center; gap: 9px; margin-bottom: 4px; }
.today-title { font-weight: 650; font-size: 1rem; }
.today-tag {
  font-size: 0.68rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
  padding: 2px 8px; border-radius: 980px;
}
.today-tag-critical    { background: rgba(227, 0, 0, 0.10); color: var(--danger); }
.today-tag-today       { background: #fff4de; color: #b8790a; }
.today-tag-warn        { background: rgba(184, 121, 10, 0.10); color: var(--dash-warn); }
.today-tag-opportunity { background: var(--accent-soft); color: var(--accent); }

.today-why { margin: 0 0 5px; color: var(--muted); font-size: 0.92rem; }
.today-do  { margin: 0; font-size: 0.93rem; }
.today-go {
  flex: none; align-self: center;
  font-weight: 600; font-size: 0.9rem;
  color: var(--accent); text-decoration: none; white-space: nowrap;
}
.today-go:hover { text-decoration: underline; }

@media (max-width: 620px) {
  .today-item { flex-wrap: wrap; }
  .today-go { align-self: flex-start; margin-left: 40px; }
}

/* ---------- business blueprint (admin only) ---------- */

.bp-svg { width: 100%; height: auto; min-width: 720px; display: block; }

.bp-box       { fill: var(--card-bg); stroke: var(--border); stroke-width: 1; }
.bp-box-accent{ fill: var(--accent-soft); stroke: var(--accent); stroke-width: 1.2; }
.bp-box-soft  { fill: var(--bg); stroke: var(--border-faint); stroke-width: 1; }
.bp-box-warn  { fill: rgba(184, 121, 10, 0.10); stroke: var(--dash-warn); stroke-width: 1.2; }

.bp-label { font-size: 13px; font-weight: 600; fill: var(--text); }
.bp-plus  { font-size: 20px; font-weight: 600; fill: var(--muted); }
.bp-sub   { font-size: 11px; fill: var(--muted); }

/* capacity bars: what the plant can do vs what the target needs vs today */
.bp-bar-capacity { fill: var(--accent); opacity: .22; }
.bp-bar-used     { fill: var(--accent); }
.bp-bar-now      { fill: var(--dash-good); }

.bp-arrow { stroke: var(--border); stroke-width: 1.5; fill: none; }
.bp-arrow-dash { stroke-dasharray: 5 4; }
.bp-arrowhead { fill: var(--border); }

/* a stated conclusion rather than a passing note - used sparingly */
.callout-strong {
  margin: 18px 0 4px;
  padding: 16px 20px;
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
  border-radius: 0 10px 10px 0;
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--text);
}

/* ---------- menu / home hub ---------- */

.menu-hero { margin: 4px 0 22px; }
.menu-hero h1 { margin-bottom: 6px; }

.menu-section {
  margin: 26px 0 10px;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.menu-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 12px;
}

.menu-tile {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
  text-decoration: none;
  color: var(--text);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.menu-tile:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
}
.menu-tile:active { transform: translateY(0); }

/* the iOS app-icon square: a soft tinted tile with the glyph in its colour */
.menu-icon {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 13px;
}
.menu-icon svg { width: 23px; height: 23px; }

.menu-icon-blue   { background: rgba(0, 113, 227, 0.12);  color: #0071e3; }
.menu-icon-indigo { background: rgba(94, 92, 230, 0.13);  color: #5e5ce6; }
.menu-icon-purple { background: rgba(191, 90, 242, 0.13); color: #a63ad6; }
.menu-icon-orange { background: rgba(255, 149, 0, 0.15);  color: #c77700; }
.menu-icon-red    { background: rgba(255, 59, 48, 0.12);  color: #e0342a; }
.menu-icon-green  { background: rgba(52, 199, 89, 0.15);  color: #1c8a3c; }
.menu-icon-teal   { background: rgba(48, 176, 199, 0.15); color: #1f8ba0; }
.menu-icon-cyan   { background: rgba(100, 210, 255, 0.20); color: #0a84c4; }
.menu-icon-grey   { background: rgba(120, 120, 128, 0.14); color: #6b6b70; }

.menu-tile-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.menu-tile-title { font-weight: 600; font-size: 0.98rem; }
.menu-tile-desc {
  font-size: 0.83rem;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
}
.menu-tile-chevron {
  margin-left: auto;
  font-size: 1.4rem;
  color: var(--border);
  line-height: 1;
}
.menu-tile:hover .menu-tile-chevron { color: var(--muted); }

/* The brand is a link back to the menu. It sits in the dark sidebar head,
   so it must keep the sidebar's own text colour - `color: inherit` dates
   from when this lived in the old light top bar and made the company name
   resolve to the dark body text, near-invisible against #111725. */
a.brand { text-decoration: none; color: var(--sidebar-text-strong); }
a.brand:hover { opacity: 0.85; }

/* multi-material quoting: one price column per material, and a grand total
   per material so the customer can compare (e.g. ENF Blockboard vs Chipboard) */
th.mat-col { white-space: nowrap; }

/* a figure labelled with its material - used wherever a subtotal/grand
   total has to be shown once per material while the customer decides */
.mat-total {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-end;
  margin-left: 22px;
  white-space: nowrap;
}
.mat-total-name {
  font-size: 0.62em;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}
.grand-total-mats { display: inline-flex; align-items: flex-end; }

/* the material a unit was finally built in, on a decided quote */
.chosen-mat {
  margin-left: 10px;
  padding: 2px 10px;
  border-radius: 980px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 0.76rem;
  font-weight: 600;
}

.grand-mat {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-end;
  margin-left: 26px;
}
.grand-mat-name {
  font-size: 0.5em;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}

/* quoted-vs-won price trend lines */
.trend-quoted { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; }
.trend-won { fill: none; stroke: var(--dash-good); stroke-width: 2; stroke-linejoin: round; }
.dot-quoted { fill: var(--accent); }
.dot-won { fill: var(--dash-good); }

.dash-dot-forecast {
  background: none;
  border: 1.5px dashed var(--accent);
}

.dash-dash-key {
  width: 14px;
  height: 0;
  border-top: 2px dashed var(--dash-warn);
  display: inline-block;
}

.dash-stat-unit {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--muted);
  margin-left: 5px;
}

.dash-callout {
  border-left: 3px solid var(--dash-warn);
  padding-left: 12px;
  margin: 0 0 18px;
}

.dash-bar-label {
  font-size: 19px;
  fill: var(--text);
  dominant-baseline: middle;
}

.dash-bar-value {
  font-size: 19px;
  font-weight: 600;
  fill: var(--muted);
  font-variant-numeric: tabular-nums;
  dominant-baseline: middle;
}

/* Data labels printed directly on column/stacked-bar charts (monthly
   sales, price range) so every value is readable at a glance instead
   of needing to hover each bar for its <title> tooltip */
.dash-col-value {
  font-size: 13px;
  font-weight: 600;
  fill: var(--text);
  font-variant-numeric: tabular-nums;
  text-anchor: middle;
}

.dash-seg-value {
  font-size: 13px;
  font-weight: 700;
  fill: #fff;
  font-variant-numeric: tabular-nums;
  text-anchor: middle;
  dominant-baseline: middle;
}

.dash-legend {
  display: flex;
  gap: 18px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}

.dash-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
}

.dash-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  display: inline-block;
}

.dash-dot-closed {
  background: var(--dash-good);
}

.dash-two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}

/* "Sales by user" reuses the shared .admin-table/.price-table - just
   bump the font sizes here to match the rest of the dashboard */
.dash-root .admin-table th {
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.dash-root .admin-table td {
  font-size: 1.05rem;
}

/* Signed / deposit status on the quote detail page - what makes a quote
   a confirmed "order" (see quote_is_order() in app.py) */
.order-status-box {
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  padding: 14px 18px;
  margin-bottom: 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* One row per setting, laid out as two columns: the state badge on the left
   and the controls on the right. Fixing the badge column means every badge
   and every control starts at the same x down the whole panel, instead of
   each row's controls landing wherever that row's badge text happened to
   end. */
.order-status-row {
  display: flex;
  align-items: center;
  gap: 10px 14px;
  flex-wrap: wrap;
  padding: 11px 0;
  border-top: 1px solid var(--border-faint);
}

.order-status-row:first-of-type { border-top: 0; padding-top: 2px; }

/* min-width, not width: the badge text is nowrap, so a fixed width makes a
   long label ("5.0% off - ENF Blockboard") spill out of its own box and
   collide with whatever follows it. This keeps the column lined up for the
   short ones and lets the long ones grow. */
.order-status-row > .order-status-badge {
  flex: 0 0 auto;
  min-width: 148px;
  text-align: center;
}

/* .hint is normally a paragraph with a bottom margin; inside a status row
   it's an inline note beside a badge, so drop that margin - otherwise it's
   counted in the flex line and shoves the text above the badge's centre. */
.order-status-row .hint {
  margin: 0;
}

/* A long explanation used to sit between the badge and the controls and
   push them off to the right edge, so no two rows lined up. It now takes
   its own line under the controls, indented to the control column. */
.order-status-row > .hint {
  flex: 1 1 100%;
  order: 9;
  padding-left: 162px;
  font-size: 0.8rem;
  line-height: 1.5;
}

/* ...except a short note - a date, a reason - which would leave a nearly
   empty row behind it. Those stay on the badge's line. */
.order-status-row > .hint.ostat-inline {
  flex: 0 1 auto;
  order: 0;
  padding-left: 0;
}

/* a quotation inside a week of closing itself is worth noticing */
.quote-expiry-soon { color: var(--danger); font-weight: 550; }

/* the same warning in the reminder panel */
.reminder-item-expiry .reminder-item-title::before {
  content: "\23F1";
  margin-right: 6px;
}

/* the material picker is a whole block, not a one-line setting */
.order-status-row.mat-choice-row,
.order-status-row.cancel-row {
  display: block;
  padding: 14px 0;
}

/* ---------- grouping ---------- */

.ostat-heading {
  margin: 16px 0 0;
  font-size: 0.7rem;
  font-weight: 650;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted-2);
  background: none;
  -webkit-text-fill-color: currentColor;
  width: auto;
}

.ostat-heading:first-child { margin-top: 0; }

/* a heading owns the rows under it, so the first of them needs no rule */
.ostat-heading + .order-status-row { border-top: 0; padding-top: 6px; }

@media (max-width: 640px) {
  .order-status-row > .order-status-badge { width: auto; }
  .order-status-row > .hint { padding-left: 0; }
}

.order-status-badge {
  font-size: 0.78rem;
  font-weight: 600;
  padding: 4px 12px;
  border-radius: 980px;
  white-space: nowrap;
}

.order-status-yes {
  background: #e3f8e9;
  color: #1c8a3c;
}

.order-status-no {
  background: #f0f0f0;
  color: var(--muted);
}

.order-status-lost {
  background: #fdecec;
  color: var(--danger);
}

.order-deposit-form {
  display: flex;
  align-items: center;
  gap: 8px;
}

.order-deposit-form .pdf-input {
  width: 140px;
}

.order-pipeline-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 6px;
}

.order-lost-form {
  display: flex;
  align-items: center;
  gap: 8px;
}

.order-lost-form .pdf-input {
  width: 180px;
}

.order-discount-form {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* 140px left only 97px of usable width once the 32px chevron gutter is
   taken off, which clipped "Percentage (%)" at 102px. */
.order-discount-form select.pdf-input {
  width: 176px;
}

.order-discount-form input.pdf-input {
  width: 100px;
}

/* The markup field shares this form's styling but not its placeholder: 100px
   fits the discount's "Value" and clips "Markup %" mid-word. */
.order-discount-form input[name="markup_percent"].pdf-input {
  width: 132px;
}

/* ---------- payments collected (order finance ledger) ----------
   Collections are situational, not phase-driven - see quote_collected()
   in app.py and QuoteStore.add_payment(). */

.payment-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 28px;
  margin: 4px 0 14px;
}

.payment-figure {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.payment-figure-value {
  font-size: 1.35rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.payment-due {
  color: var(--danger);
}

.payment-settled {
  color: #1c8a3c;
}

.payment-figure-label {
  font-size: 0.8rem;
  color: var(--muted);
}

.payment-bar {
  height: 8px;
  border-radius: 980px;
  background: #e8e8ed;
  overflow: hidden;
  margin-bottom: 18px;
}

.payment-bar-fill {
  display: block;
  height: 100%;
  border-radius: 980px;
  background: #1c8a3c;
}

.payment-note {
  display: block;
  font-size: 0.8rem;
  /* bank refs and the like are often one long unbroken string - break it
     instead of letting it stretch the table (and the page) sideways */
  overflow-wrap: anywhere;
}

.payment-add-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin-top: 16px;
}

.payment-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.payment-field label {
  font-size: 0.82rem;
  color: var(--muted);
}

.payment-field .pdf-input {
  width: 150px;
}

.payment-field-wide .pdf-input {
  width: 220px;
}

@media (max-width: 700px) {
  .payment-add-form {
    align-items: stretch;
  }

  .payment-field {
    width: 100%;
  }

  .payment-field .pdf-input,
  .payment-field-wide .pdf-input {
    width: 100%;
  }
}

/* Subtotal/discount breakdown above the Grand Total bar - visible to
   everyone (including the customer share link) and printed, since it's
   part of what the customer is actually agreeing to pay */
.quote-discount-summary {
  max-width: 900px;
  margin: 0 auto 10px;
  padding: 0 28px;
}

.quote-discount-row {
  display: flex;
  justify-content: space-between;
  font-size: 0.92rem;
  color: var(--muted);
  padding: 3px 0;
}

.quote-discount-row:last-child {
  font-weight: 600;
  color: var(--text);
}

.sig-pad {
  margin-top: 14px;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  padding: 16px 18px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}

#sig-canvas {
  width: 100%;
  max-width: 480px;
  height: 160px;
  border: 1px dashed var(--border);
  border-radius: 10px;
  background: #fff;
  touch-action: none;   /* let fingers draw instead of scrolling the page */
  display: block;
}

.sig-pad-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
}

/* ---------- calendar ---------- */

.calendar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}

.calendar-header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.calendar-nav-btn {
  padding: 8px 14px;
  border-radius: 980px;
  background: #f5f5f7;
  color: var(--text);
  font-size: 0.88rem;
  font-weight: 500;
  text-decoration: none;
  transition: background 0.15s;
}

.calendar-nav-btn:hover {
  background: #e8e8ed;
}

.calendar-add-btn {
  margin-top: 0;
}

.calendar-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  margin-bottom: 20px;
}

.calendar-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.8rem;
  color: var(--muted);
}

.calendar-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
  display: inline-block;
}

.calendar-grid {
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
  margin-bottom: 28px;
}

.calendar-grid-head {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  background: #fafafa;
  border-bottom: 1px solid var(--border-faint);
}

.calendar-weekday {
  padding: 10px 8px;
  text-align: center;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--muted);
}

.calendar-week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

.calendar-day {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0; /* grid items don't shrink below content by default - without
                   this, a long nowrap event title widens the whole column
                   past its 1/7 share and squeezes the days after it */
  min-height: 96px;
  padding: 8px;
  border-right: 1px solid var(--border-faint);
  border-bottom: 1px solid var(--border-faint);
  color: var(--text);
  text-decoration: none;
  transition: background 0.15s;
}

.calendar-day:hover {
  background: var(--bg);
}

.calendar-week .calendar-day:last-child {
  border-right: none;
}

.calendar-day-num {
  font-size: 0.85rem;
  font-weight: 600;
}

.calendar-day-outside {
  color: var(--muted);
  background: #fafafa;
}

.calendar-day-today {
  background: var(--accent-soft);
}

.calendar-day-today .calendar-day-num {
  color: var(--accent);
}

/* public holidays get a warm tint and their name, so days off stand out
   from working days when scheduling */
.calendar-day-holiday {
  background: #fff4e6;
}

.calendar-day-holiday .calendar-day-num {
  color: #b8560a;
}

.calendar-holiday-name {
  font-size: 0.62rem;
  font-weight: 600;
  color: #b8560a;
  line-height: 1.15;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.calendar-dot-holiday {
  background: #f0a04b;
}

.calendar-year-select {
  width: auto;
  padding: 7px 30px 7px 12px;
}

/* ---------- year-at-a-glance view ---------- */

.calendar-year-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
}

.mini-month {
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 14px;
  padding: 12px 14px 14px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}

.mini-month-title {
  display: block;
  margin-bottom: 8px;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--accent);
  text-decoration: none;
}

.mini-month-title:hover {
  text-decoration: underline;
}

.mini-weekdays,
.mini-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

.mini-weekdays span {
  text-align: center;
  font-size: 0.62rem;
  color: var(--muted);
  padding-bottom: 4px;
}

.mini-days {
  gap: 1px;
}

.mini-day {
  position: relative;
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.72rem;
  color: var(--text);
  text-decoration: none;
  border-radius: 6px;
}

.mini-day:hover {
  background: var(--bg);
}

.mini-day-blank {
  visibility: hidden;
}

.mini-day-today {
  background: var(--accent);
  color: #fff;
  font-weight: 700;
}

.mini-day-today:hover {
  background: var(--accent);
}

.mini-day-holiday {
  background: #fff4e6;
  color: #b8560a;
  font-weight: 600;
}

.mini-dot {
  position: absolute;
  bottom: 3px;
  left: 50%;
  transform: translateX(-50%);
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--accent);
}

.mini-day-today .mini-dot { background: #fff; }
.mini-day-holiday .mini-dot { background: #b8560a; }

@media (max-width: 900px) {
  .calendar-year-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 560px) {
  .calendar-year-grid {
    grid-template-columns: 1fr;
  }
}

.calendar-day-events {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.calendar-pill {
  font-size: 0.72rem;
  padding: 2px 6px;
  border-radius: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 500;
}

/* a finished task reads as settled - faded with a tick; an overdue one is
   flagged red, so the month view shows at a glance what ran late */
.calendar-pill-done {
  opacity: 0.6;
}

.calendar-pill-overdue {
  background: rgba(227, 0, 0, 0.12) !important;
  color: var(--danger) !important;
  box-shadow: inset 0 0 0 1px rgba(227, 0, 0, 0.35);
}

.calendar-pill-more {
  font-size: 0.7rem;
  color: var(--muted);
}

.calendar-form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 14px;
  /* Bottom-align the fields so the CONTROLS line up across the row no
     matter how many lines each label takes (a long one like "PIC (who's
     planning/running this)" wraps on narrow screens). This works because
     every field here is just [label, control] with nothing below the
     control - any explanatory hint is placed under the whole grid instead
     (see .calendar-grid-hint), so it can't unbalance the row. */
  align-items: end;
}

/* a hint that explains one field but is placed under the whole grid, so
   it doesn't add height to that field's cell and push the neighbouring
   control out of line */
.calendar-grid-hint {
  margin: -6px 0 0;
}

.calendar-fields {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.calendar-fields .field-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.calendar-fields label {
  font-weight: 600;
  font-size: 0.85rem;
}

.calendar-fields label .hint {
  font-weight: 400;
}

.calendar-fields input,
.calendar-fields textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 0.95rem;
  background: #fff;
  font-family: inherit;
}

/* selects in this form are already .pdf-input (the app's one canonical
   select style) - just stretch them to match their sibling inputs here */
.calendar-fields select.pdf-input {
  width: 100%;
}

/* PICs are picked as pill toggles - an entry can have more than one person
   running it, and a filled pill reads at a glance like the rest of the
   app's rounded controls. The checkbox itself is visually hidden; the
   selected state is the blue fill (driven by JS adding .pic-check-on, with
   :has() as a progressive enhancement). */
.pic-checklist {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 2px 0;
}

.pic-check {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 15px;
  border-radius: 980px;
  background: #ececef;
  color: var(--text);
  font-size: 0.9rem;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
  border: 1px solid transparent;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.pic-check:hover {
  background: #e2e2e6;
}

.pic-check input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}

.pic-check::before {
  content: "";
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 1.5px solid var(--muted);
  flex-shrink: 0;
  transition: background 0.15s, border-color 0.15s;
}

.pic-check.pic-check-on,
.pic-check:has(input:checked) {
  background: var(--accent);
  color: #fff;
}

.pic-check.pic-check-on::before,
.pic-check:has(input:checked)::before {
  border-color: #fff;
  background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 6.2L4.8 8.5L9.5 3.5' stroke='%230071e3' stroke-width='1.8' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/10px no-repeat;
}

.pic-check:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.calendar-fields input[readonly] {
  background: var(--bg);
  color: var(--muted);
}

.calendar-fields textarea {
  resize: vertical;
}

.calendar-add-form {
  max-width: 640px;
}

/* A day's entries are short cards, so a single full-width column left most
   of each line empty and made a busy day a long scroll. Two columns once
   there is room for them; one below that. auto-fit rather than a fixed 2,
   so it collapses on its own at the width where a column would be cramped. */
/* A day's entries are short cards of uneven height. A grid would align them
   into rows, so every card shorter than the tallest one in its row leaves a
   gap underneath it. Column flow packs each column independently instead,
   so cards butt up against each other and the gaps disappear.

   `columns: 420px 2` is column-width then column-count: at most two columns,
   each wanting ~420px, so it drops to one column on a narrow screen without
   needing a media query. Entries are time-ordered, so this reads down the
   left column and then down the right. */
/* ---------- the day as a timetable ----------
   An hour a row, a person a column. A list of cards says what is happening
   today; this says who is doing it and when, which is the question actually
   being asked when several people are booked on the same day. Each chip
   links down to that entry's card, so the buttons stay in one place. */

.day-grid-wrap {
  overflow-x: auto;      /* a wide team scrolls rather than crushing */
  margin-bottom: 24px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--card-bg);
}

.day-grid {
  width: 100%;
  min-width: 520px;
  border-collapse: collapse;
  font-size: 0.78rem;
}

.day-grid th,
.day-grid td {
  border-bottom: 1px solid var(--border-faint);
  border-right: 1px solid var(--border-faint);
  vertical-align: top;
  padding: 4px;
}

.day-grid tr > *:last-child { border-right: none; }
.day-grid tbody tr:last-child > * { border-bottom: none; }

/* the time column stays put while the people scroll past it */
.day-grid .day-grid-hour {
  position: sticky;
  left: 0;
  z-index: 1;
  width: 82px;
  min-width: 82px;
  padding: 8px 10px;
  text-align: right;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--muted);
  background: var(--surface-2);
  border-right: 1px solid var(--border);
  white-space: nowrap;
}

.day-grid thead th {
  padding: 10px;
  text-align: left;
  font-size: 0.72rem;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  min-width: 128px;
}

/* your own column, so you can find yourself in a wide board at a glance */
.day-grid thead th.day-col-mine { color: var(--text); }

.day-col-count {
  display: inline-block;
  min-width: 17px;
  margin-left: 6px;
  padding: 1px 5px;
  border-radius: 9px;
  background: var(--border);
  color: var(--text);
  font-size: 0.65rem;
  font-weight: 700;
  text-align: center;
  letter-spacing: 0;
}

.day-grid tbody td { height: 40px; }

/* the hour it is now, on today's page */
.day-row-now > td,
.day-row-now > .day-grid-hour {
  background: var(--accent-soft);
}

.day-row-now > .day-grid-hour { color: var(--accent); }

.day-row-outside > .day-grid-hour {
  font-size: 0.62rem;
  line-height: 1.3;
  white-space: normal;
}

.day-chip {
  display: block;
  border: 1px solid var(--border-faint);
  border-left: 3px solid var(--cat-color, var(--accent));
  border-radius: 8px;
  padding: 5px 8px;
  background: var(--card-bg);
  color: var(--text);
  text-decoration: none;
  transition: border-color 0.12s, background 0.12s;
}

.day-chip + .day-chip { margin-top: 4px; }

.day-chip:hover {
  background: var(--surface-2);
  border-color: var(--border-strong);
  border-left-color: var(--cat-color, var(--accent));
}

.day-chip-top {
  display: flex;
  align-items: center;
  gap: 5px;
}

/* the status mark: tick done, circle filling for in progress, clock for
   pending. It takes its colour from the status, and inherits the badge's
   colour when it sits inside one. */
.status-mark {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
}

.day-chip .status-mark-done { color: #1c8a3c; }
.day-chip .status-mark-progress { color: #b8790a; }
.day-chip .status-mark-pending { color: var(--muted-2); }

.calendar-status-badge .status-mark {
  width: 12px;
  height: 12px;
  margin-right: 1px;
}

.day-chip-time {
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.day-chip-cat,
.day-chip-client {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.day-chip-cat {
  font-size: 0.72rem;
  font-weight: 600;
}

.day-chip-client {
  display: block;
  font-size: 0.68rem;
  color: var(--muted);
}

/* The card that drops out of the grid when a chip is clicked.

   Its row spans the whole width, and while nothing in it is open the cell
   has no padding, no border and no line box - so an empty detail row is
   genuinely 0px tall and the hours stay evenly spaced.

   Opening is :target, not script: the chip is a plain link to #event-N, so
   it also works arriving from Today's Tasks or Team Job Status, which have
   always linked to …/day/DATE#event-N. */
/* `.day-grid tbody td` is (0,1,2) and sets the 40px hour-cell height, which
   reaches this cell too and propped every closed row open - so this has to
   be at least as specific to undo it */
.day-grid tbody tr.day-detail-row > td {
  height: 0;
  padding: 0;
  border: none;
  line-height: 0;
}

.day-detail { display: none; }

.day-detail:target {
  display: block;
  padding: 10px;
  line-height: 1.5;
  scroll-margin-top: 80px;   /* clear the sticky top bar when linked to */
}

/* the same flash the card used to get, so it is obvious which chip opened */
.day-detail:target > .calendar-event-card {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
  animation: event-flash 1.4s ease-out 1;
}

@media (prefers-reduced-motion: reduce) {
  .day-detail:target > .calendar-event-card { animation: none; }
}

/* ---------- Price List > Add-on types ----------
   The choices a type-priced add-on offers (Door Type: Normal, Shaker,
   Glass), each renamable in place the way a cabinet type is. */

.type-editor {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--card-bg);
  padding: 14px 18px;
  margin-bottom: 12px;
}

.type-editor-name {
  font-size: 0.9rem;
  font-weight: 650;
  margin: 0 0 10px;
}

.type-editor-list {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
}

.type-editor-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 0;
  border-bottom: 1px solid var(--border-faint);
}

.type-editor-list li:last-child { border-bottom: none; }

.type-editor-row,
.type-editor-add {
  display: flex;
  align-items: center;
  gap: 8px;
}

.type-editor-row { flex: 1; min-width: 0; }

.type-editor-row .pdf-input,
.type-editor-add .pdf-input {
  max-width: 260px;
}

.type-editor-add { padding-top: 4px; }

/* splitting a one-rate add-on in two: both names are needed at once, so
   they sit side by side with what each one means above it */
.type-editor-split {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
}

.type-editor-split label {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.type-editor-split .pdf-input { max-width: 220px; }

@media (max-width: 640px) {
  .type-editor-list li { flex-wrap: wrap; }
  .type-editor-row .pdf-input,
  .type-editor-add .pdf-input { max-width: none; flex: 1; }
}

/* Settings > Calendar Board: "following this level" is a footnote to the
   access level above it, not part of its name */
.board-default {
  display: block;
  font-size: 0.72rem;
  font-style: italic;
}

.calendar-event-top-right {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.day-detail-close {
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: var(--muted);
  font-size: 1.1rem;
  line-height: 1;
  text-decoration: none;
}

.day-detail-close:hover {
  background: var(--surface-2);
  color: var(--text);
}

/* Done work stays readable but stops competing with what is still open.
   The text fades, not the whole chip - the tick is the one thing on it
   worth seeing at a glance, so it keeps its full colour. */
.day-chip-done .day-chip-time,
.day-chip-done .day-chip-cat,
.day-chip-done .day-chip-client { opacity: 0.55; }

.day-chip-in_progress {
  background: var(--accent-soft);
  border-color: var(--accent-soft);
}

.calendar-event-list {
  columns: 420px 2;
  column-gap: 12px;
  margin-bottom: 28px;
}

/* a card must never be split across the column break */
.calendar-event-list > * {
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  page-break-inside: avoid;
  margin-bottom: 12px;
  min-width: 0;
}

.calendar-event-card {
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-left: 4px solid var(--cat-color, var(--accent));
  border-radius: 12px;
  padding: 14px 18px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
  scroll-margin-top: 70px;   /* clear the sticky top bar when linked to */
}

/* when arrived at from a reminder (…/day/DATE#event-N), flash the card so
   it's obvious which task was meant */
.calendar-event-card:target {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
  animation: event-flash 1.4s ease-out 1;
}

@keyframes event-flash {
  0%, 40% { background: var(--accent-soft); }
  100% { background: var(--card-bg); }
}

@media (prefers-reduced-motion: reduce) {
  .calendar-event-card:target { animation: none; }
}

/* Title on the left, status badge pinned top right. These cards sit in
   narrow columns, so the row must NOT wrap: a wrapped badge became the only
   item on its line, and space-between then parked it hard left under the
   title. The title block shrinks and wraps internally instead, and the badge
   stays level with the first line of it. */
.calendar-event-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: nowrap;
}

.calendar-event-top > div {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  min-width: 0;      /* or the long title refuses to shrink and shoves the badge out */
}

.calendar-event-top > .calendar-status-badge {
  flex-shrink: 0;
}

.calendar-event-cat {
  font-size: 0.78rem;
  color: var(--muted);
}

.calendar-status-badge {
  font-size: 0.72rem;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 980px;
  background: #f0f0f0;
  color: var(--muted);
  white-space: nowrap;
}

.calendar-status-in_progress {
  background: #fff4de;
  color: #b8790a;
}

.calendar-status-done {
  background: #e3f8e9;
  color: #1c8a3c;
}

/* Project-team chips (Order Management "PIC" column) - the order owner
   plus any invited schedule collaborators */
.pic-chip {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 500;
  padding: 3px 10px;
  margin: 2px 4px 2px 0;
  border-radius: 980px;
  background: #f0f0f0;
  color: var(--muted);
  white-space: nowrap;
}

.pic-chip-owner {
  background: #e7f0ff;
  color: #0a5bd3;
  font-weight: 600;
}

.calendar-event-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  margin-top: 8px;
  font-size: 0.85rem;
  color: var(--muted);
}

/* who the task is for, shown right next to the quotation id so nobody has
   to remember which client an MTQ number belongs to */
.calendar-event-client strong {
  color: var(--text);
  font-weight: 600;
}

.calendar-event-phone {
  color: var(--muted);
  white-space: nowrap;
}

/* how the phase landed against its scheduled end date, and (if late) why */
.calendar-timing {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
  margin-top: 8px;
  font-size: 0.82rem;
}

.calendar-timing-late {
  color: var(--danger);
  font-weight: 600;
}

.calendar-timing-early {
  color: #1c8a3c;
  font-weight: 600;
}

.calendar-timing-date {
  color: var(--muted);
}

.calendar-delay-tag {
  background: #fdecec;
  color: #b42318;
  padding: 2px 10px;
  border-radius: 980px;
  font-weight: 500;
}

.calendar-delay-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 10px 0 2px;
  padding: 10px 12px;
  background: #fff8f8;
  border: 1px solid rgba(227, 0, 0, 0.15);
  border-radius: 10px;
}

.calendar-delay-label {
  font-size: 0.85rem;
  font-weight: 600;
}

.calendar-delay-form select.pdf-input {
  width: 220px;
}

.calendar-delay-form input.pdf-input {
  width: 220px;
}

.calendar-event-notes {
  margin: 10px 0 0;
  font-size: 0.9rem;
  white-space: pre-wrap;
}

.calendar-event-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 8px;
  margin-top: 12px;
}

.calendar-edit-details {
  position: relative;
}

/* once opened, the edit form is much taller than the other action
   buttons - force it onto its own full-width row so it drops below
   them instead of stretching the row and centering everything else
   into the empty space beside it */
.calendar-edit-details[open] {
  flex-basis: 100%;
}

.calendar-edit-details summary {
  cursor: pointer;
  color: var(--accent);
  font-size: 0.85rem;
  list-style: none;
}

.calendar-edit-details summary::-webkit-details-marker {
  display: none;
}

.calendar-edit-details[open] .perm-edit-form {
  margin-top: 12px;
  padding: 14px 16px;
  background: var(--bg);
  border-radius: 12px;
  width: 100%;
}

/* Project Timeline (quote detail page): calendar entries linked to that quote */
.calendar-timeline {
  margin-bottom: 28px;
}

.timeline-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.timeline-item {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 10px 14px;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-left: 4px solid var(--cat-color, var(--accent));
  font-size: 0.9rem;
}

.timeline-item:first-child {
  border-radius: 12px 12px 0 0;
}

.timeline-item:last-child {
  border-radius: 0 0 12px 12px;
}

/* fixed width so every date lines up in its own column and a date range
   can't push the entry title out of alignment with the rows around it */
.timeline-date {
  width: 186px;
  flex-shrink: 0;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* the title column takes what's left - min-width:0 lets it wrap instead
   of forcing the row wider than the card */
.timeline-item > span:not([class]) {
  flex: 1;
  min-width: 0;
  /* a long unbroken title (a pasted URL, a run-on order ref) must break
     rather than push the whole page wider than a phone screen */
  overflow-wrap: anywhere;
}

.timeline-cat {
  color: var(--muted);
  font-size: 0.82rem;
}

.timeline-status {
  margin-left: auto;
  flex-shrink: 0;
}

/* how a phase landed against schedule, shown inline on the timeline */
.timeline-timing {
  margin-left: 6px;
  font-size: 0.78rem;
  font-weight: 600;
}

.timeline-timing-late { color: var(--danger); }
.timeline-timing-early { color: #1c8a3c; }

.timeline-done-date {
  margin-left: 6px;
  font-size: 0.78rem;
  color: var(--muted);
}

.timeline-delay {
  margin-left: 6px;
  font-size: 0.75rem;
  padding: 1px 8px;
  border-radius: 980px;
  background: #fdecec;
  color: #b42318;
}

/* ---------- phones ---------- */

@media (max-width: 640px) {
  .container {
    padding: 22px 14px 130px;
  }

  h1 {
    font-size: 1.55rem;
  }

  /* top nav: collapse the links behind a hamburger toggle instead of
     cramming everything into one row - keeps the bar itself clean, the
     links drop down below it when opened */
  .topbar {
    padding: 10px 16px;
  }

  .brand {
    font-size: 0.9rem;
  }

  .nav-toggle {
    display: inline-flex;
  }

  /* the bell dropdown is too wide to hang off the bell on a phone; drop it
     to a near-full-width sheet under the top bar instead */
  .reminder-panel {
    position: fixed;
    top: 54px;
    left: 10px;
    right: 10px;
    width: auto;
    max-width: none;
    max-height: 76vh;
  }

  .topbar nav {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--chrome);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
    padding: 6px 16px 14px;
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.25);
  }

  .topbar nav.nav-open {
    display: flex;
  }

  .topbar nav a {
    margin-left: 0;
    padding: 12px 2px;
    border-bottom: 1px solid rgba(245, 245, 247, 0.1);
  }

  .topbar nav a:last-child {
    border-bottom: none;
  }

  .topbar nav a.nav-user {
    margin: 4px 0;
  }

  /* in the phone menu the grouped items show expanded: the group name as a
     small section label, its links listed under it (no hover dropdown) */
  .nav-group {
    display: block;
  }

  .nav-group-btn {
    display: block;
    width: 100%;
    text-align: left;
    margin-left: 0;
    padding: 12px 2px 4px;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: rgba(245, 245, 247, 0.5);
    cursor: default;
  }

  .nav-caret {
    display: none;
  }

  .nav-menu {
    display: flex !important;
    position: static;
    min-width: 0;
    padding: 0;
    background: none;
    box-shadow: none;
    border-radius: 0;
  }

  .topbar nav .nav-menu a {
    padding: 12px 2px 12px 14px;
    border-radius: 0;
    border-bottom: 1px solid rgba(245, 245, 247, 0.1);
  }

  /* any data table (price lists, quote rows, saved quotes, breakdowns)
     becomes its own horizontally-scrolling strip instead of blowing out
     the whole page's width - tr/td keep their normal table layout even
     though the <table> itself is now display:block */
  table {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    max-width: 100%;
  }

  /* read-only quote breakdown (Base unit, add-ons): stack each row as
     label/value pairs instead of a horizontally-scrolling table, so every
     field - including Line total - is always fully on screen */
  .breakdown-table {
    overflow-x: visible;
  }

  .breakdown-table thead {
    display: none;
  }

  .breakdown-table,
  .breakdown-table tbody,
  .breakdown-table tr,
  .breakdown-table td {
    display: block;
    width: 100% !important;
  }

  .breakdown-table tr {
    padding: 8px 0;
    border-bottom: 1px solid var(--border-faint);
  }

  .breakdown-table tr:last-child {
    border-bottom: none;
  }

  .breakdown-table td {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    padding: 3px 0;
    border-bottom: none;
    text-align: right;
  }

  .breakdown-table td::before {
    content: attr(data-label);
    color: var(--muted);
    font-size: 0.75rem;
    text-align: left;
    flex-shrink: 0;
  }

  .breakdown-table td.line-total {
    font-weight: 600;
  }

  .admin-room-tabs {
    display: flex;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    white-space: nowrap;
  }

  .admin-room-tabs a {
    flex-shrink: 0;
  }

  .grand-total-bar {
    padding: 14px 16px;
    font-size: 1rem;
  }

  .quote-discount-summary {
    padding: 0 16px;
  }

  .unit-header h2 {
    font-size: 1rem;
  }

  .materials-per-product {
    grid-template-columns: 1fr;
  }

  .dash-two-col {
    grid-template-columns: 1fr;
  }

  .dash-chart-card {
    padding: 16px;
  }

  /* calendar: shrink the day cells/pills to fit 7 columns on a phone -
     rows are still free to grow taller for a busy day rather than cutting
     anything off, same rule as everywhere else on mobile in this app */
  .calendar-header h1 {
    font-size: 1.3rem;
  }

  .calendar-nav-btn {
    padding: 6px 10px;
    font-size: 0.8rem;
  }

  .calendar-weekday {
    padding: 6px 2px;
    font-size: 0.62rem;
  }

  .calendar-day {
    min-height: 62px;
    padding: 4px;
    gap: 2px;
  }

  .calendar-day-num {
    font-size: 0.72rem;
  }

  .calendar-pill {
    font-size: 0.6rem;
    padding: 1px 4px;
    border-radius: 4px;
  }

  .calendar-pill-more {
    font-size: 0.58rem;
  }

  .calendar-event-top {
    align-items: flex-start;
  }

  /* price list tables (cabinet types, add-ons, materials): stack each row
     as label/value pairs instead of a horizontally-scrolling table, same
     as the quote breakdown tables - otherwise the per-material price
     columns run well past the screen edge and there's no visual hint
     more of them are off to the side */
  .price-table thead {
    display: none;
  }

  .price-table,
  .price-table tbody,
  .price-table tr,
  .price-table td {
    display: block;
    width: 100% !important;
  }

  .price-table {
    border-radius: 12px;
  }

  .price-table tr {
    padding: 10px 14px;
    border-bottom: 1px solid var(--border-faint);
  }

  .price-table tr:last-child {
    border-bottom: none;
  }

  .price-table td {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 4px 0;
    border-bottom: none;
  }

  .price-table td::before {
    content: attr(data-label);
    color: var(--muted);
    font-size: 0.75rem;
    flex-shrink: 0;
  }

  .price-table td input[type="number"] {
    width: 130px;
    text-align: right;
  }

  /* the share link is a long URL in a monospace box - its desktop
     min-width would push the stacked row past the screen edge, and it
     has the whole cell width here anyway */
  .price-table td .share-link-input {
    min-width: 0;
  }

  /* Project Timeline rows are one line on desktop; on a phone there's no
     room for a date column beside the title, so the date takes its own
     line above and the badge drops below rather than running off-screen */
  .timeline-item {
    flex-wrap: wrap;
  }

  .timeline-date {
    width: 100%;
  }

  .timeline-status {
    margin-left: 0;
  }


  /* Saved Quotes: show the card list instead of the table, so nothing
     needs a sideways scroll to reach (client, spaces, owner, date, total
     and the View/Edit/Delete actions are all visible at once per card) */
  .quote-table-wrap {
    display: none;
  }

  .quote-cards {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .quote-card {
    background: var(--card-bg);
    border: 1px solid var(--border-faint);
    border-radius: 16px;
    padding: 16px 18px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
  }

  .quote-card-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
    margin-bottom: 10px;
  }

  .quote-card-total {
    font-weight: 600;
  }

  .quote-card-row {
    display: flex;
    justify-content: space-between;
    gap: 14px;
    padding: 7px 0;
    border-bottom: 1px solid var(--border-faint);
    font-size: 0.9rem;
  }

  .quote-card-row:last-of-type {
    border-bottom: none;
  }

  .quote-card-row span:first-child {
    color: var(--muted);
    flex-shrink: 0;
  }

  .quote-card-row span:last-child {
    text-align: right;
  }

  .quote-card-actions {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--border-faint);
    display: flex;
    gap: 10px;
    font-size: 0.9rem;
  }
}

/* ============================================================
   DESIGN SYSTEM LAYER
   Restyles the shared components (page headers, cards, tables,
   forms, buttons, badges) to a modern SaaS look. Purely visual -
   every selector here already existed in the markup, so no
   JavaScript hook, id, form field or template logic is affected.
   Deliberately placed BEFORE the print block so print rules keep
   winning when the quotation is saved as a PDF.
   ============================================================ */

/* ---------- page canvas ---------- */

.container {
  max-width: var(--content-w);
  margin-inline: auto;                  /* centred, not hugging the rail */
  padding: 28px 26px 90px;
  width: 100%;
}

/* data-dense pages get a wider column - the variable keeps the top bar's
   gutters in step so the page title stays aligned with the content below */
body.wide-page { --content-w: 1720px; }
body.dash-page { --content-w: 1720px; }

/* ---------- headings ---------- */

h1 {
  margin: 0 0 4px;
  font-size: 1.6rem;
  font-weight: 650;
  letter-spacing: -0.022em;
  line-height: 1.25;
  /* solid ink instead of the old gradient fill - reads as a product, not a
     marketing page (the gradient is kept only on the sign-in hero) */
  background: none;
  -webkit-background-clip: initial;
  background-clip: initial;
  -webkit-text-fill-color: currentColor;
  color: var(--text);
}

h2 {
  font-size: 1.08rem;
  font-weight: 620;
  letter-spacing: -0.015em;
  color: var(--text);
}

.section-heading {
  font-size: 0.95rem;
  font-weight: 620;
  letter-spacing: -0.01em;
  color: var(--text);
  margin: 22px 0 10px;
  text-transform: none;
}

.hint {
  color: var(--muted);
  font-size: 0.855rem;
  line-height: 1.5;
}

/* ---------- back link ---------- */

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.84rem;
  font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  margin-bottom: 14px;
  transition: color 0.14s;
}

.back-link:hover { color: var(--accent); }

/* ---------- cards ---------- */

.unit-card,
.dash-chart-card,
.settings-card,
.inv-panel,
.client-edit-box,
.order-status-box,
.quote-card,
.jobstat-tile,
.dash-stat {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
}

.dash-chart-card {
  padding: 20px 22px;
  margin-bottom: 16px;
}

.unit-card {
  padding: 0;
  margin-bottom: 14px;
  overflow: hidden;
  transition: box-shadow 0.16s, border-color 0.16s;
}

.unit-card:hover { box-shadow: var(--shadow-sm); }

.unit-header {
  padding: 15px 20px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}

.unit-body { padding: 18px 20px; }

/* settings / menu list rows lift slightly on hover */
.settings-card {
  transition: box-shadow 0.16s, border-color 0.16s, transform 0.16s;
}

.settings-card:hover {
  box-shadow: var(--shadow);
  border-color: var(--border-strong);
  transform: translateY(-1px);
}

/* ---------- stat tiles ---------- */

.dash-stat,
.jobstat-tile {
  padding: 16px 18px;
}

.dash-stat-value,
.jobstat-value {
  font-size: 1.55rem;
  font-weight: 650;
  letter-spacing: -0.025em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.dash-stat-label,
.jobstat-label {
  font-size: 0.78rem;
  font-weight: 500;
  color: var(--muted);
  letter-spacing: 0;
  text-transform: none;
}

.dash-panel-label {
  font-size: 0.7rem;
  font-weight: 650;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-2);
  margin: 26px 0 10px;
}

/* ---------- tables ---------- */

.admin-table,
.rows-table,
.inventory-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--card-bg);
  font-size: 0.875rem;
}

/* No `overflow: hidden` here, deliberately. It clips the rounded corners in
   one line, but an overflow ancestor becomes the scrollport for a sticky
   descendant - so `.admin-table th`'s `top: var(--topbar-h)` stopped
   pinning the header under the page's top bar and instead pushed it 60px
   down *inside the table*, out of its own header row and over the first
   data row. On Property Types that hid the Condominium row and left its
   input floating above the header. The corners are rounded per-cell
   instead (see the .admin-table thead/tbody radius rules above), which is
   why those rules exist. */
.admin-table,
.inventory-table {
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
}

.admin-table th,
.inventory-table th {
  background: var(--surface-2);
  color: var(--muted);
  font-size: 0.73rem;
  font-weight: 620;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  text-align: left;
  padding: 11px 12px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

.admin-table td,
.inventory-table td {
  padding: 12px 12px;
  border-bottom: 1px solid var(--border);
  color: var(--text-2);
  vertical-align: middle;
}

.admin-table tbody tr:last-child td,
.inventory-table tbody tr:last-child td { border-bottom: none; }

.admin-table tbody tr,
.inventory-table tbody tr { transition: background 0.12s; }

.admin-table tbody tr:hover,
.inventory-table tbody tr:hover { background: var(--surface-2); }

.rows-table th {
  background: none;
  color: var(--muted);
  font-size: 0.73rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border);
}

.rows-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-faint);
}

.quotation-id { font-weight: 600; font-variant-numeric: tabular-nums; }
.quotation-id a { color: var(--accent); text-decoration: none; }
.quotation-id a:hover { text-decoration: underline; }

.col-money,
.col-num { font-variant-numeric: tabular-nums; }

/* ---------- forms ---------- */

/* Listed per type because checkbox/radio/file must keep their native look.
   Any typed input NOT named here silently falls back to browser chrome and
   stops matching everything else - which is what happened to the phone field
   on the New Quote page, the only tel input in the app. */
input[type="text"],
input[type="number"],
input[type="date"],
input[type="time"],
input[type="password"],
input[type="search"],
input[type="tel"],
input[type="email"],
input[type="url"],
select,
textarea,
.pdf-input {
  font-family: inherit;
  font-size: 0.875rem;
  color: var(--text);
  background: #fff;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  padding: 8px 11px;
  transition: border-color 0.14s, box-shadow 0.14s;
}

input:focus,
select:focus,
textarea:focus,
.pdf-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}

input::placeholder, textarea::placeholder { color: var(--muted-2); }

label { font-size: 0.855rem; color: var(--text-2); }

.field-row > label,
.calc-field > span {
  font-size: 0.78rem;
  font-weight: 500;
  color: var(--muted);
}

/* ---------- buttons ---------- */

.save-btn,
.add-row-btn,
.danger-btn,
.add-addon-btn {
  font-family: inherit;
  font-weight: 550;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background 0.14s, border-color 0.14s, box-shadow 0.14s, color 0.14s;
}

/* primary */
.save-btn {
  background: var(--accent);
  color: #fff;
  border: 1px solid var(--accent);
  padding: 9px 18px;
  font-size: 0.875rem;
  box-shadow: var(--shadow-xs);
}

.save-btn:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  box-shadow: var(--shadow-sm);
}

/* secondary */
.add-row-btn,
.add-addon-btn {
  background: #fff;
  color: var(--text);
  border: 1px solid var(--border-strong);
  padding: 7px 14px;
  font-size: 0.845rem;
  box-shadow: var(--shadow-xs);
}

.add-row-btn:hover,
.add-addon-btn:hover {
  background: var(--surface-2);
  border-color: var(--muted-2);
}

/* destructive */
.danger-btn {
  background: var(--danger);
  color: #fff;
  border: 1px solid var(--danger);
  padding: 8px 16px;
  font-size: 0.855rem;
}

.danger-btn:hover { background: #b42318; border-color: #b42318; }

.link-danger-btn {
  background: none;
  border: none;
  color: var(--danger);
  font-family: inherit;
  font-size: 0.845rem;
  font-weight: 500;
  padding: 2px 0;
  cursor: pointer;
}

.link-danger-btn:hover { text-decoration: underline; }

.link-btn {
  background: none;
  border: none;
  color: var(--accent);
  font-family: inherit;
  font-size: 0.845rem;
  font-weight: 500;
  cursor: pointer;
  padding: 2px 0;
}

.link-btn:hover { text-decoration: underline; }

/* ---------- badges / pills ---------- */

.order-status-badge,
.calendar-status-badge,
.space-room-badge,
.collect-badge-open,
.pic-chip {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.5;
}

.order-status-yes { background: var(--success-soft); color: var(--success); }
.order-status-no  { background: rgba(102, 112, 133, 0.10); color: var(--muted); }
.order-status-lost { background: var(--danger-soft); color: var(--danger); }

.space-room-badge {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
  text-transform: none;
}

/* ---------- flash messages ---------- */

.flash-stack { margin-bottom: 18px; }

.flash {
  border-radius: var(--r);
  padding: 11px 15px;
  font-size: 0.875rem;
  font-weight: 500;
  border: 1px solid transparent;
  box-shadow: var(--shadow-xs);
}

.flash-success { background: var(--success-soft); color: var(--success); border-color: rgba(9, 146, 80, 0.2); }
.flash-error   { background: var(--danger-soft);  color: var(--danger);  border-color: rgba(217, 45, 32, 0.2); }

/* ---------- toolbar above list tables ---------- */

.table-tools {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

/* ---------- callouts ---------- */

.callout-strong {
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
  border-radius: var(--r);
  padding: 14px 16px;
  font-size: 0.885rem;
  color: var(--text-2);
  margin: 14px 0;
}

/* a callout that is warning about something, not merely explaining it */
.callout-strong.callout-warn {
  background: var(--danger-soft);
  border-left-color: var(--danger);
}

/* wide tables and charts scroll inside their own card rather than pushing
   the whole page sideways - the rail leaves less room than the old full-width
   layout did, so anything oversized has to be contained */
.dash-chart-card { overflow-x: auto; }

/* ---------- grand total bar ---------- */

.grand-total-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  background: var(--card-bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  padding: 16px 20px;
  margin-top: 18px;
  font-size: 1.05rem;
  font-weight: 650;
  color: var(--text);
  box-shadow: var(--shadow-sm);
}

/* ---------- focus visibility (keyboard) ---------- */

a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ---------- motion, but only if the viewer wants it ---------- */

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ============================================================
   CHART LAYER - professional report styling
   Restyles only the presentation of the existing dashboard SVGs
   (fills, corners, label weight, legend). Every class here already
   exists in the chart markup, and no template geometry, value or
   Jinja expression is touched - the numbers plotted are identical.
   ============================================================ */

/* ---------- bars: gradient fill, soft corners, gentle lift ---------- */

.dash-bar-primary,
.dash-bar-closed,
.dash-bar-lost,
.dash-bar-low,
.dash-bar-in,
.dash-bar-out {
  rx: 5px;                                  /* SVG2 rounded corners */
  ry: 5px;
  filter: url(#cg-shadow);
  transition: opacity 0.15s;
}

.dash-bar-primary { fill: url(#cg-blue); }
.dash-bar-closed  { fill: url(#cg-green); }
.dash-bar-lost    { fill: url(#cg-red); }
.dash-bar-in      { fill: url(#cg-green); }
.dash-bar-out     { fill: url(#cg-red); }
.dash-bar-low     { fill: url(#cg-amber); }

/* the "how bad does it get" track sits behind the median bar */
.dash-bar-p90 {
  fill: url(#cg-violet);
  opacity: 0.18;
  rx: 5px;
  ry: 5px;
}

/* a bar the pointer is over reads as selected, the rest recede - makes a
   dense 12-month column chart legible without a tooltip */
.dash-chart:hover .dash-bar-primary,
.dash-chart:hover .dash-bar-closed,
.dash-chart:hover .dash-bar-lost,
.dash-chart:hover .dash-bar-low { opacity: 0.55; }

.dash-chart .dash-bar-primary:hover,
.dash-chart .dash-bar-closed:hover,
.dash-chart .dash-bar-lost:hover,
.dash-chart .dash-bar-low:hover { opacity: 1; }

/* projected, not earned - stays hollow so it can never read as booked work */
.dash-bar-forecast {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.6;
  stroke-dasharray: 5 4;
  rx: 5px;
  ry: 5px;
  filter: none;
}

/* ---------- axis + baseline ---------- */

.dash-axis {
  stroke: var(--border-strong);
  stroke-width: 1;
}

.dash-axis-label {
  font-size: 13.5px;
  font-weight: 500;
  fill: var(--muted);
  letter-spacing: 0.01em;
}

/* ---------- data labels: the figure leads, the category supports ---------- */

/* 13px is the size the 12-month chart is laid out for - anything larger and
   the per-column figures collide (measured: 14px overlaps 5 pairs, 13px none).
   The extra confidence comes from weight and colour, not size. */
.dash-col-value {
  font-size: 13px;
  font-weight: 650;
  fill: var(--text);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.015em;
}

.dash-col-forecast {
  fill: var(--accent);
  font-weight: 600;
}

.dash-bar-value {
  font-size: 19px;
  font-weight: 650;
  fill: var(--text);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.015em;
}

.dash-bar-label {
  font-size: 18px;
  font-weight: 500;
  fill: var(--text-2);
}

.dash-seg-value {
  font-weight: 650;
  fill: #fff;
  font-variant-numeric: tabular-nums;
}

/* ---------- trend line ---------- */

.dash-trend-line {
  fill: none;
  stroke: #b45309;
  stroke-width: 2.4;
  stroke-dasharray: 7 5;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: url(#cg-shadow);
}

/* ---------- legend ---------- */

.dash-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  align-items: center;
  margin: 2px 0 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}

.dash-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 0.78rem;
  font-weight: 550;
  color: var(--muted);
  letter-spacing: 0.01em;
  text-transform: none;
}

.dash-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
  box-shadow: 0 0 0 2.5px rgba(37, 99, 235, 0.12);
}

/* ---------- card header: an eyebrow, a title, a live status ---------- */

.dash-chart-card > h2,
.dash-chart-card > .section-heading {
  font-size: 0.98rem;
  font-weight: 650;
  color: var(--text);
  letter-spacing: -0.015em;
  text-transform: none;
  margin: 0 0 4px;
}

.dash-eyebrow {
  font-size: 0.7rem;
  font-weight: 650;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.dash-title {
  font-size: 1.5rem;
  font-weight: 650;
  letter-spacing: -0.022em;
  color: var(--text);
  background: none;
  -webkit-text-fill-color: currentColor;
}

/* the "synced / live" chip on report headers */
.dash-status {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 0.76rem;
  font-weight: 550;
  color: var(--muted);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 5px 12px;
}

.dash-status-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--success);
  box-shadow: 0 0 0 3px var(--success-soft);
}

/* ---------- stat tiles: a coloured cap reads as a KPI ---------- */

.dash-stat {
  border-top: 3px solid var(--accent);
  padding-top: 15px;
}

.dash-stat--good { border-top-color: var(--success); }
.dash-stat--good .dash-stat-value { color: var(--success); }
.dash-stat--bad  { border-top-color: var(--danger); }
.dash-stat--bad  .dash-stat-value { color: var(--danger); }
.dash-stat--warn { border-top-color: var(--warn); }
.dash-stat--warn .dash-stat-value { color: var(--warn); }

.dash-stat-unit {
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--muted);
  margin-left: 3px;
}

/* ---------- the sample-size footnote under a chart ---------- */

.dash-sample,
.dash-sample-text {
  font-size: 0.8rem;
  color: var(--muted);
}

/* charts never print with a shadow filter - it rasterises badly */
@media print {
  .dash-bar-primary, .dash-bar-closed, .dash-bar-lost,
  .dash-bar-in, .dash-bar-out, .dash-trend-line { filter: none !important; }
}

/* ============================================================
   PHASE 2 - page-level polish
   Quote entry workflow, add-on sections, inventory scannability
   and form layout. Presentation only: every selector already
   exists in the markup and no template logic is involved.
   ============================================================ */

/* ---------- running-total action bar (quote entry) ----------
   It is position:fixed and was centred across the whole viewport
   (left:0/right:0/max-width:900px/margin:auto). With a rail on the left
   that left it 13px out of line with the page content, so it is anchored
   to the content column instead and reads as a proper bottom action bar. */

.grand-total-bar:not(.static) {
  left: var(--sidebar-w);
  right: 0;
  max-width: none;
  margin: 0;
  border: none;
  border-top: 1px solid var(--border);
  border-radius: 0;
  padding: 14px 26px;
  background: rgba(255, 255, 255, 0.92);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  color: var(--text);
  box-shadow: 0 -4px 18px rgba(16, 24, 40, 0.07);
}

/* the rail goes off-canvas below this width, so the bar spans everything */
@media (max-width: 1024px) {
  .grand-total-bar:not(.static) { left: 0; }
}

/* enough room that the fixed bar can never sit permanently on top of the
   last row of content (bar is ~83px tall) */
body.has-total-bar .container,
.container { padding-bottom: 130px; }

/* the quote detail page's copy is static, so it keeps the card treatment */
.grand-total-bar.static {
  position: static;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  background: var(--card-bg);
  color: var(--text);
  box-shadow: var(--shadow-sm);
  padding: 16px 20px;
}

/* ---------- unit cards: a clearer open/closed state ---------- */

.unit-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  cursor: pointer;
  transition: background 0.14s;
}

.unit-header:hover { background: #f2f4f7; }

.unit-header h2 {
  font-size: 0.95rem;
  font-weight: 620;
  color: var(--text);
  margin: 0;
}

/* the caret that marks a collapsed card */
.unit-card .unit-header::after {
  content: "";
  width: 7px;
  height: 7px;
  flex-shrink: 0;
  border-right: 1.8px solid var(--muted);
  border-bottom: 1.8px solid var(--muted);
  transform: rotate(45deg);
  transition: transform 0.18s;
  margin-left: 2px;
}

.unit-card.collapsed .unit-header::after { transform: rotate(-45deg); }

/* an open card is visibly the one being worked on */
.unit-card:not(.collapsed) {
  border-color: var(--border-strong);
  box-shadow: var(--shadow);
}

/* a unit that already carries a figure gets a subtle marker */
.unit-header-subtotal {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  text-align: right;
  margin-left: auto;
}

.unit-header-subtotal.has-value { color: var(--text); }

/* ---------- entry rows ---------- */

/* the same padding as every other field, so a measurement box in the quote
   builder is the same size as the boxes on every other page */
.rows-table input[type="number"],
.rows-table input[type="text"],
.rows-table select {
  padding: 8px 11px;
  font-variant-numeric: tabular-nums;
}

.rows-table tbody tr { transition: background 0.12s; }
.rows-table tbody tr:hover { background: var(--surface-2); }

.line-total {
  font-weight: 620;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* duplicate / remove row controls stay quiet until hovered */
.dup-row-btn,
.remove-row-btn {
  background: none;
  border: 1px solid transparent;
  border-radius: 6px;
  color: var(--muted-2);
  cursor: pointer;
  font-size: 0.95rem;
  line-height: 1;
  padding: 4px 7px;
  transition: color 0.14s, background 0.14s, border-color 0.14s;
}

.dup-row-btn:hover { color: var(--accent); background: var(--accent-soft); }
.remove-row-btn:hover { color: var(--danger); background: var(--danger-soft); }

/* ---------- add-on blocks ---------- */

.addon-section,
.addon-block {
  border-top: 1px solid var(--border);
  padding-top: 14px;
  margin-top: 16px;
}

.addon-title,
.addon-label {
  font-size: 0.8rem;
  font-weight: 620;
  letter-spacing: 0.045em;
  text-transform: uppercase;
  color: var(--muted);
}

.addon-table th {
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted-2);
  font-weight: 600;
  padding: 5px 10px;
  border-bottom: 1px solid var(--border);
}

.addon-table td { padding: 7px 10px; border-bottom: 1px solid var(--border-faint); }

/* ---------- unit + space subtotals ---------- */

.unit-subtotal {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: 12px;
  flex-wrap: wrap;
  font-size: 0.885rem;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  padding-top: 12px;
  margin-top: 12px;
  border-top: 1px solid var(--border);
}

/* The unit header has a 20px gutter but the table and the subtotal below it
   sat flush to the card, so the money ran into the border and nothing lined
   up with the unit's title. Give the outer columns the same gutter. */
.unit-card > .breakdown-table th:first-child,
.unit-card > .breakdown-table td:first-child { padding-left: 20px; }

.unit-card > .breakdown-table th:last-child,
.unit-card > .breakdown-table td:last-child { padding-right: 20px; }

.unit-card > .unit-subtotal {
  padding-right: 20px;
  padding-left: 20px;
}

/* An add-on's name ("Drawer", "Stone") is a direct child of the card, so it
   was the one label still sitting against the border once the table and the
   subtotal took the header's gutter. */
.unit-card > .addon-name-heading {
  padding-left: 20px;
  padding-right: 20px;
}

@media (max-width: 640px) {
  /* stacked rows are blocks, so the gutter belongs to the row not the cell */
  .unit-card > .breakdown-table th:first-child,
  .unit-card > .breakdown-table td:first-child,
  .unit-card > .breakdown-table th:last-child,
  .unit-card > .breakdown-table td:last-child { padding-left: 0; padding-right: 0; }

  .unit-card > .breakdown-table tr { padding-left: 14px; padding-right: 14px; }
  .unit-card > .unit-subtotal,
  .unit-card > .addon-name-heading { padding-left: 14px; padding-right: 14px; }
}

.space-subtotal {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 13px 18px;
  margin-top: 14px;
}

/* a figure per material, labelled above the amount */
.mat-total {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1.25;
}

.mat-total-name {
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted-2);
}

/* ---------- inventory: built to be scanned ---------- */

.inventory-table td { padding: 11px 12px; }

.inv-panel {
  padding: 18px 20px;
  margin-bottom: 16px;
}

.inv-panel > summary {
  font-size: 0.92rem;
  font-weight: 620;
  color: var(--text);
  cursor: pointer;
  list-style: none;
}

.inv-panel > summary::-webkit-details-marker { display: none; }

.inv-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px;
  margin-top: 14px;
}

/* stock figures read as data, not prose */
.inv-qty,
.inv-stock,
.stock-cell { font-variant-numeric: tabular-nums; font-weight: 600; }

/* ---------- forms: aligned label/field pairs ---------- */

.field-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 14px;
}

.field-row > label {
  font-size: 0.78rem;
  font-weight: 550;
  color: var(--muted);
}

.client-edit-form,
.inline-form { gap: 10px; }

.client-edit-box { padding: 18px 20px; }

/* ---------- the space / property choosers (workflow steps) ---------- */

.space-card,
.property-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
  transition: box-shadow 0.16s, border-color 0.16s, transform 0.16s;
}

.space-card:hover,
.property-card:hover {
  box-shadow: var(--shadow);
  border-color: var(--accent);
  transform: translateY(-2px);
}

/* ---------- order / status panel on a saved quote ---------- */

.order-status-box { padding: 18px 20px; }

.order-status-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 11px 0;
  border-bottom: 1px solid var(--border-faint);
}

.order-status-row:last-child { border-bottom: none; }

/* ---------- payments / collection progress ---------- */

.collect-bar {
  display: block;
  height: 5px;
  border-radius: 3px;
  background: var(--border);
  overflow: hidden;
  margin-top: 5px;
}

.collect-bar-fill {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: linear-gradient(90deg, #34d399, #059669);
}

/* ============================================================
   PHASE 3 - calendar, blueprint, settings + the responsive pass
   Presentation only. Every selector already exists in the markup;
   no template, route or script is involved.
   ============================================================ */

/* ---------- settings list ---------- */

.settings-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 720px;
}

.settings-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 15px 18px;
  text-decoration: none;
}

.settings-title {
  display: block;
  font-size: 0.92rem;
  font-weight: 620;
  color: var(--text);
}

.settings-desc {
  display: block;
  font-size: 0.82rem;
  color: var(--muted);
  line-height: 1.45;
}

.settings-chevron {
  margin-left: auto;
  color: var(--muted-2);
  font-size: 0.75rem;
  flex-shrink: 0;
}

.icon-tile {
  border-radius: 10px;
  box-shadow: var(--shadow-xs);
}

/* ---------- calendar ---------- */

.calendar-toolbar,
.calendar-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.calendar-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 7px 14px;
  margin-bottom: 16px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
  font-size: 0.78rem;
  color: var(--muted);
}

/* the month grid reads as one card */
.calendar-grid,
.calendar-table {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--shadow-xs);
}

.calendar-grid th,
.calendar-table th {
  background: var(--surface-2);
  color: var(--muted);
  font-size: 0.7rem;
  font-weight: 620;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 9px 6px;
  border-bottom: 1px solid var(--border);
}

.calendar-day,
.calendar-grid td,
.calendar-table td {
  border: 1px solid var(--border-faint);
  vertical-align: top;
  transition: background 0.12s;
}

.calendar-day:hover { background: var(--surface-2); }

/* today stands out without shouting */
.calendar-today,
.calendar-day.is-today {
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1.5px var(--accent);
}

.calendar-daynum,
.calendar-date { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }

.calendar-outside .calendar-daynum,
.calendar-day-muted { color: var(--muted-2); font-weight: 500; }

/* event chips */
.calendar-event,
.calendar-chip {
  display: block;
  border-radius: 6px;
  padding: 3px 6px;
  font-size: 0.7rem;
  font-weight: 550;
  line-height: 1.35;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: filter 0.12s;
}

.calendar-event:hover,
.calendar-chip:hover { filter: brightness(0.94); }

.calendar-status-badge {
  font-size: 0.68rem;
  font-weight: 600;
  padding: 2px 8px;
}

.calendar-status-done { background: var(--success-soft); color: var(--success); }
.calendar-status-pending { background: rgba(102, 112, 133, 0.10); color: var(--muted); }
.calendar-status-in_progress { background: var(--accent-soft); color: var(--accent); }

/* ---------- blueprint: flow charts + comparison bars ---------- */

.bp-svg { width: 100%; height: auto; }

.bp-box {
  fill: #fff;
  stroke: var(--border-strong);
  stroke-width: 1.2;
}

.bp-box-accent {
  fill: var(--accent-soft);
  stroke: var(--accent);
  stroke-width: 1.4;
}

.bp-box-soft { fill: var(--surface-2); stroke: none; }

.bp-label { font-weight: 620; fill: var(--text); }
.bp-sub { fill: var(--muted); }
.bp-plus { font-size: 22px; font-weight: 600; fill: var(--muted-2); }

.bp-arrow {
  stroke: var(--muted-2);
  stroke-width: 1.3;
  fill: none;
}

/* the capacity comparison bars - gradient, to match the dashboard charts */
.bp-bar-capacity { fill: var(--accent-soft); }
.bp-bar-used { fill: url(#cg-blue); rx: 5px; ry: 5px; }
.bp-bar-now { fill: url(#cg-green); rx: 5px; ry: 5px; }

.bp-vision { border-top: 3px solid var(--accent); }

/* ---------- the "showing only ..." focus bar ---------- */

.focus-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  background: var(--accent-soft);
  border: 1px solid rgba(37, 99, 235, 0.22);
  border-radius: var(--r);
  padding: 11px 15px;
  font-size: 0.865rem;
  margin-bottom: 16px;
}

/* ============================================================
   RESPONSIVE PASS
   ============================================================ */

/* ---------- tablet (rail off-canvas, content full width) ---------- */

@media (max-width: 1024px) {
  .container { padding: 22px 20px 130px; }

  .topbar { padding: 0 18px; gap: 10px; }

  /* a long page title must not shove the bell off the bar */
  .topbar-title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
  }

  /* a scrim behind the open rail, so the page behind reads as inactive.
     Pure CSS off the existing .nav-open class - no script change. */
  .sidebar::after {
    content: "";
    position: fixed;
    inset: 0 var(--sidebar-w) 0 0;
    background: rgba(15, 23, 41, 0.4);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.24s;
  }

  .sidebar:has(#site-nav.nav-open)::after { opacity: 1; pointer-events: auto; }

  /* the bell sits at the right of the bar, so the panel opens leftward and
     is capped to the screen so it can never cause a sideways scroll */
  .reminder-panel {
    right: 0;
    left: auto;
    width: min(340px, calc(100vw - 20px));
    max-height: 70vh;
    overflow-y: auto;
  }
}

/* ---------- phones ---------- */

@media (max-width: 640px) {
  .container { padding: 18px 14px 190px; }

  h1 { font-size: 1.35rem; }
  h2 { font-size: 1rem; }
  .dash-title { font-size: 1.25rem; }

  .topbar { padding: 0 12px; }
  .topbar-title { font-size: 0.83rem; }

  /* the total bar carries two material columns on a phone, so it is taller -
     the container padding above has to clear it */
  .grand-total-bar:not(.static) {
    padding: 12px 14px;
    font-size: 0.95rem;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
  }

  /* cards get their breathing room from the page, not from themselves */
  .dash-chart-card { padding: 15px 14px; }
  .unit-body { padding: 14px; }
  .unit-header { padding: 13px 14px; }
  .inv-panel { padding: 15px 14px; }
  .order-status-box { padding: 15px 14px; }
  .space-subtotal { padding: 11px 14px; }

  /* a unit name should not wrap mid-word next to its figures */
  .unit-header h2 { font-size: 0.9rem; }
  .unit-header-subtotal { font-size: 0.72rem; }

  /* KPI tiles two-up instead of one long column */
  .dash-stats,
  .jobstat-tiles {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
  }

  .dash-stat, .jobstat-tile { padding: 13px 14px; }
  .dash-stat-value, .jobstat-value { font-size: 1.25rem; }

  /* forms go full width - no half-width fields on a narrow screen */
  .inv-form,
  .calc-grid,
  .plan-walls { grid-template-columns: 1fr; }

  input, select, textarea, .pdf-input { width: 100%; }

  /* keep the inline row controls usable as touch targets */
  .dup-row-btn, .remove-row-btn { padding: 7px 10px; }

  .save-btn, .danger-btn { width: 100%; justify-content: center; }

  .inline-form .save-btn,
  .inline-form .add-row-btn,
  .row-actions .save-btn { width: auto; }

  /* legends and toolbars stack rather than squeeze */
  .table-tools { flex-direction: column; align-items: stretch; }
  .table-tools > * { width: 100%; }

  /* Turning the toolbar into a column swings the main axis to vertical, so
     the earlier `flex: 1 1 100%` on these controls stops being a width and
     becomes a *height* basis - it then outranks their 38px height and the
     shrink factor collapses them to content height. Pinning the basis back
     to auto hands sizing to the height rule again. */
  .table-tools > .pdf-input,
  .table-tools > .tools-search,
  .table-tools > select { flex: 0 0 auto; }

  /* saved-quote controls: these were fixed-width rows that pushed the page to
     543px on a 375px screen - they stack and fill the width instead */
  .mat-choice,
  .mat-choice-head,
  .order-discount-form,
  .order-deposit-form,
  .cancel-form,
  .pdf-bar {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    width: 100%;
    max-width: 100%;
    min-width: 0;
  }

  .order-discount-form > *,
  .order-deposit-form > * { width: 100%; }

  .mat-choice-head { flex-direction: row; flex-wrap: wrap; align-items: center; }

  /* the material picker table scrolls rather than stretching the page */
  .mat-change .table-scroll,
  .mat-choice .table-scroll { overflow-x: auto; max-width: 100%; }

  .pdf-hint { width: 100%; }

  /* anything else in the status panel wraps by default */
  .order-status-row > * { min-width: 0; max-width: 100%; }
  .order-pipeline-actions { display: flex; flex-wrap: wrap; gap: 8px; width: 100%; }

  /* charts stay legible: labels scale up slightly against a narrow viewBox */
  .dash-col-value { font-size: 15px; }
  .dash-axis-label { font-size: 15px; }
  .dash-bar-label, .dash-bar-value { font-size: 21px; }
}

/* ---------- very narrow phones ---------- */

@media (max-width: 359px) {
  .dash-stats,
  .jobstat-tiles { grid-template-columns: 1fr; }
  .container { padding-left: 12px; padding-right: 12px; }
}

/* ---------- pointer-coarse: bigger hit areas on touch ---------- */

@media (pointer: coarse) {
  #site-nav > a,
  .nav-menu a { padding-top: 11px; padding-bottom: 11px; }
  .settings-card { padding: 17px 18px; }
}

/* ============================================================
   NO SIDEWAYS SCROLLING ON A PHONE
   Everything that previously needed a horizontal drag now stacks
   or scales to fit. Presentation only - no markup or logic change.
   ============================================================ */

@media (max-width: 640px) {

  /* ---- segmented material choices ----
     "ENF Blockboard · RM 7,562.51" and "Chipboard · RM 5,800.05" sat side by
     side: ~470px of content in a 287px cell, which is what forced the quote
     page to scroll. Stacked, they also become full-width tap targets. */
  .inv-seg {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    width: 100%;
    min-width: 0;
  }

  .inv-seg-opt {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid var(--border-strong);
    border-radius: var(--r-sm);
    background: #fff;
    white-space: normal;
  }

  .inv-seg-opt span {
    white-space: normal;
    word-break: break-word;
    font-size: 0.85rem;
  }

  /* the checked option reads as chosen */
  .inv-seg-opt:has(input:checked) {
    border-color: var(--accent);
    background: var(--accent-soft);
    font-weight: 600;
  }

  /* ---- any table whose cells carry a data-label stacks ----
     The .price-table pattern already did this; this extends it to every
     labelled table (accounts, dashboard segments) so none of them scroll. */
  .admin-table:has(td[data-label]) thead { display: none; }

  .admin-table:has(td[data-label]),
  .admin-table:has(td[data-label]) tbody,
  .admin-table:has(td[data-label]) tr {
    display: block;
    width: 100%;
  }

  .admin-table:has(td[data-label]) tr {
    padding: 10px 12px;
    border-bottom: 1px solid var(--border-faint);
  }

  .admin-table:has(td[data-label]) tr:last-child { border-bottom: none; }

  .admin-table:has(td[data-label]) td {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-width: 0;
    padding: 5px 0;
    border-bottom: none;
    text-align: left;
  }

  .admin-table:has(td[data-label]) td::before {
    content: attr(data-label);
    color: var(--muted);
    font-size: 0.72rem;
    font-weight: 600;
    flex-shrink: 0;
  }

  /* a cell holding a stacked control needs the label above, not beside */
  .admin-table:has(td[data-label]) td:has(.inv-seg) {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
  }

  /* ---- blueprint flow charts ----
     These are wide diagrams whose box positions are fixed in the viewBox, so
     CSS cannot reflow them into a column. Squashed to a 375px screen they
     render at 35% scale with ~7px labels - unreadable. Held at 620px instead
     they stay legible (~12px effective) and swipe inside their own bordered
     card, which is contained: the page itself never moves sideways. */
  .bp-svg { min-width: 620px; width: 100%; }

  .bp-label { font-size: 18px; }
  .bp-sub { font-size: 15px; }
  .bp-plus { font-size: 26px; }

  /* tables stack, so their wrapper must not scroll... */
  .table-scroll { overflow-x: visible; max-height: none; }

  /* ...but a wrapper holding a flow chart is the one place a contained
     sideways swipe is the right answer, and it is signposted as such */
  .table-scroll:has(.bp-svg) {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--surface-2);
    padding: 8px;
  }

  .table-scroll:has(.bp-svg)::after {
    content: "swipe the diagram to see it all";
    display: block;
    padding-top: 6px;
    font-size: 0.7rem;
    color: var(--muted-2);
    text-align: center;
    position: sticky;
    left: 0;
  }

  /* ---- room tabs wrap instead of scrolling ---- */
  .admin-room-tabs {
    display: flex;
    flex-wrap: wrap;
    overflow-x: visible;
    white-space: normal;
    gap: 6px;
  }

  .admin-room-tabs a { flex-shrink: 1; }

  /* ---- permissions editor on the accounts page ---- */
  .perm-edit-form,
  .perm-checklist {
    width: 100%;
    min-width: 0;
    overflow: visible;
  }

  .perm-checklist {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .pdf-check {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    white-space: normal;
    min-width: 0;
  }

  .pdf-check span { white-space: normal; }

  /* ---- a global safety net ----
     nothing in the page body may be wider than the screen; long strings wrap
     instead of pushing the layout sideways */
  .container,
  .container * { max-width: 100%; }

  .container table { table-layout: auto; }

  td, th, p, span, div, label, a { min-width: 0; overflow-wrap: break-word; }

  /* long ids/emails wrap rather than extend the row */
  .quotation-id, .source-quote { overflow-wrap: anywhere; }
}

/* ============================================================
   SIGN-IN PAGE
   The mark and company name centred over the form - the layout the
   system used before, carried onto the new design system.
   ============================================================ */

/* signed out there is no nav, so the (empty) top bar is just a white strip */
.app-shell:not(:has(#site-nav)) .topbar { display: none; }

body.login-page .container {
  max-width: 420px;
  margin-inline: auto;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 40px 20px 60px;
}

body.login-page .login-wrap { width: 100%; }

body.login-page .brand-hero {
  text-align: center;
  margin-bottom: 24px;
}

/* Size and centring only - the gold stays the original satin fill from
   .hero-logo (a gentle tonal shift, no bright specular highlight), so the
   mark reads the same here as it always did. */
body.login-page .hero-logo {
  display: block;
  width: 76px;
  margin: 0 auto 18px;
}

/* The global h1 is width: fit-content, so it only sits centred while its
   side margins stay auto - a plain `margin: 0 0 6px` here silently pins
   the company name to the left edge even though .brand-hero is centred. */
body.login-page .hero-company {
  margin: 0 auto 6px;
  font-size: 1.55rem;
  font-weight: 650;
  letter-spacing: -0.025em;
  color: var(--text);
  background: none;
  -webkit-text-fill-color: currentColor;
}

body.login-page .hero-sub {
  margin: 0;
  font-size: 0.9rem;
  color: var(--muted);
}

/* "Signed out." and friends read as part of the centred stack here,
   not as a left-aligned page notice */
body.login-page .flash-stack { margin-bottom: 18px; }
body.login-page .flash-stack > * { text-align: center; }

body.login-page .login-form {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
  padding: 24px;
}

body.login-page .login-form .field-row { margin-bottom: 14px; }

body.login-page .login-form input {
  width: 100%;
  padding: 10px 12px;
  font-size: 0.95rem;
}

body.login-page .login-form .save-btn {
  width: 100%;
  margin-top: 6px;
  padding: 11px 18px;
  font-size: 0.95rem;
}

@media (max-width: 640px) {
  body.login-page .container { padding: 28px 16px 50px; min-height: 0; }
  body.login-page .hero-logo { width: 64px; }
  body.login-page .hero-company { font-size: 1.35rem; }
}

/* ============================================================
   SELECT CONTROLS
   Native selects kept the OS arrow and sat oddly against the rest
   of the system. Same shell as the text inputs, with one drawn
   chevron so every dropdown in the app matches.
   ============================================================ */

select,
select.pdf-input {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-color: #fff;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 15px 15px;
  padding-right: 32px;
  cursor: pointer;
  color: var(--text);
  font-family: inherit;
  font-size: 0.875rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  transition: border-color 0.14s, box-shadow 0.14s, background-color 0.14s;
}

select:hover:not(:disabled) {
  border-color: var(--muted-2);
  background-color: var(--surface-2);
}

select:focus,
select.pdf-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
  background-color: #fff;
}

select:disabled {
  background-color: var(--surface-2);
  color: var(--muted-2);
  cursor: not-allowed;
  opacity: 1;
}

/* a select that has an active filter reads as "on" */
select[data-tools-filter]:not([data-empty]) { font-weight: 500; }

/* The toolbar above a list: the search box and the filter selects must
   read as one set, so they share a height, a border colour and a radius.
   The type-qualified selectors are deliberate - the canonical
   input[type="search"].pdf-input block earlier in this file carries
   (0,1,2) specificity and sets its own 10px radius and lighter border,
   so anything weaker than that loses and the search box drifts away
   from the selects it sits beside. */
   No height or font-size here on purpose: left to the shared .pdf-input
   padding, these controls come out the same size as every other control in
   the app. Forcing a toolbar-only height is what made the filters on the
   list pages sit 1.7px shorter, in a slightly larger font, than the
   identical-looking selects everywhere else. */
.table-tools .pdf-input,
.table-tools select,
.table-tools input[type="search"],
.table-tools input[type="search"].pdf-input,
.table-tools input[type="search"].tools-search,
.table-tools select.pdf-input {
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
}

/* the magnifier still needs its gutter, and the chevron needs its own */
.table-tools input[type="search"].tools-search { padding-left: 34px; }
.table-tools select,
.table-tools select.pdf-input { padding-right: 32px; }

.table-tools input[type="search"] { min-width: 240px; }

.table-tools .tools-count {
  margin-left: auto;
  font-size: 0.8rem;
  color: var(--muted);
  white-space: nowrap;
}

/* The closed control is entirely ours (see the field rules above). The list
   that opens is drawn by the browser, and only its colours can be reached
   from CSS - the row padding, the corner radius and the blue highlight on
   the active row are the platform's, not ours. This at least keeps the list
   on the app's own surface and text colours. */
select option {
  background: var(--card-bg);
  color: var(--text);
}

select optgroup {
  color: var(--muted);
  font-style: normal;
}

/* multi-line selects (size > 1) are lists, not dropdowns - no chevron */
select[size]:not([size="1"]),
select[multiple] {
  background-image: none;
  padding-right: 11px;
  cursor: default;
}

/* ============================================================
   SETTINGS PANELS
   Settings pages used to be a full-width heading and paragraph followed
   by a card pinned to 480px by an inline style, which left the text
   running edge-to-edge past a narrow card and a lot of dead space to its
   right. Each section now carries its own title and description inside
   the card, and the cards share one grid so they line up and fill the
   width instead of stacking down the left edge.

   Named "panel", not "card": .settings-card is already the tile on the
   Settings landing page and centres its contents, which squeezes form
   rows to their intrinsic width.
   ============================================================ */

.setting-panels {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
  gap: 20px;
  align-items: start;
  max-width: var(--settings-w);
  margin-top: 18px;
}

/* Anything following the panels shares their width: the panels are capped
   and the container is not, so without this a trailing note runs wider than
   the cards it belongs to. */
.setting-panels ~ .form-actions,
.setting-panels ~ .hint,
.setting-panels ~ .callout-strong {
  max-width: var(--settings-w);
}

/* The page-level Save sits at the left, under the cards. Right-aligning it
   put it past their right edge, because it is a sibling of the capped grid
   rather than something inside a card - unlike the in-card .form-actions on
   the quote page, which stays right-aligned against its own card edge. */
.setting-panels ~ .form-actions { justify-content: flex-start; }

/* a panel holding a table needs the whole row, not a grid column */
.setting-panel-wide { grid-column: 1 / -1; }

.setting-panel-head {
  padding-bottom: 14px;
  margin-bottom: 2px;
  border-bottom: 1px solid var(--border-faint);
}

/* ---------- the per-person rate table ---------- */

/* it already sits inside a panel, so it brings no card of its own */
.rate-table {
  border: 0;
  border-radius: 0;
  box-shadow: none;
  background: none;
}

.rate-table th { background: none; }

/* the boxes size to their content instead of stretching the columns */
.rate-table .rate-input { max-width: 118px; margin-left: auto; }
.rate-table td.col-num { text-align: right; }

.rate-table .rate-total {
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

@media (max-width: 640px) {
  /* stacked rows: label on the left, box on the right, nothing clipped */
  .rate-table .rate-input { max-width: 118px; }
}

.setting-panel-title {
  margin: 0 0 4px;
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: -0.012em;
  line-height: 1.3;
  /* h2 carries the gradient headline treatment elsewhere; inside a panel
     it reads as a plain section label */
  background: none;
  -webkit-text-fill-color: currentColor;
  color: var(--text);
  width: auto;
}

.setting-panel-sub {
  margin: 0;
  font-size: 0.83rem;
  line-height: 1.5;
  color: var(--muted);
}

/* the signature sample sits on its own tinted strip so it reads as a
   preview rather than as stray oversized text in the middle of a form */
.setting-panel .sig-preview-box {
  display: flex;
  align-items: center;
  min-height: 76px;
  padding: 6px 14px;
  background: var(--surface-2);
  border: 1px solid var(--border-faint);
  border-radius: var(--r-sm);
  margin-bottom: 0;
  overflow: hidden;
}

.setting-panel .account-sig-preview {
  font-size: 2.1rem;
  line-height: 1.2;
  overflow-wrap: anywhere;
}

/* the action sits at the bottom-right of every settings panel */
.setting-panel .save-btn {
  align-self: flex-end;
  margin-top: 4px;
}

@media (max-width: 640px) {
  .setting-panels { gap: 16px; margin-top: 14px; }
  .setting-panel .account-sig-preview { font-size: 1.7rem; }
}

/* ============================================================
   DESIGNER COMMISSION
   The rate editor in Settings, and the commission dashboard's per-order
   breakdown.
   ============================================================ */

/* a percentage box reads as a percentage: the % sits inside the field */
.rate-input {
  position: relative;
  display: flex;
  align-items: center;
  max-width: 190px;
}

.rate-input input {
  width: 100%;
  padding-right: 34px;
}

.rate-suffix {
  position: absolute;
  right: 12px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--muted);
  pointer-events: none;
}

/* One designer per row: name on the left, their rate on the right. The
   selector carries .client-form because `.client-form .field-row` stacks
   every field into a column at (0,2,0) - anything weaker leaves the label
   sitting on top of a centred box instead of beside it. */
.client-form .field-row.rate-row {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.rate-row label {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 0;
}

.rate-note {
  font-size: 0.76rem;
  font-weight: 400;
}

/* the action row under a full-width settings form */
.form-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 16px;
}

.form-actions .hint { margin: 0; }

/* ---------- commission dashboard: one card per order ---------- */

.comm-order {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
  padding: 16px 18px;
  margin-bottom: 16px;
}

.comm-order-cancelled { opacity: 0.72; }

.comm-order-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

.comm-order-id {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  font-weight: 600;
}

.comm-order-client {
  font-weight: 400;
  font-size: 0.88rem;
  color: var(--muted);
}

.comm-order-state {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* what the job is worth, beside what it pays out */
.comm-order-value {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.comm-order-total {
  font-size: 1.05rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* pending and cancelled totals are not money anyone is owed yet */
.comm-order-total.is-muted {
  font-weight: 600;
  color: var(--muted);
}

/* ============================================================
   STOCK MOVEMENTS
   The recent-activity view: a period switcher, the products moving most,
   and a day-by-day summary under the full ledger.
   ============================================================ */

.period-tabs { margin-bottom: 18px; }

/* what is leaving the shelves fastest in this window */
.mover-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: 720px;
  margin-bottom: 22px;
}

.mover-row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  padding: 10px 14px;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: var(--r);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.14s, box-shadow 0.14s;
}

.mover-row:hover { border-color: var(--border-strong); box-shadow: var(--shadow-xs); }

.mover-sku { font-weight: 650; font-variant-numeric: tabular-nums; }
.mover-name { flex: 1 1 auto; }

.mover-qty {
  margin-left: auto;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--danger);
  white-space: nowrap;
}

/* one line per day, so a week reads at a glance */
.daylog {
  display: flex;
  flex-direction: column;
  max-width: 720px;
}

.daylog-row {
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
  padding: 10px 2px;
  border-bottom: 1px solid var(--border-faint);
}

.daylog-row:last-child { border-bottom: 0; }

.daylog-date { font-weight: 600; font-variant-numeric: tabular-nums; min-width: 108px; }
.daylog-count { flex: 1 1 auto; }

.daylog-in,
.daylog-out {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  min-width: 84px;
  text-align: right;
}

.daylog-in { color: var(--success); }
.daylog-out { color: var(--danger); }

@media (max-width: 640px) {
  .mover-qty { margin-left: 0; }
  .daylog-date { min-width: 0; }
  .daylog-in, .daylog-out { min-width: 0; text-align: left; }
}

/* Administration's own earnings, sitting among whole-book figures - tinted
   so it reads as personal and is not mistaken for a company total. */
.jobstat-tile.jobstat-own {
  background: linear-gradient(180deg, var(--success-soft), transparent 70%), var(--card-bg);
  border-color: var(--success);
}

.jobstat-tile.jobstat-own .jobstat-value { color: var(--success); }

/* ---------- payout: one row per person on a job ---------- */

.payout-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 14px;
}

.payout-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 10px 14px;
  background: var(--surface-2);
  border: 1px solid var(--border-faint);
  border-radius: var(--r);
}

/* a settled payout is history, not something to action */
.payout-row.is-paid { opacity: 0.78; }

.payout-who { font-weight: 600; min-width: 120px; }
.payout-split { flex: 0 1 auto; }

.payout-amount {
  margin-left: auto;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.payout-row .hint { margin: 0; }

@media (max-width: 640px) {
  .payout-row { align-items: flex-start; flex-direction: column; gap: 6px; }
  .payout-amount { margin-left: 0; }
  .payout-who { min-width: 0; }
}

/* who the job's sales commission belongs to, above the per-cabinet table */
.sales-credit-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 14px;
  margin-bottom: 14px;
  background: var(--surface-2);
  border: 1px solid var(--border-faint);
  border-radius: var(--r);
}

.sales-credit-row label {
  font-weight: 600;
  font-size: 0.85rem;
  margin: 0;
}

.sales-credit-row .pdf-input { min-width: 190px; }
.sales-credit-row .hint { margin: 0; }

@media (max-width: 640px) {
  .sales-credit-row { flex-direction: column; align-items: stretch; }
  .sales-credit-row .pdf-input { min-width: 0; width: 100%; }
}

/* which kind a commission line is - sales (the lead, whole job) or design
   (this cabinet). A cabinet can carry one of each. */
.comm-kind {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 650;
  letter-spacing: 0.03em;
  padding: 2px 9px;
  border-radius: 980px;
  white-space: nowrap;
}

.comm-kind-sales { background: var(--accent-soft); color: var(--accent); }
.comm-kind-design { background: var(--success-soft); color: var(--success); }

@media (max-width: 640px) {
  .comm-order { padding: 14px; }

  .comm-order-head,
  .comm-order-state {
    align-items: flex-start;
    flex-direction: column;
    gap: 8px;
  }

  /* on a phone the name and its box stack, and the box fills the width */
  .client-form .field-row.rate-row { flex-direction: column; align-items: stretch; }
  .rate-input { max-width: none; }
}

/* ---------- print / save-as-PDF (quote detail page) ---------- */

@media print {
  /* the app shell is screen chrome - the printed quotation is the page body */
  .sidebar { display: none !important; }
  /* the screen bar is a fixed strip with a hairline top edge; on paper it
     becomes a bordered box further down, so only its screen chrome and
     viewport pinning are stripped here - not its border */
  .grand-total-bar {
    box-shadow: none !important;
    left: auto !important;
    right: auto !important;
  }
  .app-shell { display: block !important; }
  .app-main { display: block !important; }
  .container { max-width: none !important; padding: 0 !important; }

  @page {
    margin: 12mm;
  }

  body {
    background: #fff;
    color: #000;
  }

  /* nothing pins to a screen that isn't scrolling, and a capped-height
     scroll box would clip rows off the printed page */
  .admin-table th {
    position: static;
    box-shadow: none;
  }

  .table-scroll {
    overflow: visible;
    max-height: none;
  }

  /* app chrome has no place on a client-facing PDF */
  .topbar,
  .back-link,
  .no-print,
  .space-heading-edit,
  .flash-stack {
    display: none !important;
  }

  /* ...and its opposite: the printed stand-in for an on-screen field */
  .chk-print-only { display: inline !important; }

  .container {
    max-width: none;
    padding: 0;
  }

  .print-letterhead {
    display: flex;
    margin-bottom: 6px;
  }

  .pdf-title {
    display: block;
    margin: 0 0 12px;
    border-bottom: 1px solid #000;
    padding-bottom: 4px;
  }

  /* gradient headline text prints as invisible on some printers - use solid ink */
  h1 {
    background: none;
    -webkit-background-clip: initial;
    background-clip: initial;
    color: #000;
    font-size: 1.6rem;
  }

  .unit-card {
    box-shadow: none;
    border: 1px solid #ccc;
    break-inside: avoid;
    padding: 12px 16px;
    margin-bottom: 10px;
  }

  .rows-table tr,
  .addon-table tr {
    break-inside: avoid;
  }

  /* Column widths for the exported quotation only - on screen these tables
     keep the layout they have always had.

     `table-layout: fixed` hands the leftover width to whichever columns are
     left auto, so which column that is decides where the whitespace lands.
     Sizing the description and the measurements and leaving only the money
     auto keeps a line reading left to right - what it is, then how big it
     is, right up against each other - with the slack falling in front of
     the amount, which is right-aligned and stays on the page edge.

     They have to beat the entry form's Type-picker width, which applies
     here too and is what printed Width at 250px against Height's 178px.
     `.rows-table th:nth-child(2):not(.variant-label-col)` is (0,3,1); the
     description rule below is (0,4,1) and outranks it outright, while the
     measurement rule ties at (0,3,1) and wins on order - this block is the
     later one in the file. Every header in these tables is a description, a
     measurement or an amount, so none is left auto by accident. */
  .rows-table.breakdown-table th:not(.dim-col):not(.line-total) {
    width: 130px;
  }

  .rows-table.breakdown-table th.dim-col {
    width: 100px;
  }

  .rows-table.breakdown-table th.line-total {
    width: auto;
  }

  /* The card's 20px gutter is charged to whichever column comes first, so
     that column is given it back - otherwise a table that opens on a
     measurement (the Stone add-on, priced on width alone) has only 76px of
     room and breaks "WIDTH (MM)" across two lines. */
  .rows-table.breakdown-table th.dim-col:first-child {
    width: 120px;
  }

  .rows-table.breakdown-table th:not(.dim-col):not(.line-total):first-child {
    width: 150px;
  }

  .space-heading {
    break-after: avoid;
  }

  /* the fixed bottom bar would overlay every printed page - make it a plain,
     ink-safe block at the end instead */
  /* The fixed bottom bar would overlay every printed page - it becomes a
     plain, ink-safe box at the end instead.

     The :not(.static) half of the selector is load-bearing. The screen
     layout pins the bar across the bottom of the viewport and strips its
     side and bottom borders with `.grand-total-bar:not(.static)`, which at
     (0,2,0) outranks a bare `.grand-total-bar` here - without matching that
     specificity the printed box loses every edge and the grand total comes
     out as a bare line of text. */
  .grand-total-bar,
  .grand-total-bar:not(.static) {
    position: static;
    background: #fff;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    color: #000;
    border: 2px solid #000;
    border-radius: 10px;
    max-width: none;
    margin: 20px 0 0;
    padding: 15px 20px;
    font-size: 1.1rem;
    font-weight: 700;
    break-inside: avoid;
  }

  /* the figure itself is the thing the customer looks for */
  .grand-total-bar > span:last-child,
  .grand-total-bar .grand-total-mats {
    font-weight: 700;
  }

  /* Room to breathe above the total. The subtotal/discount stack used to
     sit hard against the last space subtotal and the box below it, which
     read as one dense clump of numbers. */
  .space-subtotal {
    margin-bottom: 10px;
  }

  .quote-discount-summary {
    margin: 14px auto 0;
    padding: 0 20px;
  }

  .quote-discount-row {
    padding: 5px 0;
    font-size: 0.95rem;
  }

  .quote-discount-row:last-child {
    font-weight: 600;
  }

  /* "Compact" density (Admin > Quotation PDF): keep the font size normal but
     strip the screen-friendly padding/margins so more units fit per page */
  .print-density-compact .print-letterhead {
    margin-bottom: 4px;
  }

  .print-density-compact .pdf-title {
    margin-bottom: 8px;
    padding-bottom: 2px;
  }

  .print-density-compact h1 {
    font-size: 1.35rem;
    margin-bottom: 2px;
  }

  .print-density-compact .client-contact {
    margin: 0 0 2px;
    font-size: 0.9em;
  }

  .print-density-compact .hint {
    margin-bottom: 8px;
  }

  .print-density-compact .space-heading {
    margin-top: 8px;
    margin-bottom: 4px;
    padding-bottom: 3px;
    font-size: 1.05rem;
  }

  .print-density-compact .unit-card {
    padding: 6px 10px;
    margin-bottom: 6px;
    border-radius: 8px;
  }

  .print-density-compact .unit-header {
    margin-bottom: 2px;
  }

  .print-density-compact .unit-header h2 {
    font-size: 1em;
  }

  .print-density-compact .rows-table th,
  .print-density-compact .rows-table td,
  .print-density-compact .addon-table th,
  .print-density-compact .addon-table td {
    padding: 2px 4px;
  }

  .print-density-compact .breakdown-table {
    margin-bottom: 8px;
  }

  .print-density-compact .breakdown-table:last-of-type {
    margin-bottom: 2px;
  }

  .print-density-compact .unit-subtotal {
    margin-top: 2px;
  }

  .print-density-compact .space-subtotal {
    margin-bottom: 6px;
  }

  /* Compact still gives the total its own breathing room - it is the one
     figure the customer looks for, so it keeps the box and the weight and
     only gives back the padding. */
  .print-density-compact .grand-total-bar,
  .print-density-compact .grand-total-bar:not(.static) {
    margin-top: 14px;
    padding: 12px 18px;
    font-size: 1.05rem;
    font-weight: 700;
  }

  .print-density-compact .quote-discount-summary {
    margin-top: 10px;
  }

  /* footer: keep the signature row on one page, plain black rules */
  .quote-footer {
    font-size: 1em;
  }

  .sig-row {
    break-inside: avoid;
  }

  .sig-line {
    border-top-color: #000;
  }

  .print-density-compact .quote-footer {
    margin-top: 14px;
  }

  .print-density-compact .qf-block {
    margin-bottom: 8px;
  }

  .print-density-compact .sig-row {
    margin-top: 18px;
  }
}

/* ---------- inventory (ENF board stock) ---------- */

/* subheading inside the Accounts permission checklist, above the
   inventory toggles */
.perm-subhead {
  margin: 12px 0 4px;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--muted);
}

.inv-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 6px 0 18px;
}

.inv-panel {
  flex: 1 1 320px;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 14px;
  padding: 4px 16px;
  margin: 0 0 14px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}

.inv-panel > summary {
  cursor: pointer;
  padding: 12px 0;
  font-weight: 600;
  color: var(--accent);
  list-style: none;
}

.inv-panel > summary::-webkit-details-marker { display: none; }
.inv-panel[open] > summary { border-bottom: 1px solid var(--border-faint); }

.inv-form { padding: 14px 0 4px; }

/* A form that lays its fields out in an inner .inv-form-grid must not also
   be a grid itself. The rule earlier in this file dates from when the fields
   sat directly in the form; with the inner grid there, the submit button
   becomes a second grid item in the same row and stretches to the height of
   the whole field block - 734px of blue button on the stock page. */
.inv-form:has(> .inv-form-grid) {
  display: block;
}

.inv-form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
  margin-bottom: 18px;
}

/* form labels match the app's canonical form (.client-form label): dark and
   semibold, not muted grey - that's what read as "not Apple" */
.inv-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.inv-field > span {
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--text);
}

.inv-field em {
  color: var(--muted);
  font-style: normal;
  font-weight: 400;
}

.inv-field .pdf-input { width: 100%; }

.inv-form-actions {
  display: flex;
  align-items: center;
  gap: 16px;
}

/* movement direction badges - In green, Out red, Adjustment amber,
   matching the calendar status badge language */
.move-badge {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 980px;
  font-size: 0.76rem;
  font-weight: 600;
  white-space: nowrap;
}
.move-in { background: #e3f8e9; color: #1c8a3c; }
.move-out { background: #fde5e5; color: var(--danger); }
.move-adjustment { background: #fff4de; color: #b8790a; }

.inventory-table .col-num { text-align: right; font-variant-numeric: tabular-nums; }

/* a board that's out of stock - dim the row so it stands out in the list */
.inv-row-empty td { background: rgba(227, 0, 0, 0.035); }

.inv-row-actions {
  display: flex;
  align-items: center;
  gap: 14px;
  white-space: nowrap;
}

.inv-edit > summary {
  cursor: pointer;
  color: var(--accent);
  list-style: none;
}
.inv-edit > summary::-webkit-details-marker { display: none; }

.inv-edit-form {
  position: relative;
  z-index: 1;
  margin-top: 10px;
  padding: 14px;
  background: var(--bg);
  border-radius: 12px;
  min-width: 260px;
}

.inv-inline-form { display: inline; }

@media (max-width: 640px) {
  .inv-row-actions { flex-direction: column; align-items: flex-start; gap: 8px; }
}

/* inventory stock-dashboard bars */
.dash-bar-low { fill: var(--dash-warn); }
.dash-bar-empty { fill: var(--danger); font-weight: 600; }
.dash-bar-in { fill: var(--dash-good); }
.dash-bar-out { fill: var(--danger); }

/* little colour keys in the "stock by product" caption */
.inv-key {
  display: inline-block;
  padding: 1px 9px;
  margin-left: 6px;
  border-radius: 980px;
  font-size: 0.78rem;
  font-weight: 600;
  color: #fff;
}
.inv-key-ok { background: var(--accent); }
.inv-key-low { background: var(--dash-warn); }
.inv-key-out { background: var(--danger); }

.inv-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
}
.inv-dash-link {
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap;
}
.inv-dash-link:hover { text-decoration: underline; }

/* stock-dashboard group tabs (segmented control) */
.inv-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 5px;
  margin: 4px 0 16px;
  background: var(--card-bg);
  border: 1px solid var(--border-faint);
  border-radius: 12px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}
.inv-tab {
  flex: 1 1 auto;
  padding: 9px 14px;
  border: none;
  border-radius: 8px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-weight: 600;
  font-size: 0.9rem;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s;
}
.inv-tab:hover { color: var(--text); }
.inv-tab.active {
  background: var(--accent);
  color: #fff;
}

/* Apple segmented control (used for the transaction Direction: In/Out/
   Adjustment) - a light track with a raised white pill on the selected
   segment, like macOS/iOS. The radio itself is visually hidden. */
.inv-seg {
  display: inline-flex;
  align-self: flex-start;   /* size to content, don't stretch to the field width */
  gap: 3px;
  padding: 3px;
  background: #ececef;
  border-radius: 10px;
  max-width: 100%;
}
.inv-seg-opt {
  flex: 0 0 auto;           /* each segment fits its own label - no overflow */
  cursor: pointer;
}
.inv-seg-opt input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}
.inv-seg-opt > span {
  display: block;
  padding: 6px 12px;
  border-radius: 8px;
  font-size: 0.86rem;
  font-weight: 600;
  color: var(--text);
  text-align: center;
  white-space: nowrap;
  transition: background 0.15s, box-shadow 0.15s, color 0.15s;
}
.inv-seg-opt:hover > span { color: var(--accent); }
.inv-seg-opt:has(input:checked) > span {
  background: #fff;
  color: var(--text);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14);
}
.inv-seg-opt:focus-within > span {
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* "Quoted at Quartz until chosen" - which option the price currently rests
   on. Its own line under the control: inline it wraps around the segments
   and reads as part of the last one. */
.mat-standing {
  display: block;
  margin-top: 6px;
}

/* searchable Apple-styled dropdown (combobox) - see combo.js */
.combo { position: relative; }

.combo-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  padding: 8px 11px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fff;
  color: var(--text);
  font: inherit;
  font-size: 0.92rem;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.combo-trigger[aria-expanded="true"] {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.combo-value {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.combo-value.is-empty { color: var(--muted); }
.combo-caret {
  flex-shrink: 0;
  width: 12px;
  height: 8px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1.5 2L6 6.5L10.5 2' stroke='%2386868B' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/12px no-repeat;
}

.combo-pop {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 6px);
  z-index: 40;
  padding: 6px;
  background: #fff;
  border: 1px solid var(--border-faint);
  border-radius: 12px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.14);
}
.combo-search-wrap { padding: 2px 2px 6px; }
.combo-search {
  width: 100%;
  padding: 8px 11px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.9rem;
  color: var(--text);
}
.combo-search:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.combo-search::placeholder { color: var(--muted); }

.combo-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 240px;
  overflow-y: auto;
}
.combo-group {
  padding: 8px 10px 4px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
}
.combo-opt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 8px;
  font-size: 0.9rem;
  color: var(--text);
  cursor: pointer;
}
/* our display:flex/list-item would otherwise beat the UA [hidden] rule, so
   filtered-out options/headers need this to actually disappear */
.combo-opt[hidden],
.combo-group[hidden] { display: none; }

.combo-opt:hover,
.combo-opt.is-active { background: var(--bg); }
.combo-opt[aria-selected="true"] {
  color: var(--accent);
  font-weight: 600;
}
.combo-opt[aria-selected="true"]::after {
  content: "";
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath d='M2.5 7.4L5.5 10.4L11.5 3.5' stroke='%230071e3' stroke-width='1.8' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/14px no-repeat;
}
.combo-empty {
  padding: 12px 10px;
  text-align: center;
  color: var(--muted);
  font-size: 0.9rem;
}

.inv-empty {
  padding: 16px 18px;
  background: var(--accent-soft);
  border-radius: 12px;
}
.inv-empty p { margin: 0 0 8px; }
.inv-empty p:last-child { margin-bottom: 0; }

/* value labels above the In/Out flow columns */
.dash-flow-value {
  font-size: 10px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-anchor: middle;
}
.dash-flow-in { fill: var(--dash-good); }
.dash-flow-out { fill: var(--danger); }

/* ---------- numeric table cells (blueprint) ---------- */

.admin-table .col-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.admin-table .price-total-row td {
  border-top: 1px solid var(--border);
  background: var(--accent-soft);
}

/* ---------- blueprint: the vision card ---------- */

.bp-vision {
  border-top: 3px solid var(--accent);
}

.bp-vision-line {
  margin: 4px 0 14px;
  font-size: 1.5rem;
  line-height: 1.35;
  letter-spacing: -0.02em;
  color: var(--text);
}

@media (max-width: 700px) {
  .bp-vision-line { font-size: 1.2rem; }
}

/* ---------- "showing only ..." bar, when a Today's Tasks card filters a page ---------- */

.focus-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 18px;
  margin: 0 0 22px;
  padding: 12px 16px;
  border: 1px solid var(--accent);
  border-radius: 14px;
  background: var(--accent-soft);
  font-size: 0.9rem;
}

.focus-bar a {
  color: var(--accent);
  font-weight: 500;
  white-space: nowrap;
}

/* ---------- cancelling an order and recording its refund ---------- */

.cancel-row { align-items: flex-start; }

.cancel-details summary {
  cursor: pointer;
  display: inline-block;
  list-style: none;
}

.cancel-details summary::-webkit-details-marker { display: none; }

.cancel-details[open] summary { margin-bottom: 8px; }

.cancel-form {
  margin-top: 10px;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface, #fff);
}

.cancel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px;
  margin-bottom: 12px;
}

.cancel-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.cancel-field > span {
  font-size: 0.8rem;
  color: var(--text-soft, #6e6e73);
}

.cancel-field-wide { grid-column: 1 / -1; }

.cancel-field .pdf-input { width: 100%; }

/* global add-ons per unit (Spaces & Units page) */
.unit-addons-list { display: flex; flex-direction: column; gap: 8px; margin: 10px 0 4px; }
.unit-addons-row {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: #fff;
}
.unit-addons-name { font-weight: 500; min-width: 150px; }
.unit-addons-checks { display: flex; gap: 16px; flex-wrap: wrap; flex: 1; }

.grand-total-disc {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 9px;
  border-radius: 980px;
  background: rgba(48, 209, 88, 0.14);
  color: #248a3d;
  font-size: 0.72rem;
  font-weight: 600;
  vertical-align: middle;
}

/* ============================================================
   HOME DASHBOARD (the page signing in lands on)
   ============================================================ */

.home-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.home-head h1 { margin-bottom: 2px; }
.home-head .hint { margin: 0; }
.home-cta { flex-shrink: 0; text-decoration: none; }

/* ---------- alert strip ---------- */

.home-alerts { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; }

.home-alert {
  display: block;
  border-radius: var(--r);
  padding: 11px 15px;
  font-size: 0.875rem;
  text-decoration: none;
  border: 1px solid transparent;
  transition: filter 0.14s;
}

.home-alert:hover { filter: brightness(0.97); }
.home-alert-bad  { background: var(--danger-soft); color: var(--danger); border-color: rgba(217,45,32,0.2); }
.home-alert-warn { background: var(--warn-soft);  color: var(--warn);  border-color: rgba(181,71,8,0.2); }

/* ---------- KPI row ---------- */

.home-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}

.home-kpi {
  display: flex;
  flex-direction: column;
  gap: 3px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-top: 3px solid var(--accent);
  border-radius: var(--r-lg);
  padding: 15px 17px;
  text-decoration: none;
  box-shadow: var(--shadow-xs);
  transition: box-shadow 0.16s, transform 0.16s, border-color 0.16s;
}

.home-kpi:hover { box-shadow: var(--shadow); transform: translateY(-1px); }

/* Earnings read as money earned, not as another number to action: green
   top rule and green figure, so a designer's own commission stands apart
   from the workload tiles beside it. */
.home-kpi-earn {
  border-top-color: var(--success);
  background: linear-gradient(180deg, var(--success-soft), transparent 62%), var(--card-bg);
}

.home-kpi-earn .home-kpi-value { color: var(--success); }

.home-kpi-label { font-size: 0.78rem; font-weight: 550; color: var(--muted); }
.home-kpi-value {
  font-size: 1.6rem;
  font-weight: 650;
  letter-spacing: -0.025em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
}
.home-kpi-foot { font-size: 0.75rem; color: var(--muted-2); }

/* ---------- two-column detail ---------- */

.home-split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
  gap: 14px;
  margin-bottom: 26px;
}

/* A grid item's automatic minimum size is its min-content width, so a card
   holding a long unbroken job title ("Warehouse Schedule - MTQ26050016")
   pushes its own track wider than the grid - on a 375px phone the single
   column resolved to 413px and the whole page could be dragged sideways.
   The blanket mobile min-width reset misses these because it lists
   div/span/a/p and the cards are <section>. */
.home-split > * { min-width: 0; }

.home-split .home-row,
.home-split .home-row-main { min-width: 0; }

.home-split .home-row-title { overflow-wrap: anywhere; }

.home-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
  padding: 16px 18px 8px;
}

.home-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}

.home-card-head h2 { margin: 0; font-size: 0.98rem; }
.home-card-link { font-size: 0.8rem; font-weight: 550; color: var(--accent); text-decoration: none; white-space: nowrap; }
.home-card-link:hover { text-decoration: underline; }

.home-list { list-style: none; margin: 0; padding: 0; }

.home-row {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border-faint);
  text-decoration: none;
  color: inherit;
  transition: background 0.12s;
}

.home-list li:last-child .home-row { border-bottom: none; }
.home-row:hover { background: var(--surface-2); }

.home-row-time {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
  min-width: 46px;
}

.home-row-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }

.home-row-title {
  font-size: 0.875rem;
  font-weight: 550;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.home-row-sub { font-size: 0.76rem; color: var(--muted); }

.home-row-due {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--muted);
  background: var(--surface-2);
  border-radius: 999px;
  padding: 3px 9px;
  flex-shrink: 0;
}

.home-row-due.is-late { background: var(--danger-soft); color: var(--danger); }

.home-empty { padding: 6px 0 14px; margin: 0; }

@media (max-width: 640px) {
  .home-head { flex-direction: column; align-items: stretch; }
  .home-cta { width: 100%; text-align: center; }
  .home-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .home-split { grid-template-columns: 1fr; }
  .home-card { padding: 14px 14px 6px; }
}

@media (max-width: 359px) {
  .home-kpis { grid-template-columns: 1fr; }
}

/* ============================================================
   THE PRINTED QUOTATION (/quotes/<id>/print)

   A document rather than a page: a cover, a summary of the areas, the
   breakdown, and a sheet to sign. Everything sized in millimetres and
   points, because that is what the paper is, and driven by the spacing
   settings so the margins and row heights can be set without touching
   this file. On screen it is the same document on a grey desk, so what
   is being set is what will print.
   ============================================================ */

.print-page {
  background: #e9ecf1;
}

.print-page .container { max-width: none; padding: 0; }

.sheet {
  width: 210mm;
  min-height: 297mm;
  margin: 18px auto;
  padding: var(--doc-margin, 14mm);
  background: #fff;
  color: #111;
  box-shadow: 0 8px 30px rgba(16, 24, 40, 0.18);
  font-family: var(--doc-font, "Segoe UI", Arial, sans-serif);
  font-size: var(--doc-size, 9.5pt);
  line-height: var(--doc-leading, 1.35);
}

.print-bar {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 12mm;
}

/* ---- letterhead ----
   The same arrangement the classic printout uses, and driven by the same
   settings: logo beside a centred block of lines, the phone row sharing
   that block's width. Only the spacing below it belongs to this document.
   (.lh-* rules are shared - see the letterhead section above.) */
.doc-letterhead {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: var(--doc-gap, 6mm);
  padding-bottom: 2mm;
  border-bottom: 1pt solid #111;
}

.doc-letterhead .lh-logo { flex-shrink: 0; }

.doc-letterhead .lh-text {
  flex: 1;
  min-width: 0;
  line-height: 1.35;
}

/* ---- title and the meta box ---- */
.doc-title-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 10mm;
  margin-bottom: var(--doc-gap, 6mm);
}

/* The title is the document's masthead - set large above a rule, with
   everything that identifies the job in the row beneath it. Its size
   follows the heading setting so the Spacing panel still governs it. */
.doc-head {
  border-bottom: 0.8pt solid #111;
  padding-bottom: 2.5mm;
  margin-bottom: 3.5mm;
}

.doc-title {
  margin: 0;
  font-size: calc(var(--doc-heading-size, 11pt) * 1.9);
  letter-spacing: 0.02em;
  font-weight: 700;
  line-height: 1.1;
}

.doc-tagline { font-size: 9.5pt; font-style: italic; color: #333; margin-top: 1mm; }

/* The left column carries the customer, so it has to be able to wrap a
   long address rather than push the particulars off the page. */
.doc-title-main { flex: 1; min-width: 0; }
.doc-title-main .doc-label:first-child { margin-top: 0; }

.doc-client-line { font-size: 9pt; color: #333; }

/* Dropped by one label's height so the first particular rules across
   from the customer's name, not from the PREPARED FOR above it. */
.doc-meta { border-collapse: collapse; min-width: 76mm; margin-top: 3.2mm; }
.doc-meta th,
.doc-meta td { padding: 0.9mm 0; font-size: 8.5pt; vertical-align: top; }
.doc-meta th { text-align: left; letter-spacing: 0.08em; color: #111; font-weight: 700; }
.doc-meta td { text-align: right; font-weight: 400; padding-left: 8mm; }
/* the number is what the quotation is filed under - the one figure in the
   block that should catch the eye */
.doc-meta tr.strong td { font-weight: 700; }

/* ---- blocks ---- */
.doc-block { margin-bottom: var(--doc-gap, 6mm); }

.doc-label {
  margin: 2.5mm 0 0.5mm;
  font-size: 7.5pt;
  letter-spacing: 0.1em;
  font-weight: 700;
  color: #111;
}

.doc-heading {
  margin: 0 0 2mm;
  font-size: var(--doc-heading-size, 11pt);
  letter-spacing: 0.1em;
  font-weight: 700;
  border-bottom: 0.8pt solid #111;
  padding-bottom: 1mm;
}

.doc-client-name { font-size: 13pt; font-weight: 400; }

.doc-note { margin: 1.5mm 0 0; font-size: 8pt; color: #444; }
/* a remark about what is around it, rather than part of it */
.doc-note.aside { font-style: italic; margin: 3mm 0 4mm; }

/* ---- what it is made of ---- */
.doc-materials.two-up {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10mm;
}

/* The board's name is the heading here, set large and light; OPTION A is
   only a label on it, so it is small caps rather than a boxed badge -
   boxing it made the label louder than the thing it names. */
.doc-material-name {
  font-size: 13pt;
  font-weight: 400;
  margin-bottom: 2.5mm;
  line-height: 1.2;
}

.doc-option-tag {
  margin-right: 2.5mm;
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: 0.08em;
  vertical-align: 0.1em;
}

/* Dashes rather than dots, hung in the margin, with room to breathe - a
   handful of points about a material reads as a list of remarks, not as
   a tally. */
.doc-bullets { margin: 0; padding: 0; list-style: none; }

.doc-bullets li {
  position: relative;
  padding-left: 6mm;
  margin-bottom: 2.2mm;
}

.doc-bullets li::before {
  content: "\2013";
  position: absolute;
  left: 0;
}

/* ---- tables ---- */
.doc-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.doc-table th,
.doc-table td {
  padding: var(--doc-row-pad, 1.2mm) 1.6mm;
  border-bottom: 0.4pt solid #ccc;
  text-align: left;
  vertical-align: top;
}

.doc-table thead th {
  font-size: 7.5pt;
  letter-spacing: 0.06em;
  color: #333;
  border-bottom: 0.9pt solid #111;
  white-space: nowrap;
}

.doc-table .amt { text-align: right; white-space: nowrap; }
.doc-table .dim { text-align: right; width: 13mm; white-space: nowrap; }
.doc-table .num { width: 9mm; color: #555; }
.doc-table .label { text-align: right; font-weight: 600; }
.doc-table .strong { font-weight: 700; }

.doc-table tfoot td { border-bottom: none; padding-top: 1.6mm; }
.doc-table tfoot .grand td,
.doc-table .grand td {
  border-top: 0.9pt solid #111;
  font-size: 10.5pt;
  font-weight: 700;
}

/* The closing totals are a table of two columns and nothing else, so a
   right-aligned label leaves half the width empty and the words floating
   in the middle of the page. They read from the left margin, like the
   headings above them, with the figures at the right. */
.doc-totals .label { text-align: left; }

/* The summary is a handful of lines the eye takes in at a glance, so it
   needs no grid: one rule under the headings, one above the totals, and
   nothing between the areas themselves. */
.doc-summary tbody td { border-bottom: none; }
.doc-summary tbody:first-of-type tr:last-child td { padding-bottom: 2mm; }

/* The totals are rows of the table's body, not a tfoot: a table footer
   is repeated at every fold, which printed the grand total once per
   sheet on a quotation long enough to span two. */
.doc-summary-totals tr:first-child td { border-top: 0.9pt solid #111; padding-top: 2mm; }

/* A long list of areas reads in two columns so the summary stays one
   page - the gutter is what tells the halves apart. */
.doc-summary.two-up th:nth-child(4),
.doc-summary.two-up td:nth-child(4) { padding-left: 9mm; }

/* The list fills whatever room is left on the page and carries on over
   the fold if there is more of it than that - holding it whole pushed a
   long one onto a sheet of its own and left half the cover empty. Its
   column headings repeat on the continuation, and the totals stay
   together wherever they land. */
.doc-summary-totals { break-inside: avoid; }

/* ---- a long quotation sets its cover a notch tighter ----
   Twenty-odd areas leave the summary finishing a centimetre past the
   foot of the page it starts on, which puts three total lines and a
   repeated row of headings alone on a sheet of their own. So a document
   long enough to need two columns takes a little out of the cover and a
   little out of the summary's own rows: measured at 261mm against the
   269mm a page holds, where it was 284mm. A short quotation is left
   exactly as it was - it has the room, and the air reads better. */
.doc-long .doc-summary { font-size: 9pt; }

.doc-long .doc-summary th,
.doc-long .doc-summary td { padding-top: 0.7mm; padding-bottom: 0.7mm; }

.doc-long .doc-bullets li { margin-bottom: 1.5mm; }
.doc-long .doc-material-name { margin-bottom: 1.8mm; }
.doc-long .doc-note.aside { margin: 2mm 0 3mm; }

/* An area may run over a fold - see .doc-unit in the print rules, which
   is the thing that must not be split. */
.doc-space { margin-bottom: calc(var(--doc-gap, 6mm) * 1.5); }

/* Every area prints its own table, and a table sizes its columns to its
   own contents - so one area's TYPE column began where another's ended
   and nothing lined up down the page. The widths are the document's
   now, not each area's, and in proportion to the page so they follow
   the margin setting. ITEM takes whatever is left. */
.doc-breakdown { table-layout: fixed; }
.doc-breakdown thead th:nth-child(2) { width: 21%; }
.doc-breakdown .dim { width: 6.5%; }
.doc-breakdown .amt { width: 13%; }
.doc-breakdown td { overflow-wrap: break-word; }

/* Fixed columns have to earn their width back somewhere: the widths
   above are measured against the longest names a quotation actually
   carries - "Drawer (Additional Unit)", "Table (with drawer)" - and
   they only fit on one line with the gutters taken in a little. */
.doc-breakdown th,
.doc-breakdown td { padding-left: 1.2mm; padding-right: 1.2mm; }

/* An area's name is a heading on the page, not a row of the table - set
   large and light, with its number standing off to the left the way a
   numbered section does. */
.doc-space-name {
  margin: 0 0 2mm;
  font-size: 16pt;
  font-weight: 400;
  line-height: 1.2;
}

.doc-space-no { color: #999; margin-right: 5mm; }

/* A cabinet's name opens its own group of lines. It reads as a heading on
   its own - shading and a rule under it only boxed in rows that are
   already grouped by the space around them. */
.doc-subhead td {
  font-weight: 700;
  border-bottom: none;
}

/* air between one cabinet and the next, carried by whichever row opens
   the group - its name, or its first line where it prints no name */
.doc-breakdown tbody tr.doc-unit-start td { padding-top: 4.5mm; }

.doc-tickbox { float: right; font-weight: 600; letter-spacing: 0.04em; }

/* the rows themselves carry no rules - the cabinet's own subtotal closes
   the group, and that is the only line the eye needs */
.doc-breakdown tbody td { border-bottom: none; }

/* the area's own total is the one figure added up inside the breakdown,
   and it stands clear of the last cabinet's lines */
.doc-breakdown tfoot td { padding-top: 3.5mm; }
.doc-space-total td { border-top: 0.9pt solid #111; font-weight: 700; }

/* ---- terms and signatures ---- */
.doc-terms {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8mm;
  margin-top: var(--doc-gap, 6mm);
}

.doc-closing { margin: var(--doc-gap, 6mm) 0; }

.doc-signatures {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12mm;
  margin-top: 10mm;
}

/* Each side is its own column, and the line is the last thing in it -
   so with both columns the same height the two lines rule across the
   page at one level, whatever sits above them. */
.doc-sign {
  display: flex;
  flex-direction: column;
}

.doc-sign-space {
  flex: 1;
  min-height: 16mm;
  display: flex;
  align-items: flex-end;
  padding-bottom: 1mm;
}

.doc-sign-image { max-height: 18mm; max-width: 60mm; display: block; }

/* the name as it is written on the Account page - same hand on screen
   and on paper */
.doc-sign-name { font-size: 20pt; line-height: 1; }

.doc-sign-line { border-bottom: 0.8pt solid #111; }
.doc-sign-caption { font-size: 8pt; color: #444; margin-top: 1mm; }
.doc-sign-stamp { font-size: 8pt; font-weight: 600; color: #111; margin-top: 0.8mm; }

/* The running head and foot live in the printed page's margin, which has
   no equivalent on screen. These show them where they will print, set the
   same way, so what comes out of the print window is no surprise - the
   dashed rule is the edge of the paper's text area, not part of the
   document. */
.doc-margin-preview {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  font-size: 7.5pt;
  color: #999;
}

.doc-margin-preview.head {
  justify-content: flex-end;
  border-bottom: 1px dashed #d8dce3;
  padding-bottom: 2mm;
  margin-bottom: 6mm;
}

.doc-margin-preview.foot {
  border-top: 1px dashed #d8dce3;
  padding-top: 2mm;
  margin-top: 8mm;
}

.doc-margin-preview span { word-break: break-all; }

.page-break { break-before: page; }

/* What closes the document takes no sheet of its own: it follows the
   breakdown onto whatever room is left. Its parts are what must not be
   split - a totals table, the terms, the signatures - so each is held
   whole and the fold falls between them, rather than the whole block
   moving on and leaving a sheet blank behind it. */
.doc-closing-block { margin-top: calc(var(--doc-gap, 6mm) * 1.5); }

.doc-closing-block .doc-table,
.doc-terms,
.doc-signatures { break-inside: avoid; }

/* and a heading never sits alone at the foot of a page */
.doc-heading { break-after: avoid; }

@media print {
  /* The size and margin the document actually prints at are written into
     the page itself (quote_print.html), because a page box has no element
     to inherit --doc-margin from. This is only the floor under it. */
  @page { size: A4; margin: 14mm; }

  .print-page { background: #fff; }

  .sheet {
    width: auto;
    min-height: 0;
    margin: 0;
    padding: 0;
    box-shadow: none;
  }

  /* A document's own page breaks, not the app's. An area is allowed to
     span a fold - keeping one whole moved a tall one off a page that
     still had two thirds of itself left - but a cabinet is not, so the
     break falls between cabinets and the room on the page gets used. */
  .doc-unit { break-inside: avoid; }
  .doc-space-name { break-after: avoid; }
  .doc-table thead { display: table-header-group; }
  /* ...but a footer group repeats too, and a total that appears at the
     foot of every sheet reads as a different total each time */
  .doc-table tfoot { display: table-row-group; }
  .doc-table tr { break-inside: avoid; }
}

/* ---------- Settings > Quotation PDF: do these descriptions land? ----------
   A material description is matched to the price list by the name it
   starts with, and a name that matches nothing prints nothing at all.
   That used to happen in silence, so the panel now shows what each line
   claims and whether anything answers to it. */
.pdf-blurb-check {
  width: 100%;
  border-collapse: collapse;
  margin: 12px 0 10px;
  font-size: 0.855rem;
}

.pdf-blurb-check th,
.pdf-blurb-check td {
  text-align: left;
  padding: 7px 10px;
  border-bottom: 1px solid var(--border);
}

.pdf-blurb-check th { color: var(--muted); font-weight: 600; }

.pdf-blurb-check .blurb-miss td { color: var(--danger); }
.pdf-blurb-check .blurb-miss td:first-child { font-weight: 600; }

/* Renaming a material sits beside removing it, so its field has to read
   as a small inline control rather than as another form on the page. */
.material-rename {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-right: 14px;
}

.material-rename .pdf-input { width: 150px; }

@media (max-width: 640px) {
  .material-rename { display: flex; margin: 0 0 8px; }
  .material-rename .pdf-input { width: auto; flex: 1; }
}

/* ---------- the invitation a customer is sent ----------
   Two sides of one feature: the control on a calendar entry that makes
   the link, and the card the customer opens with it.

   The card is not a page of the app. It is the only thing on their
   screen, read on a phone, from a message - so it is set like an
   invitation: a masthead, a line that speaks to them by name, and then
   the three things they came for. Everything is sized in rem off a
   phone-first scale and widens rather than reflows on a desktop. */

.calendar-invite { margin-top: 12px; }

.invite-link-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.invite-link-row .pdf-input {
  flex: 1 1 240px;
  min-width: 0;
  font-size: 0.8rem;
  color: var(--muted);
}

.calendar-invite-hint { margin: 6px 0 0; }

/* ---- the card itself ---- */

.invite-page { background: #fbfbfb; }

.invite-sheet {
  max-width: 460px;
  margin: 0 auto;
  padding: 30px 26px 0;
  background: #fff;
  color: #111;
  min-height: 100vh;
}

.invite-brand { margin-bottom: 40px; }
.invite-mark { height: 62px; display: block; margin-bottom: 10px; }

.invite-wordmark {
  font-size: 0.66rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: #6b6b6b;
}

.invite-kicker {
  margin: 0 0 14px;
  font-size: 0.68rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: #8a8a8a;
}

/* The one piece of the card set large: it carries the whole tone, and a
   headline that wraps to two lines is the point rather than a problem. */
.invite-headline {
  margin: 0;
  font-size: 2.65rem;
  line-height: 1.04;
  letter-spacing: -0.03em;
  font-weight: 800;
}

.invite-greeting { margin: 16px 0 0; font-size: 1.12rem; color: #555; line-height: 1.4; }

.invite-panel {
  margin: 28px 0 0;
  padding: 22px 20px;
  background: #f4f4f5;
  border-radius: 14px;
}

.invite-label {
  margin: 0 0 10px;
  font-size: 0.64rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: #8a8a8a;
}

.invite-date { margin: 0; font-size: 1.3rem; font-weight: 700; letter-spacing: -0.015em; }
.invite-hours { margin: 2px 0 0; font-size: 1.3rem; color: #555; font-weight: 400; }
.invite-sub { margin: 4px 0 0; font-size: 0.9rem; color: #7a7a7a; line-height: 1.45; }

.invite-place { display: flex; gap: 12px; margin-top: 20px; }
.invite-pin { width: 22px; height: 22px; flex-shrink: 0; color: #9a7b45; margin-top: 1px; }
.invite-place-text { min-width: 0; }
.invite-place-name { margin: 0; font-size: 1.05rem; font-weight: 700; }
.invite-address { margin: 3px 0 0; font-size: 0.98rem; color: #666; line-height: 1.45; }

.invite-directions { display: flex; gap: 12px; margin-top: 18px; }

.invite-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex: 1;
  padding: 14px 16px;
  border-radius: 10px;
  font-size: 1rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: opacity 0.15s ease;
}

.invite-btn-solid { background: #1b1b1b; color: #fff; }
.invite-btn-hollow { background: #fff; color: #111; border: 1px solid #d8d8da; }
.invite-btn-wide { width: 100%; margin-top: 14px; }
.invite-btn:hover { opacity: 0.85; }
.invite-arrow { font-size: 0.9em; }
.invite-wa { width: 20px; height: 20px; color: #9a7b45; }

.invite-heading {
  margin: 34px 0 14px;
  font-size: 1.22rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.invite-host {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 18px 20px;
  background: #f4f4f5;
  border-radius: 14px;
}

.invite-avatar { width: 56px; height: 56px; flex-shrink: 0; }
.invite-host-name { margin: 0; font-size: 1.08rem; font-weight: 700; }

.invite-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  margin: 24px 0 26px;
}

.invite-action {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.95rem;
  color: #555;
  text-decoration: none;
  /* "Add to Calendar" over two lines reads as two links */
  white-space: nowrap;
}

.invite-action:hover { color: #111; }
.invite-icon { width: 19px; height: 19px; }
.invite-action-split { width: 1px; height: 20px; background: #dcdcde; }

.invite-photo { display: block; width: 100%; border-radius: 12px; }

.invite-tagline {
  padding: 20px 0 28px;
  text-align: center;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #9a9a9a;
}

.invite-ref { display: block; margin-top: 6px; letter-spacing: 0.08em; }

/* A phone is the common case, so the small screen keeps the full-bleed
   sheet and only the type comes down a notch. */
@media (max-width: 420px) {
  .invite-sheet { padding: 24px 20px 0; }
  .invite-headline { font-size: 2.3rem; }
  .invite-date { font-size: 1.15rem; }
  .invite-hours { font-size: 1.12rem; }
  .invite-directions { gap: 10px; }
  /* both buttons keep to one line at any width - "Google Maps"
     broken across two reads as two buttons */
  .invite-btn { padding: 13px 8px; font-size: 0.9rem; gap: 6px; }
  .invite-actions { gap: 12px; }
  .invite-action { font-size: 0.86rem; gap: 6px; }
}

/* name and number side by side in the accounts table, where the
   signature has one field and this has two */
.acct-profile-form { display: flex; gap: 6px; flex-wrap: wrap; }
.acct-profile-form .pdf-input { min-width: 0; flex: 1 1 110px; }

/* ---------- the customer book ----------
   A customer exists before there is anything to quote, so where they
   stand is the thing the list has to show at a glance: an enquiry, a
   quotation out, a job won, or one that got away. */

.cust-filters {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.cust-search { display: flex; gap: 8px; align-items: center; }
.cust-search .pdf-input { min-width: 260px; }

.cust-tabs { display: flex; gap: 8px; flex-wrap: wrap; }

.cust-tab {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 0.86rem;
  color: var(--text);
  text-decoration: none;
  background: #fff;
}

.cust-tab span {
  font-size: 0.78rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.cust-tab:hover { border-color: var(--border-strong); }
.cust-tab.on { background: var(--text); color: #fff; border-color: var(--text); }
.cust-tab.on span { color: rgba(255, 255, 255, 0.72); }

/* the four standings, in the colours the rest of the system already uses
   for the same ideas: green won, red lost, amber in flight */
.cust-pill {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.76rem;
  font-weight: 600;
  white-space: nowrap;
}

.cust-pill-enquiry { background: #eef1f6; color: #5a6475; }
.cust-pill-quoted { background: #fff4e0; color: #8a5a00; }
.cust-pill-customer { background: #e6f6ea; color: #1b6b36; }
.cust-pill-lost { background: #fdeaea; color: #9b2c2c; }

.cust-source { display: block; font-size: 0.76rem; color: var(--muted); }

.cust-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.cust-figures { display: flex; gap: 26px; }
.cust-figure { text-align: right; }
.cust-figure-num { display: block; font-size: 1.5rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.cust-figure-label { font-size: 0.74rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }

@media (max-width: 640px) {
  .cust-search .pdf-input { min-width: 0; flex: 1; }
  .cust-search { width: 100%; }
  .cust-figures { gap: 18px; }
  .cust-figure { text-align: left; }
}
