/* Fresh Cobalt: light surfaces, navy navigation and semantic status colors. */
:root {
  /* The width of a row's move controls (⠿ ▲ ▼), for the tables that give them a column. */
  --reorder-col: 78px;
  /* The workspace, the white panels on it, and the secondary panels (tracks, hovers, tab-strip backgrounds). */
  --ground: #f4f7fc;
  --surface: #ffffff;
  --sunk: #eff8fc;
  --ink: #303946;
  --muted: #5f6b7c;
  --line: #dce4ef;
  --line-strong: #b9c5d6;
  /* The border of an input, select, text box or stepper: 3:1 against the surface, so a field reads as a field. */
  --field-line: #8593a8;
  /* Primary blue: actions, focus, selected marks. Selected tabs and rows sit on --accent-soft. */
  --accent: #2457c5;
  --accent-soft: #e8eeff;
  /* A selected label's text on --accent-soft: the accent itself here (resolved per theme); a Company & look brand color sets 30% of it in --ink instead (theme.js brandProperties), so it reads at AA in light and dark. */
  --accent-ink: var(--accent);
  --on-accent: #ffffff;
  /* The navigation: the sidebar and, from 1280px, the brand block above it. Navy by default; a Company & look brand color repaints it (theme.js brandProperties). */
  --nav: #183b78;
  --nav-ink: #ffffff;
  --nav-muted: #c9d6ef;
  --nav-hover: rgb(255 255 255 / 0.08);
  --nav-active: var(--accent);
  /* The selected sidebar item's text: on the accent here (theme.js sets --on-accent for a light brand color). */
  --nav-active-ink: var(--on-accent);
  /* Statuses, each a readable color on its own pale background: booked or done green, warnings orange (pending has a separate token),
     overdue or an error red, packing purple (packing only), lost or closed grey. Always with a word or an icon. */
  --ok: #167532;
  --ok-soft: #edf9ee;
  --ok-mark: #16a34a;
  --ok-bright: #5cf576;
  --warn: #a64008;
  --warn-soft: #fff1e6;
  --pending: #5263a8;
  --pending-soft: #edf0fc;
  --due: #a64008;
  --due-soft: #fff1e6;
  --bad: #c62828;
  --bad-soft: #fff0f0;
  --bad-mark: #e53935;
  --bad-bright: #ff554d;
  --pack: #7545bb;
  --pack-soft: #f1ebfa;
  --closed: #526174;
  --closed-soft: #eef1f5;
  /* The meters, solid and stepped (scale.js): blue while there is room, orange getting close, red at the end. Green
     stays for the charts' Booked. Fixed whatever the brand color. */
  --scale-blue: #2457c5;
  --scale-green: #16a34a;
  --scale-orange: #d65a0a;
  --scale-red: #e53935;
  /* The quote's two headline charges, never the brand's color (a red brand must not make a charge read as a warning):
     Moving labor in the primary blue, the trip fee in teal, darkened for its words (5.64 on the surface, 5.05 on its
     tile) with the bright teal kept for its tile edge and bars (--charge-trip-mark). Used for nothing else. */
  --charge-labor: #2457c5;
  --charge-labor-soft: #e8eeff;
  --charge-trip: #07708f;
  --charge-trip-soft: #e6f5fa;
  --charge-trip-mark: #089cc2;
  /* Minimal shadows: a card at most --shadow-1; --shadow-2 only for popovers and sticky bars. */
  --shadow-1: 0 1px 2px rgb(23 43 70 / 0.06);
  --shadow-2: 0 8px 20px rgb(23 43 70 / 0.12);
  --radius: 8px;
  --radius-sm: 6px;
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  /* 13px chips and labels (no words under 12px anywhere), 14, 16, then the headings and key totals. */
  --fs-xs: 0.8125rem;
  --fs-sm: 0.875rem;
  --fs-base: 1rem;
  --fs-md: 1.125rem;
  --fs-lg: 1.375rem;
  --fs-xl: 1.75rem;
  --fs-2xl: 2.25rem;
  /* One clean sans-serif for headings and text (Inter); the mono only for code and the export and import boxes. */
  --font-display: "Inter", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-body: "Inter", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color-scheme: light;
}

/* Office is light-only. Legacy theme preferences may remain in storage, but no
   system preference or data-theme attribute changes this palette. */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

[hidden] {
  display: none !important;
}

/* Body text 15px on the workspace background. */
body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.5;
  overflow-x: hidden;
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.2;
  margin: 0;
}

h1 {
  font-size: var(--fs-md);
}

h2 {
  font-size: var(--fs-md);
  letter-spacing: -0.01em;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
}

h3 {
  font-size: var(--fs-sm);
  font-weight: 600;
  margin: var(--sp-4) 0 var(--sp-2);
  color: var(--muted);
}

p {
  margin: 0 0 0.5rem;
}

/* The mono only for code and the export and import boxes; numbers in the body font with even-width figures. */
code,
pre,
textarea.mono {
  font-family: var(--font-mono);
}

.mono,
input.num,
.num {
  font-family: var(--font-body);
  font-variant-numeric: tabular-nums;
}

code {
  font-size: max(12px, 0.85em);
  overflow-wrap: anywhere;
}

.nowrap {
  white-space: nowrap;
}

.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.muted {
  color: var(--muted);
}

.hint {
  color: var(--muted);
  font-size: var(--fs-sm);
}

/* Type roles: a small label over a number (13px, sentence case), and the key numbers themselves (price range, hours,
   cu ft, lifeline %, counts, $/hr), larger and bold with even-width figures. */
.eyebrow {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--muted);
}

.figure {
  font-family: var(--font-body);
  font-weight: 700;
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: -0.01em;
  line-height: 1.1;
  color: var(--ink);
}

.figure-md {
  font-size: var(--fs-md);
}

.figure-lg {
  font-size: var(--fs-lg);
}

.figure-xl {
  font-size: var(--fs-xl);
}

.figure-2xl {
  font-size: var(--fs-2xl);
}

.ok-text {
  color: var(--ok);
}

.bad-text {
  color: var(--bad);
}

/* Packing only, and lost or closed. */
.pack-text {
  color: var(--pack);
}

.closed-text {
  color: var(--closed);
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Transitions stay under 200ms, and none at all for someone who asks the Mac for less motion. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
  }
}

/* Header, sidebar and quick bar */

header.top {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

/* The top bar, the full width: the Menu button (under 900px), the brand, then the quick bar at the right. */
.top-inner {
  min-height: 56px;
  padding: var(--sp-2) 16px;
  display: flex;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  flex-wrap: wrap;
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

/* The company's mark when no logo is set: the Truestimo box mark (design/brand/mark.svg) on a small white tile, so it reads on the navy brand block and on the white header alike. */
.brand-mark {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 7px;
  background: #ffffff;
  box-shadow: inset 0 0 0 1px var(--line);
}

.brand-mark svg {
  display: block;
}

/* Settings → Company & look: the company's logo in place of the mark. */
.brand-logo {
  display: block;
  height: 22px;
  width: auto;
  max-width: 160px;
  object-fit: contain;
}

.brand-app {
  color: var(--muted);
  font-weight: 600;
}

/* A long company name wraps rather than push the tabs off a phone. */
.brand {
  min-width: 0;
}

.brand h1 {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* The view icons: 20px line drawings in the text's color. */
.nav-icon {
  display: block;
  flex: none;
  width: 20px;
  height: 20px;
}

/* The two icon buttons: Menu (under 900px only) and the quick bar's Settings gear. */
.nav-toggle,
.quick-gear {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: background-color 0.15s, color 0.15s;
}

.nav-toggle:hover,
.quick-gear:hover,
.nav-toggle[aria-expanded="true"] {
  background: var(--sunk);
  color: var(--ink);
}

.quick-gear[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--accent-ink);
}

.nav-toggle {
  display: none;
}

/* The quick bar: the Estimator ⇄ Quote switch, Follow-ups with its count, and the Settings gear. Plain buttons that show a view (the sidebar holds the tabs). */
.quick {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-left: auto;
  min-width: 0;
}

/* The Estimator ⇄ Quote switch: one joined track, both halves and the ⇄ key between them; the half that shows is lifted. */
.quick-flip {
  display: flex;
  align-items: center;
  flex: none;
  padding: 2px;
  border-radius: var(--radius-sm);
  background: var(--sunk);
  box-shadow: inset 0 0 0 1px var(--line);
}

.quick-flip [data-go],
.tab-flip-key {
  min-height: 30px;
  padding: 0 var(--sp-3);
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.15s;
}

.quick-flip [data-go]:hover {
  color: var(--ink);
}

.quick-flip [data-go][aria-current="page"] {
  background: var(--surface);
  color: var(--accent-ink);
  box-shadow: 0 0 0 1px var(--line);
}

/* A thumb-sized ⇄: at least 2rem wide. */
.tab-flip-key {
  min-width: 2rem;
  padding: 0 var(--sp-2);
  font-size: var(--fs-base);
  line-height: 1;
}

.tab-flip-key:hover {
  color: var(--accent);
}

/* The quick bar's buttons (Work log, and the Follow-ups bell below): an icon, a name and, on the bell, the due count. */
.quick-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 36px;
  padding: 0 var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.15s;
}

.quick-btn .nav-icon {
  color: var(--muted);
}

.quick-btn:hover {
  background: var(--sunk);
}

.quick-btn[aria-current="page"] {
  border-color: transparent;
  background: var(--accent-soft);
  color: var(--accent-ink);
}

.quick-btn[aria-current="page"] .nav-icon {
  color: inherit;
}

/* Follow-ups in the quick bar is a bell: a square button, its due count as a small pill on its corner. */
.quick-bell {
  position: relative;
  justify-content: center;
  flex: none;
  width: 36px;
  min-width: 36px;
  padding: 0;
}

.quick .quick-bell .tab-count {
  position: absolute;
  top: -7px;
  right: -8px;
  margin: 0;
}

/* Any call or text overdue (or a lifeline at 0%): the bell turns red and glows, and its count goes solid red. */
.quick-bell[data-overdue] {
  border-color: var(--bad-mark);
  background: var(--bad-soft);
  color: var(--bad);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--bad-mark) 22%, transparent), 0 0 12px color-mix(in srgb, var(--bad-bright) 55%, transparent);
  animation: bell-glow 1.8s ease-in-out infinite;
}

.quick-bell[data-overdue] .nav-icon {
  color: var(--bad);
}

.quick .quick-bell[data-overdue] .tab-count {
  background: var(--bad);
  color: #ffffff;
  box-shadow: 0 0 0 2px var(--surface);
}

@keyframes bell-glow {
  50% {
    box-shadow: 0 0 0 5px color-mix(in srgb, var(--bad-mark) 12%, transparent), 0 0 18px color-mix(in srgb, var(--bad-bright) 70%, transparent);
  }
}

@media (prefers-reduced-motion: reduce) {
  .quick-bell[data-overdue] {
    animation: none;
  }
}

/* A phone: the quick bar takes the header's second row, the whole width, keeping the words Estimator and Quote, the ⇄, the Work log icon, the bell with its count and the gear. */
@media (max-width: 600px) {
  .quick {
    flex: 1 1 100%;
    margin-left: 0;
  }

  .quick-flip {
    flex: 1 1 auto;
  }

  .quick-flip [data-go] {
    flex: 1 1 auto;
  }

  .quick-text {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
}

/* The page under the header: the sidebar at the left, the view beside it. --side-w: 200px, a 76px rail from 900 to 1279px, none under 900px (a drawer instead). */
:root {
  --side-w: 200px;
}

@media (max-width: 1279px) {
  :root {
    --side-w: 76px;
  }
}

@media (max-width: 899px) {
  :root {
    --side-w: 0px;
  }
}

.shell {
  display: grid;
  grid-template-columns: var(--side-w) minmax(0, 1fr);
}

.shell > main {
  grid-column: 2;
  grid-row: 1;
  min-width: 0;
}

/* The sidebar: every view, Settings at the bottom, sticking under the header (--header-h, set by app.js). */
.side {
  grid-column: 1;
  grid-row: 1;
  align-self: start;
  position: sticky;
  top: var(--header-h, 56px);
  height: calc(100dvh - var(--header-h, 56px));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-3) var(--sp-2);
  background: var(--nav);
}

.side-tabs {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 100%;
}

.side [role="tab"] {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex: none;
  width: 100%;
  min-height: 40px;
  padding: 0 var(--sp-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--nav-muted);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: background-color 0.15s, color 0.15s;
}

.side [role="tab"]:hover {
  background: var(--nav-hover);
  color: var(--nav-ink);
}

/* The view showing: filled in the primary blue (a deep blue in dark), its name white (dark on a light brand color),
   and a 3px bar at the left in the accent (it shows in dark, and with a Company & look brand color). */
.side [role="tab"][aria-selected="true"] {
  background: var(--nav-active);
  color: var(--nav-active-ink);
  box-shadow: inset 3px 0 0 var(--accent);
}

/* Inside the scrolling sidebar a focus ring sits inside the item, so the edge never clips it; white on the navy. */
.side [role="tab"]:focus-visible {
  outline: 2px solid var(--nav-ink);
  outline-offset: -2px;
}

.nav-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.side-settings {
  margin-top: auto;
}

/* 900 to 1279px: a 76px rail, each icon over its name in small type (every name shows), the count on the icon's corner. */
@media (min-width: 900px) and (max-width: 1279px) {
  .side {
    padding: var(--sp-2) 4px;
  }

  .side [role="tab"] {
    flex-direction: column;
    justify-content: center;
    gap: 3px;
    min-height: 60px;
    padding: 6px 2px;
    text-align: center;
  }

  .side .nav-label {
    max-width: 100%;
    font-size: 0.75rem;
    line-height: 1.2;
    white-space: normal;
    overflow: visible;
  }

  .side .tab-count {
    position: absolute;
    top: 5px;
    left: calc(50% + 5px);
    margin: 0;
  }
}

/* Under 900px: no sidebar in the page; the Menu button opens it as a drawer over the page, the page dimmed behind it. */
.side-backdrop {
  display: none;
}

@media (max-width: 899px) {
  .nav-toggle {
    display: inline-grid;
  }

  .side {
    position: fixed;
    top: var(--header-h, 56px);
    left: 0;
    bottom: 0;
    z-index: 12;
    width: min(280px, 85vw);
    height: auto;
    /* A fixed box in the grid follows align-self: stretch lets top and bottom set its height. */
    align-self: stretch;
    visibility: hidden;
    translate: -100% 0;
    box-shadow: var(--shadow-2);
  }

  /* It slides in; closing hides it at once, so a hidden tab never keeps focus. */
  .side.is-open {
    visibility: visible;
    translate: 0 0;
    transition: translate 0.18s ease-out;
  }

  .side-backdrop {
    display: block;
    position: fixed;
    inset: var(--header-h, 56px) 0 0 0;
    z-index: 11;
    background: rgb(0 0 0 / 0.3);
  }
}

.storage-note {
  margin: 0;
  padding: 0.4rem 16px;
  background: var(--warn-soft);
  color: var(--warn);
  text-align: center;
  font-size: 0.9rem;
}

/* "Click anywhere or press a key to turn on reminder sounds": the storage note's place in the header, calmer, since nothing is wrong. */
.storage-note.sound-note {
  background: var(--accent-soft);
  color: var(--accent-ink);
}

main {
  width: 100%;
  max-width: 1680px;
  margin: 0 auto;
  padding: var(--sp-5) 24px 4rem;
}

@media (max-width: 600px) {
  main {
    padding-inline: 16px;
  }
}

/* From 1280px the brand sits on a navy block exactly the sidebar's width, flush left and the header's full height, so
   the sidebar and the brand read as one navy column; a Company & look logo sits on a small white plate so a dark logo
   stays readable. Under 1280px the brand stays on the white header. */
@media (min-width: 1280px) {
  header.top .top-inner {
    padding-block: 0;
    padding-left: 0;
    padding-right: 24px;
  }

  header.top .brand {
    flex: none;
    align-self: stretch;
    width: var(--side-w);
    /* Over the header's bottom line, so the navy runs straight into the sidebar. */
    margin-bottom: -1px;
    padding: var(--sp-2) var(--sp-4);
    background: var(--nav);
  }

  /* A two-line name still fits the 56px header. */
  header.top .brand h1 {
    color: var(--nav-ink);
    font-size: var(--fs-base);
  }

  header.top .brand-app {
    color: var(--nav-muted);
  }


  header.top .brand-logo {
    box-sizing: content-box;
    max-width: 152px;
    padding: 4px;
    border-radius: var(--radius-sm);
    background: var(--surface);
  }

  /* With a logo showing, the name goes under it when they do not fit side by side, so a wide logo never squeezes it. */
  header.top .brand:has(> .brand-logo:not([hidden])) {
    flex-wrap: wrap;
    align-content: center;
    row-gap: var(--sp-1);
  }

  header.top .quick {
    padding-block: var(--sp-2);
  }
}

/* Banners and messages */

.banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem var(--sp-4);
  padding: 0.65rem 0.9rem;
  border-radius: var(--radius-sm);
  margin-bottom: var(--sp-4);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
}

.banner p {
  margin: 0;
}

.banner code {
  flex-basis: 100%;
}

/* A banner or message: its tone's pale background, a thin line of the tone, the words in ink. */
.banner.warn {
  background: var(--warn-soft);
  border-color: color-mix(in srgb, var(--warn) 30%, transparent);
}

.banner.bad {
  background: var(--bad-soft);
  border-color: color-mix(in srgb, var(--bad) 30%, transparent);
}

/* Good news: the browser was filled from the automatic backup. */
.banner.ok {
  background: var(--ok-soft);
  border-color: color-mix(in srgb, var(--ok) 30%, transparent);
}

.banner.ok p {
  overflow-wrap: anywhere;
}

/* Settings → Backup → Export and import quotes (quotes-backup.js), after the settings export and import */
.quotes-backup {
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
}

.quotes-backup > .hint {
  margin: 0.35rem 0 0;
}

.quotes-backup h4 {
  font-size: var(--fs-sm);
  font-weight: 600;
  margin: var(--sp-4) 0 var(--sp-2);
  color: var(--muted);
}

/* Settings → Backup → Automatic backups */
.auto-backup {
  margin-bottom: 1rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--line);
}

.auto-backup p {
  margin: 0.35rem 0;
  overflow-wrap: anywhere;
}

.auto-backup-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0.6rem 0 0.4rem;
}

.auto-backup-source {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  max-width: 100%;
}

.auto-backup-source select {
  max-width: 100%;
}

.auto-backup [aria-disabled="true"] {
  opacity: 0.6;
  cursor: progress;
}

.msg {
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 0.55rem 0.75rem;
  margin-top: 0.6rem;
  color: var(--ink);
  font-size: var(--fs-sm);
}

.msg p {
  margin: 0 0 0.25rem;
}

.msg p:last-child {
  margin-bottom: 0;
}

.msg code {
  display: block;
  color: var(--muted);
  margin-top: 0.2rem;
}

.msg .link {
  display: inline-block;
  margin-top: 0.3rem;
}

.msg.bad {
  background: var(--bad-soft);
  border-color: color-mix(in srgb, var(--bad) 30%, transparent);
}

.msg.warn {
  background: var(--warn-soft);
  border-color: color-mix(in srgb, var(--warn) 30%, transparent);
}

.calm {
  background: var(--sunk);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.65rem 0.8rem;
  color: var(--ink);
  font-size: var(--fs-sm);
  margin-top: 0.75rem;
}

/* A status label: 13px words on its tone's pale background, the words in the tone, a thin line of it. Never color
   alone: the chip always says its status. */
.chip {
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.5;
  padding: 0.1rem 0.5rem;
  border-radius: var(--radius-sm);
  white-space: nowrap;
  border: 1px solid transparent;
}

.chip.ok {
  background: var(--ok-soft);
  border-color: color-mix(in srgb, var(--ok) 25%, transparent);
  color: var(--ok);
}

.chip.warn {
  background: var(--warn-soft);
  border-color: color-mix(in srgb, var(--warn) 25%, transparent);
  color: var(--warn);
}

.chip.bad {
  background: var(--bad-soft);
  border-color: color-mix(in srgb, var(--bad) 25%, transparent);
  color: var(--bad);
}

/* Packing only. */
.chip.pack {
  background: var(--pack-soft);
  border-color: color-mix(in srgb, var(--pack) 25%, transparent);
  color: var(--pack);
}

/* Lost or closed: a calm grey, not an error. */
.chip.closed {
  background: var(--closed-soft);
  border-color: color-mix(in srgb, var(--closed) 25%, transparent);
  color: var(--closed);
}

.chip.muted {
  background: var(--sunk);
  border-color: var(--line);
  color: var(--muted);
}

.chip.accent {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 25%, transparent);
  color: var(--accent-ink);
}

/* A large chip (the status chips themselves are quote-bar.js statusChipHtml, .qb-chip-lg). */
.chip.chip-lg {
  font-size: var(--fs-base);
  font-weight: 600;
  padding: 0.3rem 0.8rem;
  min-height: 32px;
  border-radius: var(--radius-sm);
}

/* The largest chip size. */
.chip.chip-xl {
  font-size: var(--fs-lg);
  font-weight: 600;
  padding: 0.45rem 1rem;
  min-height: 40px;
  border-radius: var(--radius-sm);
}

/* Controls */

/* A button: white with a firm line (secondary). .btn.primary is the one main action of a panel, filled in the primary
   blue. Ghost, danger and icon as before. No shadows. */
.btn {
  font: inherit;
  font-weight: 600;
  font-size: var(--fs-sm);
  line-height: 1.25;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 0.4rem 0.85rem;
  cursor: pointer;
  min-height: 36px;
  transition:
    background-color 120ms ease,
    border-color 120ms ease,
    color 120ms ease;
}

.btn:hover:not(:disabled) {
  border-color: var(--accent);
  background: var(--sunk);
}

.btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.btn.primary:hover:not(:disabled) {
  background: color-mix(in srgb, var(--accent) 88%, var(--ink));
  border-color: color-mix(in srgb, var(--accent) 88%, var(--ink));
}

.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn.small {
  font-size: var(--fs-sm);
  padding: 0.25rem 0.7rem;
  min-height: 32px;
}

.btn.ghost {
  background: transparent;
  border-color: transparent;
  color: var(--muted);
}

.btn.ghost:hover:not(:disabled) {
  background: var(--sunk);
  border-color: var(--line);
  color: var(--ink);
}

.btn.danger {
  background: var(--bad);
  border-color: var(--bad);
  color: var(--surface);
}

.btn.danger:hover:not(:disabled) {
  background: color-mix(in srgb, var(--bad) 88%, var(--ink));
  border-color: color-mix(in srgb, var(--bad) 88%, var(--ink));
}

.btn.icon {
  width: 36px;
  padding: 0;
  font-size: 1.1rem;
  line-height: 1;
}

.link {
  font: inherit;
  color: var(--accent);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}

input[type="text"],
input[type="number"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="date"],
input[type="search"],
select,
textarea {
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--field-line);
  border-radius: var(--radius-sm);
  padding: 0.4rem 0.6rem;
  min-height: 36px;
  width: 100%;
  min-width: 0;
  transition:
    border-color 120ms ease,
    box-shadow 120ms ease;
}

input[type="text"]:focus-visible,
input[type="number"]:focus-visible,
input[type="email"]:focus-visible,
input[type="tel"]:focus-visible,
input[type="url"]:focus-visible,
input[type="date"]:focus-visible,
input[type="search"]:focus-visible,
select:focus-visible,
textarea:focus-visible {
  border-color: var(--accent);
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

textarea {
  resize: vertical;
  line-height: 1.45;
}

textarea.mono {
  font-size: 0.85rem;
}

/* Under 900px every box a person types in is 16px, so a phone never zooms into it. */
@media (max-width: 899px) {
  input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"], [type="color"], [type="hidden"]),
  select,
  textarea,
  textarea.mono {
    font-size: 16px;
  }
}

input.num {
  text-align: right;
}

input::placeholder,
textarea::placeholder {
  color: var(--muted);
  opacity: 0.8;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}

.field > span:first-child {
  font-size: var(--fs-sm);
  color: var(--ink);
  font-weight: 600;
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  flex-wrap: wrap;
}

.inline {
  display: inline-flex;
}

.grow {
  flex: 1 1 auto;
  min-width: 0;
}

.with-unit {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.with-unit .unit {
  color: var(--muted);
  font-size: 0.87rem;
  white-space: nowrap;
}

.row-between {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  flex-wrap: wrap;
}

.row-between h2 {
  margin-bottom: 0;
}

.two,
.grid-2 {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
}

.grid-2.align-top {
  align-items: start;
}

/* Settings → Time: the minimum hours box with its help line under it. */
.min-hours .hint {
  margin: 0.3rem 0 0;
}

.grid-3 {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.75rem;
}

.grid-4 {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.75rem;
}

/* A segmented choice: a pale track, the chosen one in the selected tint with the accent's words. */
.seg {
  display: inline-flex;
  flex-wrap: wrap;
  background: var(--sunk);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 2px;
  gap: 2px;
}

.seg-btn {
  font: inherit;
  font-weight: 600;
  font-size: var(--fs-sm);
  border: 0;
  background: transparent;
  color: var(--muted);
  padding: 0.35rem 0.8rem;
  border-radius: 4px;
  cursor: pointer;
  min-height: 34px;
  transition:
    background-color 120ms ease,
    color 120ms ease;
}

.seg-btn:hover:not([aria-pressed="true"]):not(:disabled) {
  color: var(--ink);
}

.seg-btn[aria-pressed="true"] {
  background: var(--accent-soft);
  color: var(--accent-ink);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent);
}

/* Estimator layout */

/* Top to bottom: the job bar (the page's title card), the jump tabs, then every section as a white card, all on the
   page at once (the jump tabs only scroll to one). The inputs sit in two columns when the form itself gives each at
   least 22rem (never three, one on a phone); Access, Packing and Time take the full width. The Price card is pinned
   on the right from 1200px while the rep builds; under that it sits between the inputs and the crew notes, full width.
   The truck bar stays outside the grid, so it can stick under the jump tabs while Time is on screen. */
#tab-estimator {
  --est-jump-h: 44px;
}

/* The jump tabs: one row sticking under the header (10) and under the move date's calendar (9); the current section's
   tab in the selected tint with a primary bottom edge. The row scrolls sideways in its own strip when it overflows. */
.est-jump {
  position: sticky;
  top: var(--header-h, 56px);
  z-index: 8;
  display: flex;
  align-items: center;
  height: var(--est-jump-h);
  margin: var(--sp-3) 0 0;
  padding: 0 8px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  min-width: 0;
}

/* A zero width that grows to fill the strip: the row of tabs never widens the page on a phone, it scrolls in here. */
.est-jump-list {
  position: relative;
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 4px;
  flex: 1 1 0;
  width: 0;
  min-width: 0;
  padding: 3px 0;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
}

.est-jump-btn {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  height: 36px;
  padding: 0 var(--sp-3);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  white-space: nowrap;
  color: var(--muted);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition:
    background-color 120ms ease,
    color 120ms ease;
}

.est-jump-btn:hover {
  background: var(--sunk);
  color: var(--ink);
}

.est-jump-btn:focus-visible {
  outline-offset: -2px;
}

.est-jump-btn[aria-current="location"] {
  background: var(--accent-soft);
  color: var(--accent-ink);
  box-shadow: inset 0 -2px 0 var(--accent);
}

/* The tab's step number: a quiet square, primary on the current tab (the card's own number is always primary). */
.est-jump-btn .n {
  width: 20px;
  height: 20px;
  background: var(--sunk);
  color: var(--muted);
  box-shadow: inset 0 0 0 1px var(--line);
}

.est-jump-btn[aria-current="location"] .n {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: none;
}

/* A jump lands the card's top edge just under the jump tabs (its heading is the target, the card's padding above it),
   and under the truck bar while it shows (--truck-bar-room, its height and gap, set by estimator-tab.js; 0 otherwise). */
#tab-estimator .block > h2,
#h-price,
#h-crewnotes {
  scroll-margin-top: calc(var(--header-h, 56px) + var(--est-jump-h) + var(--truck-bar-room, 0px) + 12px + 17px);
}

#tab-estimator .block,
#tab-estimator .card {
  scroll-margin-top: calc(var(--header-h, 56px) + var(--est-jump-h) + var(--truck-bar-room, 0px) + 12px);
}

#job-bar {
  scroll-margin-top: calc(var(--header-h, 56px) + 12px);
}

/* The sections: one column, 16px apart (margins, so a hidden #res-general leaves no double gap). */
.est-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  margin-top: var(--sp-4);
  min-width: 0;
}

.est-layout > * {
  min-width: 0;
}

.est-layout > * + * {
  margin-top: var(--sp-4);
}

/* From 1200px: the form on the left, the Price card pinned on the right over every row, sticking under the jump tabs
   while the rep scrolls; the last row takes what is left, so a short form never spreads out. A very short window
   scrolls inside the card. */
@media (min-width: 1200px) {
  .est-layout {
    grid-template-columns: minmax(0, 1fr) 21rem;
    grid-template-rows: auto auto 1fr;
    column-gap: var(--sp-4);
    align-items: start;
  }

  .est-layout > .est-inputs {
    grid-column: 1;
    grid-row: 1;
  }

  .est-layout > #res-general {
    grid-column: 1;
    grid-row: 2;
  }

  .est-layout > #res-crew {
    grid-column: 1;
    grid-row: 3;
  }

  /* The truck bar sits over the form's column, so it never covers the pinned Price card. */
  #tab-estimator > .truck-bar {
    margin-right: calc(21rem + var(--sp-4));
  }

  .est-layout > .price-strip {
    grid-column: 2;
    grid-row: 1 / -1;
    align-self: start;
    position: sticky;
    top: calc(var(--header-h, 56px) + var(--est-jump-h) + 12px);
    max-height: calc(100dvh - var(--header-h, 56px) - var(--est-jump-h) - 24px);
    overflow-y: auto;
    overscroll-behavior: contain;
    margin-top: 0;
  }
}

/* Two compact groups retain source/keyboard order: property, move, crew,
   then travel and access. They collapse independently when the form is narrow. */
.est-inputs {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
  container-type: inline-size;
}

.est-basics,
.est-logistics {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
  min-width: 0;
}

.est-inputs .block {
  min-width: 0;
  padding: 14px;
}

.est-inputs .block > h2 {
  font-size: 16px;
  margin-bottom: 12px;
}

.est-inputs .hint {
  font-size: 12px;
  line-height: 1.5;
}

.est-inputs .trucks {
  gap: 8px;
}

.est-inputs .truck-row > .row-label {
  flex: 0 0 4rem;
}

@container (min-width: 680px) {
  .est-basics,
  .est-logistics {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }


}

/* Local help keeps the working form short without removing explanations. */
.est-help {
  margin: 8px 0;
  color: var(--muted);
  font-size: 12px;
}

.est-help > summary {
  cursor: pointer;
  min-height: 24px;
  padding-block: 3px;
  color: var(--accent-ink);
}

.est-help .hint {
  margin: 4px 0;
}

.est-logistics .access-grid {
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
}

.est-logistics .access-loc {
  padding: 10px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 6px 10px;
}

.est-logistics .access-loc h3,
.est-logistics .access-loc .access-time {
  grid-column: 1 / -1;
  margin: 0;
}

.est-logistics .access-field {
  gap: 4px;
  margin: 0;
}

.est-logistics .access-field > span,
.est-logistics .access-time {
  font-size: 12px;
}

.est-logistics .seg-btn {
  padding-inline: 8px;
  font-size: 12px;
}

@container (max-width: 359px) {
  .est-logistics .access-loc {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* The Price card: the estimate summary, on the secondary panel colour, the charge tiles and the Total estimate white
   on it; the crew line figures large, the Total estimate the largest figure, in the accent; See full breakdown a full
   width button at the foot. Top to bottom as always, the total last. */
.price-strip {
  background: var(--sunk);
  border: 1px solid var(--line);
}

.price-strip > h2 {
  margin-bottom: var(--sp-3);
}

.price-strip #res-price-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  min-width: 0;
}

.price-strip #res-price-body > * {
  margin: 0;
  min-width: 0;
}

.price-strip .charge {
  background: var(--surface);
}

.price-strip .total-estimate {
  margin-top: 0;
}

.price-strip .total-estimate .eyebrow {
  font-size: var(--fs-sm);
}

.price-strip .total-estimate .figure {
  font-size: var(--fs-2xl);
  color: var(--accent-ink);
}

.price-strip .price-more {
  font-size: var(--fs-sm);
}

.price-strip .price-more .link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 36px;
  padding: 0.4rem 0.85rem;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  transition:
    background-color 120ms ease,
    border-color 120ms ease;
}

.price-strip .price-more .link:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}

/* Pinned, the whole summary fits a laptop window (1440×800, 1280×720) with a separate packing day: tighter padding and
   gaps, the tile amounts a size smaller. Nothing is left out and the order stays. */
@media (min-width: 1200px) {
  .est-layout > .price-strip {
    padding: var(--sp-3);
  }

  .est-layout > .price-strip > h2 {
    margin-bottom: var(--sp-2);
  }

  .est-layout > .price-strip #res-price-body,
  .est-layout > .price-strip .charges,
  .est-layout > .price-strip .charge-tiles {
    gap: var(--sp-2);
  }

  .est-layout > .price-strip .charge {
    padding: var(--sp-2) var(--sp-3);
    gap: 2px;
  }

  .est-layout > .price-strip .charge-amount {
    font-size: var(--fs-lg);
  }

  .est-layout > .price-strip .charge-how,
  .est-layout > .price-strip .price-lines {
    font-size: var(--fs-sm);
  }

  .est-layout > .price-strip .total-estimate {
    gap: var(--sp-1);
    padding: var(--sp-2) var(--sp-3);
  }

  .est-layout > .price-strip .crew-line {
    row-gap: var(--sp-1);
  }

  .est-layout > .price-strip .charge-label,
  .est-layout > .price-strip .charge-how,
  .est-layout > .price-strip .price-lines,
  .est-layout > .price-strip .total-estimate .eyebrow {
    line-height: 1.35;
  }

  .est-layout > .price-strip .price-more .link {
    min-height: 32px;
  }
}

@media (max-width: 600px) {
  .est-jump {
    margin-inline: 0;
    padding-inline: 4px;
  }
}

/* Job bar: SmartMoving #, customer name, phone, move date, status, Save quote, New call */

/* One line on wide screens: the fields on the left at sensible widths, then the
   status and the Save quote / New call buttons on the right. They wrap as the
   window narrows; messages always take their own full-width line. */
.job-bar {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: var(--sp-3) var(--sp-4);
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-2) var(--sp-4);
}

.job-bar > .job-fields {
  flex: 1 1 36rem;
  min-width: 0;
}

.job-bar > .job-msg,
.job-bar > .calm {
  flex-basis: 100%;
}

.job-row {
  display: flex;
  align-items: center;
  gap: 0.4rem 0.6rem;
  flex-wrap: wrap;
}

/* SmartMoving #, customer name and phone: a small label over each box; they wrap as a phone narrows. */
.job-fields {
  align-items: flex-end;
}

.job-field {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  flex: 1 1 9rem;
  min-width: 0;
}

.job-field-ref {
  flex: 0 1 10.5rem;
}

/* The SmartMoving # box, with an older quote's job number beside it (muted) until one is typed. */
.job-ref-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

.job-ref-row input {
  flex: 1 1 6rem;
  min-width: 0;
}

.job-old-id {
  flex: 0 0 auto;
  font-size: 0.85rem;
  color: var(--muted);
  white-space: nowrap;
}

/* Under the bar once the SmartMoving # box is left: a number not in the #123456 shape, or one another quote has too. */
.job-bar > .job-ref-note {
  flex-basis: 100%;
  margin: 0.2rem 0 0;
}

.job-ref-note > span + span::before {
  content: "· ";
}

.job-field-phone {
  flex: 1 1 8rem;
}

.job-label {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--muted);
}

.job-field input {
  min-height: 32px;
  padding: 0.25rem 0.5rem;
  font-size: 0.93rem;
}

/* The customer's name reads as the page's title. */
.job-field-name input {
  font-size: var(--fs-md);
  font-weight: 600;
}

/* Under 900px the bar's boxes are 16px too (the name stays larger), so a phone never zooms into them. */
@media (max-width: 899px) {
  .job-field input {
    font-size: 16px;
  }

  .job-field-name input {
    font-size: var(--fs-md);
  }
}

.job-msg:empty {
  display: none;
}

.job-msg p,
.job-msg .stale {
  margin: 0.45rem 0 0;
  font-size: 0.92rem;
}

.job-bar .calm {
  margin: 0.45rem 0 0;
  font-size: 0.92rem;
}

/* Move date: the date button, its clear ×, the TBD toggle, and the popover calendar under them. */

.job-field-date {
  position: relative;
  flex: 1 1 13rem;
}

/* Wide screens: fields at sensible widths instead of stretching across the bar. */
@media (min-width: 961px) {
  .job-field-ref {
    flex: 0 0 auto;
  }

  .job-field-ref input {
    flex: 0 0 8.5rem;
  }

  .job-field-name {
    flex: 1 1 12rem;
    max-width: 22rem;
  }

  .job-field-phone {
    flex: 0 1 11rem;
  }

  .job-field-date {
    flex: 0 0 auto;
  }
}

.move-date-row {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
}

.date-btn {
  flex: 1 1 auto;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-width: 0;
  min-height: 32px;
  padding: 0.25rem 0.55rem;
  font: inherit;
  font-size: 0.93rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-align: left;
  white-space: nowrap;
}

.date-btn > span:last-child {
  overflow: hidden;
  text-overflow: ellipsis;
}

.date-btn:hover:not(:disabled),
.date-btn[aria-expanded="true"] {
  border-color: var(--accent);
}

.date-btn.empty > span:last-child {
  color: var(--muted);
}

/* TBD on: the kept date is not used, so the button reads TBD and waits. */
.date-btn:disabled {
  cursor: not-allowed;
  color: var(--muted);
  background: var(--sunk);
  border-style: dashed;
}

/* A small calendar drawn in CSS: a frame with a thicker top edge. */
.date-btn-icon {
  flex: none;
  width: 14px;
  height: 13px;
  border: 1.5px solid currentColor;
  border-top-width: 3.5px;
  border-radius: 3px;
  color: var(--muted);
}

.date-clear {
  flex: none;
  width: 32px;
  height: 32px;
  padding: 0;
  font: inherit;
  font-size: 1.15rem;
  line-height: 1;
  color: var(--muted);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.date-clear:hover {
  border-color: var(--accent);
  color: var(--ink);
}

/* Scoped to the row so it wins over .chip-toggle's 30px (defined later): the toggle matches the 32px button and ×. */
.move-date-row .tbd-toggle {
  flex: none;
  min-height: 32px;
}

.cal-pop {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 9;
  width: min(18.5rem, calc(100vw - 16px));
  padding: 0.6rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-2);
}

.cal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.35rem;
}

.cal-title {
  margin: 0;
  font-size: 0.98rem;
}

.cal-nav {
  width: 32px;
  height: 32px;
  padding: 0;
  font: inherit;
  font-size: 1.3rem;
  line-height: 1;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.cal-nav:hover {
  border-color: var(--accent);
}

.cal-grid {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.cal-grid th {
  padding: 0.2rem 0;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--muted);
  text-align: center;
}

.cal-grid td {
  padding: 1px;
  text-align: center;
}

.cal-grid th,
.cal-grid td {
  border: 0;
}

.cal-day {
  width: 100%;
  min-height: 34px;
  padding: 0;
  font: inherit;
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.cal-day:hover {
  background: var(--sunk);
}

/* Past days are dimmed but can still be picked: a quote can be back-dated. The
   neighbouring months' days are muted and smaller, not faded, so every day
   button keeps a readable contrast. */
.cal-day.past,
.cal-day.out {
  color: var(--muted);
}

.cal-day.out {
  font-size: 0.8rem;
}

.cal-day.today {
  font-weight: 600;
  box-shadow: inset 0 0 0 1.5px var(--accent);
}

.cal-day.selected,
.cal-day.selected:hover {
  background: var(--accent);
  color: var(--on-accent);
}

.cal-day:focus-visible,
.cal-nav:focus-visible,
.date-btn:focus-visible,
.date-clear:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.cal-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 0.4rem;
  font-size: 0.9rem;
}

.link:disabled {
  color: var(--muted);
  text-decoration: none;
  cursor: default;
}

/* Crew notes: full width at the bottom of the Estimator, typed in by hand. At
   least 20 lines tall; it grows with its text (the page scrolls, not the box) and
   can be dragged taller. */
.crew-notes-field {
  display: block;
}

/* Larger type for hand typing: display only, since Copy (and Cmd+C) copies plain
   text, which takes the look of wherever it is pasted. */
textarea.crew-notes-text {
  font-size: 1.2rem;
  line-height: 1.5;
}

.crew-notes-text {
  width: 100%;
  min-height: 26em;
  /* 20 lines plus the box's padding and border; a browser without the lh unit keeps 26em. */
  min-height: max(26em, calc(20lh + 0.8rem + 2px));
  resize: vertical;
}

@supports (field-sizing: content) {
  .crew-notes-text {
    field-sizing: content;
  }
}

/* The Estimator's Price card ends with the way to the Quote page's full breakdown. */
.price-more {
  font-size: var(--fs-sm);
}

/* Quick's offer of a preset's window for the job's crew, with Use it. */
.preset-offer:empty {
  display: none;
}

.preset-offer {
  margin: 0.3rem 0 0;
}

/* Quote page */

#tab-quote {
  max-width: 1180px;
  margin: 0 auto;
}

.qp-empty p {
  margin: 0;
}

.qp-empty .row-actions {
  align-items: center;
}

/* One calm column at every width, read top to bottom: the head, The quote, Crew and time, Customer, Customer notes,
   Personal notes, Follow-up plan, Timeline: each a white card, 16px apart, 20px inside, every heading 18px.
   A one-track grid with a zero minimum, so a wide table (packing materials) scrolls in its own box at 375px
   instead of widening the page. */
.qp-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-4);
  max-width: 60rem;
  width: 100%;
  margin-inline: auto;
}

.qp-body > .card,
.qp-customer > .card {
  padding: 1.25rem;
}

.qp-body > .card > h2,
.qp-customer .card h2,
.qp-body .qp-fu-head h2 {
  font-size: var(--fs-md);
  line-height: 1.2;
}

.qp-body > .card > h2 {
  margin-bottom: var(--sp-3);
}

.qp-body > .banner {
  margin-bottom: 0;
}

/* A calm banner: the grey of the calm notes, for news that is no warning (the Quote page's unsaved changes). */
.banner.calm {
  background: var(--sunk);
  border-color: var(--line);
  padding: 0.65rem 0.9rem;
  margin-top: 0;
  font-size: inherit;
}

.qp-msg .stale,
.qp-msg p {
  margin: 0;
}

.qp-since {
  font-size: var(--fs-sm);
}

.qp-who {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-4);
  margin: var(--sp-3) 0 0;
  overflow-wrap: anywhere;
}

/* The customer's name, large (22px): the first thing read under the quote's number. */
.qp-who .qp-name {
  flex-basis: 100%;
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: 1.2;
}

.qp-status {
  margin-top: var(--sp-3);
}

.qp-status-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.qp-status .hint {
  margin: 0.4rem 0 0;
}

.status-btn[aria-pressed="true"][data-value="booked"] {
  background: var(--ok-soft);
  border-color: var(--ok);
  color: var(--ok);
  box-shadow: inset 0 0 0 1px var(--ok);
}

.status-btn[aria-pressed="true"][data-value="pending"] {
  background: var(--warn-soft);
  border-color: var(--warn);
  color: var(--warn);
  box-shadow: inset 0 0 0 1px var(--warn);
}

/* Lost in the calm grey of closed, not an error's red. */
.status-btn[aria-pressed="true"][data-value="lost"] {
  background: var(--closed-soft);
  border-color: var(--closed);
  color: var(--closed);
  box-shadow: inset 0 0 0 1px var(--closed);
}

/* Book on a booked quote and Lost on a lost one: lit, and not clickable again (a mistake is a correction). */
.status-btn[aria-pressed="true"]:disabled {
  opacity: 1;
  cursor: default;
}

.qp-part + .qp-part {
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
}

.qp-part > h3:first-child {
  margin-top: 0;
  font-size: var(--fs-base);
  color: var(--ink);
}

.qp-part .trips {
  margin-top: 0.4rem;
}

.qp-time .total-row td,
.qp-materials tfoot td {
  font-weight: 600;
}

.table-scroll {
  overflow-x: auto;
}

.qp-materials td.num,
.qp-materials th.num {
  white-space: nowrap;
}

/* A phone: tighter cells, the words their size (the table scrolls in its own box when it must). */
@media (max-width: 480px) {
  .qp-materials th,
  .qp-materials td {
    padding: 0.35rem 0.2rem;
  }
}

.qp-customer #res-customer .field {
  margin-top: 0.4rem;
}

#qp-personal-state {
  margin: 0.35rem 0 0;
}

/* Quotes: the status filter */

.quote-filter-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.75rem;
  margin-bottom: 0.5rem;
}

.quote-filter-row .seg {
  flex-wrap: wrap;
}

.seg-count {
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  margin-left: 0.15rem;
}

/* Quotes */

#tab-quotes {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 980px;
  margin: 0 auto;
}

.quotes-head .hint {
  margin-bottom: 0.5rem;
}

.quotes-head .banner {
  margin-bottom: 0.5rem;
}

/* The saved quotes: one card, a row to each quote with a 1px line between (not a box each). */
.quote-list {
  display: flex;
  flex-direction: column;
}

.quote-list:has(> .quote-row) {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
}

.quote-row {
  min-height: 48px;
  padding: var(--sp-3) var(--sp-4);
  display: flex;
  gap: var(--sp-2) var(--sp-4);
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  min-width: 0;
}

.quote-row + .quote-row {
  border-top: 1px solid var(--line);
}

/* The row under the pointer on the pale panel colour, inside the card's rounded corners. */
.quote-row:hover {
  background: var(--sunk);
}

.quote-row:first-child {
  border-top-left-radius: var(--radius);
  border-top-right-radius: var(--radius);
}

.quote-row:last-child {
  border-bottom-left-radius: var(--radius);
  border-bottom-right-radius: var(--radius);
}

.quote-main {
  flex: 1 1 22rem;
  min-width: 0;
}

.quote-main p {
  margin: 0;
}

/* The quote's number (15px, 600, even-width figures), its status chip, the name in ink, the phone and date muted 14px,
   on one wrapping line. */
.quote-title {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-3);
}

.quote-title > .figure {
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0;
}

.quote-title > :is(.mono, span.muted) {
  font-size: var(--fs-sm);
  color: var(--muted);
}

.quote-summary {
  margin-top: 0.2rem !important;
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.quote-main .hint {
  font-size: var(--fs-xs);
  margin-top: 0.15rem;
}

.quote-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: center;
  flex: 0 1 auto;
  min-width: 0;
}

.quote-actions .stale {
  margin: 0;
}

#quotes-clash:empty {
  display: none;
}

/* A white panel on the workspace: a thin line, the modest radius, no shadow. */
.block,
.card {
  scroll-margin-top: 7rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: none;
  padding: var(--sp-4) 20px;
  min-width: 0;
}

/* A step card's number: a small primary-blue square with a white tabular numeral. */
.n {
  display: inline-grid;
  flex: none;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 600;
  font-variant-numeric: tabular-nums lining-nums;
  line-height: 1;
}

.trucks,
.room-list,
.stops {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.truck-row,
.stop-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.row-label {
  font-weight: 600;
  min-width: 4.2rem;
}

.miles-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.miles-row .count {
  min-width: 3ch;
}

.stepper {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.count {
  min-width: 2ch;
  text-align: center;
  font-size: 1.05rem;
}

.total {
  color: var(--muted);
}

.total strong {
  color: var(--ink);
  font-size: 1.1rem;
  margin-left: 0.3rem;
}

.trucks + .row-between {
  margin-top: 0.75rem;
}

/* The mode switch: Quick · Standard · Complex */

.mode-row {
  display: flex;
  align-items: center;
  gap: 0.35rem 0.75rem;
  flex-wrap: wrap;
  margin: 0.1rem 0 0.9rem;
}

.mode-row .hint {
  margin: 0;
}

/* Step 2: Full move · Labor only, and the Packing switch beside them (on one line on a phone; under them in the
   wide layout's narrow card, where both do not fit). */
.moving-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* Quick slider */

.t1 {
  margin-top: 0.25rem;
}

.t1-head {
  display: flex;
  align-items: baseline;
  gap: 0.5rem 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.6rem;
}

.t1-window {
  font-size: 1.5rem;
  font-weight: 500;
}

.t1-quoted {
  color: var(--muted);
}

.rs {
  --start: 0%;
  --end: 10%;
  position: relative;
  height: 40px;
  margin: 0 11px;
  touch-action: none;
  cursor: pointer;
  user-select: none;
}

.rs-track {
  position: absolute;
  left: 0;
  right: 0;
  top: 17px;
  height: 6px;
  border-radius: 3px;
  background: var(--sunk);
  box-shadow: inset 0 0 0 1px var(--line);
}

.rs-band {
  position: absolute;
  top: 13px;
  height: 14px;
  left: var(--start);
  width: calc(var(--end) - var(--start));
  background: var(--accent);
  border-radius: var(--radius-sm);
  cursor: grab;
  opacity: 0.9;
}

.rs.dragging .rs-band {
  cursor: grabbing;
}

.rs-thumb {
  position: absolute;
  top: 9px;
  width: 22px;
  height: 22px;
  margin-left: -11px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--accent);
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.25);
  cursor: grab;
}

.rs-thumb:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.rs-scale {
  position: relative;
  height: 1.2rem;
  margin: 0 11px 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--muted);
}

.rs-scale span {
  position: absolute;
  transform: translateX(-50%);
}

/* Standard and Complex rooms */

.add-room {
  display: flex;
  gap: 0.5rem;
  align-items: flex-end;
  flex-wrap: wrap;
}

.room-sel {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.7rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  background: var(--ground);
}

.room-sel.missing {
  border-color: var(--warn);
}

.room-sel-head {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.label-input {
  font-weight: 600;
}

.add-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.add-chip[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
}

.room-range {
  display: block;
}

.range-ticks {
  display: flex;
  justify-content: space-between;
  gap: 0.25rem;
  font-size: 0.78rem;
  color: var(--muted);
  margin-top: -0.2rem;
}

.range-ticks span {
  min-width: 0;
  overflow-wrap: anywhere;
}

.range-ticks .on {
  color: var(--ink);
  font-weight: 600;
}

/* A point with no pieces yet. */
.range-ticks .empty {
  opacity: 0.5;
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

.job-cuft {
  margin: 0.6rem 0 0;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.job-cuft:empty {
  display: none;
}

/* Piece lines: a Complex room's, and a point's in Settings → Rooms. */
.piece-lines {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.piece-line {
  display: flex;
  align-items: center;
  gap: 0.25rem 0.5rem;
  flex-wrap: wrap;
  padding: 0.2rem 0 0.2rem 0.55rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  min-width: 0;
}

.piece-line.custom .piece-name {
  font-style: italic;
}

.piece-line.gone {
  border-color: var(--warn);
  background: var(--warn-soft);
}

.piece-name {
  flex: 1 1 6rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.piece-cuft {
  font-size: 0.87rem;
  color: var(--muted);
  white-space: nowrap;
  min-width: 4rem;
  text-align: right;
}

.piece-line {
  padding-right: 0.2rem;
}

.piece-line .btn.small {
  min-height: 30px;
  padding: 0.15rem 0.55rem;
}

.btn.icon.small-icon {
  width: 30px;
  min-height: 30px;
  font-size: 1rem;
}

.piece-line .count {
  font-size: 0.95rem;
  min-width: 2.2ch;
}

.piece-add {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 0;
}

.piece-add > .link {
  align-self: flex-start;
  font-size: 0.92rem;
}

.piece-results {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 15rem;
  overflow-y: auto;
  border-radius: var(--radius-sm);
}

.piece-results:empty {
  display: none;
}

.piece-results .hint {
  margin: 0.2rem 0.3rem;
}

.piece-result {
  font: inherit;
  font-size: 0.92rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.3rem 0.55rem;
  min-height: 34px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  text-align: left;
  cursor: pointer;
}

.piece-result:hover,
.piece-result:focus-visible,
.piece-result.active {
  border-color: var(--accent);
  background: var(--accent-soft);
}

/* The highlighted result, which Enter adds. */
.piece-result.active {
  box-shadow: inset 3px 0 0 var(--accent);
}

.piece-result span:first-child {
  min-width: 0;
  overflow-wrap: anywhere;
}

.piece-result .mono {
  font-size: 0.82rem;
  white-space: nowrap;
}

.check {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.92rem;
  min-height: 36px;
  cursor: pointer;
}

.check input {
  width: 1.1rem;
  height: 1.1rem;
  accent-color: var(--accent);
  margin: 0;
}

/* The Complex New piece form. */
.new-piece {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.4rem 0.6rem;
  background: var(--sunk);
  border-radius: var(--radius-sm);
  padding: 0.55rem 0.65rem;
}

.new-piece .grow {
  flex: 1 1 10rem;
}

.new-piece .np-cuft {
  flex: 0 1 6.5rem;
}

.np-actions {
  display: inline-flex;
  gap: 0.4rem;
}

.np-error {
  flex-basis: 100%;
  margin: 0;
  font-size: 0.88rem;
}

.room-time {
  margin: 0;
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}

.room-time.pending {
  color: var(--muted);
}

.units > .btn,
.stops > .btn,
.trucks + .row-between > .btn {
  align-self: flex-start;
}

.stops h3:first-child {
  margin-top: 1.1rem;
}

.stop-row .field {
  flex: 1 1 12rem;
}

input[type="range"] {
  width: 100%;
  accent-color: var(--accent);
  min-height: 28px;
}

/* Results */

/* Tables: compact 40px rows with a thin line between, the header row 13px on the pale panel color, a row under the
   pointer on the pale color, a selected row in the selected tint. The date picker's grid (.cal-grid) keeps its own. */
table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}

th,
td {
  text-align: left;
  padding: 0.4rem 0.5rem;
  border-bottom: 1px solid var(--line);
}

th {
  font-weight: 600;
  color: var(--muted);
  font-size: var(--fs-xs);
}

:where(table:not(.cal-grid)) td {
  height: 40px;
}

:where(table:not(.cal-grid)) th {
  background: var(--sunk);
}

:where(table:not(.cal-grid)) > tbody > tr:hover > td {
  background: var(--sunk);
}

:where(table:not(.cal-grid)) tr:is([aria-selected="true"], .is-picked) > td {
  background: var(--accent-soft);
}

td.num,
th.num {
  text-align: right;
}

tfoot td {
  font-weight: 600;
  border-bottom: 0;
}

.windows {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3);
  margin-top: var(--sp-4);
}

.window {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--sp-3);
  background: var(--surface);
  min-width: 0;
}

/* The width on the quote: its line in the brand's color, its hours and total as figures (figure-lg). */
.window.selected {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* The other width: the same figures, muted. */
.window.other .window-hours,
.window.other .total-row dd {
  color: var(--muted);
}

.window-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.4rem;
  font-weight: 600;
  font-size: var(--fs-sm);
  color: var(--muted);
}

.window-hours {
  margin: var(--sp-1) 0 var(--sp-2);
}

.window-hours.mono {
  font-size: var(--fs-md);
}

.window dl {
  margin: 0;
}

.window dl div {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  flex-wrap: wrap;
  font-size: var(--fs-sm);
}

.window dt {
  color: var(--muted);
}

.window dd {
  margin: 0;
}

.window .total-row {
  align-items: baseline;
  font-weight: 600;
  border-top: 1px solid var(--line);
  margin-top: var(--sp-2);
  padding-top: var(--sp-2);
}

.window .total-row .figure {
  overflow-wrap: anywhere;
}

/* The package charged this range's labor at the minimum hours. */
.window-minimum {
  margin: 0.4rem 0 0;
  font-size: var(--fs-xs);
  color: var(--muted);
}

.bar {
  position: relative;
  height: 14px;
  border-radius: var(--radius-sm);
  background: var(--sunk);
  box-shadow: inset 0 0 0 1px var(--line);
  margin: 0.6rem 0 0.4rem;
  overflow: hidden;
}

.bar-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background: var(--ok);
}

.bar-fill.over {
  background: var(--bad);
}

.bar-cap {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 2px;
  margin-left: -1px;
  background: var(--ink);
}

.stale {
  background: var(--warn-soft);
  color: var(--ink);
  border-radius: var(--radius-sm);
  padding: 0.4rem 0.7rem;
  margin: 0.5rem 0;
  font-size: 0.92rem;
}

.notes-text {
  font-size: 0.95rem;
  margin-top: 0.5rem;
}

#cust-warnings p {
  margin: 0 0 0.2rem;
}

#cust-warnings code {
  display: inline;
  color: var(--ink);
  margin: 0;
}

/* Settings */

#tab-settings {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 1200px;
  margin: 0 auto;
}

#tab-settings > .banner,
.set-main > .hint {
  margin-bottom: 0;
}

/* The section list down the left, beside the open section; it sticks just under the header (settings-tab.js sets --set-bar-top to the header's height). */
.set-layout {
  display: grid;
  grid-template-columns: 208px minmax(0, 1fr);
  gap: var(--sp-5);
  align-items: start;
}

.set-nav {
  position: sticky;
  top: calc(var(--set-bar-top, 56px) + var(--sp-3));
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  /* Short enough to stay whole under the header even when the open section is shorter than the list (the page's 4rem foot included). */
  max-height: calc(100dvh - var(--set-bar-top, 56px) - 24px - 4rem);
}

/* A list taller than the window scrolls on its own (settings-tab.js keeps the picked tab in view). */
.set-tabs {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.set-main {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  min-width: 0;
}

/* One section to a line, with the sidebar's look: muted, the one showing in the brand's soft tint with a bar at its left. */
.set-tab {
  display: flex;
  align-items: center;
  flex: none;
  width: 100%;
  min-height: 36px;
  padding: 0 var(--sp-3);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  text-align: left;
  color: var(--muted);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.15s, color 0.15s;
}

.set-tab:hover {
  background: var(--sunk);
  color: var(--ink);
}

.set-tab[aria-selected="true"] {
  background: var(--accent-soft);
  color: var(--accent-ink);
  box-shadow: inset 3px 0 0 var(--accent);
}

.set-tab:focus-visible {
  outline-offset: -2px;
}

/* A window with a settings problem in it. */
.set-tab-flag {
  display: inline-grid;
  place-items: center;
  width: 1.05rem;
  height: 1.05rem;
  margin-left: 0.3rem;
  border-radius: 50%;
  background: var(--bad);
  color: var(--surface);
  font-size: 0.75rem;
  line-height: 1;
}

.set-panel {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.set-panel > .card {
  scroll-margin-top: calc(var(--set-bar-top, 56px) + 4rem);
}

/* "Saved" under the section list, so the sections never move when it shows (on a phone it floats under the strip, below). */
.saved {
  flex: none;
  align-self: flex-start;
  max-width: 100%;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ok);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s;
}

.saved.bad-text {
  border-radius: var(--radius-sm);
  color: var(--bad);
}

.saved:empty {
  display: none;
}

.saved.show {
  opacity: 1;
}

.card > h2 + .hint {
  margin-top: -0.3rem;
}

/* Rates: one row per trucks + movers pair, with its $/hr, $/mi, min trip $ and cu ft/hr. */
.rates-table {
  max-width: 52rem;
}

/* Settings' column heads (Rates, Handicaps, Labor, Inventory, Special items, Packing materials): 13px 600 muted words
   on the pale panel colour, as a table's head row. */
.pair-head,
.hc-head,
.labor-head,
.piece-head,
.special-head,
.material-head {
  padding-block: 0.35rem;
  background: var(--sunk);
  border-radius: var(--radius-sm);
}

.pair-head,
.pair-row {
  display: grid;
  grid-template-columns: var(--reorder-col) 4.25rem 4.25rem minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.15fr) auto;
  gap: 0.5rem;
  align-items: center;
}

.pair-head {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--muted);
}

.pair-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-top: 0.4rem;
}

.row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.6rem;
}

.pair-row input.num {
  width: 100%;
  min-width: 0;
}

.pair-rate {
  min-width: 0;
}

.pair-err {
  grid-column: 1 / -1;
  margin: 0;
  font-size: var(--fs-sm);
}

.pair-err:empty {
  display: none;
}

/* Handicaps: one row per rates row, with its minutes per flight of stairs and per elevator, then Copy from row above and the "copied, check" mark. */
.hc-head,
.hc-row {
  display: grid;
  grid-template-columns: minmax(7.5rem, 1.1fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) 9.5rem;
  gap: 0.5rem;
  align-items: center;
}

.hc-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
}

.hc-tools .btn.small {
  font-size: var(--fs-xs);
}

/* "copied, check" under a row whose minutes Add row copied. */
.hc-copied {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
  font-size: var(--fs-sm);
}

/* Remove on a rates row with values asks first, on its own line. */
.pair-confirm {
  grid-column: 1 / -1;
}

.add-rate-msg {
  margin: 0.5rem 0 0;
}

.add-rate-msg:empty {
  display: none;
}

.hc-head {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--muted);
}

.hc-row + .hc-row,
.hc-head + .hc-row {
  margin-top: 0.4rem;
}

.hc-row input.num {
  width: 100%;
  min-width: 0;
}

.hc-pair {
  font-weight: 600;
  white-space: nowrap;
}

/* Estimator: access at pickup and drop-off. The block is a size container, so the
   two columns stack whenever it is too narrow for None · Shared · Freight on one
   line, whatever the page layout around it. */
.access-block {
  container-type: inline-size;
}

.access-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
}

.access-grid.one {
  grid-template-columns: minmax(0, 1fr);
}

/* After the two-column rule, so it wins when the block is narrow. */
@container (max-width: 500px) {
  .access-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

.access-loc {
  display: grid;
  gap: 0.45rem;
  align-content: start;
  background: var(--sunk);
  border-radius: 9px;
  padding: 0.6rem 0.7rem;
}

.access-loc h3 {
  margin: 0;
  font-size: 0.95rem;
}

.access-loc .seg {
  background: var(--surface);
}

.access-field {
  display: grid;
  gap: 0.25rem;
  font-size: 0.85rem;
  color: var(--muted);
}

/* Each keeps its line while there is no estimate yet, so the first count or room never moves the cards below. */
.access-time {
  margin: 0;
  line-height: 1.45;
  min-height: 1.45em;
  font-size: 0.88rem;
  color: var(--muted);
}

.access-total {
  margin: 0.6rem 0 0;
  line-height: 1.5;
  min-height: 1.5em;
  color: var(--muted);
}

.access-total strong {
  color: var(--ink);
}

#rates-notice,
#speed-notice,
#points-notice {
  margin-bottom: 0.6rem;
}

/* Inventory: one row per piece, filtered by the search. */
.piece-head,
.piece-row {
  display: grid;
  grid-template-columns: var(--reorder-col) minmax(0, 2fr) 5.5rem 5.5rem minmax(0, 1.2fr) auto;
  gap: 0.4rem;
  align-items: center;
}

.piece-head {
  margin-top: 0.6rem;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--muted);
}

.piece-table {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin-top: 0.3rem;
  max-height: 32rem;
  overflow-y: auto;
  padding-right: 0.2rem;
}

.piece-row input[type="text"],
.piece-row input.num {
  min-height: 32px;
  padding: 0.25rem 0.45rem;
}

.piece-row input.num {
  width: 100%;
}

.piece-confirm {
  grid-column: 1 / -1;
}

/* The column head says Counts, so the tick's own word shows only where the heads are hidden. */
.piece-counts-label {
  display: none;
}

.add-piece {
  margin-top: 0.9rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--line);
}

.add-piece h3 {
  margin-top: 0;
}

.add-piece-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 0.75rem;
}

.add-piece-row .grow {
  flex: 1 1 11rem;
}

.add-piece-row .draft-cuft {
  flex: 0 1 7rem;
}

#add-piece-msg {
  margin: 0.4rem 0 0;
  font-size: 0.9rem;
}

#add-piece-msg:empty {
  display: none;
}

.room-card {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.8rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  background: var(--ground);
}

.room-head {
  display: flex;
  gap: 0.6rem;
  align-items: flex-end;
  flex-wrap: wrap;
}

/* A room or script folded to one line: move controls, the line to click (name and totals or conditions) and its chips. */
.room-card:not(.open),
.script-card:not(.open) {
  padding-top: 0.45rem;
  padding-bottom: 0.45rem;
}

/* The line wraps: on a phone the chips drop under the name, so they never squeeze it or sit on its totals. */
.fold-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 0.5rem;
  min-width: 0;
}

.fold-toggle {
  flex: 1 1 13rem;
  min-width: 0;
  min-height: 36px;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.1rem 0.6rem;
  font: inherit;
  color: var(--ink);
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  padding: 0.25rem 0.3rem;
  text-align: left;
  cursor: pointer;
}

.fold-toggle:hover .fold-name {
  color: var(--accent);
}

.fold-caret::before {
  content: "▸";
  color: var(--accent);
}

[aria-expanded="true"] > .fold-caret::before {
  content: "▾";
}

.fold-name {
  font-weight: 600;
  overflow-wrap: anywhere;
}

.fold-sum {
  font-size: 0.85rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}

/* A room's four totals keep together, under its name when the line is narrow (they may still wrap on a very narrow screen rather than run past the card). */
.fold-sum[data-room-totals] {
  white-space: nowrap;
}

@media (max-width: 360px) {
  .fold-sum[data-room-totals] {
    white-space: normal;
  }
}

.room-chips {
  margin-left: auto;
}

.script-problem:empty {
  display: none;
}

.fold-body {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.room-chips:empty {
  display: none;
}

.room-actions {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  padding-bottom: 0.2rem;
}

.room-jump {
  max-width: 22rem;
  margin: 0.2rem 0 0.8rem;
}

/* "Copy from <the point before>", or its Replace · Append · Cancel. */
.point-copy {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.88rem;
}

.point-copy .btn.small {
  font-size: 0.82rem;
}

.room-chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.3rem;
}

/* A room's four point editors. */
.point-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.6rem;
}

.point {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.55rem 0.6rem 0.6rem;
  background: var(--sunk);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  min-width: 0;
}

.point-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
}

.point-head .mono {
  font-weight: 500;
}

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

.confirm {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.92rem;
  padding-bottom: 0.2rem;
}

details {
  border-top: 1px dashed var(--line);
  padding-top: 0.5rem;
}

summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--accent);
  font-size: 0.92rem;
}

.import textarea {
  margin: 0.4rem 0;
}

.card > .add-room {
  margin-top: 0.8rem;
}

.ac-wrap {
  position: relative;
}

.ac {
  position: absolute;
  z-index: 20;
  margin: 0;
  padding: 0.25rem;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-2);
  min-width: 170px;
}

.ac li {
  font-family: var(--font-mono);
  font-size: 0.88rem;
  padding: 0.3rem 0.55rem;
  border-radius: 5px;
  cursor: pointer;
}

.ac li[aria-selected="true"] {
  background: var(--accent);
  color: var(--on-accent);
}

.preview {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-family: var(--font-body);
  font-size: 0.95rem;
  background: var(--sunk);
  border-radius: var(--radius-sm);
  padding: 0.75rem;
  margin: 0;
}

.reset {
  margin-top: 1rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--line);
}

.field-error:empty,
[data-room-err]:empty,
.slot:empty {
  display: none;
}

/* Narrow screens */

@media (max-width: 720px) {
  .grid-3,
  .grid-4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .point-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .grid-2 {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Under 900px the section list is one line above the sections that sticks under the header and scrolls sideways; "Saved" floats just under its right end and takes no room, so the strip never moves when it shows, and the long "Not saved" message wraps instead of pushing it off a phone. */
@media (max-width: 899px) {
  .set-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
  }

  .set-nav {
    top: var(--set-bar-top, 56px);
    display: block;
    max-height: none;
    padding: 0.45rem 0;
    background: var(--ground);
    border-bottom: 1px solid var(--line);
  }

  .set-tabs {
    flex-direction: row;
    flex-wrap: nowrap;
    gap: 0.3rem;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }

  .set-tabs::-webkit-scrollbar {
    display: none;
  }

  .set-tab {
    width: auto;
    min-height: 36px;
    padding: 0.2rem 0.75rem;
  }

  /* The same colours as the list; its edge at the foot, as the Messages views' row. */
  .set-tab[aria-selected="true"] {
    box-shadow: inset 0 -2px 0 var(--accent);
  }

  .saved {
    position: absolute;
    top: calc(100% + 0.3rem);
    right: 0;
    max-width: min(22rem, 100%);
  }
}

@media (max-width: 480px) {
  .two,
  .windows {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Inventory: the name on its own line, then cu ft, Counts and category, Remove under them. */
  .piece-head {
    display: none;
  }

  .piece-row {
    grid-template-columns: auto 4.75rem auto minmax(0, 1fr) auto;
    grid-template-areas:
      "move name name name remove"
      "move cuft counts cat cat";
    padding: 0.4rem 0;
    border-bottom: 1px solid var(--line);
  }

  .piece-row .piece-name-field {
    grid-area: name;
  }

  .piece-row .piece-cuft-field {
    grid-area: cuft;
  }

  .piece-row .check {
    grid-area: counts;
  }

  .piece-row .piece-cat-field {
    grid-area: cat;
  }

  .piece-row > .btn {
    grid-area: remove;
  }

  /* The move column spans both lines, so ⠿ sits over ▲ ▼ and the column stays narrow. */
  .piece-row > .reorder {
    grid-area: move;
    flex-direction: column;
  }

  .piece-counts-label {
    display: inline;
  }

  /* A counting piece line: the name on its own row, then −/+, cu ft and × together on the right. */
  .piece-line.counting .piece-name {
    flex: 1 1 100%;
  }

  .piece-line.counting .stepper {
    margin-left: auto;
  }


  .block,
  .card {
    padding: 14px;
  }

  .top-inner {
    padding: 0.5rem 16px;
  }

  /* The four figures keep their width; Remove moves under them. Trucks and movers are a digit or two, so they give up room to the figures (2.4rem still fits "Movers" over its column), enough for "124.75" in a box. */
  .pair-head,
  .pair-row {
    grid-template-columns: 2.4rem 2.4rem repeat(4, minmax(0, 1fr));
    gap: 0.3rem;
  }

  /* Small enough that "Movers" fits over its narrow column. */
  .pair-head {
    font-size: 0.75rem;
  }

  .pair-row input.num {
    padding-left: 0.2rem;
    padding-right: 0.2rem;
  }

  /* The move controls sit under the rates, on Remove's line, so the rate boxes keep their width. */
  .pair-row > .reorder {
    grid-row: 2;
    grid-column: 1 / 3;
  }

  .pair-row > button {
    grid-row: 2;
    grid-column: 3 / -1;
    justify-self: end;
  }

  .pair-head-move {
    display: none;
  }

  /* Remove sits under the prices here, so its column head goes. */
  .pair-head-remove {
    display: none;
  }

  /* The column heads say $/hr, $/mi, Min trip $ and cu ft/hr, so the boxes get the room. */
  .pair-rate .unit {
    display: none;
  }

  /* Handicaps: the crew on its own line, then its three boxes. */
  .hc-head,
  .hc-row {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.3rem;
  }

  .hc-head span:first-child {
    display: none;
  }

  .hc-pair,
  .hc-tools {
    grid-column: 1 / -1;
  }

  .hc-head {
    font-size: 0.75rem;
  }

  .access-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Drag to reorder (reorder.js): a grab handle and ▲ ▼ on each row. */
.reorder {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  flex: none;
}

.reorder-handle {
  width: 26px;
  min-height: 32px;
  padding: 0;
  font: inherit;
  font-size: 1.05rem;
  line-height: 1;
  color: var(--muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: grab;
  /* Only the handle: the page still scrolls by touch everywhere else. */
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

.reorder-handle:hover:not(:disabled) {
  color: var(--ink);
  background: var(--sunk);
  border-color: var(--line);
}

.reorder-steps {
  display: inline-flex;
  gap: 2px;
}

/* ▲ ▼ side by side, each at least 24 × 24 px, so a finger does not hit the wrong one (WCAG 2.5.8). */
.reorder-step {
  width: 24px;
  height: 26px;
  padding: 0;
  font: inherit;
  font-size: 0.58rem;
  line-height: 1;
  color: var(--muted);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 5px;
  cursor: pointer;
}

.reorder-step:hover:not(:disabled) {
  color: var(--ink);
  border-color: var(--muted);
}

.reorder-handle:disabled,
.reorder-step:disabled {
  opacity: 0.35;
  cursor: default;
}

.piece-line .reorder-step {
  height: 24px;
  font-size: 0.5rem;
}

.piece-line .reorder-handle {
  min-height: 30px;
}

/* The row being carried, and the line where it will drop. */
/* Under the sticky header (z-index 10) and the Settings bar (5), which it never covers. */
.reorder-lifted {
  position: relative;
  z-index: 4;
  background: var(--surface);
  box-shadow: var(--shadow-2);
  border-radius: var(--radius-sm);
  opacity: 0.97;
}

.reorder-lifted .reorder-handle {
  cursor: grabbing;
}

.reorder-indicator {
  position: fixed;
  height: 3px;
  background: var(--accent);
  border-radius: 2px;
  pointer-events: none;
  z-index: 4;
}

/* A list of tall cards (the rooms) folds to each card's head while one is carried. */
[data-reorder].reorder-collapsed > [data-reorder-item] > :not([data-reorder-keep]) {
  display: none !important;
}

body.reorder-dragging,
body.reorder-dragging * {
  cursor: grabbing !important;
  -webkit-user-select: none;
  user-select: none;
}

@media (max-width: 480px) {
  /* A piece line keeps its name, cu ft and × on one row next to the move controls. */
  .piece-line .reorder-handle {
    width: 22px;
  }

  /* ⠿ ▲ ▼ take 74px, so the gaps and the cu ft give up a little room and × stays on the line. */
  .piece-line {
    column-gap: 0.35rem;
  }

  .piece-line .piece-cuft {
    min-width: 0;
  }

  .piece-line .piece-name {
    flex-basis: 3rem;
  }

  /* A counting line: the move controls and the name on the first row, then −/+, cu ft and ×. */
  .piece-line.counting .piece-name {
    flex: 1 1 calc(100% - 5.25rem);
  }

  /* A special item line: the move controls and the name on the first row, so the name stays readable; then its cu ft and time, the clicker and ×. */
  .special-line .piece-name {
    flex: 1 1 calc(100% - 5.25rem);
  }

  .special-line .piece-cuft {
    text-align: left;
  }
}

/* Standard and Complex time tabs: Rooms · Appliances · Special items · Boxes */

/* The same look as a segmented choice (.seg): a pale strip, the selected tab in the selected tint with the accent's words. */
.time-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  background: var(--sunk);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 2px;
  margin-bottom: 0.75rem;
}

.time-tab {
  font: inherit;
  font-weight: 600;
  font-size: var(--fs-sm);
  border: 0;
  background: transparent;
  color: var(--muted);
  padding: 0.35rem 0.7rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  min-height: 34px;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  flex: 1 1 auto;
  justify-content: center;
}

.time-tab:hover:not([aria-selected="true"]) {
  color: var(--ink);
}

.time-tab[aria-selected="true"] {
  background: var(--accent-soft);
  color: var(--accent-ink);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent);
}

.time-tab:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.tab-count {
  font-size: 0.8rem;
  font-weight: 500;
  min-width: 1.4rem;
  padding: 0 0.35rem;
  border-radius: 999px;
  background: var(--sunk);
  color: var(--muted);
  text-align: center;
}

.time-tab[aria-selected="true"] .tab-count {
  background: var(--accent-soft);
  color: var(--accent-ink);
}

.time-panel {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  min-width: 0;
}

.time-panel > .hint {
  margin: 0;
}

.room-time:empty {
  display: none;
}

/* A special item's extra time clicker and ×: they wrap together, to the right. */
.line-end {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem 0.5rem;
  margin-left: auto;
}

/* A special item's extra time clicker: "+30 min" between − and +. */
.extra-time .count {
  min-width: 5.5ch;
  text-align: center;
  font-size: 0.9rem;
}

/* Complex boxes: one fixed row per box piece, in the Inventory's order, with no move controls. */
.box-row {
  padding-left: 0.55rem;
}

/* Wide enough for "1,040 cu ft", so −, the count and + stay put while the count grows (on a phone too). */
.box-row .piece-cuft,
.piece-line.box-row .piece-cuft {
  min-width: 11.5ch;
}

/* A box at 0 stays on its row, dimmed: its name and cu ft muted, its + as usual. */
.box-zero .piece-name,
.box-zero .piece-cuft,
.box-zero input.count-box {
  color: var(--muted);
}

/* Standard boxes: the chosen box point's exact mix, from the package. */
.box-mix {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  font-size: 0.9rem;
}

.box-mix:empty {
  display: none;
}

.box-mix li {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  border-bottom: 1px dashed var(--line);
  padding: 0.15rem 0;
}

.box-mix .mono {
  color: var(--muted);
  white-space: nowrap;
}

/* Quick: the notes-only box picker under the slider. */
.quick-boxes {
  margin-top: 0.75rem;
  max-width: 18rem;
}

/* Settings → Special items: one row per item. */
.special-head,
.special-row {
  display: grid;
  grid-template-columns: var(--reorder-col) minmax(0, 2fr) 8rem 8rem auto;
  gap: 0.4rem;
  align-items: center;
}

.special-head {
  margin-top: 0.6rem;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--muted);
}

.special-table {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin-top: 0.3rem;
}

.special-row input[type="text"],
.special-row input.num {
  min-height: 32px;
  padding: 0.25rem 0.45rem;
  width: 100%;
}

/* Where the Estimator's clicker starts, under a row whose default is off the step. */
.special-row .special-step {
  grid-column: 2 / -1;
  margin: 0;
  font-size: 0.85rem;
}

.special-row .special-step:empty {
  display: none;
}

#add-special-msg {
  margin: 0.4rem 0 0;
  font-size: 0.9rem;
}

#add-special-msg:empty {
  display: none;
}

@media (max-width: 480px) {
  .special-head {
    display: none;
  }

  /* The name on its own line, then cu ft and extra time, Remove on the right. */
  .special-row {
    grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr) auto;
    grid-template-areas:
      "move name name remove"
      "move cuft extra extra";
    padding: 0.4rem 0;
    border-bottom: 1px solid var(--line);
  }

  .special-row > .reorder {
    grid-area: move;
    flex-direction: column;
  }

  .special-row .special-name-field {
    grid-area: name;
  }

  .special-row .special-num:nth-of-type(2) {
    grid-area: cuft;
  }

  .special-row .special-num:nth-of-type(3) {
    grid-area: extra;
  }

  .special-row > .btn {
    grid-area: remove;
  }

  .time-tab {
    padding: 0.35rem 0.45rem;
  }
}

/* Settings → Labor: one row per number of movers, with its cu ft/hr loading, onsite and unloading. */
.labor-head,
.labor-row {
  display: grid;
  grid-template-columns: var(--reorder-col) 4.25rem minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) auto;
  gap: 0.5rem;
  align-items: center;
}

.labor-head {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--muted);
}

.labor-row input.num {
  width: 100%;
  min-width: 0;
}

/* Settings → Property presets: the sizes of each property type, each a card. Each type folds away, its summary saying what it holds. */
details.preset-group {
  border-top: none;
  padding-top: 0;
}

.preset-group + .preset-group {
  margin-top: 0.8rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--line);
}

.preset-group > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.2rem 0.6rem;
  color: var(--ink);
  font-weight: 400;
}

.preset-group > summary::before {
  content: "▸";
  color: var(--accent);
}

.preset-group[open] > summary::before {
  content: "▾";
}

.preset-group > summary::-webkit-details-marker {
  display: none;
}

.preset-group > summary h3 {
  display: inline;
  margin: 0;
  color: var(--accent);
}

/* Settings → Wording (advanced): each group folds. */
details.fold-group {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.5rem 0.7rem;
  margin-top: 0.5rem;
}

details.fold-group > summary {
  list-style: none;
  color: var(--ink);
}

details.fold-group > summary::-webkit-details-marker {
  display: none;
}

details.fold-group > summary::before {
  content: "▸ ";
  color: var(--accent);
}

details.fold-group[open] > summary::before {
  content: "▾ ";
}

.fold-group-body {
  margin-top: 0.5rem;
}

.preset-snap:empty {
  display: none;
}

.preset-group-sum {
  font-size: 0.9rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.preset-group[open] > summary {
  margin-bottom: 0.6rem;
}

.preset-list {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-bottom: 0.6rem;
}

.preset-card {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.7rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  background: var(--ground);
  min-width: 0;
}

.preset-head {
  display: flex;
  gap: 0.6rem;
  align-items: flex-end;
}

.preset-head .reorder {
  padding-bottom: 0.3rem;
}

.preset-label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
}

.preset-quick {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.7rem;
  align-items: center;
}

.preset-quick .preset-label {
  min-width: 6.5rem;
}

/* The crew a preset's Quick window is set for, on the window's line. */
.preset-crew {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

.preset-crew-word {
  font-size: 0.85rem;
  color: var(--muted);
  white-space: nowrap;
}

.preset-crew select {
  min-width: 0;
  max-width: 100%;
}

.preset-quick input.num {
  width: 6rem;
}

.preset-window {
  margin: 0;
}

.preset-rooms {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.preset-rooms > .hint {
  margin: 0;
  font-size: 0.88rem;
}

/* Each room a chip: move controls, its name, its point and ×. The chips wrap. */
.preset-room-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.preset-room {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: var(--sunk);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.15rem 0.3rem;
  min-width: 0;
  max-width: 100%;
}

.preset-room-name {
  min-width: 0;
  overflow-wrap: anywhere;
  font-weight: 600;
}

.preset-room select {
  min-height: 30px;
  padding-top: 0.15rem;
  padding-bottom: 0.15rem;
}

.preset-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  align-items: flex-end;
}

.preset-room.gone .preset-room-name {
  color: var(--warn);
}

.preset-room select {
  max-width: 11rem;
}

.preset-add-room,
.preset-box {
  flex: 1 1 12rem;
  max-width: 18rem;
}

.size-msg {
  margin: 0.3rem 0 0;
  font-size: 0.9rem;
}

.size-msg:empty {
  display: none;
}

/* Estimator: the property's size picker, and what its preset did. */
.size-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.6rem;
}

.size-label,
.situation-row .row-label {
  font-weight: 600;
  font-size: 0.93rem;
}

/* The line under the size keeps its room (two lines, three on a phone) when empty, so picking a size never moves the cards below. */
.preset-note {
  display: flow-root;
  min-height: 3.2em;
}

/* On a phone the line wraps to three lines ("No Quick window for … · Standard: 5 rooms ready Undo"), so it keeps three. */
@media (max-width: 600px) {
  .preset-note {
    min-height: 4.9em;
  }
}

.preset-lead {
  color: var(--warn);
}

.preset-note p {
  margin: 0.5rem 0 0;
  font-size: 0.93rem;
}

.preset-did {
  color: var(--ok);
}

.preset-ask {
  background: var(--warn-soft);
  border-radius: var(--radius-sm);
  padding: 0.45rem 0.65rem;
}

.situation-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

@media (max-width: 480px) {
  /* Labor: the movers and three figures on one line, the move controls and Remove under them. */
  .labor-head,
  .labor-row {
    grid-template-columns: 2.9rem minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
    gap: 0.3rem;
  }

  .labor-head {
    font-size: 0.75rem;
  }

  .labor-row > .reorder {
    grid-row: 2;
    grid-column: 1 / 3;
  }

  .labor-row > button {
    grid-row: 2;
    grid-column: 3 / -1;
    justify-self: end;
  }

  .labor-row .pair-rate .unit {
    display: none;
  }

  .labor-row input.num {
    padding-left: 0.3rem;
    padding-right: 0.3rem;
  }

  .preset-head {
    flex-wrap: wrap;
  }

  /* One room chip per line: the name and × on top, its point under them, the move controls down the side. */
  .preset-room {
    width: 100%;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "move name remove"
      "move point point";
    column-gap: 0.4rem;
    row-gap: 0.2rem;
    padding: 0.3rem 0.4rem;
  }

  .preset-room > .reorder {
    grid-area: move;
    flex-direction: column;
  }

  .preset-room-name {
    grid-area: name;
    align-self: center;
  }

  .preset-room > label {
    grid-area: point;
  }

  .preset-room > button {
    grid-area: remove;
  }

  .preset-room select {
    max-width: none;
    width: 100%;
  }

  .preset-quick .preset-label {
    min-width: 0;
  }
}

/* Packing on the Estimator: level, day, that day's inputs and the package's materials. Its card's number is packing
   purple (the one place the Estimator uses it), the word Packing beside it. */
section[aria-labelledby="h-packing"] > h2 .n {
  background: var(--pack);
}

.packing-block > .seg {
  margin-bottom: 0.25rem;
}

.pack-day {
  margin-top: 0.6rem;
}

.pack-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.5rem;
  margin-top: 0.6rem;
}

.pack-row .row-label {
  min-width: 0;
}

.pack-date {
  margin-top: 0.6rem;
  max-width: 14rem;
}

/* The packing time: one two-handle range slider on both days. Its head is the label, the range and what it is, wrapping on a phone. */
.pack-time {
  margin-top: 0.75rem;
}

.pack-time .t1-head {
  margin-bottom: 0.4rem;
}

.pack-time .t1-window {
  font-size: 1.2rem;
}

.pack-materials h3 {
  margin: 0.9rem 0 0.3rem;
  font-size: 0.95rem;
}

.pack-materials:empty {
  display: none;
}

.pack-materials-total {
  margin: 0.4rem 0 0;
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  font-size: 0.93rem;
}

.pack-same {
  margin: 0;
  font-size: 0.93rem;
}

/* The Total estimate: a quiet panel (the card's surface, its line, a brand bar at the left), the label over the
   largest figure on the card (figure-xl), and the price range bar under it. */
.total-estimate {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--surface);
  min-width: 0;
}

.total-estimate .figure {
  overflow-wrap: anywhere;
}

.total-estimate + .hint {
  margin: var(--sp-2) 0 0;
}

/* The Quote page's Total estimate keeps the other width's total right under it. */
.qp-total > .total-estimate {
  margin-top: 0;
}

/* The charges (charges.js), on the Estimator's Price card and the Quote page: the crew line large (movers, trucks or
   labor only, the hourly rate and the hours as figure-lg, the 1 hr / 2 hr switch beside them), then the Trip fee and
   Moving labor tiles, each in its own color (--charge-trip teal, its tile edge the bright --charge-trip-mark;
   --charge-labor the primary blue: AA on the surface and on its tile, light and dark; fixed whatever the brand color,
   so a red brand never makes a charge read as a warning), its label in words
   so the color is never the only signal, its amount large and one plain how line under it. */
.charges {
  display: grid;
  gap: var(--sp-3);
  min-width: 0;
}

.crew-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2) var(--sp-4);
  min-width: 0;
}

.crew-line .figure {
  white-space: nowrap;
}

/* "an hour" and "hrs" after their figures, muted. */
.crew-rate,
.crew-hours {
  color: var(--muted);
  white-space: nowrap;
}

.crew-line .seg {
  align-self: center;
}

.charge-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
  gap: var(--sp-3);
}

/* The Quote page's amounts are a size larger (figure-2xl), so its tiles stack sooner rather than break a range over three lines. */
.charges-page .charge-tiles {
  grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
}

.charge {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius);
  border-left: 4px solid;
  min-width: 0;
}

.charge-label {
  font-size: var(--fs-sm);
  font-weight: 600;
}

.charge-amount {
  overflow-wrap: anywhere;
}

.charge-how {
  font-size: var(--fs-sm);
  color: var(--muted);
}

.charge-trip {
  border-left-color: var(--charge-trip-mark);
  background: var(--charge-trip-soft);
}

.charge-trip .charge-label,
.charge-trip .charge-amount {
  color: var(--charge-trip);
}

.charge-labor {
  border-left-color: var(--charge-labor);
  background: var(--charge-labor-soft);
}

.charge-labor .charge-label,
.charge-labor .charge-amount {
  color: var(--charge-labor);
}

/* The small lines under the charges: packing day (with its own minimums), same-day packing, packing materials. */
.price-lines {
  display: grid;
  gap: var(--sp-1);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-sm);
  color: var(--muted);
}

/* The Quote page's The quote: the same head as the Price card, a size larger and further apart. Crew and time under it
   is always open, smaller, in plain words. */
#qp-breakdown {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  min-width: 0;
}

#qp-breakdown > * {
  margin: 0;
  min-width: 0;
}

#qp-time-body {
  min-width: 0;
}

#qp-time-body > .qp-truck:first-child {
  margin-top: 0;
}

/* The Quote page's Total estimate: the page's key total, the largest figure on it (--fs-2xl). */
.qp-total .total-estimate .figure {
  font-size: var(--fs-2xl);
}

.qp-pack-how {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--muted);
}

/* The price range bar (charts.js rangeBarHtml, drawn only): both widths' totals on one bar, the other width's pale,
   the selected one's darker over it, and the other's two ends marked on top, so its span still shows where the
   selected band covers it (2 hr selected). Neutral tones only, never the brand's color (Company & look recolors
   that, and a red brand would read as urgent). */
.range-bar {
  position: relative;
  isolation: isolate;
  height: 10px;
  border-radius: var(--radius-sm);
  background: var(--sunk);
  overflow: hidden;
}

.range-bar > span {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: var(--radius-sm);
  transition:
    left 180ms ease,
    width 180ms ease;
}

.range-other {
  background: var(--line-strong);
}

/* The other band's two ends, above the selected band: in the pale band's own tone, so they show only on the dark one. */
.range-other::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  box-shadow:
    inset 2px 0 0 var(--line-strong),
    inset -2px 0 0 var(--line-strong);
}

.range-sel {
  background: color-mix(in oklab, var(--ink) 70%, var(--surface));
}

/* Customer notes: the script picker. */
.script-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.35rem 0.75rem;
  margin-bottom: 0.6rem;
}

.script-row .field {
  flex: 1 1 14rem;
  min-width: 0;
}

.script-note {
  margin: 0;
  font-size: 0.9rem;
  flex: 1 1 100%;
}

.script-note:empty {
  display: none;
}

.calm-inline {
  display: inline-block;
  background: var(--sunk);
  border-radius: var(--radius-sm);
  padding: 0.4rem 0.6rem;
}

/* Settings → Packing materials: one row per material. */
.material-head,
.material-row {
  display: grid;
  grid-template-columns: var(--reorder-col) minmax(0, 2fr) 10rem auto;
  gap: 0.4rem;
  align-items: center;
}

.material-head {
  margin-top: 0.6rem;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--muted);
}

.material-row input[type="text"],
.material-row input.num {
  min-height: 32px;
  padding: 0.25rem 0.45rem;
  width: 100%;
}

.material-row > .confirm {
  grid-column: 2 / -1;
}

#add-material-msg {
  margin: 0.4rem 0 0;
  font-size: 0.9rem;
}

#add-material-msg:empty {
  display: none;
}

/* Settings → Packing packages: three editors, each a name, a same-day time and material lines. */
.pkg-grid {
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
}

.pkg .pack-row {
  margin-top: 0;
}

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

.pkg-count {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.82rem;
  color: var(--muted);
}

.pkg-count input.num {
  width: 3.6rem;
  min-height: 30px;
  padding: 0.15rem 0.35rem;
}

/* Settings → Customer notes scripts: one card per script. */
.script-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin-top: 0.6rem;
}

.script-card {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 0.7rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  min-width: 0;
}

.script-conds {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.script-cond {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
}

.script-cond-label {
  font-weight: 600;
  font-size: 0.88rem;
  min-width: 7.5rem;
}

.chip-toggle {
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--muted);
  border-radius: 999px;
  padding: 0.2rem 0.7rem;
  min-height: 30px;
  cursor: pointer;
}

.chip-toggle[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.script-any {
  font-size: 0.85rem;
}

.script-for-job {
  margin: 0.5rem 0 0;
  font-weight: 600;
}

.script-for-job:empty {
  display: none;
}

.script-picked:empty {
  display: none;
}

.script-preview .preview {
  margin-top: 0.4rem;
}

.ac-alias {
  font-family: var(--font-body);
  font-size: 0.75rem;
  opacity: 0.75;
  margin-left: 0.35rem;
}

@media (max-width: 480px) {
  .material-head {
    display: none;
  }

  .material-row {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "move name remove"
      "move price price";
    padding: 0.4rem 0;
    border-bottom: 1px solid var(--line);
  }

  .material-row > .reorder {
    grid-area: move;
    flex-direction: column;
  }

  .material-row .material-name-field {
    grid-area: name;
  }

  .material-row .material-price {
    grid-area: price;
  }

  .material-row > .btn {
    grid-area: remove;
  }

  .pkg-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .script-cond-label {
    min-width: 0;
    flex: 1 1 100%;
  }
}

/* A count typed in a number box, between − and + (trip miles, counting pieces, Complex boxes). */
input.count-box {
  width: 4.2em;
  min-height: 32px;
  padding: 0.15rem 0.3rem;
  text-align: center;
  font-size: 0.98rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  -moz-appearance: textfield;
  appearance: textfield;
}

.count-box::-webkit-outer-spin-button,
.count-box::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

input.count-box:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

input.miles-box {
  width: 4.8em;
  font-size: 1.05rem;
}

.piece-line input.count-box {
  width: 3.6em;
  min-height: 30px;
  font-size: 0.92rem;
}

/* "Removed Storage unit (8 pieces) · Undo" over the rooms, until the next edit. Its line is kept when empty, so the rooms below never jump when it shows. */
.undo-line {
  margin: 0.5rem 0 0;
  min-height: 1.45em;
  font-size: 0.93rem;
  color: var(--muted);
}

/* "Added Washer to Appliances · Undo" under a Complex room's search, until the next edit. */
.added-line {
  margin: 0.35rem 0 0;
  font-size: 0.9rem;
  color: var(--ok);
}

.added-line:empty {
  display: none;
}

/* The truck bar: the truck check as one slim line, "Truck", the cu ft meter, "1,180 / 1,800 cu ft", Fits or Full and
   the Next truck switch. It sticks just under the header (--header-h, set by app.js from the header's height) and the
   jump tabs (--est-jump-h) while the Time block, where the rooms and pieces are, is on screen (.on-screen, set by
   estimator-tab.js), on Standard and Complex full moves only ([hidden] otherwise). Under the header (10) and the move
   date's calendar (9), which it never covers. */
.truck-bar {
  display: none;
  position: sticky;
  top: calc(var(--header-h, 56px) + var(--est-jump-h, 44px));
  z-index: 8;
  margin-top: 0.75rem;
  padding: 0.3rem 0.85rem;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.3rem 0.75rem;
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-2);
}

.truck-bar.on-screen {
  display: flex;
}

.truck-bar-label {
  flex: none;
  font-weight: 600;
}

/* The meter: the job's cu ft against what the trucks hold, full (red) once it is over. */
.truck-bar .truck-bar-meter {
  flex: 1 1 8rem;
  min-width: 3rem;
  max-width: 22rem;
  height: 10px;
  margin: 0;
}

/* Its fill on the one meter scale by fullness, solid (scale.js truckTone: blue while there is room, orange from 80%, red when full or over); the rim means over. */
.truck-bar .truck-bar-meter .bar-fill {
  background: var(--tone, var(--scale-blue));
  transition:
    width 180ms ease,
    background-color 180ms ease;
}

.meter.full {
  box-shadow: inset 0 0 0 1px var(--bad);
}

/* Over: a red fill is only full, so the rim sits just outside the bar where the fill cannot cover it. */
.truck-bar .truck-bar-meter.full {
  outline: 1.5px solid var(--bad);
  outline-offset: 2px;
}

.truck-bar-cuft,
.truck-bar .chip {
  flex: none;
  white-space: nowrap;
}

.truck-bar-words {
  min-width: 0;
}

/* The Next truck switches: each a switch, then what it adds or added. */
.next-trucks {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 0.75rem;
  min-width: 0;
}

.next-truck {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}

.next-truck .muted {
  margin: 0;
  font-size: 0.9rem;
}

.truck-bar .switch {
  flex: none;
  min-height: 32px;
  padding: 0.1rem 0.65rem 0.1rem 0.3rem;
  white-space: nowrap;
}

/* The crew the switch would give has no rates row: said on a line of its own under the bar. */
.truck-bar-hint {
  flex-basis: 100%;
  margin: 0;
  font-size: 0.9rem;
}

/* A phone: one thin line. The notes beside the switch and under the bar step aside (the switch still names them to
   a screen reader), the figures drop their " cu ft", the word "Truck" gives its place to a Next truck switch, and the
   meter takes what room is left. Two switches at once scroll sideways inside the bar rather than push the page
   wider. */
@media (max-width: 480px) {
  .truck-bar {
    flex-wrap: nowrap;
    gap: 0.35rem;
    padding: 0.2rem 0.5rem;
    font-size: 0.85rem;
  }

  /* The meter gives up its room first (down to 1.5rem), so the switch never scrolls while there is room for it. */
  .truck-bar .truck-bar-meter {
    flex: 1 100 4rem;
    min-width: 1.5rem;
  }

  .truck-bar .next-truck-note,
  .truck-bar-hint,
  .truck-bar-unit,
  .truck-bar-label.with-switch {
    display: none;
  }

  /* The figures (figure-md) at the bar's own size on a phone, so the bar stays one thin line. */
  .truck-bar .truck-bar-cuft {
    font-size: var(--fs-sm);
  }

  .truck-bar-words {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* The padding (taken back by the margin) leaves room for a focused switch's outline inside the scroller. */
  .truck-bar .next-trucks {
    flex: 0 1 auto;
    flex-wrap: nowrap;
    gap: 0.3rem;
    overflow-x: auto;
    scrollbar-width: none;
    padding: 4px;
    margin: -4px;
  }

  .truck-bar .next-truck {
    flex: none;
  }

  .truck-bar .switch {
    min-height: 30px;
    gap: 0.35rem;
    padding: 0.1rem 0.5rem 0.1rem 0.25rem;
  }

  .truck-bar .switch-track {
    width: 26px;
    height: 16px;
  }

  .truck-bar .switch-track::after {
    top: 3px;
    left: 3px;
    width: 10px;
    height: 10px;
  }

  .truck-bar .switch[aria-checked="true"] .switch-track::after {
    left: 13px;
  }
}

.switch {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 36px;
  padding: 0.2rem 0.7rem 0.2rem 0.35rem;
  font: inherit;
  font-weight: 600;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
}

.switch:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.switch-track {
  position: relative;
  width: 34px;
  height: 20px;
  border-radius: 10px;
  background: var(--sunk);
  box-shadow: inset 0 0 0 1px var(--line);
  flex: none;
}

.switch-track::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--muted);
  transition: left 120ms ease;
}

.switch[aria-checked="true"] {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.switch[aria-checked="true"] .switch-track {
  background: var(--accent);
  box-shadow: none;
}

.switch[aria-checked="true"] .switch-track::after {
  left: 17px;
  background: var(--on-accent);
}

@media (prefers-reduced-motion: reduce) {
  .switch-track::after {
    transition: none;
  }
}

/* Copy's question while the customer notes still hold tokens. */
.copy-ask[hidden] {
  display: none;
}

.copy-ask .stale {
  margin-top: 0.5rem;
}

/* The Quote page: the saved price against the current one, next to Book, and the truck space in the breakdown. */
.qp-price-note {
  margin: 0.5rem 0 0;
}

.qp-truck {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin: 0.75rem 0 0;
}

.qp-truck p {
  margin: 0;
  min-width: 0;
}

/* The truck radial (charts.js ringSvg, 56px, drawn only) and its percent beside it. */
.qp-truck-radial {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: var(--sp-2);
}

.qp-truck-radial .ring {
  width: 56px;
  height: 56px;
}

.qp-truck.bad-text .figure {
  color: var(--bad);
}

/* The work log's inline forms (log-forms.js): Did not book, Lost, Set follow-up date and the corrections */

.log-form {
  margin-top: 0.6rem;
  padding: 0.65rem 0.75rem;
  background: var(--sunk);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-width: 0;
}

.log-form p {
  margin: 0;
}

.log-message {
  margin: 0.5rem 0 0;
}

.lf-fields {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 0.75rem;
  min-width: 0;
}

.lf-fields .field.grow {
  flex: 1 1 14rem;
}

.lf-fields select,
.lf-fields input[type="text"],
.lf-fields input[type="time"] {
  min-height: 32px;
}

.lf-date {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
  min-width: 0;
}

.lf-label {
  font-size: var(--fs-xs);
  color: var(--muted);
  font-weight: 600;
}

.lf-date .date-btn {
  flex: 0 0 auto;
}

.lf-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.small-link {
  font-size: var(--fs-sm);
}

/* Quote page: History (the Timeline's rows): 14px, the time muted with even-width figures, a --line between. */

.history-list {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.history-item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.1rem 0.6rem;
  padding: 0.45rem 0;
  border-top: 1px solid var(--line);
  font-size: var(--fs-sm);
  overflow-wrap: anywhere;
}

.history-item:first-child {
  border-top: 0;
}

.history-time {
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  flex: 0 0 auto;
}

.history-what {
  font-weight: 600;
}

.history-by {
  font-size: var(--fs-xs);
}

.history-note {
  flex: 1 0 100%;
  margin: 0;
  white-space: pre-wrap;
}

.history-correct {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.6rem;
}

.history-add {
  margin-top: 0.75rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.history-add textarea {
  width: 100%;
  resize: vertical;
}

/* Work log tab */

#tab-worklog {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 1080px;
  margin: 0 auto;
}

.wl-head {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.wl-head .hint,
.wl-head .banner {
  margin: 0;
}

.wl-day {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

.wl-day-field {
  position: relative;
  min-width: 0;
}

.wl-day-field .date-btn {
  font-weight: 600;
}

.wl-counts {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: var(--sp-2);
}

/* Each count a small card: the number (figure-lg), its label, and a thin bar of its share of its group
   (worklog-tab.js countsHtml: the day's outcomes, the to-dos and Contacts, each scaled on its own). */
.wl-count {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  min-width: 0;
}

.wl-count-label {
  flex: 1 0 auto;
  font-size: var(--fs-xs);
  color: var(--muted);
  line-height: 1.25;
}

.wl-count-bar {
  display: block;
  height: 4px;
  margin-top: var(--sp-1);
  border-radius: 2px;
  background: var(--sunk);
  overflow: hidden;
}

.wl-count-bar > span {
  display: block;
  height: 100%;
  border-radius: 2px;
  background: var(--line-strong);
}

/* The bars' colours carry meaning only: booked green, overdue red, lost the calm grey of closed; the rest (Contacts
   too) a quiet grey. */
.wl-count[data-count="booked"] .wl-count-bar > span {
  background: var(--ok);
}

.wl-count[data-count="overdue"] .wl-count-bar > span {
  background: var(--bad);
}

.wl-count[data-count="lost"] .wl-count-bar > span {
  background: var(--closed);
}

@media (max-width: 960px) {
  .wl-counts {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* A phone: three to a row, tighter, the figures their size. */
@media (max-width: 480px) {
  .wl-counts {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.3rem;
  }

  .wl-count {
    padding: var(--sp-2);
  }
}

.wl-body {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.wl-section h2 {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
}

.wl-section > .hint {
  margin: 0.25rem 0 0;
}

/* The section's rows: compact (44px at least), a 1px line between, inside the section's card (not a box each). */
.wl-list {
  display: flex;
  flex-direction: column;
  margin-top: 0.5rem;
  border-top: 1px solid var(--line);
}

.wl-row {
  min-height: 44px;
  border-bottom: 1px solid var(--line);
  padding: var(--sp-2) 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  min-width: 0;
}

.wl-row:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.wl-main {
  flex: 1 1 20rem;
  min-width: 0;
}

.wl-main p {
  margin: 0;
}

.wl-main .hint {
  font-size: var(--fs-sm);
  margin-top: 0.15rem;
}

.wl-line {
  color: var(--ink);
  font-weight: 600;
}

.wl-actions {
  flex: 1 1 18rem;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 0.35rem;
  min-width: 0;
}

.wl-row > .stale,
.wl-row > .log-form,
.wl-row > .log-message {
  flex: 1 0 100%;
  margin: 0;
}

.wl-empty {
  margin: 0;
}

/* The pending quotes with no follow-up date: folded under its heading. */
.wl-undated > summary {
  cursor: pointer;
  list-style-position: inside;
}

.wl-undated > summary h2 {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  margin: 0;
}

.wl-undated > .hint {
  margin: 0.4rem 0 0;
}

/* A follow-up date before today: kept, with this warning under it. */
.log-form .lf-past {
  margin: 0;
  padding: 0.4rem 0.6rem;
  font-size: var(--fs-sm);
}

/* Follow-ups tab: every sent, pending quote with its plan, what is due at the top. */

#tab-followups {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  max-width: 1080px;
  margin: 0 auto;
}

.fu-head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.fu-head .hint,
.fu-head .banner,
.fu-title {
  margin: 0;
}

.fu-head .quote-filter-row {
  margin-bottom: 0;
}

/* The reminders' line and the one mute switch, in the tab's head. */
.fu-remind {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.75rem;
}

.fu-remind-line {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--muted);
  min-width: 0;
}

.fu-remind-line strong {
  color: var(--ink);
}

.fu-remind-line.is-muted strong {
  color: var(--warn);
}

.fu-mute-problem {
  flex-basis: 100%;
  margin: 0;
}

/* The queue's health (followups.js queueHealthHtml): due now as a figure, the lifelines' spread as one thin bar, its legend by percent. */
.fu-queue-wrap:empty {
  display: none;
}

.fu-queue {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
}

.fu-queue-now {
  grid-row: span 2;
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin: 0;
  white-space: nowrap;
}

.fu-queue-now span {
  color: var(--muted);
  font-weight: 600;
}

.fu-queue-now > span:only-child {
  color: var(--ink);
  font-size: var(--fs-md);
}

.fu-queue-bar {
  display: flex;
  gap: 2px;
  height: 8px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--sunk);
}

.fu-band {
  flex: 1 1 0;
  min-width: 4px;
}

/* The queue's bands in the meter's steps: 75–100% blue, 50–74% a lighter blue, 20–49% orange, under 20% red. */
.fu-band-fresh {
  background: var(--scale-blue);
}

.fu-band-track {
  background: color-mix(in srgb, var(--scale-blue) 60%, var(--surface));
}

.fu-band-close {
  background: var(--scale-orange);
}

.fu-band-attention {
  background: var(--scale-red);
}

.fu-queue-legend {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.fu-legend-item {
  white-space: nowrap;
}

.fu-swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 0.3rem;
  border-radius: 2px;
  vertical-align: -0.05em;
}

.fu-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.fu-empty {
  margin: 0;
}

/* A Follow-ups row: the whole plan in plain view, top to bottom (followups-tab.js rowHtml). */
.fu-row {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: var(--sp-4) var(--sp-5);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-3);
  min-width: 0;
}

.fu-row > * {
  min-width: 0;
}

.fu-row > p,
.fu-who p {
  margin: 0;
}

/* Due now or overdue: a 3px amber edge; a plan that is over: a red one. */
.fu-row.is-due {
  box-shadow:
    inset 3px 0 0 var(--warn),
    var(--shadow-1);
}

.fu-row.is-over {
  box-shadow:
    inset 3px 0 0 var(--bad),
    var(--shadow-1);
}

/* The ring on the left, the booking chip, number, name and contact line beside it. */
.fu-top {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: center;
}

.fu-ring-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-1);
}

.fu-who {
  display: grid;
  gap: var(--sp-1);
  min-width: 0;
}

.fu-who-line {
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
}

.fu-who-line [data-number] {
  font-size: var(--fs-md);
}

.fu-name {
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: 1.2;
  overflow-wrap: anywhere;
}

.fu-contact {
  font-size: var(--fs-sm);
  color: var(--muted);
  overflow-wrap: anywhere;
}

/* The row's lifeline ring (followups.js ringHtml, 48px as drawn): 72px here, the percent in its middle. */
.fu-ring {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 48px;
  height: 48px;
  vertical-align: middle;
}

.fu-row .fu-ring,
.fu-row .fu-ring .ring {
  width: 72px;
  height: 72px;
}

.fu-ring > * {
  grid-area: 1 / 1;
}

.fu-pct {
  font-size: var(--fs-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: -0.02em;
  line-height: 1;
}

.fu-row .fu-pct {
  font-size: var(--fs-lg);
}

/* A ring (charts.js ringSvg): a track, the arc in its --tone, a dot where each follow-up was done (hollow when skipped). */
.ring {
  display: block;
  overflow: visible;
}

.ring-track {
  fill: none;
  stroke: var(--sunk);
  stroke-width: var(--ring-stroke, 5);
}

.ring-arc {
  fill: none;
  stroke-width: var(--ring-stroke, 5);
  stroke-linecap: round;
  transition: stroke-dasharray 180ms ease;
}

/* At 0%: an empty ring on a pale red track with a red rim, as the slim meter's. */
.ring.is-over {
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px var(--bad);
}

.ring.is-over .ring-track {
  stroke: var(--bad-soft);
}

.ring-dot {
  fill: var(--ink);
  stroke: var(--surface);
  stroke-width: 1.5;
}

.ring-dot.is-skipped {
  fill: var(--surface);
  stroke: var(--ink);
}

/* Where the lifeline reaches 0% and why (the book-by point or a cap), and the last reply that lifted it. */
.fu-lifeline {
  font-size: var(--fs-sm);
  overflow-wrap: anywhere;
}

/* What is next and when, large: amber when due, red when overdue. */
.fu-line {
  font-size: var(--fs-md);
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.fu-line.is-due strong {
  color: var(--warn);
}

.fu-line.is-overdue strong {
  color: var(--bad);
}

/* The calls and texts done so far. */
.fu-tally {
  font-size: var(--fs-base);
  font-weight: 600;
}

.fu-group-line {
  font-size: var(--fs-sm);
}

.fu-hand,
.fu-earlier {
  font-size: var(--fs-sm);
}

/* The prompt at 0%: calm, across the row, above its buttons. */
.fu-over {
  margin: 0;
  padding: 0.45rem 0.7rem;
  border-radius: var(--radius-sm);
  background: var(--sunk);
  color: var(--ink);
  font-size: var(--fs-sm);
}

.fu-actions {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: var(--sp-2);
  min-width: 0;
  padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
}

/*
 * The plan track (plan-track.js): the lifeline as a bar from Sent (left) to 0% (right), the part used shaded in the
 * ring's tone with an ink tick at now, each planned call or text a stop at its meter point (drawn only, aria-hidden),
 * then the same stops as a numbered list in words. Every stop has its icon and its words, never colour alone.
 */
.pt {
  display: grid;
  min-width: 0;
}

.pt-bar {
  position: relative;
  height: 10px;
  margin: 18px 12px;
  border-radius: 999px;
  background: var(--sunk);
}

.pt-spent {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--now);
  border-radius: inherit;
  background: color-mix(in srgb, var(--tone) 35%, var(--sunk));
}

.pt-now {
  position: absolute;
  top: 50%;
  left: var(--now);
  width: 3px;
  height: 22px;
  border-radius: 2px;
  background: var(--ink);
  translate: -50% -50%;
}

.pt-stop {
  position: absolute;
  top: 50%;
  left: var(--at);
  translate: -50% -50%;
  z-index: 1;
  box-sizing: border-box;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 2px solid var(--line-strong);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
}

.pt-stop .pt-ico {
  width: 14px;
  height: 14px;
}

.pt-stop.is-done {
  background: var(--ok);
  border-color: var(--ok);
  color: var(--surface);
}

/* A done stop's ✓ badge: readable in both themes (the surface on the ok green's rim). */
.pt-stop.is-done::after {
  content: "✓";
  position: absolute;
  top: -6px;
  right: -6px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--surface);
  color: var(--ok);
  box-shadow: 0 0 0 1.5px var(--ok);
  font-size: 12px;
  font-weight: 600;
  line-height: 12px;
  text-align: center;
}

.pt-stop.is-skipped {
  border-style: dashed;
  color: var(--muted);
}

.pt-stop.is-due {
  background: var(--warn-soft);
  border: 3px solid var(--warn);
  color: var(--warn);
}

.pt-stop.is-overdue {
  background: var(--bad-soft);
  border: 3px solid var(--bad);
  color: var(--bad);
}

.pt-stop.is-passed,
.pt-stop.is-dropped,
.pt-stop.is-over {
  border-style: dashed;
  border-color: var(--line);
  color: var(--muted);
  opacity: 0.55;
}

/* The next stop: a neutral ink ring, never the brand's accent (a red brand must not make it read as Overdue). */
.pt-stop.is-next {
  z-index: 2;
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--ink);
}

.pt-ends {
  display: flex;
  justify-content: space-between;
  margin-top: -6px;
  font-size: var(--fs-xs);
  color: var(--muted);
}

.pt-stops {
  list-style: none;
  margin: var(--sp-3) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: var(--sp-2);
}

.pt-item {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  column-gap: var(--sp-2);
  align-items: start;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  min-width: 0;
}

.pt-num,
.pt-icon {
  grid-row: 1 / span 3;
}

.pt-num {
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--sunk);
  font-size: var(--fs-sm);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.pt-icon {
  display: grid;
  place-items: center;
  height: 1.5rem;
  color: var(--muted);
}

.pt-what,
.pt-mark,
.pt-when {
  grid-column: 3;
  overflow-wrap: anywhere;
}

.pt-what {
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: 1.5rem;
}

.pt-mark {
  font-weight: 600;
  color: var(--ink);
}

.pt-when {
  font-size: var(--fs-sm);
  color: var(--muted);
}

.pt-item.is-done .pt-mark,
.pt-item.is-done .pt-icon {
  color: var(--ok);
}

.pt-item.is-due .pt-mark,
.pt-item.is-due .pt-icon {
  color: var(--warn);
}

.pt-item.is-overdue .pt-mark,
.pt-item.is-overdue .pt-icon {
  color: var(--bad);
}

.pt-item.is-skipped .pt-mark,
.pt-item.is-passed .pt-mark,
.pt-item.is-dropped .pt-mark,
.pt-item.is-over .pt-mark {
  color: var(--muted);
}

/* The next card: a heavier ink border, neutral in every brand; its mark keeps its own status color. */
.pt-item.is-next {
  border-color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--ink);
}

.pt-none {
  margin: 0;
}

/* Did they reply? On a done follow-up: its words (bold; waiting warn, replied ok, no reply muted, each a word, never colour alone), its
   buttons wrapping on a phone, the kind picker across the whole card; an earlier plan's done follow-ups under the list; the row's count. */
.pt-answer-box {
  grid-column: 3;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-2);
  margin-top: var(--sp-1);
  min-width: 0;
}

.pt-item.is-asking {
  grid-column: 1 / -1;
}

.pt-answer {
  font-size: var(--fs-sm);
  font-weight: 600;
  overflow-wrap: anywhere;
}

.pt-answer.is-waiting {
  color: var(--warn);
}

.pt-answer.is-replied {
  color: var(--ok);
}

.pt-answer.is-noreply {
  color: var(--muted);
}

.pt-answer-btns {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-2);
  min-width: 0;
}

.pt-answer-box > .fu-reply,
.pt-earlier-item > .fu-reply {
  flex: 1 0 100%;
  margin: 0;
  min-width: 0;
}

.pt-earlier {
  list-style: none;
  margin: var(--sp-2) 0 0;
  padding: 0;
  display: grid;
  gap: var(--sp-2);
}

.pt-earlier-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-2);
  font-size: var(--fs-sm);
  min-width: 0;
}

.pt-earlier-what {
  color: var(--muted);
  overflow-wrap: anywhere;
}

.fu-waiting {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-sm);
  font-weight: 600;
}

.qp-fu-answer-note {
  margin: 0;
}

/* More time's calendar opens under its button. */
.fu-more-field {
  position: relative;
  display: inline-flex;
}

.fu-row > .stale,
.fu-row > .log-form,
.fu-row > .log-message {
  flex: 1 0 100%;
  margin: 0;
}

.fu-note {
  font-size: var(--fs-sm);
}

/* Customer replied: what came in since the last follow-up (across the row, above its buttons), and the kind picker. */
.fu-came-in {
  flex: 1 0 100%;
  margin: 0;
  font-size: var(--fs-sm);
  overflow-wrap: anywhere;
}

.fu-reply .hint {
  font-size: var(--fs-sm);
}

/* On the Quote page: the picker, or what the reply did, under the plan line, the Log buttons or a Timeline row. */
.qp-reply {
  flex: 1 0 100%;
  min-width: 0;
}

.qp-reply > p {
  margin: 0.35rem 0 0;
}

.tl-reply {
  font-size: var(--fs-sm);
}

/*
 * Plan with Claude: the card under a Follow-ups row or the Quote page's plan block (followups.js claudeCardHtml).
 * The suggested points as a small table, the wording Claude suggested for this quote, the reason and the tokens.
 */
.qp-claude {
  flex: 1 0 100%;
  min-width: 0;
}

.fu-claude.is-asking {
  color: var(--muted);
}

.fu-claude-points {
  border-collapse: collapse;
  font-size: var(--fs-sm);
  width: auto;
  max-width: 100%;
}

.fu-claude-points th,
.fu-claude-points td {
  text-align: left;
  padding: 0.2rem 0.9rem 0.2rem 0;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.fu-claude-points th {
  font-weight: 600;
  color: var(--muted);
  font-size: var(--fs-xs);
}

.fu-claude-points td.num {
  font-variant-numeric: tabular-nums;
}

.fu-claude-tweak {
  font-size: var(--fs-sm);
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

.fu-claude-reason {
  font-size: var(--fs-sm);
  overflow-wrap: anywhere;
}

/* Text on the Follow-ups tab: the prepared text's card under its row (read-only; nothing is sent by the page). */
.fu-text-card .fu-tc-line {
  font-size: var(--fs-sm);
}

/* Read-only, so it grows to its text where the browser can (four rows elsewhere). */
.fu-text-card .fu-tc-text textarea {
  background: var(--surface);
  field-sizing: content;
  min-height: 4.5rem;
}

.fu-text-card .fu-tc-missing {
  background: var(--warn-soft);
  border-radius: var(--radius-sm);
  padding: 0.35rem 0.6rem;
  font-size: var(--fs-sm);
}

.fu-text-card a.btn {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}

.fu-text-card .fu-tc-nophone {
  align-self: center;
}

/*
 * The lifeline meter: a 6px track with a rounded solid fill in the one scale's tone (--tone, scale.js lifelineTone:
 * blue at 50% and over, orange from 20% to 49%, red under 20%; no gradient), a red rim at 0%,
 * and a dot where each follow-up was done, at the percent the meter read then (hollow for a skipped one). The dots
 * are wider than the track, so the track does not clip them; the fill keeps its own rounded ends.
 */
.fu-meter {
  display: inline-block;
  position: relative;
  flex: none;
  height: 6px;
  border-radius: 999px;
  background: var(--sunk);
  vertical-align: middle;
}

.fu-dot {
  position: absolute;
  top: 50%;
  left: var(--at, 0%);
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  border-radius: 50%;
  background: var(--ink);
  box-shadow: 0 0 0 1.5px var(--surface);
}

.fu-dot.is-skipped {
  background: var(--surface);
  box-shadow: inset 0 0 0 1.5px var(--ink);
}

.fu-meter-inline .fu-dot {
  width: 7px;
  height: 7px;
  margin: -3.5px 0 0 -3.5px;
}

.fu-meter-row {
  width: 120px;
}

.fu-meter-inline {
  width: 80px;
}

.fu-meter-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--fill, 0%);
  border-radius: inherit;
  background-color: var(--tone, var(--scale-blue));
  background-image: none;
  transition: width 180ms ease;
}

.fu-meter.over {
  background: var(--bad-soft);
  box-shadow: inset 0 0 0 1px var(--bad);
}

/* The meter elsewhere: under the Quote page's status chip, and at the front of a Quotes row's hint line (80px, inline). */
.qp-plan {
  margin: 0.35rem 0 0;
  font-size: var(--fs-sm);
}

.qp-plan p {
  margin: 0;
}

.qp-plan p + p {
  margin-top: 0.25rem;
}

/* Flows as text, so a narrow window wraps it between words; each "·" stays with the word before it. */
.qp-plan-line {
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}

.qp-plan-line .fu-meter {
  margin-right: 0.3rem;
  vertical-align: 0.1em;
}

.qp-plan.is-over .qp-plan-line > [data-qp-plan-words] {
  color: var(--bad);
  font-weight: 600;
}

.qp-more-field {
  position: relative;
  display: inline-flex;
}

/* The Follow-up section (quote-tab.js, plan-track.js planPanelHtml): the plan large, always on the Quote page, between
 * Personal notes and the Timeline. Its heading and booking chip, the plan line, a 112px ring, what's next, the calls and
 * texts as figures, the plan track at panel size and the replies. A white card like every other section. */
.qp-fu {
  display: grid;
  gap: var(--sp-4);
  padding: 1.25rem;
}

.qp-fu-inner {
  display: grid;
  gap: var(--sp-4);
  min-width: 0;
}

.qp-fu-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
}

.qp-fu-head h2 {
  margin: 0;
  font-size: var(--fs-md);
  line-height: 1.2;
}

.qp-fu-top {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--sp-5);
  align-items: center;
}

.qp-fu-ring {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-1);
}

.qp-fu .fu-ring,
.qp-fu .fu-ring .ring {
  width: 112px;
  height: 112px;
}

.qp-fu .fu-pct {
  font-size: var(--fs-2xl);
  /* "100%" stays inside the ring's stroke at this size. */
  letter-spacing: -0.04em;
}

.qp-fu-next {
  display: grid;
  gap: var(--sp-1);
  min-width: 0;
}

.qp-fu-next p {
  margin: 0;
  overflow-wrap: anywhere;
}

.qp-fu-next-line {
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: 1.3;
}

.qp-fu-next-line.is-due {
  color: var(--warn);
}

.qp-fu-tally {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  margin: 0;
}

.qp-fu-tally dt {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--muted);
}

.qp-fu-tally dd {
  margin: 0;
}

/* The track at panel size: bigger stops and bar, the list in larger type. */
.pt-panel .pt-bar {
  height: 14px;
  margin: 24px 20px;
}

.pt-panel .pt-now {
  height: 30px;
}

.pt-panel .pt-stop {
  width: 40px;
  height: 40px;
}

.pt-panel .pt-stop .pt-ico {
  width: 20px;
  height: 20px;
}

.pt-panel .pt-stops {
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
}

.pt-panel .pt-what,
.pt-panel .pt-mark {
  font-size: var(--fs-base);
}

.pt-panel .pt-when {
  font-size: var(--fs-sm);
}

.qp-fu-replies {
  display: grid;
  gap: var(--sp-2);
}

.qp-fu-replies h3 {
  margin: 0;
  font-size: var(--fs-md);
}

.qp-fu-replies ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--sp-1);
  font-size: var(--fs-base);
  font-variant-numeric: tabular-nums;
}

.qp-fu-replies li {
  overflow-wrap: anywhere;
}

.qp-fu-replies p,
.qp-fu-closed {
  margin: 0;
}

.qp-fu-closed {
  font-size: var(--fs-md);
  font-weight: 600;
}

@media (max-width: 760px) {
  .qp-fu-top {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-4);
    justify-items: start;
  }
}

@media (max-width: 480px) {
  .qp-fu {
    padding: var(--sp-4);
  }

  .qp-fu .pt-stops {
    grid-template-columns: minmax(0, 1fr);
  }

  .pt-panel .pt-bar {
    margin: 22px 16px;
  }

  .pt-panel .pt-stop {
    width: 32px;
    height: 32px;
  }

  .pt-panel .pt-stop .pt-ico {
    width: 16px;
    height: 16px;
  }
}

/* The job page (job-tab.js, job-page.js): one quote's own page in one calm column like the Quote page's, read top to
   bottom: the bar (back, Estimator, Quote page, Follow-ups row), Customer with the largest booking chip, The quote as
   saved (the crew line, the two charge tiles in their own colours, the Total estimate), the Follow-up plan large, and
   the Timeline. Colours are the tokens only, so both dark blocks already cover it. */
.job-page {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  max-width: 60rem;
  width: 100%;
  margin-inline: auto;
}

.job-page > .card {
  padding: 1.25rem;
  min-width: 0;
}

.job-page > .card > h2,
.job-page .qp-fu-head h2 {
  font-size: var(--fs-md);
  line-height: 1.2;
}

.job-page > .card > h2 {
  margin: 0 0 var(--sp-3);
}

.jp-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
}

.jp-guard:empty {
  display: none;
}

.jp-guard .stale {
  margin: 0;
}

/* The number (figure-lg) with the customer's name large under it: the heading of the page. */
.job-page .jp-title {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-1);
  margin: 0;
}

.jp-name {
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: 1.2;
  overflow-wrap: anywhere;
}

.jp-contact {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
  gap: var(--sp-3) var(--sp-5);
  margin: var(--sp-4) 0 0;
}

.jp-contact dt {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--muted);
}

.jp-contact dd {
  margin: 0;
  overflow-wrap: anywhere;
}

.jp-contact .jp-route {
  grid-column: 1 / -1;
}

.jp-status {
  display: grid;
  gap: var(--sp-3);
  margin-top: var(--sp-5);
}

.jp-status > .log-form,
.jp-status > .log-message,
.jp-status > p {
  margin: 0;
}

.jp-quote .charges {
  gap: var(--sp-4);
}

.jp-price {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2);
  margin: 0;
}

.jp-charges-later,
.jp-not-priced {
  margin: 0;
}

.jp-quote .total-estimate {
  margin-top: var(--sp-4);
}

.jp-detail,
.jp-saved {
  margin: var(--sp-3) 0 0;
}

.jp-follow {
  display: grid;
  gap: var(--sp-4);
}

.jp-follow > p {
  margin: 0;
}

/* The plan at the job size: the ring 144px with its percent scaled with it, what's next a size up. */
.jp-size .fu-ring,
.jp-size .fu-ring .ring {
  width: 144px;
  height: 144px;
}

.jp-size .fu-pct {
  font-size: calc(var(--fs-2xl) * 1.25);
  /* "100%" stays inside the ring's stroke at this size. */
  letter-spacing: -0.04em;
}

.jp-size .qp-fu-next-line {
  font-size: var(--fs-xl);
}

.jp-timeline-hint {
  margin: var(--sp-4) 0 0;
}

/* A phone: the cards a little tighter and the track's stops one to a line; the ring (the plan above its words under
   760px) and the words keep their size. */
@media (max-width: 480px) {
  .job-page > .card {
    padding: var(--sp-4);
  }

  .jp-follow .pt-stops {
    grid-template-columns: minmax(0, 1fr);
  }
}

.quote-plan {
  font-variant-numeric: tabular-nums;
}

.quote-plan .fu-meter {
  margin-right: 0.15rem;
  vertical-align: 0.1em;
}

/* The Estimator's time tabs' counts (estimator-tab.js): a small white pill with a thin line, its figure in the accent
   on the selected tab. */
.time-tab .tab-count {
  display: inline-block;
  min-width: 1.3rem;
  margin-left: 0.35rem;
  padding: 0 0.3rem;
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.3rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.time-tab[aria-selected="true"] .tab-count {
  background: var(--surface);
  color: var(--accent-ink);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* The Follow-ups count, on the sidebar's tab and the quick bar's button (the reminders fill both): a light pill with
   navy numerals on the navy sidebar, amber on its pale background (waiting) in the white header. */
.side .tab-count,
.quick .tab-count {
  display: inline-block;
  flex: none;
  min-width: 1.25rem;
  margin-left: auto;
  padding: 0 0.35rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.25rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.side .tab-count {
  background: var(--nav-ink);
  color: var(--nav);
}

.quick .tab-count {
  background: var(--warn-soft);
  color: var(--warn);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--warn) 25%, transparent);
}

@media (max-width: 480px) {
  .fu-row {
    padding: var(--sp-3);
  }

  /* On a phone: the ring 56px beside the name, the plan's list one column. */
  .fu-top {
    gap: var(--sp-3);
  }

  .fu-row .fu-ring,
  .fu-row .fu-ring .ring {
    width: 56px;
    height: 56px;
  }

  .fu-row .fu-pct {
    font-size: var(--fs-md);
  }

  .pt-stops {
    grid-template-columns: minmax(0, 1fr);
  }

  .fu-meter-row {
    width: 96px;
  }

  .fu-queue {
    grid-template-columns: minmax(0, 1fr);
    padding: var(--sp-3);
  }

  .fu-queue-now {
    grid-row: auto;
  }
}

/* Settings → Work log: the lost reasons */

.reason-list {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin-top: 0.4rem;
}

.reason-row {
  display: grid;
  grid-template-columns: var(--reorder-col) minmax(0, 1fr) auto auto;
  gap: 0.4rem 0.6rem;
  align-items: center;
}

.reason-row input[type="text"] {
  min-height: 32px;
  padding: 0.25rem 0.45rem;
  width: 100%;
}

.reason-uses {
  font-size: var(--fs-sm);
  white-space: nowrap;
}

.reason-row .confirm,
.reason-row .reason-error {
  grid-column: 2 / -1;
  margin: 0;
}

@media (max-width: 480px) {
  .reason-row {
    grid-template-columns: var(--reorder-col) minmax(0, 1fr) auto;
  }

  .reason-uses {
    grid-column: 2;
    grid-row: 2;
  }
}

.reason-add {
  margin-top: 0.6rem;
}

/* Settings → Follow-ups: the lifeline's boxes, the move-type switch, the two plan cards side by side (one column under
   960px), each meter point a row that wraps, the best-time windows, the replies and the gap, the five texts with their
   placeholder buttons and preview, then the reminders. */

.fu-card h3 {
  margin-top: 1.25rem;
}

.fu-card [aria-invalid="true"] {
  border-color: var(--bad);
  outline: 1px solid var(--bad);
}

.fu-card input[type="time"] {
  font: inherit;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--field-line);
  border-radius: var(--radius-sm);
  padding: 0.25rem 0.4rem;
  min-height: 32px;
  min-width: 0;
}

.fu-unsaved p {
  margin: 0;
}

.fu-unsaved [data-fu-slot]:empty {
  display: none;
}

.fu-types {
  margin: 0.25rem 0 0.75rem;
}

.fu-plans {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
  align-items: start;
}

.fu-plan {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.7rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-width: 0;
}

.fu-plan > .hint {
  margin: 0;
}

.fu-plan-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.4rem 0.75rem;
}

.fu-plan-head h4 {
  margin: 0;
  font-size: var(--fs-base);
}

.fu-points,
.fu-texts {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.fu-points {
  gap: 0.35rem;
}

.fu-point {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.45rem;
  padding: 0.35rem 0;
  border-top: 1px solid var(--line);
  min-width: 0;
}

.fu-point:first-child {
  border-top: 0;
}

.fu-pos {
  min-width: 1.1rem;
  text-align: right;
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}

.fu-f {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  min-width: 0;
  font-size: var(--fs-sm);
  color: var(--muted);
}

.fu-f select {
  min-height: 32px;
  padding: 0.2rem 0.4rem;
  width: auto;
  max-width: 100%;
}

.fu-at input {
  width: 3.8rem;
  min-height: 32px;
  padding: 0.2rem 0.4rem;
}

.fu-sends {
  flex: 1 1 11rem;
}

.fu-sends select {
  width: 100%;
}

.fu-id {
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}

.fu-remove {
  margin-left: auto;
}

.fu-point > .fu-error {
  flex: 1 1 100%;
  margin: 0;
}

.fu-plan > .fu-error {
  margin: 0;
}

.fu-plan-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.75rem;
}

.fu-live {
  font-size: var(--fs-sm);
}

/* The lifeline's book-by time and caps, the reply points and the gap: small labelled boxes on one wrapping row. */
.fu-knobs {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 1.25rem;
  margin: 0.25rem 0 0.4rem;
}

.fu-knob input.num {
  width: 5rem;
  min-height: 36px;
}

.fu-knob-time input[type="time"],
.fu-best-row input[type="time"] {
  min-height: 36px;
}

.fu-knob-time {
  width: 9rem;
}

#fu-mount > .fu-error {
  margin: 0 0 0.4rem;
}

/* Best time: the calls' and the texts' windows for the move type shown, each a From–To pair with its words under it. */
.fu-best {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
  margin: 0.25rem 0 0.4rem;
}

.fu-best-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.35rem 0.75rem;
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0;
}

.fu-best-row legend {
  width: 100%;
  padding: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
}

.fu-best-row .field {
  width: 9rem;
}

.fu-best-row > .fu-error {
  flex: 1 1 100%;
  margin: 0;
}

.fu-texts {
  gap: 0.75rem;
}

.fu-text {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.7rem;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  min-width: 0;
}

.fu-text-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
}

.fu-slot-name {
  flex: none;
  font-weight: 600;
  font-size: var(--fs-sm);
}

.fu-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
}

.fu-chips .hint {
  margin: 0 0.2rem 0 0;
  font-size: var(--fs-sm);
}

/* The placeholder buttons: dashed, as the Messages editor's customer and rep ones are. */
.fu-chip {
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--accent);
  background: var(--surface);
  border: 1px dashed var(--accent);
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
  min-height: 28px;
  cursor: pointer;
}

.fu-chip:hover {
  background: var(--accent-soft);
}

.fu-preview {
  background: var(--ground);
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
  padding: 0.5rem 0.65rem;
  min-width: 0;
}

.fu-preview p {
  margin: 0;
}

.fu-bubble {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.fu-preview .fu-count {
  margin-top: 0.3rem;
  font-size: var(--fs-xs);
}

.fu-text > .fu-error {
  margin: 0;
}

.fu-days {
  display: flex;
  flex-wrap: wrap;
  gap: 0.1rem 0.9rem;
  border: 0;
  padding: 0;
  margin: 0.25rem 0 0.5rem;
  min-width: 0;
}

.fu-days legend {
  width: 100%;
  padding: 0;
  font-size: var(--fs-sm);
  color: var(--muted);
  font-weight: 600;
}

.fu-hours {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
}

.fu-hours .field {
  width: 9rem;
}

.fu-hours input[type="time"] {
  min-height: 36px;
}

.fu-sound {
  margin-top: 0.5rem;
}

/* "Reminder sound off: …" under the switch while it is off (the Follow-ups tab's Mute reminders flips it too). */
.fu-sound-off {
  margin: 0.25rem 0 0;
  color: var(--warn);
  font-weight: 600;
  font-size: var(--fs-sm);
}

.fu-sound-off:empty {
  display: none;
}

@media (max-width: 960px) {
  .fu-plans {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 480px) {
  .fu-plan,
  .fu-text {
    padding: 0.55rem;
  }

  .fu-remove {
    margin-left: 0;
  }
}

/* Settings → Company & look: name, brand color (a text box and a swatch kept in step) and logo, with the header as it will show. */
.company-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.9fr) minmax(0, 1.5fr);
  gap: 0.75rem;
  align-items: start;
}

.color-pair {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.color-pair input[type="color"] {
  order: -1;
  flex: none;
  width: 44px;
  height: 36px;
  padding: 2px;
  border: 1px solid var(--field-line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
}

/* Light or dark (this browser): Auto · Light · Dark, under the company's boxes. */
.theme-field {
  margin-top: var(--sp-3);
}

.theme-field .seg {
  align-self: flex-start;
}

.theme-field .hint {
  margin: 0;
}

.company-preview {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem 0.75rem;
  margin: 0.75rem 0 0.5rem;
  padding: 0.6rem 0.75rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
  background: var(--ground);
}

.company-preview .hint {
  margin: 0;
}

.brand-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-md);
  line-height: 1.15;
  overflow-wrap: anywhere;
}

@media (max-width: 720px) {
  .company-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* AI inventory: the AI inventory app's page (inventory-styles.css, every rule under .ai-inventory) on Office's tokens.
   Its totals bar sits under the sticky header (--inv-top, set from the header's height by inventory-tab.js), and its
   picture viewer is position: fixed above the header (z-index 20), so no ancestor of #tab-inventory may carry a
   transform or contain. Cards get Office's line in place of the page's shadow. */

#tab-inventory {
  --brand: var(--accent);
  --brand-text: var(--accent);
  --brand-soft: var(--accent-soft);
  --on-brand: var(--on-accent);
  --card: var(--surface);
  --page: var(--ground);
  --quiet: var(--sunk);
  --field: var(--surface);
  --text: var(--ink);
  --problem: var(--bad);
  --problem-bg: var(--bad-soft);
  --ok-bg: var(--ok-soft);
  --warn-bg: var(--warn-soft);
  --low: var(--warn);
  --low-bg: var(--warn-soft);
  --on-low: var(--on-accent);
  --font: var(--font-body);
  --shadow: var(--shadow-1);
  --glow: none;
  --card-border: 1px solid var(--line);
}

/* Its headings in Office's face (Inter), at the sizes of Office's card headings (h2) and sub-headings. */
#tab-inventory .ai-inventory :is(h2, h3) {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: 600;
  letter-spacing: -0.005em;
  line-height: 1.15;
}

#tab-inventory .ai-inventory h4 {
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: 600;
}

/* Its cards with Office's card padding, and its field labels at Office's weight. */
#tab-inventory .ai-inventory .card {
  padding: var(--sp-4) var(--sp-5);
}

#tab-inventory .ai-inventory :is(.field__label, .field > .field__label) {
  font-size: var(--fs-sm);
  font-weight: 600;
}

@media (max-width: 480px) {
  #tab-inventory .ai-inventory .card {
    padding: 0.8rem;
  }
}

/* Office's main already gives the column and its gutters; its body text at Office's size (its own page's is larger). */
#tab-inventory > .ai-inventory {
  max-width: none;
  margin: 0;
  padding: 0 0 2rem;
  font-size: var(--fs-base);
  line-height: 1.45;
}

/* Messages: the rep console's views (messages-styles.css, every rule under .rep-console) on Office's tokens.
   Its own .tabs rule is .rep-console .tabs, so it never reaches the header's view tabs.
   Settings → Move ready's panel (move-ready-panel.js) is the console's checklist settings card, on the same tokens. */

#tab-messages,
.move-ready-panel {
  --brand: var(--accent);
  --brand-text: var(--accent);
  --brand-soft: var(--accent-soft);
  --on-brand: var(--on-accent);
  --band: var(--ink);
  --page: var(--ground);
  --card: var(--surface);
  --quiet: var(--sunk);
  --field: var(--surface);
  --text: var(--ink);
  --problem: var(--bad);
  --problem-bg: var(--bad-soft);
  --warn-bg: var(--warn-soft);
  --font: var(--font-body);
  --shadow: var(--shadow-1);
  --glow: none;
}

/* No words under 12px in the mounted views: the console's small uppercase badges, its chip notes and its small
   uppercase headings, and the AI inventory's tile labels, lifted to 12px in sentence case (an id beats their class
   rules, so apps/rep-console and apps/ai-inventory stay as they are). */
#tab-messages .rep-console .badge {
  font-size: 12px;
  letter-spacing: 0;
  text-transform: none;
}

#tab-messages .rep-console .chip__note {
  font-size: 12px;
}

#tab-messages .rep-console :is(.tokens__heading, .quote > legend) {
  font-size: 12px;
  letter-spacing: 0;
  text-transform: none;
}

#tab-inventory .ai-inventory .tile__label {
  font-size: 12px;
  letter-spacing: 0;
}

.messages {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

/* The four views, with the Settings list's look: muted, the one showing in the brand's soft tint with a bar under it
   (the list's bar is at its left; this row's is at its foot). */
.messages-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 2px var(--sp-1);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--line);
}

.messages-tab {
  display: inline-flex;
  align-items: center;
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--muted);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  padding: 0 var(--sp-3);
  min-height: 36px;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color 0.15s,
    color 0.15s;
}

.messages-tab:hover {
  background: var(--sunk);
  color: var(--ink);
}

.messages-tab[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--accent-ink);
  box-shadow: inset 0 -2px 0 var(--accent);
}

/* The quote picker */
.messages-picker h2 {
  margin-bottom: 0.5rem;
}

.messages-picker > * + * {
  margin-top: 0.6rem;
}

.messages-picked {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.6rem;
  margin: 0;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.messages-search {
  max-width: 34rem;
}

.messages-results {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.35rem;
}

.messages-results li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
}

.messages-result-line {
  min-width: 0;
  overflow-wrap: anywhere;
}

.messages-lead {
  border-top: 1px solid var(--line);
  padding-top: 0.6rem;
}

.messages-lead h3 {
  margin-top: 0;
}

.messages-lead-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  gap: 0.5rem;
  align-items: end;
}

/* The console's view sits in Office's column: no column, gutter or background of its own. */
#tab-messages .rep-console {
  max-width: none;
  margin: 0;
  padding: 0;
  background: transparent;
}

/* Office's own heading and chip rules stop at the console's views. */
#tab-messages .rep-console h2,
#tab-messages .rep-console h3 {
  display: block;
  font-family: var(--font-display);
  line-height: 1.15;
}

/* The same sizes as Office's own h2 and h3. */
#tab-messages .rep-console h2 {
  font-size: var(--fs-md);
  font-weight: 600;
  letter-spacing: -0.005em;
}

#tab-messages .rep-console h3 {
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
  color: var(--muted);
}

/* The console's cards take no line of their own (console.css reads no --card-border), so Office gives them one, and
   Office's card padding. */
#tab-messages .rep-console .card {
  border: 1px solid var(--line);
  padding: var(--sp-4) var(--sp-5);
}

#tab-messages .rep-console .card--quiet {
  box-shadow: none;
}

/* A label over a heading or a number, as Office's (.eyebrow): 13px, muted, sentence case. */
#tab-messages .rep-console .eyebrow {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
  color: var(--muted);
}

/* The console's and the AI inventory's buttons and boxes in Office's shapes: sentence case, the small radius, Office's
   sizes, targets still at least 36px (the big ones 48px). */
#tab-messages .rep-console .button,
#tab-inventory .ai-inventory .button {
  min-height: 40px;
  padding: 0.5rem 1rem;
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
  box-shadow: var(--shadow-1);
}

#tab-messages .rep-console .button--small,
#tab-inventory .ai-inventory .button--small {
  min-height: 36px;
  padding: 0.35rem 0.85rem;
}

#tab-inventory .ai-inventory .button--big {
  min-height: 48px;
  padding: 0.7rem 1.4rem;
  font-size: var(--fs-base);
}

#tab-messages .rep-console .button--quiet,
#tab-inventory .ai-inventory .button--quiet {
  border-color: var(--line-strong);
}

/* The AI inventory's choices (One walkthrough video or Room by room, a map's rooms) in Office's button shape, not pills:
   the small radius, .btn's 36px (the big ones 40px, as its buttons). */
#tab-inventory .ai-inventory .choice {
  min-height: 36px;
  padding: 0.4rem 0.85rem;
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  font-weight: 600;
}

#tab-inventory .ai-inventory .choice.choice--big {
  min-height: 40px;
  padding: 0.5rem 1rem;
  font-size: var(--fs-base);
}

/* Its totals bar as an Office card (the surface, a thin line, the sticky bars' raised shadow) instead of a solid brand
   band, inside Office's column at every width; the labels muted, the numbers in ink. */
#tab-inventory .ai-inventory .totals {
  margin: var(--sp-4) 0 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-2);
}

/* The totals' labels muted and in sentence case (its own page writes them in capitals). */
#tab-inventory .ai-inventory .tile__label {
  color: var(--muted);
  opacity: 1;
  text-transform: none;
}

#tab-messages .rep-console :is(textarea, select, input:not([type="checkbox"], [type="radio"], [type="file"], [type="range"])),
#tab-inventory .ai-inventory :is(textarea, select, input:not([type="checkbox"], [type="radio"], [type="file"], [type="range"], .stepper__box)) {
  padding: 0.45rem 0.7rem;
  border-radius: var(--radius-sm);
  font-size: var(--fs-base);
}

#tab-messages .rep-console :is(select, input:not([type="checkbox"], [type="radio"], [type="file"], [type="range"])),
#tab-inventory .ai-inventory :is(select, input:not([type="checkbox"], [type="radio"], [type="file"], [type="range"], .stepper__box)) {
  min-height: 40px;
}

#tab-inventory .ai-inventory :is(.notice, .problem) {
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
}

#tab-messages .rep-console .notice {
  border-radius: var(--radius-sm);
}

#tab-messages .rep-console .chip {
  display: inline-block;
  white-space: normal;
  text-align: left;
}

#tab-messages .rep-console .count {
  min-width: 0;
  text-align: left;
}

/* Recent's On this Mac chip: the demo-only marker, in the warning tone so it stands apart from the Email and Text badges. */
#tab-messages .rep-console .badge--mac {
  background: var(--warn-soft);
  color: var(--warn);
  border: 1px solid transparent;
}

/* The finish buttons and I sent it */
#tab-messages .finish__line {
  margin-top: 0;
}

#tab-messages .finish__tick {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}

#tab-messages .finish__tick input {
  width: auto;
  min-height: 0;
  margin: 0;
}

#tab-messages .finish__recorded {
  margin-top: 16px;
}

#tab-messages .finish__recorded:focus {
  outline: none;
}

@media (max-width: 480px) {
  /* One row that scrolls sideways; its width is the column's (inline-size containment), so its four views never
     widen the page (main's auto margins size it to its content). */
  .messages-nav {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    contain: inline-size;
  }

  .messages-lead-row {
    grid-template-columns: minmax(0, 1fr);
  }

  .messages-results li {
    flex-wrap: wrap;
  }
}

/* Settings → Move ready: the console's checklist settings card inside Office's section, without a card of its own.
   messages-styles.css loads after this file, so these rules carry both classes to outweigh its .rep-console ones. */
.rep-console.move-ready-panel {
  max-width: none;
  margin: 0;
  padding: 0;
  background: transparent;
}

.rep-console.move-ready-panel .card {
  padding: 0;
  border: 0;
  box-shadow: none;
  background: transparent;
}

.rep-console.move-ready-panel .card > .eyebrow {
  display: none;
}

/* Office's own h2 and h3 are flex rows; the console's headings are blocks. */
.rep-console.move-ready-panel h2,
.rep-console.move-ready-panel h3 {
  display: block;
}

.rep-console.move-ready-panel .card h2 {
  font-size: var(--fs-base);
}

/* Its buttons in Office's shape, as on the Messages tab: sentence case, the small radius, Office's sizes. */
.rep-console.move-ready-panel .button {
  min-height: 40px;
  padding: 0.5rem 1rem;
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
}

.rep-console.move-ready-panel .move-ready-time {
  margin: 0 0 12px;
}

.rep-console.move-ready-panel .move-ready-time + .notice {
  margin: -4px 0 16px;
}

/* Messages → Move ready: the customer's checklist page in its frame, about a phone's width. */
.checklist-frame {
  display: block;
  width: 100%;
  max-width: 440px;
  height: 760px;
  max-height: 80vh;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

/* The Dashboard (dashboard-tab.js, dashboard.js): what Office opens on, first in the sidebar. White cards on the
   workspace ground, a thin line, no shadow. Top to bottom: the head (the title and date, then the greeting, its one
   line and Numbers for), At a glance (six cards: six across from 1120px of room, then three, two and one), the work row
   (Calls and texts to make beside the picked customer and Replies waiting on you from 1100px, stacked under), the
   Calendar the full width, then Numbers (three tiles, two, then one). Every colour is a token (a chip's tone, the
   meter scale, the status colours), each colour has its word or shape beside it. */
.dash {
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
}

.dash > .banner {
  margin: 0;
}

/* 1. The head: "Dashboard" and the date on one line, the greeting large under it, Numbers for at its right. */
.dash-top {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-width: 0;
}

.dash-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-1) var(--sp-4);
}

.dash .dash-title {
  font-size: 14px;
  color: var(--muted);
  margin: 0;
}

.dash-date {
  margin: 0;
  color: var(--muted);
  font-size: var(--fs-sm);
  font-weight: 600;
}

.dash-greet-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-3) var(--sp-5);
  min-width: 0;
}

.dash-greet-words {
  flex: 1 1 20rem;
  min-width: 0;
}

.dash-greet {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.dash-summary {
  margin: var(--sp-1) 0 0;
  color: var(--muted);
  font-size: 14px;
}

.dash-period {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  max-width: 100%;
}

.dash-period-label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--muted);
}

/* 2. At a glance: six white cards, each a label, a figure, a small drawn chart when it has one, and its words. The
   columns follow the room the cards have (a container query: six across from 1120px, then three, two and one), so a
   row never ends with one card alone. */
.dash-strip {
  container-type: inline-size;
  min-width: 0;
}

.dash-metrics {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
}

@container (min-width: 330px) {
  .dash-metrics {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@container (min-width: 600px) {
  .dash-metrics {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@container (min-width: 1120px) {
  .dash-metrics {
    grid-template-columns: repeat(5, minmax(0, 1fr)) minmax(0, 1.3fr);
  }
}

.dash-metric {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-width: 0;
  position: relative;
  padding: 14px;
  min-height: 160px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.dash .dash-metric-label {
  margin: 0;
  padding-right: 20px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--muted);
}

.dash-metric-fig {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-2);
  margin: 0;
}

.dash-metric-fig .figure {
  overflow-wrap: anywhere;
}

.dash-metric-words,
.dash-metric > .dash-none,
.dash-metric > .bad-text {
  margin: 0;
  font-size: var(--fs-sm);
}

.dash-metric-words {
  color: var(--muted);
}

.dash-metric-words.is-strong,
.dash-metric .dash-rate-words {
  color: var(--ink);
  font-size: var(--fs-sm);
  font-weight: 600;
}

/* Open Follow-ups at the card's foot. */
.dash-metric .dash-more {
  margin: auto 0 0;
  font-size: var(--fs-sm);
}

/* Calls and texts today: a 6px bar of overdue (red), due now (orange) and later today (grey), each its count wide. */
.dash-stack {
  display: flex;
  gap: 2px;
  height: 6px;
  border-radius: 3px;
  overflow: hidden;
  background: var(--sunk);
}

.dash-stack-part {
  flex: 1 1 0;
  min-width: 4px;
}

.dash-stack-part.is-overdue {
  background: var(--bad);
}

.dash-stack-part.is-due {
  background: var(--warn);
}

.dash-stack-part.is-later {
  background: var(--line-strong);
}

/* Follow-ups · quotes: the Follow-ups head's queue health in the card's order (its due count the figure, its bands
   the chart, its legend the words), with no box of its own. */
.dash-metric .fu-queue {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-2);
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}

.dash-metric .fu-queue-now {
  white-space: normal;
}

.dash-metric .fu-queue-bar {
  height: 6px;
}

.dash-metric .fu-legend-item {
  white-space: normal;
}

/* Quotes sent: the columns (charts.js columnsSvg) in the primary blue, at most about 40px tall. */
.dash-chart {
  color: var(--accent);
  max-width: 16rem;
}

.chart-cols {
  display: block;
  max-width: 100%;
  height: auto;
}

.chart-col.is-zero,
.chart-base {
  fill: var(--line-strong);
}

/* Booked: the figure with the booking rate's ring beside it and the rate's words under both. */
.dash-metric-main {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-2) var(--sp-5);
}

.dash-metric-main .dash-ring {
  justify-self: start;
}

.dash-metric-main > .dash-rate {
  display: contents;
}

.dash-metric-main .dash-rate-words,
.dash-metric-main > .dash-none {
  grid-column: 1 / -1;
  margin: 0;
  font-size: var(--fs-sm);
}

/* A rate's ring (charts.js ringSvg: 56px in a card) as a meter, its figure in its middle and its words beside it. */
.dash-rate {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
}

.dash-ring {
  position: relative;
  flex: none;
  line-height: 0;
}

.dash-ring > svg {
  display: block;
}

.dash-ring-num {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

.dash-metric .dash-ring-num {
  font-size: var(--fs-xs);
}

.dash-rate-words {
  margin: 0;
  font-weight: 600;
}

/* 3. The work row: Calls and texts to make, and beside it (from 1100px) the picked customer and Replies waiting. */
.dash-work {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}

.dash-side {
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
}

.dash-card {
  padding: var(--sp-4);
  min-width: 0;
}

.dash .dash-card > h2 {
  font-size: var(--fs-md);
  line-height: 1.25;
  margin: 0 0 var(--sp-3);
}

.dash-none {
  margin: 0;
  color: var(--muted);
}

/* A count as a figure with its words: "3 calls and texts · 1 overdue · 2 due now". */
.dash-figline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-2);
  margin: 0 0 var(--sp-2);
}

.dash-figline > span {
  color: var(--muted);
  font-weight: 600;
}

/* A list of quotes: compact rows (44px at least), a 1px line between, a pale hover; the buttons at the right. */
.dash-list {
  list-style: none;
  margin: 0 calc(-1 * var(--sp-2));
  padding: 0;
}

.dash-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-3);
  min-height: 44px;
  padding: var(--sp-1) var(--sp-2);
  border-top: 1px solid var(--line);
  border-radius: var(--radius-sm);
  transition: background-color 120ms ease;
}

.dash-line:first-child {
  border-top-color: transparent;
}

.dash-line:hover {
  background: var(--sunk);
}

.dash-ico {
  display: inline-flex;
  flex: none;
  color: var(--muted);
}

.dash-touch.is-overdue .dash-ico {
  color: var(--bad);
}

.dash-touch.is-due .dash-ico {
  color: var(--warn);
}

.dash-main {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-2);
  flex: 1 1 14rem;
  min-width: 0;
}

.dash-who {
  overflow-wrap: anywhere;
}

.dash-name {
  font-weight: 600;
}

.dash-step,
.dash-time {
  color: var(--muted);
  font-size: var(--fs-sm);
}

.dash-time {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.dash-btns {
  display: flex;
  flex: none;
  gap: var(--sp-2);
  margin-left: auto;
}

/* Calls and texts to make: aligned rows (the shape · the customer · when · the follow-up · Call and Open) where the
   card is wide; the follow-up and the buttons under the name where it is not; when under that too on a phone. The
   picked row in the selected tone with a line of the primary blue at its left (and aria-pressed on its name). */
.dash-touches-card {
  container-type: inline-size;
}

.dash-touch {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "ico who who"
    ". when when"
    ". step btns";
  align-items: center;
  gap: var(--sp-1) var(--sp-3);
}

.dash-touch > .dash-ico {
  grid-area: ico;
}

.dash-touch > .dash-pick-btn {
  grid-area: who;
}

.dash-touch > .dash-when {
  grid-area: when;
  justify-self: start;
}

.dash-touch > .dash-step {
  grid-area: step;
}

.dash-touch > .dash-btns {
  grid-area: btns;
  justify-self: end;
  margin-left: 0;
}

@container (min-width: 460px) {
  .dash-touch {
    grid-template-areas:
      "ico who when"
      ". step btns";
  }

  .dash-touch > .dash-when {
    justify-self: end;
  }
}

@container (min-width: 700px) {
  .dash-touch {
    grid-template-columns: auto minmax(8rem, 1fr) auto auto auto;
    grid-template-areas: "ico who when step btns";
  }
}

.dash-touch.is-picked,
.dash-touch.is-picked:hover {
  background: var(--accent-soft);
  box-shadow: inset 3px 0 0 var(--accent);
}

.dash-pick-btn {
  font: inherit;
  color: var(--ink);
  text-align: left;
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  padding: 0.3rem 0;
  min-height: 32px;
  min-width: 0;
  cursor: pointer;
}

.dash-pick-btn:hover .dash-name {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* The picked customer: the name large with its number, the booking chip at the right, the facts as label and value
   rows each with its shape, then Call or Text (the panel's one primary action) and Open. */
.dash-pick {
  container-type: inline-size;
}

.dash-pick-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-3);
}

.dash-pick-who {
  min-width: 0;
}

.dash .dash-pick h2 {
  font-size: var(--fs-lg);
  margin: 0;
  overflow-wrap: anywhere;
}

.dash-pick-num {
  margin: var(--sp-1) 0 0;
  color: var(--muted);
  font-size: var(--fs-sm);
}

.dash-facts {
  margin: 0;
}

.dash-fact {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr);
  align-items: baseline;
  gap: var(--sp-1) var(--sp-3);
  padding: var(--sp-2) 0;
  border-top: 1px solid var(--line);
}

.dash-fact:first-child {
  border-top: 0;
}

.dash-fact dt {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--muted);
}

.dash-fact-ico {
  display: inline-flex;
  flex: none;
  color: var(--muted);
}

.dash-fact dd {
  margin: 0;
  color: var(--ink);
  overflow-wrap: anywhere;
}

@container (max-width: 359px) {
  .dash-fact {
    grid-template-columns: minmax(0, 1fr);
  }

  .dash-fact dd {
    padding-left: calc(16px + var(--sp-2));
  }
}

.dash-pick-btns {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
}

.dash-pick-btns .btn {
  flex: 1 1 8rem;
  min-height: 40px;
}

/* 4. The calendar: its title at the left, Week | Month and ‹ Today › at the right, a legend, the days as one table of
   white cells, then the picked day's list. */
.dash-cal-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-3);
}

.dash-cal-nav {
  display: flex;
  gap: var(--sp-1);
}

.dash .dash-cal-title {
  order: -1;
  margin: 0 auto 0 0;
  font-size: var(--fs-md);
  color: var(--ink);
}

.dash-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-3);
}

/* An item on a day: a chip in its tone (words in the tone on its pale background) with its shape, wrapping inside a
   narrow day. */
.chip.dash-item {
  gap: 0.3rem;
  align-items: flex-start;
  white-space: normal;
  line-height: 1.35;
  text-align: left;
  overflow-wrap: anywhere;
}

.dash-item .pt-ico,
.dash-cnt .pt-ico {
  flex: none;
  width: 13px;
  height: 13px;
  margin-top: 0.15rem;
}

.dash-days,
.dash-month-heads {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
}

/* The days share one frame: 1px lines between white cells. */
.dash-days {
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

.dash-month-heads {
  margin-bottom: var(--sp-1);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-align: center;
  color: var(--muted);
}

.dash-day {
  font: inherit;
  color: var(--ink);
  text-align: left;
  background: var(--surface);
  border: 0;
  border-radius: 0;
  padding: var(--sp-2);
  cursor: pointer;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  transition: background-color 120ms ease;
}

.dash-day:focus-visible {
  outline-offset: -3px;
}

.dash-day > span {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 0;
}

.dash-days-week .dash-day {
  min-height: 6rem;
}

.dash-days-month .dash-day {
  min-height: 88px;
}

.dash-day:hover {
  background: var(--sunk);
}

/* A day of the months either side in the month view: the workspace ground, its words muted. */
.dash-day.is-out {
  background: var(--ground);
  color: var(--muted);
}

.dash-day.is-out .dash-dnum {
  color: var(--muted);
}

/* The picked day: the selected tone with a line of the primary blue round it (and aria-pressed). */
.dash-day[aria-pressed="true"] {
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* Today: its head in the primary blue with a 2px edge of it along the top (its name says "today"). */
.dash-day.is-today {
  box-shadow: inset 0 2px 0 var(--accent);
}

.dash-day.is-today[aria-pressed="true"] {
  box-shadow:
    inset 0 2px 0 var(--accent),
    inset 0 0 0 1px var(--accent);
}

.dash-day-head {
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
  color: var(--muted);
}

.dash-dow {
  font-size: var(--fs-sm);
  font-weight: 600;
}

.dash-days-month .dash-dow {
  display: none;
}

.dash-dnum {
  font-family: var(--font-display);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.dash-day.is-today .dash-day-head,
.dash-day.is-today .dash-dnum {
  color: var(--accent-ink);
}

.dash-day-items {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.dash-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 0.45rem;
  font-size: var(--fs-xs);
}

.dash-cnt {
  display: inline-flex;
  align-items: flex-start;
  gap: 0.15rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.dash-cnt .pt-ico {
  color: var(--muted);
}

/* A packing count's box in the packing purple, as its chips are. */
.dash-cnt.is-packing .pt-ico {
  color: var(--pack);
}

.dash-cnt-word {
  font-weight: 400;
  color: var(--muted);
}

.dash-picked {
  margin-top: var(--sp-4);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
}

.dash .dash-picked-title {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-base);
  color: var(--ink);
}

/* 5. Numbers: three tiles, each a label, its figures and bars, and its words. */
.dash-num-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-3);
}

.dash-tile {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-width: 0;
  position: relative;
  padding: 14px;
  min-height: 160px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.dash-tile > p {
  margin: 0;
}

.dash .dash-tile-label {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--muted);
}

.dash-figs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
}

.dash-figs p {
  display: flex;
  flex-direction: column;
  margin: 0;
}

.dash-fig-label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--muted);
}

/* Bars (charts.js barsSvg) with their words beside them, one 20px line to each bar. */
.dash-bars {
  display: grid;
  grid-template-columns: fit-content(60%) minmax(6rem, 1fr);
  gap: 0 var(--sp-3);
  align-items: start;
}

.dash-bar-words {
  list-style: none;
  margin: 0;
  padding: 0;
  min-width: 0;
}

.dash-bar-words li {
  height: 20px;
  line-height: 20px;
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.chart-bars {
  display: block;
  margin-top: 4px;
}

.chart-track {
  fill: var(--sunk);
}

.chart-bar.is-zero {
  fill: var(--line-strong);
}

@media (min-width: 700px) {
  .dash-num-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1100px) {
  .dash-work {
    grid-template-columns: minmax(0, 1.9fr) minmax(20rem, 1fr);
  }

  .dash-num-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* A month cell's words ("2 moves") only where the cells are wide; the shape and the number always. */
@media (max-width: 1279px) {
  .dash-cnt-word {
    display: none;
  }
}

/* Under 900px the week's days become a list, one row to each day (the day at the left, its items beside it); the
   month keeps its seven columns with counts only. */
@media (max-width: 899px) {
  .dash-days-week {
    grid-template-columns: minmax(0, 1fr);
  }

  .dash-days-week .dash-day {
    min-height: 44px;
  }

  .dash-days-week .dash-day > span {
    flex-direction: row;
    align-items: flex-start;
    gap: var(--sp-3);
  }

  .dash-days-week .dash-day-head {
    flex: none;
    width: 4.5rem;
  }

  .dash-days-week .dash-day-items {
    flex: 1 1 auto;
    flex-flow: row wrap;
    min-width: 0;
  }
}

/* A phone: the greeting a little smaller, Numbers for under it the full width (its switch scrolling sideways in its
   own box if it must); the month's cells narrow, their counts stacked. */
@media (max-width: 700px) {
  .dash-greet {
    font-size: 1.5rem;
  }

  .dash-period {
    flex: 1 1 100%;
  }

  .dash-period .seg {
    flex-wrap: nowrap;
    max-width: 100%;
    overflow-x: auto;
  }

  .dash-period .seg-btn {
    flex: none;
    white-space: nowrap;
  }

  .dash-days-month .dash-day {
    padding: 0.2rem;
    min-height: 3.5rem;
    align-items: center;
  }

  .dash-days-month .dash-day > span {
    align-items: center;
  }

  .dash-days-month .dash-counts {
    flex-direction: column;
    align-items: center;
    gap: 0;
  }
}

/* Dashboard and Estimator refinement, September 2026. These rules stay scoped
   to the two working screens; shared controls keep their existing handlers. */
.dash-metric-fig .figure {
  font-size: 28px;
  letter-spacing: -0.035em;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}

.dash-m-pipe .dash-metric-fig .figure {
  font-size: clamp(16px, 1.2vw, 22px);
  letter-spacing: -0.045em;
  overflow-wrap: normal;
}

.dash-metric-words,
.dash-metric-words.is-strong,
.dash-metric .dash-rate-words,
.dash-metric > .dash-none,
.dash-metric .dash-more {
  font-size: 12px;
  line-height: 1.45;
}

.dash-metric > .dash-metric-words:last-child {
  margin-top: auto;
}

.dash-m-calls { border-top: 3px solid var(--accent); }
.dash-m-fu { border-top: 3px solid var(--warn); }
.dash-m-sent { border-top: 3px solid var(--scale-blue); }
.dash-m-booked { border-top: 3px solid var(--ok); }
.dash-m-reply { border-top: 3px solid var(--accent); }
.dash-m-pipe { border-top: 3px solid var(--warn); }

.dash-metric .fu-queue-now { font-size: 18px; }
.dash-metric .fu-legend { font-size: 12px; }
.dash-metric-main { column-gap: 12px; }

.dash-help {
  position: absolute;
  top: 9px;
  right: 6px;
  font-size: 12px;
  font-weight: 400;
}

.dash-help > summary {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  cursor: pointer;
  list-style: none;
  color: var(--muted);
  border-radius: 50%;
}

.dash-help > summary::-webkit-details-marker { display: none; }
.dash-help > summary:hover { background: var(--accent-soft); }
.dash-help[open] { z-index: 5; }
.dash-help-body {
  position: absolute;
  right: 0;
  top: 28px;
  width: 220px;
  max-width: calc(100vw - 48px);
  padding: 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-2);
}

.dash-help-body p { margin: 0; }
.dash-work, .dash-side { gap: 16px; }
.dash-card { padding: 16px; }
.dash .dash-card > h2 { font-size: 17px; }
.dash-touch { padding-block: 10px; }
.dash-pick { background: var(--sunk); }
.dash-picked { margin-top: 12px; padding-top: 12px; }

#tab-estimator > .banner { font-size: 12px; padding: 8px 12px; }
#tab-estimator .job-bar { box-shadow: none; }
#tab-estimator .job-field-name input { font-size: 16px; }
#tab-estimator .block .n { width: 22px; height: 22px; font-size: 12px; }
#tab-estimator .est-jump { border-radius: 6px 6px 0 0; }
#tab-estimator .price-strip { background: var(--accent-soft); padding: 18px; }
#tab-estimator .price-strip > h2 { font-size: 17px; }
#tab-estimator .price-strip .crew-line { gap: 10px 16px; }
#tab-estimator .price-strip .crew-line > strong { flex-basis: 100%; font-size: 20px; }
#tab-estimator .price-strip .charge { background: transparent; border: 0; border-radius: 0; padding: 12px 0; gap: 4px; }
#tab-estimator .price-strip .charge-tiles { gap: 0; border-block: 1px solid var(--line-strong); }
#tab-estimator .price-strip .charge + .charge { border-top: 1px solid var(--line); }
#tab-estimator .price-strip .charge-label { font-size: 12px; }
#tab-estimator .price-strip .charge-amount { font-size: 22px; }
#tab-estimator .price-strip .charge-how { font-size: 12px; }
#tab-estimator .price-strip .total-estimate { padding: 0; border: 0; background: transparent; }
#tab-estimator .price-strip .total-estimate .figure { font-size: 28px; letter-spacing: -0.04em; overflow-wrap: normal; }
#tab-estimator .price-strip .price-more .link { background: var(--accent); color: var(--on-accent); }

/* Room amount controls and editable notes share one row on a wide form. */
@container (min-width: 680px) {
  .est-inputs .room-sel:not(.missing) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: 20px;
    row-gap: 6px;
  }
  .est-inputs .room-sel-head { grid-column: 1 / -1; }
  .est-inputs .room-sel > .room-range,
  .est-inputs .room-sel > .range-ticks,
  .est-inputs .room-sel > .room-time { grid-column: 1; }
  .est-inputs .room-sel > .field { grid-column: 2; grid-row: 2 / 5; }
  .est-inputs .room-sel textarea { min-height: 64px; }
}

@media (max-width: 599px) {
  .dash-help-body { position: static; width: auto; margin-top: 4px; }
  .dash-help[open] { position: static; }
  .dash-metric { min-height: 148px; }
  .dash-m-pipe .dash-metric-fig .figure { font-size: 20px; }
  #tab-estimator .price-strip .total-estimate .figure { font-size: 26px; }
}

@media (min-width: 1100px) {
  .dash-touches {
    max-height: 320px;
    overflow-y: auto;
    scrollbar-width: thin;
    overscroll-behavior: contain;
  }
}

/* Moving type and crew share a compact panel beside Property. Their DOM order
   stays 1, 2, 3; the shared frame avoids stretching the short moving controls. */
.est-crew-stack {
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.est-crew-stack .block {
  border: 0;
  border-radius: 0;
  background: transparent;
}
.est-crew-stack .block + .block { border-top: 1px solid var(--line); }
.est-crew-stack .trucks { margin-top: 0; }
.est-crew-stack .block > h2 { margin-bottom: 8px; }
.est-crew-stack .trucks { flex-direction: row; flex-wrap: wrap; gap: 8px 16px; }
.est-crew-stack .truck-row > .row-label { min-width: 0; flex-basis: auto; }
.est-inputs .est-help { border: 0; padding-top: 0; margin: 4px 0 8px; }
.est-inputs .est-help > summary { font-size: 12px; }
.est-inputs .access-total { font-size: 13px; }

.dash-pick-btn .dash-who { display: flex; flex-direction: column; gap: 2px; }
.dash-pick-btn .dash-name { order: -1; font-size: 14px; }
.dash-pick-btn .dash-who > strong { font-size: 12px; color: var(--muted); font-weight: 400; }

@media (max-width: 599px) {
  #tab-estimator .job-field-name { flex-basis: 100%; }
}

/* Customer facts stay readable while the calendar remains close to the queue. */
.dash-pick-head { margin-bottom: 8px; }
.dash .dash-pick h2 { font-size: 20px; }
.dash-fact { padding-block: 6px; }
.dash-fact dt { font-size: 12px; }
.dash-fact dd { font-size: 13px; }
.dash-side > [aria-labelledby="h-dash-glance"] { padding: 12px 16px; }
.dash-side > [aria-labelledby="h-dash-glance"] h2 { font-size: 14px; margin-bottom: 6px; }
#dash-glance > .dash-none { font-size: 12px; }
.est-inputs .undo-line:empty { min-height: 12px; margin-block: 4px; }

/* Booked stays green regardless of rate; the percentage itself is unchanged. */
.dash-m-booked {
  --scale-blue: var(--ok-mark);
  --scale-orange: var(--ok-mark);
  --scale-red: var(--ok-mark);
}
#tab-estimator .reorder-step { font-size: 12px; }

/* Shared type hierarchy: regular working text, semibold names/headings, bold
   key figures. Match the quieter Leads reference without shrinking controls. */
strong, b { font-weight: 600; }
.figure, .fu-pct { font-weight: 700; }
.btn, .seg-btn, .set-tab, .side [role="tab"], .time-tab, .messages-tab,
.quick-flip [data-go], .quick-btn, .est-jump-btn,
.field > span:first-child, .row-label, .eyebrow, .charge-label,
.dash-date, .dash-period-label, .dash .dash-metric-label,
.dash .dash-tile-label, .dash-fig-label, .dash-time,
.dash-figline > span, .fu-queue-now span,
.pair-head, .hc-head, .labor-head, .piece-head, .special-head, .material-head {
  font-weight: 400;
}
.btn.primary, .seg-btn[aria-pressed="true"], .set-tab[aria-selected="true"],
.side [role="tab"][aria-selected="true"], .time-tab[aria-selected="true"],
.messages-tab[aria-current="page"], .est-jump-btn[aria-current="location"] {
  font-weight: 600;
}
.dash-metric-words.is-strong, .dash-rate-words, .history-what,
.qp-contact-who dt, .wl-contacts-label { font-weight: 400; }
.dash .dash-metric-label { font-size: 12px; letter-spacing: 0.02em; }
.qp-who .qp-name, .fu-name, .jp-name, .job-field-name input { font-weight: 600; }

/* Embedded working programs inherit the same hierarchy through Office only. */
#tab-messages .rep-console :is(.field__label, .eyebrow, .button, .tab),
#tab-inventory .ai-inventory :is(.field__label, .field > .field__label, .button),
.move-ready-panel .field__label { font-weight: 400; }
#tab-messages .rep-console .button:not(.button--quiet),
#tab-inventory .ai-inventory .button:not(.button--quiet) { font-weight: 600; }

/* Pending is an open quote, not a warning. The existing status classes and
   handlers stay intact; presentation scopes distinguish booking from alerts. */
[data-booking].warn,
.quote-title > .chip.warn, .dash-legend .chip.warn,
.dash-item[data-calendar-kind="move"].warn {
  color: var(--pending);
  background: var(--pending-soft);
  border-color: color-mix(in srgb, var(--pending) 25%, transparent);
}
.status-btn[aria-pressed="true"][data-value="pending"] {
  color: var(--pending);
  background: var(--pending-soft);
  border-color: var(--pending);
  box-shadow: inset 0 0 0 1px var(--pending);
}
.quick .tab-count, .fu-waiting .chip.warn, .dash-touch .chip.warn,
.dash-item[data-calendar-kind="touch"].warn {
  color: var(--due);
  background: var(--due-soft);
  border-color: color-mix(in srgb, var(--due) 25%, transparent);
  box-shadow: none;
}
.fu-line.is-due:not(.is-overdue) strong,
.qp-fu-next-line.is-due:not(.is-overdue),
.pt-item.is-due .pt-mark, .pt-item.is-due .pt-icon,
.dash-touch.is-due:not(.is-overdue) .dash-ico { color: var(--due); }
.pt-stop.is-due { color: var(--due); background: var(--due-soft); border-color: var(--due); }
.pt-stop.is-overdue { color: var(--bad); background: var(--bad-soft); border-color: var(--bad-mark); }
.dash-stack-part.is-due { background: var(--due); }
.dash-stack-part.is-overdue { background: var(--bad-mark); }
.dash-m-fu { border-top-color: var(--due); }
.dash-m-pipe { border-top-color: var(--pending); }
.dash-m-booked { border-top-color: var(--ok-mark); }
.fu-row.is-due { box-shadow: inset 3px 0 0 var(--due); }
.fu-row.is-over { box-shadow: inset 3px 0 0 var(--bad-mark); }

/* Bright color is a small redundant cue, never small neon text on white.
   The dark rim and explicit status label keep each cue legible. */
.chip.ok::before, .chip.bad::before {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  margin-right: 5px;
  border-radius: 50%;
  background: var(--ok-bright);
  box-shadow: 0 0 0 1px var(--ok);
}
.chip.bad::before { background: var(--bad-bright); box-shadow: 0 0 0 1px var(--bad); }
.wl-count[data-count="booked"] .wl-count-bar > span { background: var(--ok-mark); }

/* Carry the approved spacing into the other working tabs. Long-form content
   keeps its own controls and source order; fields continue wrapping on phones. */
#tab-quotes, #tab-followups, #tab-settings, #tab-worklog, #tab-quote,
.qp-body { max-width: none; }
.qp-body > .card, .qp-customer > .card, .fu-row,
#tab-settings .card, #tab-messages .rep-console .card,
#tab-inventory .ai-inventory .card { padding: 16px; }
.fu-row { gap: 10px; box-shadow: none; }
.fu-line { font-size: 15px; }
.fu-name { font-size: 19px; }
.fu-tally { font-size: 14px; font-weight: 400; }
.fu-top { gap: 14px; }
.fu-row .fu-ring, .fu-row .fu-ring .ring { width: 56px; height: 56px; }
.fu-row .fu-pct { font-size: 18px; }
.chip.chip-lg { font-size: 14px; padding: 3px 9px; min-height: 28px; }
.set-layout { column-gap: 16px; }
.set-main, .set-panel { gap: 14px; }
.rates-table { max-width: none; }
.quote-row { padding-block: 12px; }
@media (min-width: 900px) {
  .set-layout { grid-template-columns: 184px minmax(0, 1fr); }
}
@media (max-width: 480px) {
  .qp-body > .card, .qp-customer > .card, .fu-row,
  #tab-settings .card, #tab-messages .rep-console .card,
  #tab-inventory .ai-inventory .card { padding: 12px; }
}

/* Approved refined preview: quiet cards and compact, repeated summary strips.
   Orange warnings and black amounts are shared across all working views. */
:root {
  --review-orange: #d65a0a;
  --review-orange-ink: #a64008;
  --review-orange-soft: #fff1e6;
}
#tab-dashboard { --due: var(--review-orange-ink); --due-soft: var(--review-orange-soft); --scale-orange: var(--review-orange); }
#tab-dashboard .dash-metric { border-top: 1px solid var(--line); border-radius: 9px; box-shadow: none; min-height: 154px; padding: 14px; }
#tab-dashboard .dash-metric-label { text-transform: uppercase; letter-spacing: .065em; font-size: 12px; font-weight: 400; }
#tab-dashboard .dash-metric-fig .figure { font-size: 26px; }
#tab-dashboard .dash-m-pipe .dash-metric-fig .figure { font-size: 20px; }
#tab-dashboard .dash-m-fu .fu-queue-now span { color: var(--review-orange-ink); }
#tab-dashboard .dash-m-fu .fu-queue-bar { height: 12px; border-radius: 2px; }
#tab-dashboard .dash-touch:hover { background: var(--accent-soft); }
#tab-dashboard .dash-touch.is-picked,
#tab-dashboard .dash-touch.is-picked:hover { background: var(--sunk); }
#tab-dashboard .dash-touch:focus-within { outline: 1px solid var(--accent); outline-offset: -1px; }

/* Keep the calendar's controls, day cells and agenda in bounded columns.
   Every event remains present; long text wraps inside its own column. */
.dash-calendar-layout { display: grid; gap: 20px; }
.dash-calendar-grid { min-width: 0; }
#tab-dashboard .dash-cal-bar { justify-content: flex-start; gap: 8px; }
#tab-dashboard .dash-cal-title { margin-right: 12px; font-size: 16px; }
#tab-dashboard .dash-picked { margin: 0; padding: 0; border: 0; min-width: 0; }
#tab-dashboard .dash-picked .dash-list { margin: 0; }
#tab-dashboard .dash-picked .dash-line { display: grid; grid-template-columns: 16px minmax(0,1fr) auto; padding: 10px 0; gap: 10px; }
#tab-dashboard .dash-picked .dash-main { display: flex; flex-wrap: wrap; gap: 5px 8px; min-width: 0; }
#tab-dashboard .dash-picked .dash-btns { margin: 0; }
#tab-dashboard .dash-days-week .dash-day { min-height: 150px; }
@media (min-width: 1280px) {
  .dash-calendar-layout { grid-template-columns: minmax(0, 1.9fr) minmax(300px, 1fr); align-items: start; }
  #tab-dashboard .dash-picked { border-left: 1px solid var(--line); padding-left: 20px; }
}

.office-summary { display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); border: 1px solid var(--line); border-radius: 9px; background: var(--surface); overflow: hidden; }
.office-summary-cell { min-width: 0; padding: 15px 18px; display: flex; flex-direction: column; align-items: flex-start; gap: 9px; border-right: 1px solid var(--line); }
.office-summary-cell:last-child { border-right: 0; }
.summary-label { color: var(--muted); text-transform: uppercase; letter-spacing: .065em; font-size: 12px; font-weight: 400; }
.summary-value { font-size: 20px; line-height: 1.25; font-weight: 600; color: #171717; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.summary-detail { color: var(--muted); font-size: 12px; line-height: 1.4; }
.est-overview { margin-bottom: 14px; }
#tab-estimator .price-strip { background: var(--surface); border-radius: 9px; box-shadow: none; }
#tab-estimator .price-strip :is(.charge-amount,.figure,.crew-line > strong) { color: #171717; }
#tab-estimator .price-strip .charge-label { color: var(--muted); }
#tab-estimator .price-strip .total-estimate { background: var(--ground); padding: 14px; border-radius: 6px; }
#tab-estimator .truck-bar { --scale-blue: var(--ok-mark); --scale-orange: var(--review-orange); --scale-red: var(--bad-mark); box-shadow: none; }
#tab-estimator .truck-bar-meter { height: 12px; border-radius: 2px; }
/* Solid fill with narrow separators gives the reference its segmented meter. */
#tab-estimator .truck-bar-meter .bar-fill { transition: width 160ms ease, background-color 160ms ease; }
#tab-estimator .block { box-shadow: none; }
#tab-estimator .room-sel { box-shadow: none; border-radius: 5px; }

#tab-followups { --due: var(--review-orange-ink); --due-soft: var(--review-orange-soft); --scale-orange: var(--review-orange); }
#tab-followups .fu-guide { font-size: 13px; color: var(--muted); }
#tab-followups .fu-guide summary { cursor: pointer; color: var(--accent-ink); }
#tab-followups .fu-guide p { max-width: 100ch; line-height: 1.55; }
#tab-followups .fu-row { padding: 18px; box-shadow: none; border-radius: 9px; gap: 12px; }
#tab-followups .fu-top { margin-bottom: 2px; }
#tab-followups .fu-overview { margin-bottom: -12px; border-radius: 8px 8px 0 0; }
.fu-health .fu-ring { width: auto; height: auto; display: block; }
.fu-health .ring { display: none; }
.fu-health .fu-pct { position: static; font-size: 24px; }
.health-segments { display: flex; width: 100%; height: 12px; gap: 3px; }
.health-segments i { flex: 1; border-radius: 1px; background: var(--line); }
.health-segments i.on { background: var(--scale-blue); }
.fu-health:has(.fu-ring.warn) .health-segments i.on { background: var(--scale-orange); }
.fu-health:has(.fu-ring.bad,.fu-ring.over) .health-segments i.on { background: var(--scale-red); }
#tab-followups .fu-next { padding: 12px 18px; margin: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 16px; border: 1px solid var(--line); border-radius: 0 0 8px 8px; background: #fbfcff; font-size: 14px; }
#tab-followups .fu-activity-title { font-size: 15px; margin: 5px 0 0; }
:is(#tab-followups, .qp-fu-inner) .pt-stops { grid-template-columns: 1fr; gap: 0; margin-top: 8px; }
:is(#tab-followups, .qp-fu-inner) .pt-item { grid-template-columns: 24px 18px minmax(180px,1fr) minmax(90px,.55fr) minmax(150px,1fr); align-items: center; padding: 11px 8px; border: 0; border-bottom: 1px solid var(--line); border-radius: 0; }
:is(#tab-followups, .qp-fu-inner) .pt-item.is-next { background: var(--sunk); box-shadow: inset 3px 0 var(--accent); }
:is(#tab-followups, .qp-fu-inner) .pt-num,:is(#tab-followups, .qp-fu-inner) .pt-icon { grid-row: 1; }
:is(#tab-followups, .qp-fu-inner) .pt-what { grid-column: 3; }
:is(#tab-followups, .qp-fu-inner) .pt-mark { grid-column: 4; }
:is(#tab-followups, .qp-fu-inner) .pt-when { grid-column: 5; }
:is(#tab-followups, .qp-fu-inner) .pt-answer-box { grid-column: 3 / -1; }
#tab-followups .fu-actions { padding-top: 12px; }
#tab-followups .fu-lifeline { max-width: 100ch; }

.set-group-heading { display: block; font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .065em; padding: 18px 10px 5px; }
.set-group-heading:first-child { padding-top: 0; }
#tab-settings .set-tabs { gap: 2px; }
#tab-settings .set-tab { padding-block: 7px; }
#tab-settings .rates-table .pair-row { border-bottom: 1px solid var(--line); padding-block: 10px; }
#tab-settings .rates-table input { text-align: right; font-variant-numeric: tabular-nums; }

#tab-estimator .est-overview { --scale-blue: var(--ok-mark); --scale-orange: var(--review-orange); --scale-red: var(--bad-mark); }
#tab-estimator .truck-segments i.on { background: var(--tone); }
#tab-estimator .truck-bar-meter { position: relative; }
.truck-ticks { position: absolute; inset: 0; display: flex; pointer-events: none; }
.truck-ticks i { flex: 1; border-right: 3px solid var(--surface); }
.truck-ticks i:last-child { border: 0; }
#tab-estimator .job-bar { margin-bottom: 14px; }
/* Keep seven days readable before putting the agenda beside them. */
@media (min-width: 1280px) and (max-width: 1599px) {
  .dash-calendar-layout { grid-template-columns: minmax(0,1fr); }
  #tab-dashboard .dash-picked { border-left: 0; border-top: 1px solid var(--line); padding: 14px 0 0; }
  #tab-dashboard .dash-picked .dash-list { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); column-gap: 24px; }
}
#tab-dashboard .dash-day .dash-item { align-items: center; }
#tab-dashboard .dash-day .dash-item::before { display: none; }
#tab-dashboard .dash-day .dash-item > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#tab-dashboard .dash-picked .dash-who { flex-basis: 100%; }

#tab-dashboard .dash-sparkline { width: 100%; height: 34px; color: var(--accent); display: block; }
#tab-dashboard .dash-m-fu .fu-queue-bar { position: relative; }
#tab-dashboard .dash-m-fu .fu-queue-bar::after { content: ""; position: absolute; inset: 0; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='12'%3E%3Cpath d='M9 0v12' stroke='white' stroke-width='2'/%3E%3C/svg%3E") repeat-x; pointer-events: none; }
@media (min-width: 1280px) {
  #tab-dashboard .dash-picked .dash-main { display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: center; }
  #tab-dashboard .dash-picked .dash-time { grid-column: 1; grid-row: 1; }
  #tab-dashboard .dash-picked .dash-main > .chip { grid-column: 2; grid-row: 1; justify-self: start; }
  #tab-dashboard .dash-picked .dash-who { grid-column: 1; grid-row: 2; }
  #tab-dashboard .dash-picked .dash-step { grid-column: 2; grid-row: 2; font-size: 12px; }
}
/* Preserve narrow-screen wrapping; detailed phone review is deferred. */
@media (max-width: 899px) {
  .office-summary { grid-template-columns: repeat(2,minmax(0,1fr)); }
  .office-summary-cell { border-bottom: 1px solid var(--line); }
  .office-summary-cell:nth-child(even) { border-right: 0; }
  .office-summary-cell:nth-last-child(-n+2) { border-bottom: 0; }
  :is(#tab-followups, .qp-fu-inner) .pt-item { grid-template-columns: 24px 18px minmax(0,1fr); }
  :is(#tab-followups, .qp-fu-inner) .pt-mark,:is(#tab-followups, .qp-fu-inner) .pt-when { grid-column: 3; }
  .set-group-heading { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  #tab-estimator .truck-bar-meter .bar-fill { transition: none; }
}

/* Office-wide rollout: every working surface uses the approved type, color
   and spacing. Embedded programs are themed here, never in their packages. */
:root { --amount-ink: #171717; }
.card, .quote-row, .wl-count { box-shadow: none; border-radius: 9px; }
.charge-trip, .charge-labor { background: var(--surface); border: 1px solid var(--line); border-radius: 6px; padding: 14px; }
.charge :is(.charge-label) { color: var(--muted); font-size: 12px; font-weight: 400; }
.charge :is(.charge-amount), .total-estimate .figure,
.crew-line .figure, .jp-price .figure, .window dd, .window.other .total-row dd { color: var(--amount-ink); }
.charge-amount { font-size: 26px; }
.total-estimate { background: var(--ground); border: 1px solid var(--line); border-left-width: 1px; border-radius: 6px; }
.qp-body, .job-page { gap: 16px; }
.job-page { max-width: none; }
.job-page > .card { padding: 16px; }
.qp-body .crew-line > strong { flex-basis: 100%; font-size: 20px; }
.qp-body .total-estimate .figure { font-size: 28px; }
.qp-body .charge-tiles { grid-template-columns: 1fr; gap: 0; border-block: 1px solid var(--line); }
.qp-body .charge { border: 0; border-radius: 0; padding: 12px 0; }
.qp-body .charge + .charge { border-top: 1px solid var(--line); }
.qp-body .charge-amount { font-size: 23px; }
.qp-body .crew-rate .figure, .qp-body .crew-hours .figure { font-size: 20px; }
.qp-body .qp-msg:empty { display: none; }
.qp-body .qp-truck { --scale-blue: var(--ok-mark); }
.qp-fu-top { grid-template-columns: minmax(150px,.7fr) minmax(0,2fr) minmax(140px,.7fr); gap: 0; align-items: stretch; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.qp-fu-top > * { padding: 15px 18px; border-right: 1px solid var(--line); }
.qp-fu-top > :last-child { border-right: 0; }
.qp-fu-ring { align-items: flex-start; justify-content: flex-start; gap: 9px; }
.qp-fu-ring .eyebrow { order: -1; }
.qp-fu-ring .health-segments { max-width: 180px; }
.qp-fu-next { align-content: start; gap: 8px; }
.qp-fu-next-line, .jp-size .qp-fu-next-line { font-size: 16px; line-height: 1.4; }
.qp-fu-tally { align-content: start; gap: 14px 24px; }
.qp-fu-tally dt, .jp-contact dt { font-weight: 400; }
.qp-fu-tally dd { font-size: 24px; color: var(--amount-ink); }
.qp-fu-next-line.is-overdue { color: var(--bad); }
.qp-fu-closed { padding: 12px 14px; background: var(--ground); border-radius: 6px; font-size: 14px; font-weight: 400; }
.qp-fu-replies { border-top: 1px solid var(--line); padding-top: 12px; }
.qp-fu-inner .pt-what, .qp-fu-inner .pt-mark { font-size: 14px; }
.qp-fu-inner .pt-when { font-size: 13px; }
.qp-fu-inner .pt-bar { height: 8px; margin-block: 18px; }
.qp-fu-inner .pt-stop { width: 30px; height: 30px; }
.qp-fu-inner .pt-stop .pt-ico { width: 15px; height: 15px; }
.quote-row { padding: 15px 16px; background: var(--surface); }
.quote-row:hover, .wl-row:hover { background: #fbfcff; }
.quote-title .quote-customer-name { font-size: 16px; font-weight: 600; }
.quote-title [data-number] { font-size: 13px; font-weight: 400; color: var(--muted); }
.quote-row .quote-summary { margin-block: 6px; }
.quote-actions, .wl-actions { flex: 0 1 auto; gap: 8px; }
.quote-filter-row { gap: 12px; }
.wl-count { padding: 14px; gap: 9px; }
.wl-count-label { order: -1; text-transform: uppercase; letter-spacing: .05em; font-size: 12px; }
.wl-count .figure { font-size: 26px; color: var(--amount-ink); }
.wl-count-bar { height: 7px; background: var(--line); }
.wl-count[data-count="pending"] .wl-count-bar > span { background: var(--pending); }
.wl-count[data-count="due"] .wl-count-bar > span { background: var(--due); }
.wl-section.card { padding: 16px; }
.wl-section h2 { font-size: 17px; margin: 0; }
.wl-line { font-weight: 400; }
.wl-guide { color: var(--muted); font-size: 13px; }
.wl-guide summary { cursor: pointer; color: var(--accent-ink); }
.wl-guide p { max-width: 105ch; line-height: 1.5; }
.messages-nav { padding: 5px; border: 1px solid var(--line); border-radius: 8px; background: var(--ground); align-self: flex-start; }
.messages-tab[aria-current="page"] { background: var(--surface); box-shadow: inset 0 0 0 1px var(--line-strong); color: var(--ink); }
.messages-picker { padding: 16px; }
.messages-results { gap: 0; border-block: 1px solid var(--line); }
.messages-results li { padding: 9px 0; border: 0; border-bottom: 1px solid var(--line); border-radius: 0; }
.messages-results li:last-child { border-bottom: 0; }
.messages-results li:hover { background: var(--accent-soft); }
.messages-picked { padding: 12px; background: var(--sunk); border-radius: 6px; font-size: 15px; }
#tab-messages .rep-console, #tab-inventory .ai-inventory, .move-ready-panel { --shadow: none; --glow: none; }
#tab-messages .rep-console .card, #tab-inventory .ai-inventory .card, .move-ready-panel .card { border-radius: 9px; box-shadow: none; }
#tab-messages .rep-console .button, #tab-inventory .ai-inventory .button { box-shadow: none; border-radius: 6px; }
#tab-messages .rep-console :is(h2,h3), #tab-inventory .ai-inventory :is(h2,h3) { font-weight: 600; letter-spacing: -.02em; }
#tab-messages .rep-console .field__label, #tab-inventory .ai-inventory .field__label { font-size: 13px; }
#tab-inventory .ai-inventory .totals { background: var(--surface); border: 1px solid var(--line); border-radius: 8px; }
#tab-settings .set-panel > .card { box-shadow: none; border-radius: 9px; }
#tab-settings .set-panel h2 { font-size: 18px; }
#tab-settings .set-panel h3 { font-size: 15px; }
#tab-settings :is(.pair-row,.hc-row,.labor-row,.special-row,.material-row) { row-gap: 8px; }
@media (min-width: 1200px) {
  .qp-body { display: grid; grid-template-columns: repeat(12,minmax(0,1fr)); align-items: start; }
  .qp-body > * { grid-column: 1 / -1; min-width: 0; }
  .qp-body > .qp-charges { grid-column: span 5; }
  .qp-body > .qp-time-card { grid-column: span 7; }
  .qp-body > .qp-customer { grid-column: span 8; }
  .qp-body > .qp-personal-card { grid-column: span 4; }
}
@media (max-width: 899px) {
  .qp-fu-top { grid-template-columns: 1fr; }
  .qp-fu-top > * { border-right: 0; border-bottom: 1px solid var(--line); }
  .qp-fu-top > :last-child { border-bottom: 0; }
}

.office-page-title { margin: 0 0 14px; font-size: 26px; letter-spacing: -.035em; font-weight: 600; }
.qp-guide { margin-top: 10px; font-size: 13px; color: var(--muted); }
.job-page .jp-status .chip { font-size: 14px; padding: 3px 9px; min-height: 28px; }
.job-page .jp-title > :first-child { font-size: 13px; color: var(--muted); font-weight: 400; }
.job-page .jp-name { font-size: 22px; }
.job-page .jp-contact { gap: 14px; }
.job-page .jp-status { margin-top: 16px; }
.wl-contacts .wl-count { display: grid; grid-template-columns: 1fr auto; align-items: center; padding: 10px 14px; }
.wl-contacts .wl-count-label { order: 0; grid-column: 1; grid-row: 1; }
.wl-contacts .wl-count .figure { grid-column: 2; grid-row: 1; font-size: 22px; }
.wl-contacts .wl-count-bar { grid-column: 1 / -1; margin-top: 0; height: 4px; }
#tab-inventory .ai-inventory { font-size: 14px; }
#tab-inventory .ai-inventory .lead { font-size: 14px; line-height: 1.5; margin-block: 8px; }
#tab-inventory .ai-inventory .hint { font-size: 13px; line-height: 1.5; }
#tab-inventory .ai-inventory .step { margin-block: 16px; padding: 16px; background: var(--surface); border: 1px solid var(--line); border-radius: 9px; }
#tab-inventory .ai-inventory .step__title { gap: 10px; font-size: 17px; margin-bottom: 10px; }
#tab-inventory .ai-inventory .step__number { width: 24px; height: 24px; font-size: 13px; background: var(--accent-soft); color: var(--accent-ink); }
#tab-inventory .ai-inventory .totals { box-shadow: none; }
#tab-inventory .ai-inventory .totals__inner { padding: 0; gap: 0; }
#tab-inventory .ai-inventory .tile { display: flex; flex-direction: column; gap: 9px; padding: 15px 18px; border-right: 1px solid var(--line); }
#tab-inventory .ai-inventory .tile:last-child { border-right: 0; }
#tab-inventory .ai-inventory .tile__label { order: -1; font-size: 12px; font-weight: 400; text-transform: uppercase; letter-spacing: .055em; }
#tab-inventory .ai-inventory .tile__value { font-size: 26px; font-weight: 700; color: var(--amount-ink); }
#tab-inventory .ai-inventory .drop { padding: 18px; background: var(--ground); }
#tab-inventory .ai-inventory .drop__text { font-size: 16px; font-weight: 600; }
#tab-inventory .ai-inventory .choice { font-size: 14px; font-weight: 400; min-height: 36px; }
#tab-inventory .ai-inventory .choice[aria-pressed="true"] { font-weight: 600; }
#tab-inventory .ai-inventory .pill { font-size: 13px; font-weight: 400; }
@media (min-width: 1200px) {
  .job-page { display: grid; grid-template-columns: repeat(12,minmax(0,1fr)); align-items: start; }
  .job-page > * { grid-column: 1 / -1; min-width: 0; }
  .job-page > .jp-head { grid-column: span 5; }
  .job-page > .jp-quote { grid-column: span 7; }
  .job-page .charge-amount { font-size: 23px; }
}

/* Forms in embedded Messages use q__label, rather than Office's field label. */
#tab-messages .rep-console .q__label,
#tab-messages .rep-console .caps > legend,
#tab-messages .rep-console fieldset.plain > legend { font-size: 13px; font-weight: 400; }
#tab-messages .rep-console .q__hint { font-size: 13px; }
#tab-messages .rep-console :is(.list__name,.quote__job,.kind__name) { font-weight: 600; }
#tab-messages .rep-console :is(.badge,.chip__note,.tokens__heading,.quote > legend) { font-size: 12px; }
#tab-settings .reorder-step { font-size: 12px; }
#tab-inventory .ai-inventory .totals { padding: 0; }
#tab-inventory .ai-inventory .step__number { box-shadow: none; }

/* Lead rotation (rotation.js, rotation-tab.js): Fresh Cobalt tokens only, no new colours. The strip is the shared .office-summary. */
.rot-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 10px 16px; }
.rot-head .office-page-title { margin-bottom: 0; }
.rot-view { min-width: 200px; max-width: 100%; }
.rot-view select { width: 100%; }
.rot-strip { margin: 12px 0 14px; }
.rot-clock-text { font-variant-numeric: tabular-nums; }
.rot-clock-text.is-low { color: var(--due); }
.rot-closed { margin: 0 0 14px; }
.rot-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; align-items: start; }
.rot-col { display: grid; gap: 14px; min-width: 0; }
@media (min-width: 1100px) {
  .rot-grid { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
}
.rot-card { display: grid; gap: 10px; }
.rot-card > * { margin: 0; }
.rot-title { margin: 0; font-size: 17px; font-weight: 600; display: flex; align-items: center; gap: 8px; }
.rot-sub { margin: 6px 0 0; font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.rot-lead-title { overflow-wrap: anywhere; font-size: var(--fs-base); }
.rot-with, .rot-must { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.rot-clock { display: inline-block; font-size: 20px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ink); background: var(--sunk); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 1px 8px; }
.rot-clock.is-low { color: var(--due); background: var(--due-soft); border-color: color-mix(in srgb, var(--due) 25%, transparent); }
.rot-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; }
.rot-pick { width: auto; max-width: 100%; min-width: 0; }
.rot-form { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) auto; gap: 10px 12px; align-items: end; }
.rot-form input { width: 100%; }
.rot-order, .rot-leads, .rot-decisions, .rot-crew { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.rot-row, .rot-lead, .rot-crew-row { display: grid; gap: 6px 10px; padding: 10px 0; border-top: 1px solid var(--line); min-width: 0; }
.rot-order > :first-child, .rot-leads > :first-child, .rot-crew > :first-child { border-top: 0; }
.rot-row { grid-template-columns: 28px minmax(0, 1fr) auto; align-items: center; }
.rot-row.is-next { background: var(--accent-soft); border-radius: var(--radius-sm); padding-left: 6px; padding-right: 6px; }
.rot-row > .rot-acts, .rot-row > .rot-reason { grid-column: 2 / -1; }
.rot-pos { display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: var(--radius-sm); background: var(--sunk); border: 1px solid var(--line); font-size: var(--fs-xs); font-weight: 600; font-variant-numeric: tabular-nums; }
.rot-name { font-weight: 600; overflow-wrap: anywhere; }
.rot-marks { display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; }
.rot-lead { grid-template-columns: minmax(0, 1fr); }
.rot-meta { color: var(--muted); font-size: var(--fs-xs); overflow-wrap: anywhere; }
.rot-decisions li { display: grid; grid-template-columns: 110px minmax(0, 1fr); gap: 4px 10px; padding: 8px 0; border-top: 1px solid var(--line); overflow-wrap: anywhere; font-size: var(--fs-sm); }
.rot-decisions li:first-child { border-top: 0; }
.rot-tally-wrap { overflow-x: auto; max-width: 100%; }
.rot-tally { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.rot-tally th, .rot-tally td { padding: 6px 8px; border-bottom: 1px solid var(--line); text-align: right; white-space: nowrap; }
.rot-tally th[scope="row"], .rot-tally thead tr:first-child th:first-child { text-align: left; white-space: normal; }
.rot-tally thead th { color: var(--muted); font-weight: 400; font-size: var(--fs-xs); }
.rot-tally th[scope="colgroup"] { text-align: center; }
.rot-reason { display: grid; gap: 8px; padding: 10px 12px; background: var(--sunk); border: 1px solid var(--line); border-radius: var(--radius-sm); }
.rot-reason input { width: 100%; }
.rot-error { margin: 0; }
.rot-copy { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px 10px; align-items: center; padding: 10px 12px; background: var(--ok-soft); border: 1px solid color-mix(in srgb, var(--ok) 25%, transparent); border-radius: var(--radius-sm); }
.rot-copy .summary-label { grid-column: 1 / -1; }
.rot-copy-line { font-size: var(--fs-sm); color: var(--ink); overflow-wrap: anywhere; white-space: normal; }
.rot-foot { display: flex; justify-content: flex-end; padding-top: 6px; border-top: 1px solid var(--line); }
.rot-settings { margin-top: 14px; }
.rot-crew-row { grid-template-columns: 28px minmax(0, 1fr) auto auto; align-items: center; }
.rot-crew-name { min-width: 0; overflow-wrap: anywhere; }
.rot-crew-name input { width: 100%; }
.rot-check { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-sm); }
.rot-fields { display: grid; gap: 6px; max-width: 420px; }
.rot-fields > * { margin: 0; }
.rot-minutes input { width: 8ch; }
.rot-confirm { display: grid; gap: 8px; }
.rot-confirm p { margin: 0; }
.rot-unreadable { display: grid; gap: 8px; }
.rot-unreadable textarea { width: 100%; }
@media (max-width: 639px) {
  .rot-form { grid-template-columns: minmax(0, 1fr); }
  .rot-row { grid-template-columns: 28px minmax(0, 1fr); }
  .rot-marks { grid-column: 2; justify-content: flex-start; }
  .rot-crew-row { grid-template-columns: 28px minmax(0, 1fr); }
  .rot-crew-row > .rot-check, .rot-crew-row > .rot-acts { grid-column: 2; }
  .rot-decisions li { grid-template-columns: minmax(0, 1fr); }
  .rot-view { min-width: 0; width: 100%; }
}
/* A lead You claimed: its quote's status chip, Start estimate and Open (or Make the quote), and the unsaved-job question. */
.rot-quote { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; min-width: 0; }
.rot-lead > .stale, .rot-quote-note { margin: 0; }

/* quote bar */
/* One quote bar on the Estimator, the Quote page and the job page (quote-bar.js): the who (name · number · status),
   always three buttons in the same order (Save quote · Mark sent · Open), and the Next step line under them. One
   primary (filled) button at a time. On the Quote page and the job page it sticks under the header; on the Estimator
   it heads the job panel (the jump tabs and the Price card stick there). */
.quote-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px 16px;
  background: #ffffff;
  border: 1px solid #dce4ef;
  border-radius: 9px;
  padding: 16px 24px;
  min-width: 0;
}
#tab-quote .quote-bar,
#tab-job .quote-bar {
  position: sticky;
  top: var(--header-h, 56px);
  z-index: 7;
  box-shadow: var(--shadow-2, 0 4px 12px rgb(16 24 40 / 0.08));
}
.qb-who {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 12px;
  min-width: 0;
}
.qb-name {
  margin: 0;
  font-size: 20px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.qb-num {
  font-size: 15px;
  color: var(--ink);
}
.qb-num.muted { color: #526174; }
.qb-actions {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: 8px;
}
.qb-slot {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
  min-width: 0;
}
.qb-btn { white-space: nowrap; }
.qb-again { align-self: center; font-size: 13px; }
.qb-next {
  grid-column: 1 / -1;
  margin: 0;
  font-size: 14px;
  color: var(--ink);
}
.qb-next strong { font-weight: 700; }
.qb-next.is-overdue,
.qb-next.is-overdue strong { color: var(--bad); }
/* The status chips: the same four words and colours everywhere. */
.chip.qb-chip { border-width: 1px; border-style: solid; }
.chip.st-notsent { color: #526174; border-color: #8593a8; background: #ffffff; }
.chip.st-waiting { color: #5263a8; border-color: color-mix(in srgb, #5263a8 30%, transparent); background: #edf0fc; }
.chip.st-booked { color: #167532; border-color: color-mix(in srgb, #167532 30%, transparent); background: #edf9ee; }
.chip.st-lost { color: #526174; border-color: color-mix(in srgb, #526174 25%, transparent); background: #f1f3f6; }
.chip.qb-chip-lg { font-size: 14px; padding: 3px 9px; min-height: 28px; }
/* The Estimator: the bar heads the job panel, flat inside it, a line under it. */
.job-bar > .job-qb { flex-basis: 100%; min-width: 0; }
.job-bar > .job-msg { order: 0; }
.job-qb .quote-bar {
  border: 0;
  border-radius: 0;
  padding: 0 0 12px;
  border-bottom: 1px solid #dce4ef;
  background: transparent;
}
.job-new-call { margin-left: auto; align-self: flex-end; }
/* The sent line on top of the Estimator (and above the job page's bar) after Mark sent. */
.qb-sent { margin: 0 0 12px; }
.qb-sent p { margin: 0; }
.qb-sent .link { font-weight: 600; }
/* The job page's top: the way back, the sent words, the bar, the Quote page link. */
#tab-job .jp-bar { display: block; }
#tab-job .jp-bar > * + * { margin-top: 8px; }
.jp-back-row, .jp-links { margin: 0; }
/* The top bar's New call: the one filled button up there. */
.quick-new {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 0 12px;
  white-space: nowrap;
}
.quick-new .nav-icon { color: inherit; }
@media (max-width: 700px) {
  .quote-bar { grid-template-columns: minmax(0, 1fr); padding: 12px 16px; }
  .qb-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .qb-btn { width: 100%; white-space: normal; min-height: 44px; }
  .job-qb .quote-bar { padding: 0 0 12px; }
}
/* At phone width the quick bar keeps New call, the flip, Work log, the bell and the gear on one line with no sideways scroll. */
@media (max-width: 420px) {
  .quick { gap: 4px; }
  .quick-new { padding: 0 10px; }
}

/* next step
 * The Next step card, its follow-up protocol and the message chips (quote-bar.js nextStepCardHtml, protocolHtml,
 * messageChipHtml): the same card right under the quote bar on the job page and the Quote page, and on each
 * Follow-ups row beside who it is. Fresh Cobalt, light only; spacing 8/16/24; one primary button per card. */
.ns-place { display: grid; gap: 16px; min-width: 0; }
.ns-card { display: grid; gap: 8px; min-width: 0; background: var(--surface); border: 1px solid var(--line); border-radius: 9px; padding: 16px 24px; box-shadow: inset 4px 0 0 var(--accent); }
.ns-card.is-due { box-shadow: inset 4px 0 0 #a64008; }
.ns-card.is-overdue { box-shadow: inset 4px 0 0 #c62828; }
.ns-card.is-closed { box-shadow: inset 4px 0 0 #526174; }
.ns-card[data-status="notSent"] { box-shadow: inset 4px 0 0 #8593a8; }
.ns-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }
.ns-title { margin: 0; font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.ns-line { margin: 0; font-size: 20px; font-weight: 600; line-height: 1.3; color: var(--ink); overflow-wrap: anywhere; }
.ns-meta { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; font-size: 14px; color: var(--muted); }
.ns-life { display: inline-flex; align-items: center; gap: 8px; }
.ns-card .fu-ring, .ns-card .fu-ring .ring { width: 44px; height: 44px; }
.ns-card .fu-pct { font-size: 11px; }
.ns-dot { color: var(--line-strong); }
.ns-buttons { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.ns-buttons .btn { min-height: 36px; }
.ns-links { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; font-size: 13px; }
.ns-card > .log-form, .ns-card > .stale, .ns-card > .fu-reply, .ns-card > .qp-plan, .ns-card > p.bad-text, .ns-card > p.ok-text { margin-top: 8px; }
.ns-protocol { display: grid; gap: 8px; min-width: 0; }
.ns-place > .ns-protocol, .ns-place > .qp-fu-more { background: var(--surface); border: 1px solid var(--line); border-radius: 9px; padding: 16px 24px; }
.ns-protocol-title { margin: 0; font-size: 17px; font-weight: 600; }
.ns-protocol-note { margin: 0; color: var(--muted); font-size: 14px; }
.ns-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.ns-step { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; padding: 8px 12px; border-radius: 6px; font-size: 14px; min-width: 0; }
.ns-step + .ns-step { border-top: 1px solid var(--line); border-radius: 0; }
.ns-step.is-next { background: #eff8fc; border-radius: 6px; }
.ns-num { flex: none; display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; background: var(--accent-soft); color: var(--accent-ink); font-size: 13px; font-weight: 600; }
.ns-mark { flex: none; width: 14px; text-align: center; font-weight: 700; color: var(--accent); }
.ns-step.is-done .ns-mark { color: #167532; }
.ns-step.is-due .ns-mark { color: #a64008; }
.ns-step.is-overdue .ns-mark { color: #c62828; }
.ns-what { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; color: var(--ink); min-width: 0; overflow-wrap: anywhere; }
.ns-what .pt-ico { color: var(--muted); }
.ns-state .ns-word { color: var(--ink); }
.ns-step.is-done .ns-state .ns-word { color: #167532; font-weight: 600; }
.ns-when { color: var(--muted); }
.ns-next-tag { font-weight: 600; color: var(--accent-ink); }
.ns-answer { flex-basis: 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-left: 50px; }
.ns-step.is-skipped, .ns-step.is-passed, .ns-step.is-dropped, .ns-step.is-unreached { color: #5f6b7c; }
.ns-step.is-skipped .ns-what, .ns-step.is-passed .ns-what, .ns-step.is-dropped .ns-what, .ns-step.is-unreached .ns-what,
.ns-step.is-skipped .ns-word, .ns-step.is-passed .ns-word, .ns-step.is-dropped .ns-word, .ns-step.is-unreached .ns-word { color: #5f6b7c; font-weight: 400; }
.ns-fold { border-top: 1px solid var(--line); padding-top: 8px; min-width: 0; }
.ns-fold-summary, .qp-fu-more-summary { cursor: pointer; font-size: 14px; font-weight: 600; color: var(--accent-ink); padding: 4px 0; }
.ns-fold[open] > .ns-protocol { margin-top: 8px; }
.qp-fu-more { display: grid; gap: 16px; min-width: 0; }
.qp-fu-more[open] > .qp-fu-top { margin-top: 8px; }
/* The message chips: icon + words, never colour alone. */
.chip.msg-chip { gap: 4px; border-width: 1px; border-style: solid; }
.chip.msg-chip .mc-ico { flex: none; }
.chip.mc-draft { color: #526174; background: #ffffff; border: 1px dashed #8593a8; }
.chip.mc-sent { color: #167532; background: #edf9ee; border-color: color-mix(in srgb, #167532 30%, transparent); }
.chip.mc-due { color: #a64008; background: #fff1e6; border-color: color-mix(in srgb, #a64008 30%, transparent); }
.chip.mc-overdue { color: #c62828; background: #fff0f0; border-color: color-mix(in srgb, #c62828 30%, transparent); }
.chip.mc-soon { color: #5263a8; background: #edf0fc; border-color: color-mix(in srgb, #5263a8 30%, transparent); }
#tab-messages .recent__side .msg-chip { font-size: 13px; }
/* A Follow-ups row: who and its chip on the left, the card on the right (stacked under 1100px). */
.fu-row { grid-template-columns: minmax(0, 1fr); gap: 16px; }
.fu-row .fu-who { align-content: start; gap: 8px; }
.fu-who-chip { margin: 0; }
.fu-facts { margin: 0; }
.fu-open { margin: 0; display: flex; flex-wrap: wrap; gap: 4px 8px; font-size: 13px; }
.fu-main { min-width: 0; display: grid; gap: 8px; }
.fu-row .ns-card { box-shadow: none; border: 0; padding: 0; }
.fu-row .fu-ring, .fu-row .fu-ring .ring { width: 44px; height: 44px; }
.fu-row .fu-pct { font-size: 11px; }
@media (min-width: 1100px) {
  .fu-row { grid-template-columns: minmax(220px, 280px) minmax(0, 1fr); gap: 24px; }
}
@media (max-width: 520px) {
  .ns-card, .ns-place > .ns-protocol, .ns-place > .qp-fu-more { padding: 16px; }
  .ns-line { font-size: 18px; }
  .ns-answer { padding-left: 0; }
}

/* demo path (2026-09-29 overhaul): reads like a CRM. The demo tabs' column at most 1280px, centered; 24px between
   the Dashboard's parts; the key numbers large (28px/700) with a small ring or bar and their definitions folded away;
   the funnel of the period's saved quotes; the quote rows with the customer's name strongest and the Next step line,
   as cards on a phone. Fresh Cobalt colours only (design/SYSTEM.md). */
:is(#tab-dashboard, #tab-rotation, #tab-estimator, #tab-quote, #tab-quotes, #tab-job, #tab-followups, #tab-inventory) {
  max-width: 1280px;
  margin-inline: auto;
}

.dash,
.dash-work {
  gap: 24px;
}

.dash-key {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
  margin-bottom: 16px;
}

@container (min-width: 330px) {
  .dash-key {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@container (min-width: 760px) {
  .dash-key {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.dash-key-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.dash .dash-key-label {
  margin: 0;
  padding-right: 24px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--muted);
}

.dash-key-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-width: 0;
}

.dash-key-fig {
  font-size: 28px;
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.dash-key-words {
  margin: 0;
  font-size: 13px;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.dash-key-ring {
  display: inline-flex;
  flex: none;
}

.dash-key-chart {
  display: block;
  flex: 0 1 96px;
  min-width: 48px;
  color: #2457c5;
}

.dash-key-chart svg {
  display: block;
  width: 100%;
  height: 34px;
}

.dash-key-bar {
  display: block;
  flex: 0 1 96px;
  height: 8px;
  overflow: hidden;
  background: var(--sunk);
  border-radius: 4px;
}

.dash-key-bar > span {
  display: block;
  height: 100%;
  background: #d65a0a;
}

.dash-key-tile .dash-more {
  margin: auto 0 0;
  font-size: 14px;
}

.dash-funnel {
  margin-bottom: 16px;
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.dash-funnel-steps {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}

@container (min-width: 560px) {
  .dash-funnel-steps {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px 32px;
  }

  .dash-funnel-step + .dash-funnel-step::before {
    content: "→";
    position: absolute;
    left: -22px;
    top: 0;
    color: var(--muted);
  }
}

.dash-funnel-step {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 4px 8px;
  min-width: 0;
}

.dash-funnel-words {
  font-size: 14px;
  color: var(--ink);
}

.dash-funnel-n {
  font-size: 22px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.dash-funnel-bar {
  grid-column: 1 / -1;
  height: 8px;
  overflow: hidden;
  background: var(--sunk);
  border-radius: 4px;
}

.dash-funnel-bar > span {
  display: block;
  height: 100%;
  min-width: 0;
}

.dash-funnel-step.is-notSent .dash-funnel-bar > span {
  background: #8593a8;
}

.dash-funnel-step.is-waiting .dash-funnel-bar > span {
  background: #5263a8;
}

.dash-funnel-step.is-booked .dash-funnel-bar > span {
  background: #167532;
}

.dash-funnel-lost {
  margin: 8px 0 0;
  font-size: 13px;
  color: var(--muted);
}

/* The three cards the key numbers don't already say, in one row when there is room. */
@container (min-width: 600px) {
  .dash-metrics {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@container (min-width: 1120px) {
  .dash-metrics {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* Quotes: the customer's name strongest, the chip beside it; the number, phone and move date under it; the Next step line. */
.quote-title .quote-customer-name {
  font-size: 17px;
  font-weight: 600;
  color: var(--ink);
}

.quote-meta {
  margin-top: 2px !important;
  font-size: 13px;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.quote-meta strong {
  font-weight: 600;
  color: var(--ink);
}

.quote-next .qb-next {
  margin: 4px 0 0;
  font-size: 14px;
}

@media (max-width: 600px) {
  .quote-list:has(> .quote-row) {
    background: none;
    border: 0;
    box-shadow: none;
  }

  .quote-list > .quote-row {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
  }

  .quote-list > .quote-row + .quote-row {
    margin-top: 8px;
  }

  .quote-actions {
    width: 100%;
  }
}

/* Truestimo, the mascot (mascot.js): beside an empty or all-caught-up state, in the Dashboard greeting, and the quick
   "Booked!" moment. Decorative art next to words that say the same; never beside prices or money. */
.mascot-note {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.mascot-note .mascot {
  flex: none;
  width: auto;
}

.mascot-note-words > :first-child {
  margin-top: 0;
}

.mascot-note-words > :last-child {
  margin-bottom: 0;
}

@media (max-width: 480px) {
  .mascot-note .mascot {
    height: 72px;
  }
}

.dash-greet {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.dash-greet-mascot {
  flex: none;
  width: 36px;
  height: 36px;
}

.mascot-cheer {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4) var(--sp-2) var(--sp-2);
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: 0 8px 24px rgb(24 59 120 / 0.18);
  animation: mascot-cheer 2.2s ease-out both;
  pointer-events: none;
}

.mascot-cheer .mascot {
  width: auto;
  height: 88px;
}

.mascot-cheer-words {
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--ok);
}

@keyframes mascot-cheer {
  0% { opacity: 0; transform: translateY(16px); }
  12% { opacity: 1; transform: translateY(0); }
  85% { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(8px); }
}

@media (prefers-reduced-motion: reduce) {
  .mascot-cheer {
    animation: none;
  }
}

/* The AI inventory Sample's results: Truestimo holding his tablet beside the done line. */
#tab-inventory .sample__mascot {
  display: block;
  width: auto;
  height: 96px;
  margin: var(--sp-2) 0 0 auto;
}
