/* BuildUpQuote shared UI helpers -- plain CSS (Tailwind CDN doesn't run @apply) */
/* "Graphite and Signal": every colour below is a design token from tokens.css,
   never a raw hex, so the light/dark, colour-blind and dyslexia settings reach
   these house classes too. A token flips with the theme on its own, which is
   why the old `.dark .bq-*` overrides are gone -- except `.dark .bq-input`,
   which tests/test_design_system.py pins as the rule the cockpit block below
   has to follow. */

.bq-card {
  background: rgb(var(--surface));
  border: 1px solid rgb(var(--line));
  border-radius: var(--r-card);
}

/* The eyebrow over a page or card title ("Insurance quote · editing", Task
   96a): small, gold and upper-case. The CASE lives here, never in the text a
   person reads (AGENTS.md rule 11), and the colour stays a token in the
   template's own class list. */
.bq-eyebrow {
  text-transform: uppercase;
  letter-spacing: .08em;
}

/* Touch targets (clinerules section 3): contractors tap these outdoors with
   gloved hands, so every control clears 44px. min-height wins over a utility
   height in a template's class list, which is the point -- a control cannot
   quietly shrink below the minimum. */
.bq-input {
  width: 100%;
  min-height: 44px;
  border: 1px solid rgb(var(--input));
  border-radius: var(--r-input);
  padding: .5rem .75rem;
  font-size: .875rem;
  color: rgb(var(--ink));
  background: rgb(var(--surface));
  transition: border-color .15s ease, box-shadow .15s ease;
}
/* Focus: 2px of accent with a 2px offset, the ring .clinerules section 1 asks
   for. The offset is the page colour, so it reads on both themes. */
.bq-input:focus { outline: none; border-color: rgb(var(--accent)); box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }
/* Kept as the ordering anchor tests/test_design_system.py::DarkCockpitContrastTests
   names: the cockpit block below must come after it. The tokens flip by
   themselves now, so this rule no longer changes what the box looks like. */
.dark .bq-input { border-color: rgb(var(--input)); background: rgb(var(--surface)); color: rgb(var(--ink)); }
/* A box the server refused (Task 95): a red edge, and a red ring when it takes
   focus so the one thing the contractor has to fix cannot hide behind the focus
   state. Marked with aria-invalid, so the markup says the same thing to a screen
   reader as the red edge says to the eye. */
.bq-input[aria-invalid="true"] { border-color: rgb(var(--danger)); }
.bq-input[aria-invalid="true"]:focus {
  border-color: rgb(var(--danger));
  box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--danger));
}

/* Primary: a flat accent fill with the accent edge as its border and always-dark
   ink on top. The old amber-to-orange gradient, the white text and the lift on
   hover are gone with the re-skin (mapping steps 3 and 8): one signal colour and
   no shadow -- a border carries the button. Hover LIGHTENS it (Task W2-3 step 7,
   Glenn's button standard): a filled button darkening its own ink when a pointer
   arrives read as "pressed", and the gold went brown. */
/* Button standard (Task 60 item 8, Glenn's approved mockup). One rule set for
   every button in Clavoz, so the gold action, the steel action and a quiet
   secondary all behave the same way:
     - the shadow is the button's OWN border colour (a 2px edge, never a grey
       drop shadow that floats over the card);
     - a STRONG button (gold, steel) lightens slightly on hover; a LIGHT one
       darkens slightly. A strong fill has nowhere to go but up;
     - pressing shrinks it to 0.96 and takes the edge shadow away, so the button
       reads as going into the surface;
     - an "on" button (aria-pressed="true") is PUSHED IN: no edge shadow, an
       inner shadow instead. Icon buttons in the crossed-out list and the
       switches use the same three states;
     - buttons are never joined into groups (no segmented controls, no
       first/middle/last border surgery): every button keeps its own edge. */
.bq-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .25rem;
  min-height: 44px;
  border-radius: var(--r-btn);
  border: 1px solid rgb(var(--accent-edge));
  background: rgb(var(--accent));
  color: rgb(var(--on-accent));
  padding: .5rem .75rem;
  font-size: .875rem;
  font-weight: 500;
  box-shadow: 0 2px 0 rgb(var(--accent-edge));
  transition: filter .15s ease, box-shadow .1s ease, transform .08s ease;
}
.bq-btn:hover { filter: brightness(1.08); }
.bq-btn:active { transform: scale(.96); box-shadow: 0 0 0 rgb(var(--accent-edge)); }
.bq-btn[aria-pressed="true"] { box-shadow: inset 0 2px 4px rgb(var(--accent-edge) / .55); }
.bq-btn:disabled { opacity: .5; cursor: not-allowed; filter: none; box-shadow: 0 2px 0 rgb(var(--accent-edge)); transform: none; }

/* Secondary: the surface with a steel edge and steel text, so the second brand
   colour marks every action that is not the primary one; hover mixes about 10%
   of that steel into the surface, never accent text on a light background. */
.bq-btn-secondary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .25rem;
  min-height: 44px;
  border-radius: var(--r-btn);
  border: 1px solid rgb(var(--brand2) / .4);
  background: rgb(var(--surface));
  color: rgb(var(--brand2-text));
  padding: .5rem .75rem;
  font-size: .875rem;
  font-weight: 500;
  box-shadow: 0 2px 0 rgb(var(--brand2) / .4);
  transition: background .15s ease, border-color .15s ease, color .15s ease, box-shadow .1s ease, transform .08s ease;
}
/* A light button is already near the top of its range, so hover takes it DOWN a
   touch, towards steel and never towards the accent, which would make it flash
   like the call to action. Its own steel edge, steel text and steel edge shadow
   stay -- they are what make it the second action, so no border-color, no color
   and no filter here. */
.bq-btn-secondary:hover { background: color-mix(in srgb, rgb(var(--surface)) 90%, rgb(var(--brand2)) 10%); }
.bq-btn-secondary:active { transform: scale(.96); box-shadow: 0 0 0 rgb(var(--brand2) / .4); }
.bq-btn-secondary[aria-pressed="true"] { box-shadow: inset 0 2px 4px rgb(var(--brand2) / .45); }

/* The steel strong button. Steel carries structure, never the main action, so
   this is for the second strong action on a screen (Task 60's "put back",
   "ask the adjuster" and the sheet's secondary commits). Same three states as
   .bq-btn, in the same order. */
.bq-btn-strong {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  min-height: 44px;
  border-radius: var(--r-btn);
  border: 1px solid rgb(var(--brand2));
  background: rgb(var(--brand2));
  color: rgb(var(--on-brand2));
  padding: .5rem .75rem;
  font-size: .875rem;
  font-weight: 500;
  box-shadow: 0 2px 0 rgb(var(--brand2-raised));
  transition: filter .15s ease, box-shadow .1s ease, transform .08s ease;
}
.bq-btn-strong:hover { filter: brightness(1.12); }
.bq-btn-strong:active { transform: scale(.96); box-shadow: 0 0 0 rgb(var(--brand2-raised)); }
.bq-btn-strong[aria-pressed="true"] { box-shadow: inset 0 2px 4px rgb(0 0 0 / .35); }
.bq-btn-strong:disabled { opacity: .5; cursor: not-allowed; filter: none; }

/* The danger strong button: the same three states as .bq-btn-strong, in the
   danger colour, for the destructive commit in a sheet ("Delete line"). The
   confirm is still an explicit word, never colour alone. */
.bq-btn-danger {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  min-height: 44px;
  border-radius: var(--r-btn);
  border: 1px solid rgb(var(--danger));
  background: rgb(var(--danger));
  color: rgb(var(--surface));
  padding: .5rem .75rem;
  font-size: .875rem;
  font-weight: 500;
  box-shadow: 0 2px 0 rgb(var(--danger));
  transition: filter .15s ease, box-shadow .1s ease, transform .08s ease;
}
.bq-btn-danger:hover { filter: brightness(1.08); }
.bq-btn-danger:active { transform: scale(.96); box-shadow: 0 0 0 rgb(var(--danger)); }
.bq-btn-danger[aria-pressed="true"] { box-shadow: inset 0 2px 4px rgb(0 0 0 / .35); }
.bq-btn-danger:disabled { opacity: .5; cursor: not-allowed; filter: none; }

/* A square icon button: 44x44, its own edge, and the same pressed-in state, for
   the three separate icon actions on a crossed-out line (see the PDF, put it
   back, ask the adjuster). Never joined into a group -- each one is its own
   button with its own gap. */
.bq-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: var(--r-btn);
  border: 1px solid rgb(var(--input));
  background: rgb(var(--surface));
  color: rgb(var(--brand2-text));
  box-shadow: 0 2px 0 rgb(var(--input));
  transition: background .15s ease, box-shadow .1s ease, transform .08s ease, color .15s ease;
}
.bq-icon-btn:hover { background: rgb(var(--mist)); }
.bq-icon-btn:active { transform: scale(.96); box-shadow: 0 0 0 rgb(var(--input)); }
/* A disabled icon button has to look disabled (Task W2-14 item 3): Record is off
   where the deployment cannot transcribe, and an icon that still presses would
   promise a recording that will not happen. */
.bq-icon-btn:disabled,
.bq-icon-btn:disabled:hover,
.bq-icon-btn:disabled:active {
  opacity: .5;
  cursor: not-allowed;
  transform: none;
  background: rgb(var(--surface));
  box-shadow: 0 2px 0 rgb(var(--input));
}
.bq-icon-btn[aria-pressed="true"] {
  border-color: rgb(var(--brand2));
  background: rgb(var(--brand2));
  color: rgb(var(--on-brand2));
  box-shadow: inset 0 2px 4px rgb(0 0 0 / .35);
}

/* A flat button: the box is the row, the card or the sheet it sits in, so it
   carries no edge or fill of its own -- a More menu item, a collapsible card
   header, a table row action, a stepper. It still presses like every other
   button (scale to 0.96) and still shows the pushed-in state when it is on, so
   the same gesture means the same thing everywhere; that is the whole point of
   one button standard. */
.bq-btn-flat {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  background: none;
  border: 0;
  box-shadow: none;
  cursor: pointer;
  transition: background .15s ease, color .15s ease, transform .08s ease, box-shadow .1s ease;
}
.bq-btn-flat:active { transform: scale(.96); }
.bq-btn-flat[aria-pressed="true"] { box-shadow: inset 0 2px 4px rgb(var(--input) / .45); }
.bq-btn-flat:disabled { opacity: .5; cursor: not-allowed; }

/* A plain link with a 44px hit area: the "also download" actions and the
   Delete-line link. Steel plus an underline (accent is a fill and a line, never
   text on a light background), and `.bq-link.danger` for the destructive one --
   which still needs a real confirm, not a colour. */
.bq-link {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  min-height: 44px;
  padding: 0 .25rem;
  background: none;
  border: 0;
  color: rgb(var(--brand2-text));
  font-size: .875rem;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.bq-link:hover { text-decoration-thickness: 2px; }
.bq-link.danger { color: rgb(var(--danger)); }

/* A switch: the on/off controls on the work table ("show my cost and margin",
   "show the crossed-out lines"). The input is the control (so the keyboard and
   a screen reader drive it) dressed as a track with a knob; the label beside it
   carries the words. 44px tall like everything else. */
.bq-switch {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  min-height: 44px;
  font-size: .875rem;
  color: rgb(var(--body));
  cursor: pointer;
}
.bq-switch input {
  appearance: none;
  width: 40px;
  height: 24px;
  flex: none;
  border-radius: 9999px;
  border: 1px solid rgb(var(--edge));
  background: rgb(var(--edge));
  position: relative;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease;
}
.bq-switch input::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  border-radius: 9999px;
  background: rgb(var(--surface));
  box-shadow: 0 1px 2px rgb(var(--ink) / .35);
  transition: transform .15s ease;
}
.bq-switch input:checked { background: rgb(var(--brand2)); border-color: rgb(var(--brand2)); }
.bq-switch input:checked::after { transform: translateX(16px); background: rgb(var(--surface)); }
.bq-switch input:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }

/* ---- Job photos (Task 136) ------------------------------------------------
   The Photos card on a job, on the quote page, in Your work, and the "Which
   job?" sheet. Three columns of square tiles on a phone and six from md: up
   (Task 136 item 7b), chips 44 px tall for a gloved thumb, and one gold outline
   only where the design system allows it. Pictures are the server's 600 px
   WebP cards; nothing here builds an image path of its own. */
.bq-photos-take {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  width: 100%;
  min-height: 56px;
  margin-top: .75rem;
  border: 1px solid rgb(var(--edge));
  border-radius: var(--r-btn);
  background: rgb(var(--surface));
  color: rgb(var(--brand2-text));
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}
.bq-photos-take:hover { background: rgb(var(--mist) / .6); }
.bq-photos-take:active { transform: scale(.98); }
.bq-photos-take:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }

/* Drag and drop onto the card (Task 136 item 7b). A desk has a pointer and no
   camera, so the hint is hidden below md and the whole card answers a drag with
   a gold dashed outline -- a token, never a hex, so it survives all four looks. */
.bq-photos-drop-hint {
  display: none;
  margin-top: .5rem;
  font-size: 12px;
  font-weight: 600;
  color: rgb(var(--muted));
}
@media (min-width: 768px) {
  .bq-photos-drop-hint { display: block; }
}
.bq-qb-section.is-dropping {
  outline: 2px dashed rgb(var(--accent));
  outline-offset: 2px;
  background: rgb(var(--accent) / .06);
}

.bq-photos-tag { margin-top: .75rem; }
.bq-photos-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.bq-photo-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid rgb(var(--edge));
  border-radius: 9999px;
  background: rgb(var(--surface));
  color: rgb(var(--ink));
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}
.bq-photo-chip:hover { background: rgb(var(--mist) / .6); }
.bq-photo-chip:active { transform: scale(.97); }
.bq-photo-chip[aria-pressed="true"],
.bq-photo-chip.is-on {
  background: rgb(var(--accent) / .18);
  border-color: rgb(var(--accent-edge));
  color: rgb(var(--ink));
}
.bq-photo-chip--quiet { color: rgb(var(--muted)); }
.bq-photo-chip:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }

.bq-photos-uploads { margin-top: .75rem; display: grid; gap: 8px; }
.bq-photos-upload { display: flex; align-items: flex-start; gap: 8px; }
.bq-photos-bar {
  display: block;
  height: 4px;
  margin-top: 4px;
  border-radius: 9999px;
  background: rgb(var(--edge));
  overflow: hidden;
}
.bq-photos-bar-fill { display: block; height: 100%; background: rgb(var(--brand2)); transition: width .2s ease; }

.bq-photo-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}
@media (min-width: 768px) {
  .bq-photo-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}
.bq-photo-tile {
  position: relative;
  display: block;
  aspect-ratio: 1 / 1;
  width: 100%;
  overflow: hidden;
  border: 1px solid rgb(var(--line));
  border-radius: 8px;
  background: rgb(var(--mist));
  padding: 0;
  cursor: pointer;
}
.bq-photo-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.bq-photo-tile:active { transform: scale(.98); }
.bq-photo-tile:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }
.bq-photo-tag {
  position: absolute;
  left: 6px;
  bottom: 6px;
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 8px;
  border-radius: 9999px;
  background: rgb(var(--ink) / .78);
  color: rgb(var(--page));
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .02em;
}
.bq-photo-cover {
  position: absolute;
  top: 6px;
  left: 6px;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  height: 20px;
  padding: 0 8px;
  border-radius: 9999px;
  background: rgb(var(--accent));
  color: rgb(var(--on-accent));
  font-size: 10px;
  font-weight: 700;
}

.bq-photos-proposal { margin-top: 1rem; padding-top: .75rem; border-top: 1px solid rgb(var(--line)); }

/* The card's two homes and its one row of controls (Task 136c item 1).
   On a phone the card stays in the job-details rows, exactly where it was, and
   the control, the drag hint and the chips stack as they always have. From md:
   up the page's own script moves the card into #bq-photos-slot -- under the work
   it belongs to, in the main column's width -- so it is a card of its own there
   (surface, line, 8 px radius, like every other card) and its three controls
   share one row where they fit. #bq-photos-slot is an ordinary block, so the
   moved card still takes a block's place in the column's gaps; empty (no quote
   yet, or the section hidden) it takes no room at all. */
#bq-photos-slot:empty { display: none; }
#bq-photos-slot > .bq-qb-section {
  overflow: hidden;
  background: rgb(var(--surface));
  border: 1px solid rgb(var(--line));
  border-radius: var(--r-card);
}
.bq-photos-actions { display: flex; flex-direction: column; }
.bq-photos-actions .bq-photos-chips { margin-top: .75rem; }
@media (min-width: 768px) {
  .bq-photos-actions { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: .75rem; }
  .bq-photos-actions > * { margin-top: 0; }
  .bq-photos-actions > .bq-photos-take { width: auto; flex: none; padding: 0 20px; }
}

/* The one photo, opened: a sheet over the page. Escape, the X and a tap on the
   backdrop all close it (clinerules section 5). */
.bq-photo-sheet-backdrop {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgb(var(--ink) / .55);
  padding: 16px;
}
@media (min-width: 768px) {
  .bq-photo-sheet-backdrop { align-items: center; }
}
.bq-photo-sheet {
  width: 100%;
  max-width: 480px;
  max-height: 88vh;
  overflow-y: auto;
  padding: 16px;
  border-radius: 12px;
  background: rgb(var(--surface));
  border: 1px solid rgb(var(--line));
  box-shadow: 0 18px 48px rgb(var(--ink) / .35);
}
.bq-photo-sheet-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.bq-photo-sheet-image {
  width: 100%;
  max-height: 46vh;
  margin-top: .75rem;
  object-fit: contain;
  border-radius: 8px;
  background: rgb(var(--mist));
}

/* "Which job?" (Task 136 item 5). The same bottom sheet on a phone and a
   centred panel on a desk, above the More panel's own layers so it is never
   hidden behind one. */
.bq-job-sheet {
  position: fixed;
  z-index: 62;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  width: 100%;
  max-width: 420px;
  max-height: 82vh;
  overflow-y: auto;
  padding: 16px;
  padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  border-radius: var(--r-card) var(--r-card) 0 0;
  background: rgb(var(--surface));
  border: 1px solid rgb(var(--line));
  box-shadow: 0 -8px 24px -12px rgb(0 0 0 / .4);
}
@media (min-width: 768px) {
  .bq-job-sheet {
    bottom: auto;
    top: 50%;
    transform: translate(-50%, -50%);
    border-radius: var(--r-card);
    box-shadow: 0 18px 48px rgb(var(--ink) / .35);
  }
}
.bq-job-choice {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 56px;
  padding: 6px 12px;
  border: 1px solid rgb(var(--line));
  border-radius: 8px;
  background: rgb(var(--surface));
  color: rgb(var(--ink));
  cursor: pointer;
}
.bq-job-choice:hover { background: rgb(var(--mist) / .6); }
.bq-job-choice:active { transform: scale(.99); }
.bq-job-choice:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }


   3). `contain` stops the browser's own overscroll gesture -- Chrome on Android
   pulls to refresh, iOS rubber-bands the page -- from turning into a reload
   that would throw away a half-typed quote. The class rides on the app shell's
   <body> (app/templates/base.html); the pages that are NOT the app shell
   (public_base.html) do not carry it. */
.bq-app { overscroll-behavior-y: contain; }

/* A chip: a small pill for a fact beside a line (a likelihood word, a trade, a
   count). Status badges keep their own .badge + token pairs; a chip is never a
   status. */
.bq-chip {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  height: 22px;
  border-radius: var(--r-chip);
  background: rgb(var(--mist));
  color: rgb(var(--brand2-text));
  padding: 0 .5rem;
  font-size: var(--fs-label);
  font-weight: 700;
  white-space: nowrap;
}
.bq-chip.likely { background: rgb(var(--money-tint)); color: rgb(var(--money-ink)); }
.bq-chip.check { background: rgb(var(--accent) / .18); color: rgb(var(--ink)); }
/* The code or law a suggestion rests on (Task 119 item 4): gold, a FILL with
   ink on it -- yellow is never text (clinerules section 1 rule 1). A long
   reference wraps to a second line inside its own chip rather than being cut
   off with an ellipsis (Task 119c item 5). */
.bq-chip.code { background: rgb(var(--accent)); color: rgb(var(--on-accent)); }
.bq-pz-item-head .bq-chip.code { height: auto; min-height: 24px; padding-top: 2px; padding-bottom: 2px; white-space: normal; overflow-wrap: anywhere; text-align: left; }
/* A trade chip in its trade's colour (Task 119 item 4; the hues are tokens in
   tokens.css). The slug is the first word of the trade, lower case, which is
   what BQParser.tradeSlug / the builder's chip write into data-trade. */
.bq-chip[data-trade="roofing"] { background: rgb(var(--trade-clay)); color: rgb(var(--trade-clay-ink)); }
.bq-chip[data-trade="siding"] { background: rgb(var(--trade-teal)); color: rgb(var(--trade-teal-ink)); }
.bq-chip[data-trade="gutters"] { background: rgb(var(--trade-blue)); color: rgb(var(--trade-blue-ink)); }
.bq-chip[data-trade="fascia"] { background: rgb(var(--trade-teal)); color: rgb(var(--trade-teal-ink)); }
.bq-chip[data-trade="masonry"] { background: rgb(var(--trade-stone)); color: rgb(var(--trade-stone-ink)); }
.bq-chip[data-trade="windows"] { background: rgb(var(--trade-sky)); color: rgb(var(--trade-sky-ink)); }
.bq-chip[data-trade="carpentry"] { background: rgb(var(--trade-wood)); color: rgb(var(--trade-wood-ink)); }
.bq-chip[data-trade="painting"] { background: rgb(var(--trade-violet)); color: rgb(var(--trade-violet-ink)); }
.bq-chip[data-trade="drywall"] { background: rgb(var(--trade-lilac)); color: rgb(var(--trade-lilac-ink)); }
.bq-chip[data-trade="flooring"] { background: rgb(var(--trade-wood)); color: rgb(var(--trade-wood-ink)); }
.bq-chip[data-trade="insulation"] { background: rgb(var(--trade-rose)); color: rgb(var(--trade-rose-ink)); }
.bq-chip[data-trade="electrical"] { background: rgb(var(--pill-amber)); color: rgb(var(--pill-amber-ink)); }
.bq-chip[data-trade="plumbing"] { background: rgb(var(--trade-blue)); color: rgb(var(--trade-blue-ink)); }
.bq-chip[data-trade="hvac"] { background: rgb(var(--trade-cyan)); color: rgb(var(--trade-cyan-ink)); }
.bq-chip[data-trade="fencing"] { background: rgb(var(--trade-wood)); color: rgb(var(--trade-wood-ink)); }
.bq-chip[data-trade="tree"] { background: rgb(var(--trade-stone)); color: rgb(var(--trade-stone-ink)); }
.bq-chip[data-trade="demolition"] { background: rgb(var(--trade-stone)); color: rgb(var(--trade-stone-ink)); }
.bq-chip[data-trade="cleaning"] { background: rgb(var(--trade-cyan)); color: rgb(var(--trade-cyan-ink)); }
.bq-chip[data-trade="contents"] { background: rgb(var(--trade-lilac)); color: rgb(var(--trade-lilac-ink)); }
.bq-chip[data-trade="general"] { background: rgb(var(--pill-grey)); color: rgb(var(--pill-grey-ink)); }
.bq-chip[data-trade="other"] { background: rgb(var(--pill-grey)); color: rgb(var(--pill-grey-ink)); }

/* ---- The insurance PDF page (Task 119, Glenn's walkthrough of 18 Oct) ----
   .bq-pz-* is this page's own vocabulary; everything else on it is the house
   classes above. The page is the quote builder's width (1280 px) and sits on
   the shell's left edge, so a 1920 screen does not centre a narrow column
   between two empty bands. */
.bq-shell--parser .bq-main { max-width: 1280px; margin: 0; }
.bq-pz { font-size: var(--fs-body); }
.bq-pz .bq-card { border-radius: var(--r-card); }
/* Titles 16 px semibold, body 15-16 px, chips 12 px (item 11). */
.bq-pz-title { font-family: var(--font-display); font-size: 16px; font-weight: 600; line-height: 1.3; color: rgb(var(--ink)); }
.bq-pz-text { font-size: 15px; line-height: 1.5; color: rgb(var(--body)); }
.bq-pz-small { font-size: var(--fs-label); line-height: 1.4; color: rgb(var(--muted)); }
/* The claim's facts: a grid of label-over-value cells, two across on a phone,
   four from md:, one left edge per column. */
.bq-pz-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
@media (min-width: 768px) { .bq-pz-facts { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.bq-pz-facts dt { font-size: var(--fs-label); font-weight: 500; color: rgb(var(--muted)); }
.bq-pz-facts dd { margin-top: 2px; font-size: 15px; font-weight: 600; color: rgb(var(--ink)); overflow-wrap: anywhere; }
/* One thing their estimate may be missing: the words on the left, the two
   choices on the right from md: and under the words on a phone, 44 px each. */
.bq-pz-item { display: flex; flex-direction: column; gap: 12px; }
@media (min-width: 768px) { .bq-pz-item { flex-direction: row; align-items: flex-start; gap: 24px; } }
.bq-pz-item-main { min-width: 0; flex: 1; }
.bq-pz-item-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.bq-pz-item-head .bq-chip { height: 24px; }
.bq-pz-item-why { margin-top: 4px; font-size: 15px; line-height: 1.5; color: rgb(var(--body)); }
.bq-pz-item-from, .bq-pz-item-add { margin-top: 4px; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; font-size: var(--fs-table); line-height: 1.45; color: rgb(var(--body)); }
.bq-pz-item-from .bq-link, .bq-pz-item-add .bq-link { min-height: 24px; font-size: var(--fs-table); }
.bq-pz-item-detail { margin-top: 8px; display: flex; flex-direction: column; gap: 4px; padding: 12px; border-radius: var(--r-input); background: rgb(var(--mist)); font-size: var(--fs-table); line-height: 1.45; color: rgb(var(--body)); }
.bq-pz-item-actions { display: flex; flex: none; align-items: center; gap: 8px; }
/* Code reminders (Task 119c item 2): one quiet note under the list, never a
   row with Add and Not needed -- "install wind-rated shingles" is a rule the
   work must meet, not a line a contractor adds to a quote. */
.bq-pz-reminders { margin-top: 12px; padding: 10px 12px; border-radius: var(--r-input); background: rgb(var(--mist)); font-size: var(--fs-table); line-height: 1.45; color: rgb(var(--muted)); }
/* Not needed: the row goes quiet, the title gets its strike, and Undo stays. */
.bq-pz-item.is-no .bq-pz-item-title { text-decoration: line-through; color: rgb(var(--muted)); }
.bq-pz-item.is-no .bq-pz-item-why, .bq-pz-item.is-no .bq-pz-item-from, .bq-pz-item.is-no .bq-pz-item-add, .bq-pz-item.is-no .bq-pz-item-head .bq-chip { opacity: .55; }
/* The "?" right after the title (item 3): a 24 px ring, a 44 px tap on a
   phone, never inside a sentence. */
.bq-pz-why { display: inline-grid; place-items: center; flex: none; vertical-align: middle; margin-left: 4px; width: 24px; height: 24px; border-radius: var(--r-pill); border: 1px solid rgb(var(--brand2-text)); background: none; color: rgb(var(--brand2-text)); font-size: 12px; font-weight: 700; line-height: 1; cursor: pointer; }
.bq-pz-why:hover { background: rgb(var(--brand2) / .10); }
.bq-pz-why[aria-expanded="true"] { background: rgb(var(--brand2)); color: rgb(var(--on-brand2)); }
@media (max-width: 767.98px) { .bq-pz-why { width: 32px; height: 32px; font-size: 14px; } }
/* Add / Not needed (item 4): real labelled buttons, 44 px, a clear tint of the
   action's colour on hover rather than grey, and solid steel with white-on-steel
   text once chosen. */
.bq-choice { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 44px; padding: 0 16px; border-radius: var(--r-btn); border: 1px solid rgb(var(--edge)); background: rgb(var(--surface)); color: rgb(var(--ink)); font-size: var(--fs-table); font-weight: 700; line-height: 1; white-space: nowrap; box-shadow: 0 2px 0 rgb(var(--edge)); transition: background .15s ease, color .15s ease, border-color .15s ease, transform .08s ease, box-shadow .1s ease; }
.bq-choice svg { width: 16px; height: 16px; flex: none; }
.bq-choice:active { transform: scale(.96); box-shadow: 0 0 0 rgb(var(--edge)); }
.bq-choice:disabled { opacity: .5; cursor: not-allowed; }
.bq-choice--add { border-color: rgb(var(--brand2)); color: rgb(var(--brand2-text)); box-shadow: 0 2px 0 rgb(var(--brand2) / .6); }
.bq-choice--add:hover { background: rgb(var(--brand2) / .12); }
.bq-choice--add[aria-pressed="true"] { background: rgb(var(--brand2)); border-color: rgb(var(--brand2)); color: rgb(var(--rail-active)); box-shadow: inset 0 2px 4px rgb(0 0 0 / .35); }
.bq-choice--no { color: rgb(var(--muted)); }
.bq-choice--no:hover { background: rgb(var(--danger) / .10); border-color: rgb(var(--danger) / .6); color: rgb(var(--danger)); }
.bq-choice--no[aria-pressed="true"] { background: rgb(var(--draft-tint)); border-color: rgb(var(--input)); color: rgb(var(--ink)); box-shadow: inset 0 2px 4px rgb(0 0 0 / .18); }
@media (max-width: 767.98px) { .bq-pz-item-actions { width: 100%; } .bq-pz-item-actions .bq-choice { flex: 1; } }
/* The work (item 6): the lines grouped by trade, each group a bar that folds,
   each line one grid row -- Service · Description · Qty · Unit · Their price ·
   Your price · Total · tools -- with the figures edited where they are read.
   On a phone the row becomes a card: the service and the description on top,
   the three figures in a row, the tools under them. */
.bq-pz-group { border-top: 1px solid rgb(var(--line)); }
.bq-pz-group:first-child { border-top: 0; }
.bq-pz-group-bar { display: flex; width: 100%; align-items: center; gap: 8px; min-height: 44px; padding: 8px 0; background: none; border: 0; color: rgb(var(--ink)); font: inherit; text-align: left; cursor: pointer; }
.bq-pz-group-bar svg { width: 16px; height: 16px; flex: none; color: rgb(var(--muted)); transition: transform .15s ease; }
.bq-pz-group-bar[aria-expanded="false"] svg { transform: rotate(-90deg); }
.bq-pz-group-name { min-width: 0; font-weight: 700; font-size: 15px; }
.bq-pz-group-count { font-size: var(--fs-label); color: rgb(var(--muted)); white-space: nowrap; }
.bq-pz-group-total { margin-left: auto; font-weight: 700; font-size: 15px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.bq-pz-cols, .bq-pz-row { display: grid; grid-template-columns: 160px minmax(0, 1fr) 72px 56px 104px 104px 104px 88px; gap: 8px; align-items: center; }
.bq-pz-cols { display: none; }
@media (min-width: 1024px) { .bq-pz-cols { display: grid; padding: 4px 0; font-size: var(--fs-label); font-weight: 600; text-transform: uppercase; letter-spacing: .06em; color: rgb(var(--eyebrow)); } }
.bq-pz-cols .bq-num, .bq-pz-row .bq-num { text-align: right; }
.bq-pz-row { min-height: 56px; padding: 8px 0; border-top: 1px solid rgb(var(--divider)); }
.bq-pz-row.is-off { opacity: .55; }
.bq-pz-row.is-open { background: rgb(var(--page)); }
/* The trade tag stays inside its column (Task 119c item 1): the longest name
   ("Gutters & Downspouts", 20 characters) wraps to a second line inside the
   112 px Service column instead of running over the description beside it.
   Wrapping, never clipping and never an ellipsis -- Glenn has complained about
   this exact overlap. */
.bq-pz-cell-service { min-width: 0; }
/* One line, whole (Task 128a item 3): "Windows & Doors" used to break inside the
   tag ("Windows &/Doors"). The column is 160 px, which is the longest real
   trade plus its padding; the tag never wraps and never ellipsises. */
.bq-pz-cell-service .bq-chip { display: inline-block; max-width: 100%; height: auto; min-height: 22px; padding: 2px 8px; white-space: nowrap; overflow: hidden; text-overflow: clip; line-height: 1.3; vertical-align: middle; }
.bq-pz-cell-desc { min-width: 0; }
.bq-pz-desc { display: block; width: 100%; min-height: 32px; padding: 0; border: 0; background: none; text-align: left; font: inherit; font-size: 15px; font-weight: 500; line-height: 1.35; color: rgb(var(--ink)); cursor: pointer; }
.bq-pz-desc:hover { text-decoration: underline; }
.bq-pz-desc.is-struck { text-decoration: line-through; color: rgb(var(--muted)); }
.bq-pz-flags { display: flex; flex-wrap: wrap; gap: 4px 8px; margin-top: 2px; }
.bq-pz-flags:empty { display: none; }
.bq-pz-box { width: 100%; min-height: 40px; padding: 0 8px; border: 1px solid rgb(var(--edge)); border-radius: var(--r-input); background: rgb(var(--surface)); color: rgb(var(--ink)); font-size: var(--fs-table); font-variant-numeric: tabular-nums; text-align: right; }
.bq-pz-box:focus { outline: none; border-color: rgb(var(--accent)); box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }
.bq-pz-box.is-unit { text-align: left; text-transform: uppercase; }
.bq-pz-theirs { font-size: var(--fs-table); color: rgb(var(--muted)); font-variant-numeric: tabular-nums; white-space: nowrap; }
.bq-pz-total { font-size: 15px; font-weight: 700; color: rgb(var(--ink)); font-variant-numeric: tabular-nums; white-space: nowrap; }
.bq-pz-total.is-up { color: rgb(var(--money-ink)); }
.bq-pz-tools { display: flex; justify-content: flex-end; gap: 0; }
.bq-pz-tools .bq-icon-quiet { width: 44px; height: 44px; }
/* Task 137 item 5: the Check chip. Amber is a FILL here, never amber text on a
   light page (the design system's rule 1), and the whole chip is a button --
   44 px tall on a phone, where a thumb is aiming at it, and 26 px beside a desk
   row where the line is already 56 px. The icon is the badge's icon, so the
   chip still says what it means in colour-blind mode and in dark. */
.bq-check-chip { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; padding: 0 10px;
  border: 1px solid rgb(var(--accent)); border-radius: 999px;
  background: rgb(var(--accent) / .18); color: rgb(var(--ink));
  font: inherit; font-size: var(--fs-label); font-weight: 700; line-height: 1; cursor: pointer; }
.bq-check-chip svg { width: 14px; height: 14px; flex: none; }
.bq-check-chip:hover { background: rgb(var(--accent) / .28); }
.bq-check-chip:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }
@media (min-width: 768px) { .bq-check-chip { min-height: 26px; padding: 0 8px; } }
/* What the chip opens: the reader's own sentence, and the way to the strip of
   the PDF it came from. Full width under the row, like the line editor. */
.bq-check-panel { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  margin: 0 0 8px; padding: 10px 12px; border-left: 3px solid rgb(var(--accent));
  border-radius: var(--r-input); background: rgb(var(--accent) / .12); }
.bq-check-reason { min-width: 0; flex: 1 1 16rem; margin: 0; font-size: 13px; line-height: 1.4; color: rgb(var(--ink)); }
.bq-check-peek { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 12px;
  border: 1px solid rgb(var(--edge)); border-radius: var(--r-input); background: rgb(var(--surface));
  color: rgb(var(--ink)); font: inherit; font-size: var(--fs-label); font-weight: 600; cursor: pointer; }
@media (max-width: 1023.98px) {
  .bq-pz-row { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "service tools" "desc desc" "figures figures"; gap: 8px 12px; padding: 12px 0; }
  .bq-pz-cell-service { grid-area: service; }
  .bq-pz-cell-desc { grid-area: desc; }
  .bq-pz-tools { grid-area: tools; }
  .bq-pz-figures { grid-area: figures; display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 8px; align-items: end; }
  .bq-pz-figures > div:nth-child(-n+2) { grid-column: span 3; }
  .bq-pz-figures > div:nth-child(n+3) { grid-column: span 2; }
  .bq-pz-figures > div { min-width: 0; }
  .bq-pz-figures .bq-pz-lab { display: block; font-size: var(--fs-label); color: rgb(var(--muted)); margin-bottom: 2px; }
  .bq-pz-figures .bq-pz-box { font-size: 16px; min-height: 44px; }
  .bq-pz-figures .bq-pz-theirs, .bq-pz-figures .bq-pz-total { display: block; min-height: 44px; line-height: 44px; text-align: right; }
}
@media (min-width: 1024px) {
  .bq-pz-figures { display: contents; }
  .bq-pz-figures .bq-pz-lab { display: none; }
}
/* A phone's line card (Task 129b item 6, corrected by Task 129d item 1 and
   Task 129e): the trade chip and the three tools share the top line, the
   description follows, then the figures in two rows. Qty | Unit is two EQUAL
   columns in their own half of the card; Their price | Your price | Total are
   three EQUAL columns below. Every one of the five has its label ABOVE its
   value -- in Task 129d that was the fix for the money row (a label beside a
   value in a third of a 375 px card left "Your price" 30 px, so $123.12 read
   "$12" and its label sat on top of Their price), and Task 129e gave Qty and
   Unit the same shape. A label BESIDE the Qty box is what broke them: an
   input's min-content width is its size attribute (~170 px), so the box would
   not shrink into half a card, its figure was drawn over the Unit label
   ("Uni9") and the Unit box reached ~40 px past the card's edge. min-width: 0
   is the part that lets a box be narrower than its own default size. A label
   above costs one 14 px line and gives the figure the whole column (98 px),
   which is what "$99,999.99" needs. Money that still cannot fit one line wraps
   inside its own column rather than running past the card: never clipped,
   never over its neighbour (Glenn's hardest rule). */
@media (max-width: 767.98px) {
  .bq-pz-row { gap: 6px 8px; padding: 8px 0; }
  .bq-pz-desc { min-height: 0; line-height: 1.3; }
  .bq-pz-flags { margin-top: 0; gap: 4px 6px; }
  .bq-pz-figures { gap: 6px 8px; align-items: start; }
  .bq-pz-figures > div { min-width: 0; }
  .bq-pz-figures .bq-pz-lab { display: block; margin: 0 0 2px; font-size: 11px; line-height: 1.3; }
  .bq-pz-figures .bq-pz-box { width: 100%; min-width: 0; min-height: 44px; padding: 0 4px; }
  .bq-pz-figures .bq-pz-theirs,
  .bq-pz-figures .bq-pz-total { display: flex; align-items: center; justify-content: flex-end;
    width: 100%; min-height: 44px; line-height: 1.25; text-align: right;
    white-space: normal; overflow-wrap: anywhere; }
}


/* Always-dark panels: the quote cockpit cards (bg-[#111827]), the financial
   cockpit and the drawers/modals whose surface is near-black whatever the theme
   toggle says. This block must stay AFTER the .dark rules above: same
   specificity, so source order is what makes it win.
   Why it exists (quote #Q-58): a child of one of these panels sees the LIGHT
   theme, so `class="bq-input"` painted a white box with slate-800 ink on a
   near-black card, and a heading written `text-slate-900 dark:text-white` stayed
   invisible until someone flipped the toggle -- a quote title and a money column
   that read as empty fields. Markup inside these panels uses always-on colors
   (text-white / text-slate-100/300); the .dark: variants are irrelevant here. */
.bq-cockpit { color: #e2e8f0; }
.bq-cockpit .bq-input {
  background: #1e293b;
  border-color: #475569;
  color: #f1f5f9;
}
.bq-cockpit .bq-input::placeholder { color: #94a3b8; }
.bq-cockpit .bq-input:focus { border-color: #f59e0b; }
.bq-cockpit .bq-btn-secondary { background: #1e293b; border-color: #475569; color: #e2e8f0; }
.bq-cockpit .bq-btn-secondary:hover { background: #334155; border-color: #f59e0b; color: #fbbf24; }
.bq-cockpit table.grid-table th { color: #cbd5e1; border-color: #334155; }
.bq-cockpit table.grid-table td { color: #e2e8f0; border-color: #1e293b; }

.badge {
  display: inline-flex;
  align-items: center;
  border-radius: 9999px;
  padding: .125rem .625rem;
  font-size: .75rem;
  font-weight: 600;
  white-space: nowrap;
}
/* Status colours live in tokens.css (bg-draft-tint / text-draft, bg-sent-tint /
   text-sent, bg-money-tint / text-money-ink) and are chosen by BQ.statusClass()
   in app.js, so a switched palette or dark mode recolours them together. */

/* Table header rows are steel (Task 44): the band that names the columns is
   structure, and structure is steel. This is one rule for the three grid tables
   (quotes, parser, the builder's line items); the other tables in the app carry
   `bg-brand2 text-on-brand2` on their <thead> instead. The `th` rule below still
   colours a table with no <thead> (the print views), and the .bq-cockpit block
   wins inside an always-dark panel (it has the higher specificity). */
table.grid-table thead { background: rgb(var(--brand2)); }
table.grid-table thead th {
  color: rgb(var(--on-brand2));
  border-bottom-color: rgb(var(--brand2-raised));
}

table.grid-table th {
  text-align: left;
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: rgb(var(--muted));
  padding: .5rem .5rem;
  border-bottom: 1px solid rgb(var(--line));
}
table.grid-table td { padding: .35rem .5rem; border-bottom: 1px solid rgb(var(--line)); vertical-align: middle; }

/* ------------------------------------------------------------------ */
/* Design system: page hero, icon chips, empty states                  */
/* ------------------------------------------------------------------ */

/* A legacy hero panel, always dark by design like .bq-cockpit: a near-black
   fill with always-on light ink, because a flipping token would put light text
   on a light slab. The gradient and the amber glows are gone with the re-skin
   (mapping step 8) -- a border, not a shadow, carries it now. */
.bq-hero {
  position: relative;
  overflow: hidden;
  border-radius: .5rem;
  border: 1px solid rgb(var(--line));
  background: rgb(var(--totalbar));
  color: #ffffff;
  padding: 1.5rem 1.75rem;
}

.bq-hero .hero-content { position: relative; z-index: 1; }
.bq-hero .hero-eyebrow { font-size: .7rem; font-weight: 600; text-transform: uppercase; letter-spacing: .14em; color: rgb(var(--accent)); }
.bq-hero h1 { margin-top: .25rem; font-family: var(--font-display); font-size: 1.5rem; font-weight: 700; letter-spacing: -.01em; }
.bq-hero p.hero-sub { margin-top: .25rem; font-size: .875rem; color: #cbd5e1; }
.bq-hero .hero-actions { position: relative; z-index: 1; }

.icon-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: .75rem;
  flex-shrink: 0;
}
.icon-chip.sm { width: 1.75rem; height: 1.75rem; border-radius: .5rem; }

.card-title {
  display: flex;
  align-items: center;
  gap: .6rem;
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 2.5rem 1.5rem;
  text-align: center;
}




/* Flash for voice-recognized fields / rows. --money is "money that is earned",
   and it flips to blue with the colour-blind palette, which is the point: the
   flash is a state cue, so it must not rely on one palette's green. */
@keyframes bq-flash { 0%, 100% { background-color: transparent; } 50% { background-color: rgb(var(--money) / .22); } }
.bq-flash { animation: bq-flash 0.9s ease-in-out 2; border-radius: 0.5rem; }

/* The staged line a quick question changed (Task 107b): amber, once, because
   this is the reader saying "that is the row your answer moved" -- not money
   earned, so it must not use the money green (clinerules section 1). A fill
   behind the row's own ink, never amber text, and the animation is one pass so
   a list of ten rows cannot turn into a light show. */
@keyframes bq-flash-accent { 0%, 100% { background-color: transparent; } 45% { background-color: rgb(var(--accent) / .22); } }
.bq-flash-accent { animation: bq-flash-accent 0.9s ease-in-out 1; border-radius: 0.5rem; }

/* ------------------------------------------------------------------ */
/* Task 109: the app shell and the parts every page shares             */
/* (Glenn approved the designs 17 Oct 2026: .ai/design/app/*.png;      */
/* the rules are .ai/design/layout-rules.md). Plain CSS on the tokens  */
/* so every look -- light, dark, colour-blind, dyslexia -- gets them.  */
/* ------------------------------------------------------------------ */

/* Type roles (six sizes, layout-rules section 5). Headings and money in Space
   Grotesk; the eyebrow's CAPS live here, never in the source text. */
.bq-eyebrow {
  margin: 0;
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgb(var(--eyebrow));
}
.bq-h1 { margin: 0; font-family: var(--font-display); font-size: var(--fs-title); font-weight: 700; line-height: 1.15; letter-spacing: -.01em; color: rgb(var(--ink)); }
.bq-h2 { margin: 0; font-family: var(--font-display); font-size: var(--fs-card); font-weight: 700; line-height: 1.2; letter-spacing: -.01em; color: rgb(var(--ink)); }
.bq-money { font-family: var(--font-display); font-size: var(--fs-money); font-weight: 700; line-height: 1.05; letter-spacing: -.01em; color: rgb(var(--ink)); font-variant-numeric: tabular-nums; }
.bq-num { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }

/* A row inside a card: 60 px, one line of title and one of detail, whatever
   is on the right pinned to the right. Rows divide with the hairline, never
   with a gap. */
.bq-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 60px;
  padding: 10px 16px;
  border-top: 1px solid rgb(var(--divider));
  color: rgb(var(--muted));
}
.bq-row:first-child { border-top: 0; }
.bq-row-text { flex: 1; min-width: 0; }
.bq-row-text b { display: block; color: rgb(var(--ink)); font-size: 15px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bq-row-text small {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  /* Two lines, then an ellipsis (Task 129a): a row's detail is a sentence, and
     a phone's 343 px cuts most of them in half. Rows still divide evenly. */
  -webkit-line-clamp: 2;
  line-clamp: 2;
  color: rgb(var(--muted));
  font-size: 13px;
  line-height: 1.35;
  white-space: normal;
  overflow: hidden;
}
a.bq-row, button.bq-row { width: 100%; text-align: left; background: none; border-left: 0; border-right: 0; border-bottom: 0; cursor: pointer; text-decoration: none; transition: background .15s ease, transform .08s ease; }
a.bq-row:hover, button.bq-row:hover { background: rgb(var(--mist) / .5); }
a.bq-row:active, button.bq-row:active { transform: scale(.99); }

/* A pill: a status or a fact, with its word (and its icon). Five tints, each
   with the ink that reads on it; colour is never the only signal. */
.bq-pill {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 10px;
  border-radius: var(--r-pill);
  font-size: var(--fs-label);
  font-weight: 700;
  white-space: nowrap;
  background: rgb(var(--pill-grey));
  color: rgb(var(--pill-grey-ink));
}
.bq-pill--red { background: rgb(var(--pill-red)); color: rgb(var(--pill-red-ink)); }
.bq-pill--amber { background: rgb(var(--pill-amber)); color: rgb(var(--pill-amber-ink)); }
.bq-pill--green { background: rgb(var(--pill-green)); color: rgb(var(--pill-green-ink)); }
.bq-pill--blue { background: rgb(var(--pill-blue)); color: rgb(var(--pill-blue-ink)); }
.bq-pill--grey { background: rgb(var(--pill-grey)); color: rgb(var(--pill-grey-ink)); }
.bq-pill svg { width: 14px; height: 14px; }

/* Buttons the designs add to the standard above. `.bq-btn-lg` is the main
   action's size (48 px, 15 px bold, 20 px sides) on any of the family;
   `.bq-btn-outline` is the design's quiet button (surface, steel words, the
   edge token, no lift); `.bq-btn-text` is a bare steel word with a 44 px hit
   area. All three press like every other button. */
.bq-btn-lg { min-height: 48px; padding: 0 20px; font-size: 15px; font-weight: 700; gap: 8px; }
.bq-btn-outline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: 44px;
  padding: 0 1rem;
  border-radius: var(--r-btn);
  border: 1px solid rgb(var(--edge));
  background: rgb(var(--surface));
  color: rgb(var(--brand2-text));
  font-size: .875rem;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  transition: background .15s ease, transform .08s ease;
}
.bq-btn-outline:hover { background: rgb(var(--mist) / .6); }
.bq-btn-outline:active { transform: scale(.97); }
/* A quiet button with only an icon (Task 128a item 2): the carrier's PDF on a
   phone, whose words made the 375 px header row 4 px too wide. Square, 44 px,
   and still named by its aria-label and title. */
.bq-btn-outline.bq-qb-icon-only { width: 44px; min-width: 44px; padding: 0; gap: 0; }
.bq-btn-outline[aria-pressed="true"] { background: rgb(var(--mist)); box-shadow: inset 0 2px 4px rgb(var(--brand2) / .25); }
.bq-btn-outline:disabled { opacity: .5; cursor: not-allowed; }
.bq-btn-text {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .25rem;
  min-height: 44px;
  padding: 0 .5rem;
  border: 0;
  background: none;
  color: rgb(var(--brand2-text));
  font-size: .875rem;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  border-radius: var(--r-input);
  transition: background .15s ease, transform .08s ease;
}
.bq-btn-text:hover { background: rgb(var(--mist) / .6); }
.bq-btn-text:active { transform: scale(.97); }

/* A segmented control: one choice among a few, in one box (the quotes list's
   All / Needs you / Draft / Sent / Signed; the builder's price tiers). The
   chosen segment is a white card on the mist track; every segment is 40 px
   tall inside a 48 px box. aria-pressed carries the state, as everywhere. */
.bq-seg {
  display: inline-flex;
  align-items: stretch;
  gap: 4px;
  padding: 4px;
  border-radius: var(--r-btn);
  background: rgb(var(--mist));
  max-width: 100%;
  overflow-x: auto;
}
.bq-seg > button, .bq-seg > a {
  flex: 1 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 40px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--r-input);
  background: none;
  color: rgb(var(--muted));
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  transition: background .15s ease, color .15s ease, transform .08s ease;
}
.bq-seg > button:active, .bq-seg > a:active { transform: scale(.97); }
.bq-seg > [aria-pressed="true"], .bq-seg > [aria-current] {
  background: rgb(var(--surface));
  color: rgb(var(--brand2-text));
  box-shadow: 0 1px 2px rgb(var(--ink) / .12);
}

/* Inputs on a phone: 48 px tall and 16 px text (layout-rules section 5: body
   and ALL phone inputs are 16), which is also what stops iOS zooming in on
   focus. From md: up the house 44 px / 14 px box stays. */
@media (max-width: 767.98px) {
  .bq-input { min-height: 48px; font-size: var(--fs-body); }
}

/* The warning strip ("1 line has no price"): amber tint, amber edge, amber
   words, 52 px, with its one action on the right. Problems first. */
.bq-warn {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 52px;
  padding: 0 16px;
  border: 1px solid rgb(var(--warn-edge));
  border-radius: var(--r-card);
  background: rgb(var(--warn-tint));
  color: rgb(var(--warn-ink));
  font-weight: 600;
}

/* ---- The shell ------------------------------------------------------- */

/* The rail (md: and up): 80 px of steel down the left, the gold logo tile,
   then the five items 8 px apart, each an icon with its word under it (Task
   121 item 1: Glenn, 18 Oct -- a tooltip is not enough; the labels are always
   on, 12 px, and the rail is just wide enough that none of them wraps). The
   lit one is a white-on-steel chip. Log out sits at the foot of the rail, one
   click from any page (item 2).
   The strip (.bq-rail) is the content column's flex sibling in .bq-shell-row,
   stretched to the row, so it is as tall as the page itself and the steel runs
   the full height of every page -- a full-page screenshot included, which
   draws a fixed element only as tall as the first screen (Task 113c: the
   menu looked as if it stopped halfway down a long page). The menu inside it
   (.bq-rail-menu) is a sticky 100vh column, so the tile and the buttons stay
   in view at any scroll position and its bottom edge is always the
   viewport's. */
.bq-rail {
  position: relative;
  z-index: 40;
  width: var(--rail-w);
  flex: none;
  align-self: stretch;
  display: none;
  background: rgb(var(--brand2));
}
@media (min-width: 768px) { .bq-rail { display: flex; } }
.bq-rail-menu {
  position: sticky;
  top: 0;
  height: 100vh;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding-top: 16px;
  padding-bottom: 16px;
}
.bq-rail-logo {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin-bottom: 16px;
  border-radius: var(--r-btn);
  /* Steel with the white mark, not gold (Task 135): the gold on the rail is
     the + button under it, one gold thing per screen. */
  border: 1px solid rgb(var(--rail-active) / .18);
  background: rgb(var(--rail-active) / .10);
  flex: none;
}
.bq-rail-item {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: 64px;
  height: 56px;
  flex: none;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: none;
  color: rgb(var(--rail-icon));
  font-family: var(--font-sans);
  cursor: pointer;
  text-decoration: none;
  transition: background .15s ease, color .15s ease, transform .08s ease;
}
.bq-rail-item:hover { background: rgb(var(--rail-active) / .08); color: rgb(var(--rail-active)); }
.bq-rail-item:active { transform: scale(.97); }
.bq-rail-item.is-active, .bq-rail-item.is-open { background: rgb(var(--rail-active) / .16); color: rgb(var(--rail-active)); }
.bq-rail-item:focus-visible, .bq-tab:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--brand2)), 0 0 0 4px rgb(var(--accent)); }
.bq-rail-item svg, .bq-tab svg { width: 22px; height: 22px; stroke-width: 2.2; }
/* The word under the icon: 12 px, one line, never clipped (the item is 64 px
   and the longest word, "Log out", is under 50). */
.bq-rail-label { display: block; font-size: 12px; font-weight: 700; line-height: 14px; letter-spacing: 0; white-space: nowrap; }
/* The icon's own box: the count badge is placed against it, not against the
   item, so the figure sits at the icon's top-right corner and clear of the
   glyph whatever the item's size. */
.bq-rail-icon, .bq-tab-icon { position: relative; display: block; width: 22px; height: 22px; flex: none; }
/* Log out: pushed to the foot of the rail, the one item that is a button
   with no destination. */
.bq-rail-item--logout { margin-top: auto; }
/* The gold + under the logo (Task 135): a 48 px circle with its word under
   it, the rail's one gold thing. It opens the create menu the phone's tab bar
   opens, and the plus turns 45 deg into an X while that menu is open. */
.bq-rail-plus {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 64px;
  flex: none;
  padding: 0;
  border: 0;
  background: none;
  color: rgb(var(--rail-icon));
  font-family: var(--font-sans);
  cursor: pointer;
  transition: color .15s ease;
}
.bq-rail-plus-circle {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px solid rgb(var(--accent-edge));
  background: rgb(var(--accent));
  color: rgb(var(--on-accent));
  box-shadow: 0 2px 0 rgb(var(--accent-edge));
  transition: filter .15s ease, transform .15s ease;
}
.bq-rail-plus svg { width: 24px; height: 24px; stroke-width: 2.4; transition: transform .15s ease; }
.bq-rail-plus:hover { color: rgb(var(--rail-active)); }
.bq-rail-plus:hover .bq-rail-plus-circle { filter: brightness(1.08); }
.bq-rail-plus:active .bq-rail-plus-circle { transform: scale(.97); }
.bq-rail-plus[aria-expanded="true"] .bq-rail-plus-circle svg { transform: rotate(45deg); }
.bq-rail-plus:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--brand2)), 0 0 0 4px rgb(var(--accent)); border-radius: 12px; }
.bq-rail-plus-label { display: block; font-size: 12px; font-weight: 700; line-height: 14px; white-space: nowrap; }
/* The open-quotes count on the Quotes item (Task 121 item 3): a small signal
   badge at the icon's top-right corner, offset so the icon stays whole, in a
   colour that is not the icon's -- the count badge token with a white figure
   -- and capped at "9+" so it never grows over the icon.
   Task 129a: it sits OFF the glyph, outside the icon box's top-right corner,
   and it counts what "Needs you" counts rather than the open quotes, so the
   badge and the card agree. The 8 px `-right-2` offset alone still laid the
   16 px badge across the last ~6 px of the file glyph (the Task 121 browser
   check measures exactly that), so the offset is the badge's own width plus
   its gap: 19 px out, 4 px up, still inside the 64 px item. */
.bq-nav-count {
  position: absolute;
  top: -4px;
  right: -19px;
  left: auto;
  min-width: 16px;
  height: 16px;
  padding: 0 3px;
  border-radius: var(--r-pill);
  border: 1.5px solid rgb(var(--brand2));
  background: rgb(var(--count-badge));
  color: rgb(var(--on-count-badge));
  font-size: 10px;
  font-weight: 800;
  line-height: 13px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}

/* The shell's row: the rail and the content column side by side from md: up
   (one under the other below it, where the rail is not drawn). At least one
   screen tall, and as tall as the page, so the rail stretches with it. */
.bq-shell-row { min-height: 100vh; }
@media (min-width: 768px) { .bq-shell-row { display: flex; align-items: stretch; } }
/* The content column takes what is left of the row beside the rail. */
.bq-shell-column { display: flex; min-height: 100vh; flex-direction: column; flex: 1 1 0%; min-width: 0; }

/* The top bar: 60 px on a phone, 72 from md: up; back and forward on the
   left, search, then the bell, the look toggle and Help on the right. Every
   control in it is a 44 px square. */
.bq-topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 4px;
  height: var(--topbar-h);
  padding: 0 16px;
  border-bottom: 1px solid rgb(var(--line));
  background: rgb(var(--surface));
}
@media (min-width: 768px) { .bq-topbar { height: var(--topbar-h-lg); padding: 0 24px; gap: 8px; } }
.bq-topbar-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex: none;
  border: 0;
  border-radius: var(--r-btn);
  background: none;
  color: rgb(var(--brand2-text));
  cursor: pointer;
  transition: background .15s ease, transform .08s ease;
}
.bq-topbar-btn:hover { background: rgb(var(--mist)); }
.bq-topbar-btn:active { transform: scale(.97); }
.bq-topbar-btn:disabled { opacity: .4; cursor: not-allowed; }
.bq-topbar-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }
/* The search box (md: and up): 44 px, the edge token, 320 px at most. */
.bq-topbar-search {
  display: none;
  align-items: center;
  gap: 8px;
  width: 100%;
  max-width: 320px;
  height: 44px;
  padding: 0 12px;
  border: 1px solid rgb(var(--edge));
  border-radius: var(--r-btn);
  background: rgb(var(--surface));
  color: rgb(var(--eyebrow));
  font-size: 14px;
  text-align: left;
  cursor: pointer;
  transition: border-color .15s ease;
}
.bq-topbar-search:hover { border-color: rgb(var(--input)); }
@media (min-width: 768px) { .bq-topbar-search { display: flex; } }
.bq-topbar-logo {
  display: none;
  place-items: center;
  width: 32px;
  height: 32px;
  flex: none;
  margin-right: 4px;
  border-radius: var(--r-input);
  /* Steel with the white mark (Task 135): the gold on a phone is the tab
     bar's New plus, one gold thing per screen. */
  background: rgb(var(--brand2));
}
@media (min-width: 360px) and (max-width: 767.98px) { .bq-topbar-logo { display: grid; } }

/* The page content: one left and one right edge for everything inside it
   (layout-rules section 1), 16 px gutters on a phone and 24 from md: up,
   never wider than 1200 px, and room under the last card for the tab bar.
   The top padding is the standard 16 px gap, so a banner above (the
   verification nudge) sits 16 px off the page's first block, not the ~60 px
   a page's own py-8 used to add on top of it (Task 110). */
.bq-main {
  width: 100%;
  max-width: var(--content-w);
  margin: 0 auto;
  flex: 1;
  overflow-x: hidden;
  padding: 16px 16px calc(var(--tabbar-h) + 16px + env(safe-area-inset-bottom, 0px));
}
@media (min-width: 768px) { .bq-main { padding: 16px 24px 24px; } }
.bq-banner { width: 100%; max-width: var(--content-w); margin: 0 auto; padding: 16px 16px 0; }
@media (min-width: 768px) { .bq-banner { padding: 24px 24px 0; } }
/* A page that draws its own bar across the bottom of a phone (the quote
   page's total bar) tells the shell so, and the shell takes its tab bar and
   the room it kept for it away. */
.bq-shell--no-tabbar .bq-main { padding-bottom: 16px; }

/* The tab bar (phone only): Home, Quotes, the gold New quote in the middle,
   Jobs, More. 66 px plus the safe area, labels 11 px bold, the lit tab steel. */
.bq-tabbar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 40;
  display: flex;
  align-items: stretch;
  height: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
  padding-bottom: env(safe-area-inset-bottom, 0px);
  border-top: 1px solid rgb(var(--line));
  background: rgb(var(--surface));
}
@media (min-width: 768px) { .bq-tabbar { display: none; } }
.bq-tab {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 2px;
  padding-top: 8px;
  min-width: 0;
  border: 0;
  background: none;
  color: rgb(var(--eyebrow));
  font-size: 11px;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  position: relative;
  transition: color .15s ease, transform .08s ease;
}
.bq-tab:active { transform: scale(.97); }
.bq-tab.is-active { color: rgb(var(--brand2-text)); }
.bq-tab .bq-nav-count { border-color: rgb(var(--surface)); }
/* The one gold thing on a phone screen: a 60 px circle lifted 26 px above the
   bar, its own dark edge under it, the mic inside. */
.bq-tab-new { color: rgb(var(--ink)); }
.bq-tab-new .bq-tab-new-circle {
  display: grid;
  place-items: center;
  width: 60px;
  height: 60px;
  margin-top: -26px;
  border-radius: 50%;
  border: 1px solid rgb(var(--accent-edge));
  background: rgb(var(--accent));
  color: rgb(var(--on-accent));
  box-shadow: 0 2px 0 rgb(var(--accent-edge)), 0 8px 20px -8px rgb(0 0 0 / .4);
  transition: filter .15s ease;
}
.bq-tab-new .bq-tab-new-circle svg { width: 26px; height: 26px; stroke-width: 2.4; transition: transform .15s ease; }
.bq-tab-new:hover .bq-tab-new-circle { filter: brightness(1.08); }
.bq-tab-new:active .bq-tab-new-circle { box-shadow: 0 0 0 rgb(var(--accent-edge)); }
/* Open, the plus is an X: the same glyph turned 45 deg (Task 135). */
.bq-tab-new[aria-expanded="true"] .bq-tab-new-circle svg { transform: rotate(45deg); }
[data-motion="reduce"] .bq-tab-new .bq-tab-new-circle svg,
[data-motion="reduce"] .bq-rail-plus svg { transition: none; }

/* The More panel: everything that is not on the rail or the tab bar. A sheet
   from the bottom on a phone (the thumb is already there), a 300 px panel
   that slides out from the rail from md: up (Task 121 item 5: Glenn, 18 Oct
   -- "an in and out menu", the same More button opens it and closes it, so
   the backdrop stops at the rail's edge and the rail stays clickable). Rows
   are the card rows above; group headings are eyebrows. */
.bq-more-backdrop { position: fixed; inset: 0; z-index: 50; background: rgb(0 0 0 / .5); }
@media (min-width: 768px) { .bq-more-backdrop { left: var(--rail-w); background: rgb(0 0 0 / .25); } }
.bq-more {
  position: fixed;
  z-index: 51;
  display: flex;
  flex-direction: column;
  background: rgb(var(--page));
  inset: auto 0 0 0;
  max-height: 85vh;
  border-radius: var(--r-card) var(--r-card) 0 0;
  padding-bottom: env(safe-area-inset-bottom, 0px);
  box-shadow: 0 -8px 24px -12px rgb(0 0 0 / .4);
  transition: transform .2s ease;
}
/* Where the panel starts from and leaves to: under the phone's bottom edge,
   behind the rail from md: up. Alpine's x-transition applies this class. */
.bq-more-off { transform: translateY(100%); }
@media (min-width: 768px) {
  .bq-more {
    inset: 0 auto 0 var(--rail-w);
    width: 300px;
    max-height: none;
    border-radius: 0;
    border-right: 1px solid rgb(var(--line));
    box-shadow: 8px 0 24px -16px rgb(0 0 0 / .35);
  }
  .bq-more-off { transform: translateX(-100%); }
}
[data-motion="reduce"] .bq-more { transition: none; }
.bq-more-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; height: 60px; padding: 0 8px 0 16px; border-bottom: 1px solid rgb(var(--line)); background: rgb(var(--surface)); flex: none; }
.bq-more-body { flex: 1; min-height: 0; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 16px; }
.bq-more .bq-row { min-height: 52px; padding: 6px 16px; color: rgb(var(--ink)); font-size: 15px; font-weight: 600; }
.bq-more .bq-row svg { width: 20px; height: 20px; flex: none; color: rgb(var(--brand2-text)); }
.bq-more .bq-row.is-active { box-shadow: inset 3px 0 0 rgb(var(--brand2)); background: rgb(var(--mist)); }
/* The big Your work row at the top of the panel (Task 135): 68 px, the Sent
   tint's circle, and the row still divides like every other one. */
.bq-more .bq-more-yourwork { min-height: 68px; }
.bq-more .bq-more-yourwork .bq-create-icon { width: 44px; height: 44px; }
.bq-more .bq-row .bq-create-icon svg { width: 22px; height: 22px; color: inherit; }
/* The Account row (Task 135; Claude, 22 Oct 2026): Help and Display share the
   first line and Log out is full width under them. At the desk's 300 px panel
   three equal columns left "Log out" 84 px and it wrapped onto two lines. */
.bq-more-pills { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 8px; }
.bq-more-pill--wide { grid-column: 1 / -1; }
.bq-more-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 10px;
  border: 1px solid rgb(var(--edge));
  border-radius: var(--r-btn);
  background: rgb(var(--surface));
  color: rgb(var(--ink));
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background .15s ease, transform .08s ease;
}
.bq-more-pill:hover { background: rgb(var(--mist) / .6); }
.bq-more-pill:active { transform: scale(.97); }

/* The create menu (Task 135): the gold plus's menu, one source for the phone
   and the desk. A phone gets a column that rises from just above the gold
   circle -- centred, 360 px at most, 16 px gutters, clear of the home
   indicator; from md: up the same column is a 360 px popover beside the rail,
   placed by the two numbers base.html measured from the button that opened it.
   The cards rise 12 px and fade, 40 ms apart from the bottom up; a person who
   asked for less motion gets the fade alone. */
.bq-create-backdrop {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgb(0 0 0 / .5);
  animation: bq-create-fade .15s ease both;
}
.bq-create-menu {
  position: fixed;
  z-index: 61;
  left: 16px;
  right: 16px;
  bottom: calc(var(--tabbar-h) + 42px + env(safe-area-inset-bottom, 0px));
  width: min(360px, calc(100vw - 32px));
  margin: 0 auto;
  padding: 8px;
  border: 1px solid rgb(var(--line));
  border-radius: var(--r-card);
  background: rgb(var(--surface));
  box-shadow: 0 12px 32px -12px rgb(0 0 0 / .45);
  transition: transform .18s ease, opacity .15s ease;
}
@media (min-width: 768px) {
  .bq-create-menu {
    left: var(--create-left, calc(var(--rail-w) + 8px));
    right: auto;
    top: var(--create-top, 8px);
    bottom: auto;
    margin: 0;
    width: min(360px, calc(100vw - var(--rail-w) - 32px));
  }
}
.bq-create-off { transform: translateY(12px); opacity: 0; }
.bq-create-body { display: flex; flex-direction: column; gap: 8px; }
@keyframes bq-create-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes bq-create-rise {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}
/* `backwards`, not `both`: a filled last frame would keep `transform: none` on
   the card for good, and an animation's value beats a normal rule, so the
   press feedback below (`:active` scale) would never be seen. */
.bq-create-body > * {
  animation: bq-create-rise .18s ease backwards;
  animation-delay: calc(var(--i, 0) * 40ms);
}
.bq-create-card {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid rgb(var(--edge));
  border-radius: var(--r-card);
  background: rgb(var(--surface));
  color: rgb(var(--ink));
  font-size: var(--fs-body);
  font-weight: 600;
  text-decoration: none;
  transition: background .15s ease, transform .08s ease;
}
.bq-create-card:hover { background: rgb(var(--mist) / .6); }
.bq-create-card:active { transform: scale(.97); }
.bq-create-card--big { min-height: 72px; padding: 0 16px; }
.bq-create-card--small {
  flex-direction: column;
  justify-content: center;
  gap: 6px;
  min-height: 76px;
  padding: 8px 4px;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
}
.bq-create-icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 50%;
}
.bq-create-icon--small { width: 36px; height: 36px; }
.bq-create-icon--sent { background: rgb(var(--pill-blue)); color: rgb(var(--pill-blue-ink)); }
.bq-create-icon--money { background: rgb(var(--pill-green)); color: rgb(var(--pill-green-ink)); }
.bq-create-icon--draft { background: rgb(var(--pill-grey)); color: rgb(var(--pill-grey-ink)); }
.bq-create-text { flex: 1; min-width: 0; }
.bq-create-text b { display: block; font-size: 16px; font-weight: 700; color: rgb(var(--ink)); }
.bq-create-text small { display: block; margin-top: 2px; font-size: 13px; font-weight: 500; color: rgb(var(--muted)); }
.bq-create-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.bq-create-blank {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  border-radius: var(--r-btn);
  color: rgb(var(--brand2-text));
  font-size: 14px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: transform .08s ease;
}
.bq-create-blank:active { transform: scale(.97); }
@media (prefers-reduced-motion: reduce) {
  .bq-create-backdrop,
  .bq-create-body > * { animation: bq-create-fade .15s ease backwards; animation-delay: 0s; }
  .bq-create-menu { transition: opacity .15s ease; }
}
[data-motion="reduce"] .bq-create-backdrop,
[data-motion="reduce"] .bq-create-body > * { animation: bq-create-fade .15s ease backwards; animation-delay: 0s; }
[data-motion="reduce"] .bq-create-menu { transition: opacity .15s ease; }

/* The steel header band (the quote page and the workbench): the progress
   bar's six steps, an eyebrow in gold-on-steel, a white title, one line under
   it, the actions on the right (stacked under the title on a phone). */
.bq-steel-header { background: rgb(var(--brand2)); color: rgb(var(--on-steel-sub)); padding: 12px 16px 16px; display: flex; flex-direction: column; gap: 12px; }
@media (min-width: 768px) { .bq-steel-header { padding: 16px 24px; gap: 16px; } }
.bq-steel-header .bq-eyebrow { color: rgb(var(--gold-on-steel)); }
.bq-steel-header .bq-h1 { color: rgb(var(--rail-active)); }
.bq-steel-header .bq-steel-line { margin: 4px 0 0; color: rgb(var(--on-steel-sub)); font-size: 14px; }
.bq-steel-header .bq-btn-outline { background: transparent; color: rgb(var(--rail-active)); border-color: rgb(var(--rail-active) / .45); }
.bq-steel-header .bq-btn-outline:hover { background: rgb(var(--rail-active) / .08); }
.bq-steel-header .bq-icon-btn { background: transparent; color: rgb(var(--rail-active)); border-color: rgb(var(--rail-active) / .45); box-shadow: none; width: 48px; height: 48px; }
.bq-steps { display: flex; align-items: center; gap: 6px; }
.bq-step { display: flex; align-items: center; gap: 6px; flex: none; }
.bq-step-dot { width: 20px; height: 20px; border-radius: 50%; display: inline-grid; place-items: center; font-size: 11px; font-weight: 700; flex: none; border: 1.5px solid rgb(var(--rail-active) / .35); color: rgb(var(--on-steel-dim)); }
.bq-step.is-done .bq-step-dot { background: rgb(var(--accent)); border-color: rgb(var(--accent)); color: rgb(var(--on-accent)); }
.bq-step.is-current .bq-step-dot { background: rgb(var(--rail-active)); border-color: rgb(var(--rail-active)); color: rgb(var(--brand2)); }
.bq-step-label { display: none; }
@media (min-width: 768px) { .bq-step-label { display: block; } }
.bq-step-label b { display: block; font-size: 12px; line-height: 1.1; font-weight: 600; color: rgb(var(--on-steel-dim)); white-space: nowrap; }
.bq-step-label small { display: block; font-size: 11px; line-height: 1.1; color: rgb(var(--on-steel-dim)); min-height: 11px; }
.bq-step.is-current .bq-step-label b { color: rgb(var(--rail-active)); font-weight: 700; }
.bq-step-line { flex: 1; min-width: 8px; height: 2px; border-radius: 1px; background: rgb(var(--rail-active) / .2); }
.bq-step-line.is-done { background: rgb(var(--accent)); }

/* ---- Help Center article typography -------------------------------------
   The Markdown renderer emits plain HTML, so the house look has to come from
   rules rather than utility classes on every tag. Scoped to `.help-prose` so
   nothing else in the app is touched, and kept FLAT -- no nested rules or
   at-rules -- because tests/test_design_system.py parses this file with a
   `selector { declarations }` pattern. */
.help-prose { color: rgb(var(--body)); font-size: 0.95rem; line-height: 1.7; }
.help-prose h1, .help-prose h2, .help-prose h3 { font-family: var(--font-display); color: rgb(var(--brand2-text)); font-weight: 700; margin: 1.6em 0 0.6em; }
.help-prose h1 { font-size: 1.5rem; }
.help-prose h2 { font-size: 1.2rem; }
.help-prose h3 { font-size: 1.05rem; }
.help-prose p, .help-prose ul, .help-prose ol { margin: 0.85em 0; }
.help-prose ul { list-style: disc; padding-left: 1.25rem; }
.help-prose ol { list-style: decimal; padding-left: 1.25rem; }
.help-prose strong { font-weight: 700; color: rgb(var(--ink)); }
/* Links are steel plus an underline (Task 44): the accent is a fill and a line,
   never text on a light background, so steel carries the link instead. Hover
   thickens the rule. */
.help-prose a { color: rgb(var(--brand2-text)); text-decoration: underline; text-underline-offset: 2px; }
.help-prose a:hover { text-decoration-thickness: 2px; }
.help-prose table { width: 100%; border-collapse: collapse; margin: 1em 0; font-size: 0.9rem; }
.help-prose th, .help-prose td { border: 1px solid rgb(var(--line)); padding: 0.5rem 0.65rem; text-align: left; }
.help-prose th { background: rgb(var(--brand2)); color: rgb(var(--on-brand2)); font-weight: 700; }
/* Callouts: the accent-left-border block from the design system. A tint, so one
   rule covers both themes and the colour-blind palette. */
.help-prose blockquote { border-left: 4px solid rgb(var(--accent)); background: rgb(var(--accent) / .06); padding: 0.75rem 1rem; border-radius: 0 0.5rem 0.5rem 0; margin: 1em 0; }
/* Code blocks are always dark, like .bq-cockpit: a near-black fill with
   always-on light ink, which is why the text is a literal and not a token. */
.help-prose code { background: rgb(var(--totalbar)); color: #e2e8f0; padding: 0.15rem 0.35rem; border-radius: 0.375rem; font-size: 0.85em; }
.help-prose pre { background: rgb(var(--totalbar)); color: #e2e8f0; padding: 1rem; border-radius: 0.5rem; border: 1px solid rgb(var(--input)); overflow-x: auto; }
.help-prose pre code { background: transparent; padding: 0; }
.help-prose-warning { border-left: 4px solid rgb(var(--accent)); background: rgb(var(--accent) / .08); padding: 0.75rem 1rem; border-radius: 0 0.5rem 0.5rem 0; }


/* ------------------------------------------------------------------ */
/* Task 110: the home page, built to Glenn's approved dashboard design */
/* (`.ai/design/app/App-dashboard-*.png`, 17 Oct 2026). Flat rules on the
   tokens, like the rest of the house stylesheet. Ordering between the phone's
   column (what needs you, today, the month's money) and the wider layout
   (money first) lives in the template's order-* utilities; these rules only
   size the blocks. */
/* ------------------------------------------------------------------ */

.bq-dash { display: flex; flex-direction: column; gap: 16px; }
@media (min-width: 768px) { .bq-dash { gap: 24px; } }
.bq-dash-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; }

/* The four money cards: 2 x 2 on a phone, one row of four from md: up. */
.bq-dash-money { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
@media (min-width: 768px) { .bq-dash-money { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; } }
.bq-money-card { padding: 12px 16px; min-width: 0; }
@media (min-width: 768px) { .bq-money-card { padding: 16px; } }
/* The design's card figure: 22 px on a phone, 24 from md: up -- smaller than
   the page's own 32 px money role, because four of them share one row. */
.bq-money-card .bq-money { font-size: 22px; white-space: nowrap; }
@media (min-width: 768px) { .bq-money-card .bq-money { font-size: 24px; } }

/* Money to collect (Task 121 item 6): two cards side by side -- three when a
   carrier holds money -- each a link. On a phone an odd last card takes the
   whole row, so there is never a half-empty row. */
.bq-dash-collect { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.bq-dash-collect > :last-child:nth-child(odd) { grid-column: 1 / -1; }
@media (min-width: 768px) {
  .bq-dash-collect { display: flex; gap: 16px; }
  .bq-dash-collect > * { flex: 1 1 0; }
  .bq-dash-collect > :last-child:nth-child(odd) { grid-column: auto; }
}
.bq-collect-card { display: block; text-decoration: none; color: inherit; transition: border-color .15s ease, transform .08s ease; }
.bq-collect-card:hover { border-color: rgb(var(--edge)); }
.bq-collect-card:active { transform: scale(.99); }

/* Needs you and today stand side by side from md: up, level; one column on a
   phone where Needs you comes first. Each group is its OWN height (Task 129a:
   align-items start), so the Needs you card ends where its rows end instead of
   stretching down the taller Today card and leaving a blank half. */
.bq-dash-cols { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; align-items: start; }
@media (min-width: 768px) { .bq-dash-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.bq-dash-group { display: flex; flex-direction: column; min-width: 0; }
.bq-dash-group > .bq-eyebrow { margin-bottom: 8px; }
.bq-dash-card-body { flex: 1; overflow: hidden; }

/* A row's signals. The dot is the design's, and the words beside it carry the
   same news, so colour is never the only cue. */
.bq-dot { width: 10px; height: 10px; flex: none; border-radius: 50%; background: rgb(var(--muted)); }
.bq-dot--red { background: rgb(var(--danger)); }
.bq-dot--amber { background: rgb(var(--warn-ink)); }
.bq-dot--blue { background: rgb(var(--sent)); }
.bq-dot--green { background: rgb(var(--money)); }
.bq-row-action { flex: none; font-size: var(--fs-table); font-weight: 700; color: rgb(var(--brand2-text)); }
.bq-row-icon { flex: none; color: rgb(var(--brand2-text)); }
.bq-chevron { color: rgb(var(--eyebrow)); }
.bq-day-badge { flex: none; width: 48px; font-size: var(--fs-table); font-weight: 700; font-variant-numeric: tabular-nums; color: rgb(var(--ink)); }

/* The empty state of a card: icon, one sentence, one way forward. */
.bq-dash-clear { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; padding: 24px 16px; text-align: center; font-size: var(--fs-table); color: rgb(var(--muted)); }
.bq-dash-clear svg { color: rgb(var(--brand2-text)); }

/* This week: five equal tiles in one row at every width, today's picked out
   with the accent edge. On a phone the content column is 343 px, so with the
   8 px gaps each tile is 62 px wide (Task 121b: at 12 px padding "Mon 19"
   wrapped and "12 jobs" ran out of its tile). So below 768 px the tile is a
   small calendar tile: 6 px side padding, everything centred, the weekday
   over the day number, the count at 14 px -- and the widest words of the
   year ("Wed 30", "12 jobs") each stay on one line with room to spare. From
   768 px the tile is wide enough for the label on one line, the 20 px count
   and the job names, left-aligned like the cards around it. */
.bq-week { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px; }
.bq-week-day { min-width: 0; padding: 10px 6px; text-align: center; }
.bq-week-day.is-today { border-color: rgb(var(--accent)); }
.bq-week-label { white-space: nowrap; }
.bq-week-num { display: block; margin-top: 2px; font-family: var(--font-display); font-size: 16px; font-weight: 700; line-height: 1.2; letter-spacing: 0; color: rgb(var(--ink)); }
.bq-week-count { margin: 4px 0 0; font-family: var(--font-display); font-size: 14px; font-weight: 700; color: rgb(var(--ink)); white-space: nowrap; }
.bq-week-name { margin: 2px 0 8px; font-size: 13px; color: rgb(var(--muted)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bq-week-bars { display: flex; gap: 4px; margin-top: 8px; }
.bq-week-bars span { flex: 1; height: 6px; border-radius: 3px; background: rgb(var(--mist)); }
.bq-week-bars span.is-on { background: rgb(var(--accent)); }
@media (min-width: 768px) {
  .bq-week { gap: 16px; }
  .bq-week-day { padding: 16px; text-align: left; }
  .bq-week-num { display: inline; margin: 0; font: inherit; letter-spacing: inherit; color: inherit; }
  .bq-week-count { font-size: 20px; }
  .bq-week-bars { margin-top: 0; }
}

/* Recent quotes, wide screens only: the header band names the columns, the
   rows divide with the hairline, money is right-aligned by .bq-num. */
.bq-dash-table { border-collapse: collapse; }
.bq-dash-table thead th { padding: 12px 16px; font-size: var(--fs-label); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: rgb(var(--eyebrow)); border-bottom: 1px solid rgb(var(--line)); }
.bq-dash-table tbody td { padding: 12px 16px; font-size: var(--fs-table); color: rgb(var(--muted)); border-top: 1px solid rgb(var(--divider)); vertical-align: middle; }
.bq-dash-table tbody tr:first-child td { border-top: 0; }
.bq-dash-table tbody td small { display: block; font-size: 13px; color: rgb(var(--muted)); }
.bq-dash-table tbody td .bq-num { color: rgb(var(--ink)); font-weight: 700; }
.bq-dash-quote-link { display: block; font-size: 15px; font-weight: 600; color: rgb(var(--ink)); text-decoration: none; }
.bq-dash-quote-link:hover { text-decoration: underline; text-underline-offset: 2px; }
/* The quiet icon action on a table row (open, PDF, share, delete): a 44 px
   target with no edge and no shadow -- the edged .bq-icon-btn above is for the
   workbench's three line actions, and on a list row it read as a big outlined
   box (the 17 Oct review of Home). The money stays the loudest thing. */
.bq-icon-quiet { display: inline-grid; place-items: center; width: 44px; height: 44px; flex: none; border: 0; border-radius: var(--r-input); background: none; color: rgb(var(--muted)); cursor: pointer; transition: background .15s ease, color .15s ease, transform .08s ease; }
.bq-icon-quiet:hover { background: rgb(var(--mist) / .6); color: rgb(var(--ink)); }
.bq-icon-quiet:active { transform: scale(.97); }
/* A list row's "…" menu (Task 129a): the items that change or destroy a row
   live in one panel with their words on, opened from a labelled 44 px button.
   `position: fixed` because the card the row sits in clips anything that hangs
   outside it; the button's own box supplies top/left when it opens. */
.bq-actions-menu {
  position: fixed;
  z-index: 60;
  width: 200px;
  padding: 4px;
  border: 1px solid rgb(var(--line));
  border-radius: var(--r-card);
  background: rgb(var(--surface));
  box-shadow: 0 12px 28px rgb(var(--ink) / .18);
}
.bq-actions-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 44px;
  padding: 0 10px;
  border: 0;
  border-radius: var(--r-input);
  background: none;
  color: rgb(var(--body));
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 600;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background .15s ease;
}
.bq-actions-menu-item:hover { background: rgb(var(--mist)); }
.bq-actions-menu-item svg { color: rgb(var(--muted)); }
.bq-actions-menu-item.is-danger { color: rgb(var(--danger)); }
.bq-actions-menu-item.is-danger svg { color: rgb(var(--danger)); }
.bq-actions-menu-item.is-danger:hover { background: rgb(var(--danger-tint)); }
.bq-icon-quiet.is-danger:hover { background: rgb(var(--danger-tint)); color: rgb(var(--danger)); }
.bq-icon-quiet svg { width: 16px; height: 16px; }
/* The actions cell is as narrow as its two icons and 8 px shorter top and
   bottom, so a 44 px target keeps the row at the design's height. */
.bq-dash-table td.bq-dash-actions { width: 1%; padding-top: 8px; padding-bottom: 8px; white-space: nowrap; }



/* ------------------------------------------------------------------ */
/* Task 111: the quotes list, built to Glenn's approved design         */
/* (`.ai/design/app/App-quotes-phone.png`, 17 Oct 2026; wide screens   */
/* use the home page's Recent quotes table). Flat rules on the tokens, */
/* like the rest of the house stylesheet.                              */
/* ------------------------------------------------------------------ */

.bq-quotes { display: flex; flex-direction: column; gap: 12px; }
@media (min-width: 768px) { .bq-quotes { gap: 24px; } }

/* The white band: on a phone it runs edge to edge (the page's 16 px gutters
   are pulled back and put inside it) with the hairline under it. From md: up
   it is just the header row and the toolbar, on the page colour. */
.bq-quotes-band { display: flex; flex-direction: column; gap: 12px; margin: -16px -16px 0; padding: 16px 16px 12px; background: rgb(var(--surface)); border-bottom: 1px solid rgb(var(--line)); }
@media (min-width: 768px) { .bq-quotes-band { gap: 24px; margin: 0; padding: 0; background: none; border-bottom: 0; } }
.bq-quotes-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 44px; }
@media (min-width: 768px) { .bq-quotes-head { min-height: 48px; } }

/* The picture's quiet plus on a phone: 44 px square, the edge token, steel. */
.bq-icon-plus { display: inline-grid; place-items: center; width: 44px; height: 44px; flex: none; border: 1px solid rgb(var(--edge)); border-radius: var(--r-btn); background: rgb(var(--surface)); color: rgb(var(--brand2-text)); cursor: pointer; transition: background .15s ease, transform .08s ease; }
.bq-icon-plus:hover { background: rgb(var(--mist) / .6); }
.bq-icon-plus:active { transform: scale(.97); }

/* The toolbar: the search box over the pills on a phone; side by side and
   level from md: up. */
.bq-quotes-tools { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
@media (min-width: 768px) { .bq-quotes-tools { flex-direction: row; align-items: center; gap: 16px; } }

/* The search box: 48 px, 16 px text (every phone input is 16), the edge
   token, the house focus ring on the box itself. */
.bq-search { display: flex; align-items: center; gap: 8px; height: 48px; padding: 0 12px; border: 1px solid rgb(var(--edge)); border-radius: var(--r-btn); background: rgb(var(--surface)); color: rgb(var(--eyebrow)); cursor: text; transition: border-color .15s ease, box-shadow .15s ease; }
.bq-search:focus-within { border-color: rgb(var(--input)); box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }
.bq-search input { flex: 1; min-width: 0; height: 100%; border: 0; background: none; padding: 0; font-size: var(--fs-body); color: rgb(var(--ink)); outline: none; }
.bq-search input::placeholder { color: rgb(var(--eyebrow)); }
.bq-search input::-webkit-search-cancel-button { -webkit-appearance: none; }
@media (min-width: 768px) { .bq-search { width: 320px; flex: none; } }

/* The filter pills: a 44 px target around the picture's 36 px pill, 8 px
   apart, one row that scrolls sideways on a phone without a scrollbar. The
   chosen pill is the blue tint, the rest grey; the count is bold beside the
   word. */
/* The filter pills: one strip, the chosen one blue. Task 129a: the strip wraps
   on a phone instead of scrolling sideways -- a pill the contractor cannot see
   (the active one, usually) is a filter they did not choose. Each pill still
   keeps its own words on one line. */
.bq-filters { display: flex; flex-wrap: wrap; gap: 8px; min-width: 0; }
.bq-filter { flex: none; display: inline-flex; align-items: center; height: 44px; padding: 0; border: 0; background: none; cursor: pointer; }
.bq-filter:active .bq-filter-pill { transform: scale(.97); }
.bq-filter:focus-visible { outline: none; }
.bq-filter:focus-visible .bq-filter-pill { box-shadow: 0 0 0 2px rgb(var(--surface)), 0 0 0 4px rgb(var(--accent)); }
.bq-filter-pill { display: inline-flex; align-items: center; gap: 5px; height: 36px; padding: 0 14px; border-radius: var(--r-pill); background: rgb(var(--pill-grey)); color: rgb(var(--pill-grey-ink)); font-size: 13px; font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; transition: background .15s ease, color .15s ease, transform .08s ease; }
.bq-filter[aria-pressed="true"] .bq-filter-pill { background: rgb(var(--pill-blue)); color: rgb(var(--pill-blue-ink)); }

/* A few choices as separate pills, never one joined box (Glenn's rule, Task
   129c): Layout, Font, Show, Group by, Mode, the billing interval and the
   crew's two tabs. The pills are the filter pills' own colours and 44 px tall,
   so a gloved thumb outdoors hits one; they wrap onto a second row rather than
   shrinking, and the chosen one is the blue tint. aria-checked (a radio group),
   aria-pressed (a toggle) and aria-selected (a tab) all light the pill, because
   the pages use all three. The buttons are the group's own children, so no new
   button class can collide with `.bq-choice` on the parser page. */
.bq-choices { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px; min-width: 0; max-width: 100%; }
.bq-choices > button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 44px; padding: 0 16px; border: 0; border-radius: var(--r-pill); background: rgb(var(--pill-grey)); color: rgb(var(--pill-grey-ink)); font-family: inherit; font-size: 13px; font-weight: 700; line-height: 1.2; white-space: nowrap; cursor: pointer; transition: background .15s ease, color .15s ease, transform .08s ease; }
.bq-choices > button:active { transform: scale(.97); }
.bq-choices > button:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--surface)), 0 0 0 4px rgb(var(--accent)); }
.bq-choices > button[aria-checked="true"], .bq-choices > button[aria-pressed="true"], .bq-choices > button[aria-selected="true"] { background: rgb(var(--pill-blue)); color: rgb(var(--pill-blue-ink)); }
.bq-choices > button:disabled { opacity: .5; cursor: default; }

/* The phone's groups: an eyebrow and a card each, 12 px apart like the
   picture; a row is 72 px with the money and the pill stacked on the right. */
.bq-quotes-groups { display: flex; flex-direction: column; gap: 12px; }
.bq-quotes-group { display: flex; flex-direction: column; gap: 12px; }
.bq-quote-row { min-height: 72px; }
.bq-quote-right { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex: none; }
.bq-quote-right .bq-num { color: rgb(var(--ink)); font-size: 15px; font-weight: 700; }

/* Task 152: a phone row with the "Turn on follow-ups" control under it. The
   wrapper carries the card's divider (the row is the first child of its own
   wrapper now, so `.bq-row:first-child` no longer draws it), and the control
   sits on the card's own right padding, 44 px tall like every tap target. */
.bq-quote-item { border-top: 1px solid rgb(var(--divider)); }
.bq-quote-item:first-child { border-top: 0; }
.bq-quote-item .bq-row { border-top: 0; }
.bq-quote-followup { display: flex; justify-content: flex-end; padding: 0 16px 8px; }
.bq-quote-followup .bq-btn-text { min-height: 44px; }

/* The count and money under the list (the shown family's whole total). Its
   right padding is the card's 16 px plus the card's 1 px edge, so the money
   ends on the same line as every amount in the cards above it. */
.bq-quotes-sum { margin: 0; padding: 0 17px; text-align: right; font-size: var(--fs-table); color: rgb(var(--muted)); }
.bq-quotes-sum .bq-num { color: rgb(var(--ink)); font-weight: 700; }

/* The empty state: icon, the family's own sentence, one way forward. */
.bq-quotes-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; padding: 32px 16px; text-align: center; font-size: var(--fs-table); color: rgb(var(--muted)); }
.bq-quotes-empty svg { color: rgb(var(--brand2-text)); }
.bq-quotes-empty-title { margin: 0; font-size: 15px; font-weight: 600; color: rgb(var(--ink)); }

/* The wide table adds a group row (an eyebrow across the table) before each
   group's rows and a foot with the family's total under the money column.
   The status and date columns take only what their words need, so the job's
   name keeps the width and the headers stay on one line (at 820 "Last
   activity" and the names wrapped otherwise). */
.bq-quotes-table thead th { white-space: nowrap; }
.bq-quotes-table th.bq-fit, .bq-quotes-table td.bq-fit { width: 1%; white-space: nowrap; }
.bq-quotes-table tbody tr.bq-group-row th { padding: 16px 16px 4px; text-align: left; border-top: 0; }
.bq-quotes-table tbody + tbody tr.bq-group-row th { border-top: 1px solid rgb(var(--line)); }
.bq-quotes-table tbody tr.bq-group-row + tr td { border-top: 0; }
.bq-quotes-table tfoot td { padding: 12px 16px; font-size: var(--fs-table); color: rgb(var(--muted)); border-top: 1px solid rgb(var(--line)); }
.bq-quotes-table tfoot td.bq-num { color: rgb(var(--ink)); font-weight: 700; }


/* ------------------------------------------------------------------ */
/* Task 112: the quote builder, built to Glenn's approved design       */
/* (`.ai/design/app/App-quote-builder-laptop.png` and `-phone.png`,    */
/* 17 Oct 2026). Flat rules on the tokens, like the rest of the house  */
/* stylesheet. The work is one grid at every width: a table-like row   */
/* from md: up, a stacked row on a phone.                              */
/* ------------------------------------------------------------------ */

/* The page: 16 px between stacked blocks on a phone, 24 from md: up, and
   room under the last card for the phone's own bar. */
/* The room under the last card on a phone is the bar's own height (12 px of
   padding, the 52 px mic, 12 px or the safe area under it) plus one 16 px
   step, so the bar can never cover a line at any scroll (Task 113b item 4). */
.bq-qb { display: flex; flex-direction: column; gap: 16px; padding-bottom: calc(64px + max(12px, env(safe-area-inset-bottom, 0px)) + 16px); }
@media (min-width: 768px) { .bq-qb { gap: 24px; padding-bottom: 0; } }

/* The steel header's extras: a phone's first row (back to the list, More),
   the save and sent lines under the title. */
/* The header's phone row and its md: actions row swap with the width in
   house rules, not Tailwind's `hidden`: the React island's stylesheet (on
   when the island is) declares a `.hidden` of its own and is loaded last,
   which used to win the tie and hide the actions row on a desktop. */
.bq-qb-header-top { display: flex; align-items: center; justify-content: space-between; height: 44px; gap: 8px; min-width: 0; }
@media (min-width: 768px) { .bq-qb-header-top { display: none; } }
.bq-qb-actions { display: none; }
@media (min-width: 768px) { .bq-qb-actions { display: flex; } }
.bq-steel-line--wide { display: none; }
@media (min-width: 768px) { .bq-steel-line--wide { display: block; } .bq-steel-line--phone { display: none; } }
.bq-qb-back { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; color: rgb(var(--rail-active)); font-weight: 700; text-decoration: none; }
.bq-qb-back:hover { text-decoration: underline; text-underline-offset: 2px; }
.bq-qb-saveline { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 8px 0 0; font-size: 13px; color: rgb(var(--on-steel-sub)); }
.bq-qb-saveline .bq-btn-text { min-height: 32px; padding: 0 8px; color: rgb(var(--rail-active)); text-decoration: underline; text-underline-offset: 2px; }
.bq-qb-header .bq-step-dot svg { width: 12px; height: 12px; }
/* The menu's rows: 44 px, the icon then the words. */
.bq-qb-menu-item { display: flex; align-items: center; gap: 8px; width: 100%; min-height: 44px; padding: 0 12px; text-align: left; font-size: 14px; font-weight: 500; color: rgb(var(--body)); text-decoration: none; transition: background .15s ease; }
.bq-qb-menu-item:hover { background: rgb(var(--mist)); }
.bq-qb-menu-item:disabled { opacity: .4; cursor: not-allowed; }
.bq-qb-menu-item.is-danger { color: rgb(var(--danger)); font-weight: 600; }
.bq-qb-menu-item.is-danger:hover { background: rgb(var(--danger-tint)); }

/* Two columns from xl: the work, and the money column, which stays put while
   the work scrolls. From xl, not lg (Task 122b): below xl the grid beside the
   panel left the work only ~550 px, too narrow for the line row's columns, so
   the money column stacks under the work as it does on a tablet. The panel is
   260 px (Task 122b item 2), and the page's own content is 1280 px (the width
   Task 119's note gives the builder): the 60 px that frees, plus the panel's
   60, is the Description's -- 368 px at 1366 where it had 174, the widest
   column on the row and 40% of it, so a carrier's line reads on one or two
   lines instead of three or four. */
.bq-qb-grid { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
@media (min-width: 768px) { .bq-qb-grid { gap: 24px; } }
/* The quote page is the one page with `bq-shell--no-tabbar` (its own bar at
   the foot), so this reaches the builder alone; every other page keeps the
   shared 1200 px. */
@media (min-width: 1280px) {
  .bq-shell--no-tabbar .bq-main, .bq-shell--no-tabbar .bq-banner { max-width: 1280px; }
}
/* From xl: two columns and two rows. The rows card is the grid's third child
   (Task 113b item 1): on a cash quote the work spans both rows and the card
   sits under the price panel (the builder picture); on a claim
   (.is-workbench) the money column spans both rows and the card is "Job
   details" under the work, so neither column ends far above the other. The
   second row is 1fr so the card always starts right under the first row's
   block, never halfway down a blank. */
@media (min-width: 1280px) {
  .bq-qb-grid.has-side { display: grid; grid-template-columns: minmax(0, 1fr) 260px; grid-template-rows: auto 1fr; align-items: start; }
  .bq-qb-main { grid-column: 1; grid-row: 1 / span 2; }
  .bq-qb-side { grid-column: 2; grid-row: 1; }
  .bq-qb-rows { grid-column: 2; grid-row: 2; }
  .bq-qb-grid.is-workbench .bq-qb-main { grid-row: 1; }
  .bq-qb-grid.is-workbench .bq-qb-side { grid-row: 1 / span 2; }
  .bq-qb-grid.is-workbench .bq-qb-rows { grid-column: 1; grid-row: 2; }
}
.bq-qb-main { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
/* The skeletons the page draws while the quote loads (Task 122 item 2): the
   work's and the money column's own places, so the first paint is the last. */
.bq-qb-skeleton { display: flex; flex-direction: column; gap: 12px; padding: 16px; }
.bq-qb-skel-bar, .bq-qb-skel-row, .bq-qb-skel-money { display: block; border-radius: var(--r-chip); background: rgb(var(--line)); animation: bq-pulse 1.6s ease-in-out infinite; }
.bq-qb-skel-bar { height: 16px; }
.bq-qb-skel-row { height: 44px; width: 100%; }
.bq-qb-skel-money { height: 32px; width: 60%; }
@keyframes bq-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
@media (min-width: 768px) { .bq-qb-main { gap: 24px; } }
.bq-qb-side { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
@media (min-width: 768px) { .bq-qb-side { gap: 24px; } }

/* The problem strip's fix on the right, in the strip's own ink. */
.bq-qb-problem .bq-qb-fix { color: rgb(var(--warn-ink)); padding: 0 4px; }
.bq-qb-recorder { display: flex; flex-direction: column; gap: 8px; }
.bq-qb-recorder:empty { display: none; }

/* ---- The notices row (Task 112b) --------------------------------------- */
/* Above the two columns: the unverified email and the voice engine, one slim
   line each (48 px: the text, its one action, the X), so the work starts
   higher. The amber strip's own colours, a quieter weight. On a phone the
   voice notice stacks: the text and the X on top, the button the whole width
   under them. */
.bq-qb-notices { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.bq-notice { display: flex; align-items: center; gap: 8px; min-height: 48px; padding: 2px 2px 2px 16px; border: 1px solid rgb(var(--warn-edge)); border-radius: var(--r-card); background: rgb(var(--warn-tint)); color: rgb(var(--warn-ink)); font-size: var(--fs-table); font-weight: 600; }
.bq-notice-text { display: flex; align-items: center; gap: 8px; flex: 1 1 0; min-width: 0; }
.bq-notice-action { flex: none; min-height: 44px; color: rgb(var(--warn-ink)); }
.bq-notice-action.bq-btn-outline { color: rgb(var(--brand2-text)); }
.bq-notice-x { flex: none; color: rgb(var(--warn-ink)); }
@media (max-width: 767.98px) {
  .bq-notice--voice { flex-wrap: wrap; padding-bottom: 8px; }
  .bq-notice--voice .bq-notice-x { order: 1; }
  .bq-notice--voice .bq-notice-action { order: 2; flex: 1 1 100%; width: 100%; margin-right: 14px; }
}

/* ---- The work ------------------------------------------------------- */
/* From md: up one card holds the head, the column names, the rooms and the
   foot; on a phone the card dissolves and each room is a card of its own,
   like the picture. */
.bq-work { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
@media (min-width: 768px) { .bq-work { gap: 0; background: rgb(var(--surface)); border: 1px solid rgb(var(--line)); border-radius: var(--r-card); overflow: visible; } }
.bq-work-head { display: flex; flex-direction: column; gap: 12px; }
@media (min-width: 768px) { .bq-work-head { flex-direction: row; align-items: center; justify-content: space-between; gap: 16px; padding: 16px; border-bottom: 1px solid rgb(var(--line)); } }
.bq-work-title { white-space: nowrap; }
/* One line above the table: "All 32 lines match their estimate" (Task 128a
   item 7). Words and a tick, in body ink -- green stays for money. */
.bq-work-match { display: flex; align-items: center; gap: 6px; margin: 0; padding: 8px 16px 0; font-size: var(--fs-table); font-weight: 600; color: rgb(var(--body)); }
.bq-work-count { font-weight: 700; }
/* On a phone the tools wrap (Task 112b): Find a line takes the row's remaining
   width beside Group (an icon and the one word), and Good / better / best
   drops under them -- nothing may pass 375 px. From md: one row, the picture's. */
.bq-work-tools { display: flex; flex-wrap: wrap; gap: 8px; min-width: 0; }
.bq-work-tools > * { flex: none; }
.bq-work-tools .bq-btn-outline { min-height: 44px; }
.bq-work-find { height: 44px; flex: 1 1 160px; min-width: 0; }
.bq-work-group-icon, .bq-work-group-short { display: none; }
@media (max-width: 767.98px) { .bq-work-group-icon { display: block; } .bq-work-group-short { display: inline; } .bq-work-group-long { display: none; } }
@media (min-width: 768px) { .bq-work-tools { flex: 1 1 auto; flex-wrap: nowrap; justify-content: flex-end; } .bq-work-find { flex: 1 1 120px; min-width: 120px; max-width: 220px; } }
@media (min-width: 1024px) { .bq-work-tools { flex: none; } .bq-work-find { flex: none; width: 220px; } }

/* One grid for the column names and every row (Task 122b, the money columns
   measured by Task 122c). The handle, the service chip, the description (the
   only column that grows), qty with its unit, the carrier's figure when a line
   came off an estimate, the unit price box, the total and the quiet pencil.
   Every cell is sized to what it holds and the description takes the rest, so
   a row and its heading cannot drift apart.
   "Money is never clipped" (Task 122c): the row's money is set in tabular
   figures, where the widest value a line can hold, "$99,999.99", is 87 px at
   14 px in Public Sans -- not the 77 px its proportional figures measure. So
   Theirs gets 102 (12 px inset + 90), the Yours box 114 (102 px of box, 92 of
   text) and Total 102, and Unit is its own 40 px inside the quantity's 142 px
   cell. The money cells carry a 12 px left inset, which with the 4 px grid gap
   makes the gap between two of them the 16 px the review asked for. */
.bq-work-cols { display: none; }
/* `.bq-work .bq-line` on purpose: the phone's flex rule below is written on
   `.bq-line` alone, so the grid wins by specificity at md: and up. */
@media (min-width: 768px) {
  .bq-work .bq-work-cols, .bq-work .bq-line { display: grid; grid-template-columns: 0px 160px minmax(0, 1fr) 110px 92px 88px 44px; column-gap: 4px; align-items: center; }
  .bq-work-cols { padding: 10px 16px; font-size: var(--fs-label); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: rgb(var(--eyebrow)); border-bottom: 1px solid rgb(var(--line)); }
}
/* The service column is 160 px -- the longest real trade ("Gutters &
   Downspouts" at 145 px with its padding, "Tree/Debris Removal" at 136) plus
   room to spare -- so the tag reads whole (Task 128a item 3): one line, never
   an ellipsis, never over the description. */
@media (min-width: 1280px) {
  .bq-work .bq-work-cols, .bq-work .bq-line { grid-template-columns: 0px 160px minmax(0, 1fr) 142px 114px 102px 44px; }
  .bq-work.is-workbench .bq-work-cols, .bq-work.is-workbench .bq-line { grid-template-columns: 0px 160px minmax(0, 1fr) 142px 102px 114px 102px 44px; }
  /* The 12 px inset that makes a 16 px gap between the money cells (Task 122c);
     the headings stay on the cells' right edges, so nothing drifts. The pencil
     keeps the grid's own gap: it is not money. */
  .bq-work .bq-line-qty, .bq-work .bq-line-theirs, .bq-work .bq-line-price,
  .bq-work .bq-line-total { padding-left: 12px; }
  .bq-work .bq-line-unit { width: 40px; flex: none; }
}
/* From 1536 there is room for the grip back (it is a 16 px cell and a 4 px
   gap out of the description), for the hand that drags a line. */
@media (min-width: 1536px) {
  .bq-work .bq-work-cols, .bq-work .bq-line { grid-template-columns: 16px 160px minmax(0, 1fr) 142px 114px 102px 44px; }
  .bq-work.is-workbench .bq-work-cols, .bq-work.is-workbench .bq-line { grid-template-columns: 16px 160px minmax(0, 1fr) 142px 102px 114px 102px 44px; }
}
.bq-work-cols .bq-num { text-align: right; }

/* A room: its bar, then its lines. A card on a phone. */
.bq-room { background: rgb(var(--surface)); border: 1px solid rgb(var(--line)); border-radius: var(--r-card); overflow: hidden; }
@media (min-width: 768px) { .bq-room { border: 0; border-radius: 0; overflow: visible; } }
.bq-room-bar { display: flex; align-items: center; gap: 8px; min-height: 52px; padding: 4px 16px; }
@media (min-width: 768px) { .bq-room-bar { background: rgb(var(--page)); border-top: 1px solid rgb(var(--line)); border-bottom: 1px solid rgb(var(--line)); padding: 4px 16px; } .bq-room:first-of-type .bq-room-bar { border-top: 0; } }
.bq-room-name, .bq-room-name-static { flex: 1 1 auto; min-width: 72px; max-width: 220px; font-family: var(--font-display); font-size: 17px; font-weight: 700; color: rgb(var(--brand2-text)); background: none; border: 1px solid transparent; border-radius: var(--r-chip); padding: 2px 4px; margin-left: -4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bq-room-name { width: 160px; }
@media (max-width: 767.98px) { .bq-room-name, .bq-room-name-static { font-size: 16px; padding-left: 0; padding-right: 0; margin-left: 0; } }
@media (min-width: 768px) { .bq-room-name, .bq-room-name-static { flex: 0 1 auto; } }
.bq-room-name:hover { border-color: rgb(var(--edge)); }
.bq-room-name:focus { outline: none; border-color: rgb(var(--accent)); box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }
.bq-room-count { display: none; flex: none; font-size: var(--fs-table); color: rgb(var(--muted)); white-space: nowrap; }
@media (min-width: 768px) { .bq-room-count { display: inline; } }
.bq-room-spacer { flex: 1; }
.bq-room-talk { display: none; flex: none; gap: 6px; padding: 0 8px; }
@media (min-width: 768px) { .bq-room-talk { display: inline-flex; } }
.bq-room-money { display: flex; flex-direction: column; align-items: flex-end; flex: none; }
.bq-room-total { font-size: 15px; font-weight: 700; color: rgb(var(--brand2-text)); }
.bq-room-options { font-size: var(--fs-label); color: rgb(var(--muted)); white-space: nowrap; }

/* A line: a 72 px row on a phone (the description, the chip and the
   arithmetic under it, the money on the right), the grid above from md: up. */
.bq-line-wrap { border-top: 1px solid rgb(var(--divider)); }
.bq-line-wrap.is-drop { box-shadow: inset 0 2px 0 rgb(var(--brand2)); }
.bq-line { display: flex; align-items: center; gap: 12px; min-height: 72px; padding: 12px 16px; }
@media (min-width: 768px) { .bq-line { min-height: 60px; padding: 8px 16px; } }
.bq-line.is-glow { background: rgb(var(--accent) / .12); box-shadow: inset 3px 0 0 rgb(var(--accent)); }
.bq-line-handle, .bq-line-service, .bq-line-qty, .bq-line-price, .bq-line-actions { display: none; }
/* The handle keeps its (zero-width) cell from md: so the columns line up with
   their names; it is drawn from lg:, where the grid gives it 20 px. */
@media (min-width: 768px) { .bq-line-handle, .bq-line-service, .bq-line-qty, .bq-line-price, .bq-line-actions { display: flex; align-items: center; min-width: 0; } }
/* The service chip reads whole (Task 128a item 3): its column is 160 px, the
   longest real trade plus its padding, so the tag is one line and is never
   ellipsised. The full trade stays the chip's title and the editor's Service
   field; a trade longer than any real one is the only thing that could clip,
   and it never runs under the description. */
.bq-line-service .bq-chip { display: block; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: clip; line-height: 22px; }
.bq-line-handle { width: 0; color: rgb(var(--eyebrow)); cursor: grab; overflow: hidden; }
@media (min-width: 1536px) { .bq-line-handle { width: auto; } }
.bq-line-handle:active { cursor: grabbing; }
.bq-line-desc { flex: 1; min-width: 0; }
.bq-line-open { display: block; width: 100%; padding: 0; text-align: left; border: 0; background: none; border-radius: var(--r-chip); }
.bq-line-open b { display: block; font-size: 15px; font-weight: 600; color: rgb(var(--ink)); line-height: 1.3; overflow-wrap: break-word; }
.bq-line-open:hover b { text-decoration: underline; text-underline-offset: 2px; }
.bq-line-flags { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 4px; }
.bq-line-flags:empty { display: none; }
.bq-line-math { font-size: 13px; color: rgb(var(--muted)); }
@media (min-width: 768px) { .bq-line-chip-phone, .bq-line-math { display: none; } }
/* The phone's trade chip leads the card (Task 128d item 3): its own line above
   the description, as on the import page, then the arithmetic and "theirs $".
   The chip is an inline-flex, so the block description under it starts the next
   line; the margin is the one 4 px step the flags use. */
.bq-line-chip-phone { margin-bottom: 4px; }
.bq-line-qty { justify-content: flex-end; gap: 6px; font-size: 15px; color: rgb(var(--muted)); white-space: nowrap; }
.bq-line-qty b { color: rgb(var(--ink)); font-weight: 600; margin-right: 4px; }
/* The quantity box (Task 122 items 5 and 122b): the price box's twin, 84 px
   wide so six characters and a decimal ("1234.56") fit in full at 14 px and
   in the 16 px dyslexia face, the unit in words beside it. */
.bq-line-qty-box { width: 84px; height: 40px; flex: none; padding: 0 8px; border: 1px solid rgb(var(--edge)); border-radius: var(--r-input); background: rgb(var(--surface)); color: rgb(var(--ink)); font-size: var(--fs-table); font-weight: 600; text-align: right; transition: border-color .15s ease, box-shadow .15s ease; }
.bq-line-qty-box:focus { outline: none; border-color: rgb(var(--accent)); box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }
.bq-line-unit { font-size: 13px; color: rgb(var(--muted)); min-width: 20px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bq-line-mine { font-size: 13px; color: rgb(var(--muted)); }
.bq-line-price { justify-content: flex-end; }
.bq-line-price-box { width: 100%; max-width: none; height: 40px; padding: 0 4px; border: 1px solid rgb(var(--edge)); border-radius: var(--r-input); background: rgb(var(--surface)); color: rgb(var(--ink)); font-size: var(--fs-table); text-align: right; transition: border-color .15s ease, box-shadow .15s ease; }
.bq-line-price-box:focus { outline: none; border-color: rgb(var(--accent)); box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }
.bq-line-price-box.is-missing { background: rgb(var(--pill-red)); border-color: rgb(var(--pill-red-ink) / .5); color: rgb(var(--pill-red-ink)); }
.bq-line-price-box::placeholder { color: rgb(var(--pill-red-ink)); }
.bq-line-total { flex: none; display: flex; align-items: center; justify-content: flex-end; font-size: var(--fs-table); font-weight: 700; color: rgb(var(--ink)); white-space: nowrap; }
.bq-line-actions { justify-content: flex-end; gap: 0; position: relative; }
.bq-line-menu { top: 100%; }
/* The pencil takes the whole 44 px cell, so the row's one icon is also a
   full touch target and no 40 px of dead space sits inside the grid. */
.bq-line-actions .bq-icon-quiet { width: 44px; height: 44px; }
.bq-line-source { padding: 0 16px 16px; }

/* The editor under its line: the picture's tinted block with the steel edge
   down the left. On a phone the fields stack two to a row. */
.bq-line-editor { padding: 16px; background: rgb(var(--page)); border-top: 1px solid rgb(var(--divider)); box-shadow: inset 3px 0 0 rgb(var(--brand2)); display: flex; flex-direction: column; gap: 12px; }
.bq-editor-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
/* Where the line came from, at the top of the editor (Task 122 items 6 and 8):
   the carrier's wording and the crop of their estimate. */
.bq-editor-source { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 16px; }
.bq-editor-source-text { margin: 0; font-size: 13px; color: rgb(var(--muted)); min-width: 0; }
.bq-editor-source-text .bq-lab { display: inline; margin: 0 6px 0 0; }
.bq-editor-source-btn { min-height: 36px; padding: 0 8px; gap: 6px; }
/* Service is always first (Glenn, Task 112b), and from md: up the editor is
   TWO rows (Task 129d item 3): Service | Description, then the numbers under
   them. The old from-lg: one row gave Service 112 px, so "Windows & Doors"
   read "Windows &" and "Gutters & Downspouts" (165 px of text at 14 px) lost
   its tail. Two rows give the field 190 px and the description all the rest
   (348 px at 1366 against the 270 it had); the numbers keep their widths and
   still end on the card's right edge. A claim carries Their price as well, so
   its number row is one column more -- the grid is told which job it is on by
   `is-workbench`, the class the template binds to workbenchOn(). */
@media (min-width: 768px) {
  .bq-editor-grid--more { grid-template-columns: repeat(4, minmax(0, 1fr)); align-items: start; }
  .bq-editor-grid:not(.bq-editor-grid--more) {
    grid-template-columns: 190px minmax(0, 1fr) 112px 112px;
    grid-template-areas: "service desc desc desc"
                         "qty     unit price total";
    align-items: start;
  }
  .bq-editor-grid.is-workbench:not(.bq-editor-grid--more) {
    grid-template-columns: 190px minmax(0, 1fr) 104px 112px 112px;
    grid-template-areas: "service desc desc desc desc"
                         "qty     unit theirs price total";
  }
  .bq-editor-grid:not(.bq-editor-grid--more) > .bq-editor-service { grid-area: service; }
  .bq-editor-grid:not(.bq-editor-grid--more) > .bq-editor-desc { grid-area: desc; }
  .bq-editor-grid:not(.bq-editor-grid--more) > .bq-editor-qty { grid-area: qty; }
  .bq-editor-grid:not(.bq-editor-grid--more) > .bq-editor-unit { grid-area: unit; }
  .bq-editor-grid:not(.bq-editor-grid--more) > .bq-editor-theirs { grid-area: theirs; }
  .bq-editor-grid:not(.bq-editor-grid--more) > .bq-editor-price { grid-area: price; }
  .bq-editor-grid:not(.bq-editor-grid--more) > .bq-editor-total { grid-area: total; }
  /* 8 px of side padding in the money cells: "$99,999.99" is 87 px of tabular
     figures at 14 px and .bq-input's own 12 px leaves 86 of a 112 px column. */
  .bq-editor-grid:not(.bq-editor-grid--more) .bq-editor-price .bq-input { padding-left: 8px; padding-right: 8px; }
  .bq-editor-grid:not(.bq-editor-grid--more) .bq-editor-totalbox { padding-left: 8px; padding-right: 8px; }
}
.bq-editor-field { min-width: 0; }
/* The phone's order: Service and the description each take the row, then
   Unit | Qty, then Unit price | Total. */
@media (max-width: 767.98px) { .bq-editor-service { grid-column: 1 / -1; order: -2; } .bq-editor-desc { grid-column: 1 / -1; order: -1; } .bq-editor-unit { order: 1; } .bq-editor-qty { order: 2; } .bq-editor-price { order: 3; } .bq-editor-total { order: 4; } }
.bq-editor-total-inline { display: none; }
.bq-lab { display: block; margin: 0 0 4px; font-size: var(--fs-label); font-weight: 700; color: rgb(var(--muted)); }
.bq-editor-descbox { position: relative; }
.bq-editor-descbox textarea { min-height: 48px; padding-right: 56px; resize: none; line-height: 1.4; border-width: 2px; border-color: rgb(var(--brand2)); }
.bq-editor-mic { position: absolute; right: 2px; top: 2px; width: 44px; height: 44px; border-radius: var(--r-input); background: rgb(var(--brand2)); color: rgb(var(--rail-active)); display: grid; place-items: center; }
.bq-editor-mic.is-on { background: rgb(var(--accent)); color: rgb(var(--on-accent)); }
.bq-stepper { display: flex; height: 48px; border: 1px solid rgb(var(--input)); border-radius: var(--r-input); background: rgb(var(--surface)); overflow: hidden; }
@media (min-width: 768px) { .bq-stepper { height: 44px; } }
.bq-stepper > button { width: 44px; flex: none; display: grid; place-items: center; border: 0; border-radius: 0; background: none; color: rgb(var(--brand2-text)); }
.bq-stepper > button:first-child { border-right: 1px solid rgb(var(--divider)); }
.bq-stepper > button:last-child { border-left: 1px solid rgb(var(--divider)); }
.bq-stepper > input { flex: 1; min-width: 0; width: 100%; border: 0; background: none; text-align: center; font-size: var(--fs-body); font-weight: 700; color: rgb(var(--ink)); -moz-appearance: textfield; }
.bq-stepper > input::-webkit-outer-spin-button, .bq-stepper > input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.bq-stepper > input:focus { outline: none; }
/* The buttons reach over the box's 1 px border so each is the full 44 px
   target inside a 44 px box (Task 112b); from lg: they are 36 px wide so the
   124 px Qty column shows four digits. */
@media (min-width: 768px) { .bq-stepper > button { height: calc(100% + 2px); margin: -1px 0; } }
@media (min-width: 1024px) { .bq-stepper > button { width: 36px; } }
/* The stepper is the phone's (Task 122 item 5): from md: the editor's Qty is a
   plain box, like the row's. */
@media (min-width: 768px) { .bq-stepper > button { display: none; } .bq-stepper > input { text-align: right; padding: 0 10px; } }
.bq-editor-totalbox { display: flex; align-items: center; justify-content: flex-end; height: 48px; padding: 0 10px; border-radius: var(--r-input); background: rgb(var(--mist)); font-weight: 700; color: rgb(var(--ink)); }
@media (min-width: 768px) { .bq-editor-totalbox { height: 44px; } }
.bq-editor-numbers { margin: 0; font-size: 13px; color: rgb(var(--muted)); }
.bq-editor-numbers b { color: rgb(var(--ink)); font-weight: 700; }
.bq-editor-numbers b.is-money { color: rgb(var(--money-ink)); }
.bq-editor-more-btn { align-self: flex-start; padding: 0 4px; max-width: 100%; }
.bq-editor-more-short { display: none; }
@media (max-width: 767.98px) { .bq-editor-more-long { display: none; } .bq-editor-more-short { display: inline; } }
.bq-editor-more { display: flex; flex-direction: column; gap: 12px; }
.bq-editor-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.bq-editor-actions > * { min-height: 44px; }
.bq-editor-cancel { grid-column: 1 / -1; justify-self: start; }
@media (min-width: 768px) { .bq-editor-actions { display: flex; justify-content: flex-end; } .bq-editor-cancel { margin-right: auto; } .bq-editor-actions .bq-btn-outline, .bq-editor-actions .bq-btn-dark { min-height: 44px; padding: 0 20px; } }
.bq-btn-outline.is-danger { color: rgb(var(--danger)); }
/* The steel button: the editor's Done, the one dark control in the picture
   (never gold; gold is the page's own main action). */
.bq-btn-dark { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 44px; padding: 0 16px; border: 1px solid rgb(var(--brand2)); border-radius: var(--r-btn); background: rgb(var(--brand2)); color: rgb(var(--rail-active)); font-size: 14px; font-weight: 700; white-space: nowrap; cursor: pointer; transition: filter .15s ease, transform .08s ease; }
.bq-btn-dark:hover { filter: brightness(1.12); }
.bq-btn-dark:active { transform: scale(.97); }
.bq-btn-dark:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent)); }

/* The foot: Add line, From price list, Room, and Undo on the right. Two to a
   row on a phone, one row from md: up. */
.bq-work-nomatch { margin: 0; padding: 12px 16px; font-size: var(--fs-table); color: rgb(var(--muted)); }
.bq-work-foot { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.bq-work-foot .bq-btn-outline { min-height: 48px; font-size: 15px; }
/* A phone's two-to-a-row foot buttons keep their words inside 166 px (Task 122). */
@media (max-width: 767.98px) { .bq-work-foot .bq-btn-outline { padding: 4px 8px; white-space: normal; text-align: center; line-height: 1.2; } }
.bq-work-foot-spacer { display: none; }
@media (min-width: 768px) { .bq-work-foot { display: flex; align-items: center; gap: 8px; padding: 16px; border-top: 1px solid rgb(var(--line)); } .bq-work-foot .bq-btn-outline { min-height: 44px; font-size: 14px; } .bq-work-foot-spacer { display: block; flex: 1; } }
.bq-work-pricelist { padding: 0 0 4px; }
@media (min-width: 768px) { .bq-work-pricelist { padding: 0 16px 16px; } }
/* The adjuster's remarks fold keeps its old band under the foot. */
.bq-work > div[x-data] { border-top: 1px solid rgb(var(--line)); border-radius: var(--r-card); overflow: hidden; }
@media (min-width: 768px) { .bq-work > div[x-data] { border-radius: 0 0 var(--r-card) var(--r-card); } }

/* ---- The price panel ------------------------------------------------ */
.bq-pays-card { overflow: hidden; }
.bq-pays { padding: 16px; background: rgb(var(--totalbar)); color: rgb(var(--rail-icon)); }
.bq-pays-label { margin: 0; font-size: var(--fs-label); font-weight: 600; color: rgb(var(--rail-icon)); }
.bq-pays-total { margin: 4px 0 0; color: rgb(var(--rail-active)); }
.bq-pays-note { margin: 4px 0 0; font-size: var(--fs-table); color: rgb(var(--rail-icon)); }
.bq-pays-rows { margin: 0; padding: 8px 16px; display: flex; flex-direction: column; }
.bq-pays-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 36px; font-size: var(--fs-table); color: rgb(var(--muted)); }
.bq-pays-row dt { min-width: 0; }
.bq-pays-row dd { margin: 0; flex: none; font-size: 15px; font-weight: 700; color: rgb(var(--ink)); }
.bq-pays-row dd.is-money { color: rgb(var(--money-ink)); }
.bq-pays-link { display: inline-flex; align-items: center; gap: 4px; max-width: 100%; min-height: 36px; padding: 0; border: 0; background: none; color: rgb(var(--muted)); font-size: var(--fs-table); text-align: left; border-radius: var(--r-chip); }
.bq-pays-link:hover { color: rgb(var(--ink)); text-decoration: underline; text-underline-offset: 2px; }
.bq-pays-sub { color: rgb(var(--eyebrow)); white-space: nowrap; }
.bq-pays-fold { display: flex; flex-direction: column; gap: 12px; padding: 12px; margin: 4px 0 8px; border-radius: var(--r-input); background: rgb(var(--page)); font-size: var(--fs-table); color: rgb(var(--muted)); }
.bq-pays-more { margin: 0 16px 8px; }
.bq-pays-more-btn { margin: 0 12px 4px; padding: 0 4px; align-self: flex-start; }
/* Options (Task 122 item 6): one row, closed by default, over the cushion, the
   permit, the tax rule, the packages and "Show my numbers". */
.bq-pays-options-btn { display: inline-flex; align-items: center; gap: 4px; margin: 0 12px 8px; padding: 0 4px; min-height: 44px; align-self: flex-start; max-width: calc(100% - 24px); font-size: var(--fs-table); font-weight: 700; color: rgb(var(--ink)); }
.bq-pays-options-btn .bq-pays-sub { font-weight: 500; overflow: hidden; text-overflow: ellipsis; }
.bq-pays-options { display: flex; flex-direction: column; }
.bq-pays-rows--options { padding-top: 0; }
.bq-pays-contract { min-height: 44px; padding: 0 8px; font-size: 13px; white-space: normal; text-align: center; line-height: 1.2; }
.bq-pays-hint { margin: 0; font-size: var(--fs-label); color: rgb(var(--muted)); }
.bq-pays-numbers { padding: 8px 16px 16px; border-top: 1px solid rgb(var(--divider)); }
.bq-pays-switch { display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; min-height: 44px; }
.bq-pays-switch-label { font-size: 15px; font-weight: 700; color: rgb(var(--ink)); }
.bq-switch--bare { min-height: 24px; }
.bq-pays-mine { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; padding: 12px; border-radius: var(--r-input); background: rgb(var(--page)); }
.bq-pays-pill { align-self: flex-start; }
.bq-pays-shuffle { min-height: 36px; padding: 0 12px; font-size: 13px; }
.bq-range { width: 100%; height: 24px; margin: 0; accent-color: rgb(var(--brand2)); cursor: pointer; }
.bq-pays-actions { display: flex; flex-direction: column; gap: 8px; padding: 0 16px 16px; }
.bq-pays-actions .bq-btn-lg { width: 100%; }

/* ---- The one-line rows ----------------------------------------------- */
.bq-qb-rows { overflow: hidden; }
.bq-qb-rows-head { display: flex; flex-direction: column; gap: 2px; padding: 12px 16px; border-bottom: 1px solid rgb(var(--divider)); }
.bq-qb-rows-head b { font-family: var(--font-display); font-size: var(--fs-card); font-weight: 700; color: rgb(var(--ink)); }
.bq-qb-rows-head small { font-size: 13px; color: rgb(var(--muted)); }
.bq-qb-rows > .bq-qb-rows-head + div .bq-qb-section:first-child { border-top: 0; }
/* Job details from lg (Task 113b item 1): the six one-tap rows in two columns
   under the head, so the card is three rows tall and the work's column ends
   near the money column's. The wrappers the rows keep for the signed quote's
   tabs are `display: contents`, so each row is a cell of its own; an opened
   row takes the whole width, as its form was drawn for one column. */
@media (min-width: 1024px) {
  .bq-qb-rows.is-workbench { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 24px; align-items: start; }
  .bq-qb-rows.is-workbench > .bq-qb-rows-head { grid-column: 1 / -1; border-bottom: 0; }
  .bq-qb-rows.is-workbench > div:not(.bq-qb-rows-head) { display: contents; }
  .bq-qb-rows.is-workbench .bq-qb-section { border-top: 1px solid rgb(var(--divider)); }
  .bq-qb-rows.is-workbench .bq-qb-section:has(> .bq-qb-row[aria-expanded="true"]) { grid-column: 1 / -1; }
}
.bq-qb-section { border-top: 1px solid rgb(var(--divider)); }
.bq-qb-section:first-child { border-top: 0; }
.bq-qb-rows > [data-signed-panel] > .bq-qb-section:first-child, .bq-qb-rows > div > .bq-qb-section:first-child { border-top: 0; }
.bq-qb-rows > [data-signed-panel] + * .bq-qb-section:first-child, .bq-qb-rows > div + * .bq-qb-section:first-child { border-top: 1px solid rgb(var(--divider)); }
.bq-qb-row { border-top: 0; }
.bq-qb-row .bq-row-text b { font-size: 15px; }
.bq-qb-row .bq-row-text small { white-space: normal; }
.bq-qb-row .bq-chevron { flex: none; transition: transform .15s ease; }
.bq-qb-body { padding: 0 16px 16px; border-top: 1px solid rgb(var(--divider)); padding-top: 16px; }
.bq-qb-body > :first-child { margin-top: 0; }
.bq-qb-insurance { margin-bottom: 16px; }
.bq-qb-insurance:empty { display: none; }

/* ---- The phone's bar ------------------------------------------------- */
.bq-qb-bar { display: flex; align-items: center; gap: 12px; padding: 12px 16px; background: rgb(var(--totalbar)); color: rgb(var(--rail-icon)); }
/* The bar's mic (Task 122 item 4): a normal 44 px button with its word, not a
   52 px circle. */
.bq-qb-bar-mic { display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 44px; min-width: 44px; flex: none; padding: 0 12px; border-radius: var(--r-btn); background: rgb(var(--brand2)); border: 1px solid rgb(var(--rail-active) / .25); color: rgb(var(--rail-active)); font-size: 13px; font-weight: 700; }
.bq-qb-bar-mic:disabled { opacity: .5; }
.bq-qb-bar-label { margin: 0; font-size: var(--fs-label); color: rgb(var(--rail-icon)); }
.bq-qb-bar-total { margin: 0; font-family: var(--font-display); font-size: var(--fs-title); font-weight: 700; line-height: 1.1; color: rgb(var(--rail-active)); white-space: nowrap; }
.bq-qb-bar-go { flex: none; padding: 0 16px; }
/* Under 400 px the bar cannot hold the mic's word and the whole total at the
   title size: the total steps down one size and the mic becomes its 44 px icon
   button (aria-label still says "Add lines by voice"), so "$125,044.03" is
   never cut by the button beside it (Task 122c). From 400 px the word is back. */
@media (max-width: 399.98px) {
  .bq-qb-bar-mic-word { display: none; }
  .bq-qb-bar-mic { padding: 0; }
  .bq-qb-bar-total { font-size: var(--fs-card); }
}

/* ------------------------------------------------------------------ */
/* Task 113: the insurance workbench, inside the new quote builder     */
/* (`.ai/design/app/App-workbench-laptop.png`, Glenn approved 17 Oct   */
/* 2026; the phone follows the builder's phone picture). The same      */
/* page as the cash quote, with the claim's parts: the seven-step bar, */
/* the checks row, Theirs beside Yours, the flags, the band a group is */
/* read under, Total to send, and They wanted vs you found.            */
/* ------------------------------------------------------------------ */

/* The steps are buttons (a tap says what happened and when, Task 96a item
   2): the shell's look, a 44 px target, no button chrome. */
button.bq-step { display: flex; gap: 6px; background: none; border: 0; padding: 0; min-height: 44px; cursor: pointer; color: inherit; font: inherit; text-align: left; border-radius: var(--r-chip); }
button.bq-step:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--brand2)), 0 0 0 4px rgb(var(--accent)); }
/* A claim's seven names need the room: the words show from lg: there (the
   phone's sentence under the circles covers md: too). */
.bq-qb-header.is-workbench .bq-step-label { display: none; }
@media (min-width: 1024px) { .bq-qb-header.is-workbench .bq-step-label { display: block; } }
.bq-steps-line { display: none; margin: -4px 0 0; font-size: 13px; font-weight: 600; color: rgb(var(--rail-active)); }
.bq-qb-header.is-workbench .bq-steps-line { display: block; }
@media (min-width: 1024px) { .bq-qb-header.is-workbench .bq-steps-line { display: none; } }
.bq-step-detail { margin: -4px 0 0; padding: 8px 12px; border-radius: var(--r-input); background: rgb(var(--brand2-raised)); font-size: 13px; color: rgb(var(--on-steel-sub)); }
.bq-step-detail b { color: rgb(var(--rail-active)); font-weight: 700; }
.bq-step-detail .bq-btn-text { min-height: 32px; padding: 0 8px; color: rgb(var(--rail-active)); text-decoration: underline; text-underline-offset: 2px; }

/* The checks row: N cards share the width equally (four in the picture),
   one height, the words at the top. A phone (Task 122c) stacks them: one
   full-width 44 px chip a row, the icon and the title, the body folded into the
   chip's title attribute -- so the second card is whole and nothing is cut by
   the viewport's edge (the swipeable row of Task 113b item 4 hid the second
   card past the edge with no way to tell there was one). The problem strip's
   chip comes last on a phone, so the notices are a short list before the work,
   not a stack of one. */
.bq-checks { display: flex; flex-direction: column; gap: 8px; }
.bq-check { display: flex; gap: 8px; align-items: center; flex: none; width: 100%; min-height: 44px; height: auto; padding: 10px 12px 10px 8px; cursor: pointer; font: inherit; text-align: left; }
.bq-check .bq-check-body { display: none; }
.bq-check .bq-check-title { white-space: normal; }
.bq-check--problem { border: 1px solid rgb(var(--warn-edge)); background: rgb(var(--warn-tint)); }
.bq-check--problem .bq-check-title { color: rgb(var(--warn-ink)); }
/* The strip and its chip are never both drawn: x-show owns each one's own
   showing, and the width decides which of the two exists at all. */
@media (max-width: 767.98px) { .bq-qb-problem.is-workbench { display: none !important; } }
@media (min-width: 768px) {
  .bq-checks { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; overflow: visible; }
  .bq-check { display: flex; gap: 12px; align-items: flex-start; flex: initial; height: auto; min-height: 72px; padding: 12px 16px; cursor: default; }
  .bq-check .bq-check-body { display: block; }
  .bq-check .bq-check-title { white-space: normal; }
  .bq-check--problem { display: none !important; }
}
.bq-check-icon { flex: none; display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: var(--r-pill); background: rgb(var(--pill-grey)); color: rgb(var(--pill-grey-ink)); }
.bq-check-icon svg { width: 16px; height: 16px; }
.bq-check.is-ok .bq-check-icon { background: rgb(var(--pill-green)); color: rgb(var(--pill-green-ink)); }
.bq-check.is-amber .bq-check-icon { background: rgb(var(--pill-amber)); color: rgb(var(--pill-amber-ink)); }
.bq-check.is-red .bq-check-icon { background: rgb(var(--pill-red)); color: rgb(var(--pill-red-ink)); }
.bq-check-title { display: block; font-size: var(--fs-table); font-weight: 700; color: rgb(var(--ink)); line-height: 1.3; }
.bq-check-body { display: block; margin-top: 2px; font-size: 13px; color: rgb(var(--muted)); line-height: 1.4; }
.bq-check-action { display: inline-flex; align-items: center; min-height: 24px; padding: 0 2px; border: 0; background: none; font: inherit; font-weight: 700; color: rgb(var(--brand2-text)); cursor: pointer; border-radius: var(--r-chip); }
.bq-check-action:hover { text-decoration: underline; text-underline-offset: 2px; }
@media (max-width: 767.98px) { .bq-check-action { min-height: 44px; } }

/* The carrier's figure is its own column only from xl, where the work card is
   wide enough for eight columns (the grid above, on .is-workbench). Narrower,
   the page draws it under the line as "theirs $50.84" -- the phone's own words,
   never a dropped fact. */
.bq-col-theirs, .bq-line-theirs { display: none; }
@media (min-width: 1280px) {
  .bq-work.is-workbench .bq-col-theirs, .bq-work.is-workbench .bq-line-theirs { display: flex; align-items: center; justify-content: flex-end; min-width: 0; }
  .bq-line-theirs-phone { display: none; }
}
.bq-line-theirs { font-size: var(--fs-table); color: rgb(var(--muted)); white-space: nowrap; }
/* Between md and xl the carrier's figure reads under the line, where the phone
   puts it; `.bq-line-math` hides that line from md: up, so this wins it back
   for the one figure that has no column there. */
@media (min-width: 768px) and (max-width: 1279.98px) { .bq-line-theirs-phone { display: inline; } }
/* Yours, amber when it differs from theirs (Task 96b item 1): a fill and an
   edge, never a colour alone -- the flag under the description says why. */
.bq-line-price-box.is-amber { background: rgb(var(--warn-tint)); border-color: rgb(var(--accent-edge) / .55); color: rgb(var(--ink)); }

/* A flag under the description: the shared pill with its "?" on the end
   (24 px beside the words from md:, a 44 px target on a phone). A pill that
   names its code ("Zeroed out by insurance · IRC R905.2.8.5", Task 96c) is
   longer than the description's column at 1366; the words stay on ONE line
   (Task 122b) and end in an ellipsis inside the pill -- never a second line
   that doubles the row's height, never under the next column. */
.bq-line-flag { flex: 0 1 auto; max-width: 100%; height: auto; min-height: 24px; gap: 4px; padding: 2px 4px 2px 10px; white-space: nowrap; line-height: 1.25; }
/* The code behind a flag is its own gold chip after the "?" (Task 119 item 3),
   never joined to the label. */
.bq-line-flags .bq-chip.code { height: 24px; }
.bq-line-flag > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Every pill under a line obeys the description's column (Task 122b): a long
   one ("Option · client can add it") ends in an ellipsis rather than running
   under the money, and the words stay on one line. Scoped to the line row: the
   safety band's own pills wrap their OSHA citation instead (Task 96c). */
.bq-line .bq-line-flags .bq-pill { flex: 0 1 auto; min-width: 0; max-width: 100%; }
.bq-line .bq-line-flags .bq-pill > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bq-line-flag-why { display: inline-grid; place-items: center; flex: none; width: 24px; height: 24px; margin: 0 -2px 0 2px; border: 0; border-radius: var(--r-pill); background: none; color: inherit; cursor: pointer; }
.bq-line-flag-why svg { width: 14px; height: 14px; }
.bq-line-flag-why:hover { background: rgb(var(--ink) / .08); }
@media (max-width: 767.98px) { .bq-line-flag { min-height: 32px; } .bq-line-flag-why { width: 44px; height: 44px; margin: -6px -4px -6px 0; } }
/* The "?" panel under a line (Task 96c item 1): the editor's tinted block
   with the steel edge, holding three parts -- why it's flagged, the line from
   their PDF, what has to be added -- side by side from md: (24 px apart) and
   stacked on a phone (16 px). The same block, one part wide, is a suggestion
   row's "why it's missing". */
.bq-flagpanel { padding: 12px 16px 16px; background: rgb(var(--page)); border-top: 1px solid rgb(var(--divider)); box-shadow: inset 3px 0 0 rgb(var(--brand2)); font-size: 13px; line-height: 1.45; color: rgb(var(--muted)); }
.bq-flagpanel-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
@media (min-width: 768px) { .bq-flagpanel-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; } }
.bq-flagpanel-part { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.bq-flagpanel-eyebrow { margin: 0; font-size: var(--fs-label); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: rgb(var(--eyebrow)); }
.bq-flagpanel-part > b, .bq-flagpanel-add > b { display: block; color: rgb(var(--ink)); font-size: var(--fs-table); font-weight: 700; }
.bq-flagpanel p { margin: 0; }
.bq-flagpanel-rule { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.bq-flagpanel-code b, .bq-flagpanel-inline { color: rgb(var(--ink)); font-weight: 700; }
.bq-flagpanel-code .bq-link { margin-left: 4px; font-size: 13px; }
.bq-flagpanel .is-needs { color: rgb(var(--ink)); font-weight: 600; }
.bq-flagpanel-values { display: flex; flex-wrap: wrap; gap: 4px 16px; }
.bq-flagpanel-value b { color: rgb(var(--ink)); font-weight: 700; }
.bq-flagpanel-value.is-wrong b { color: rgb(var(--danger)); }
.bq-flagpanel-strip { width: 100%; }
.bq-flagpanel-add { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.bq-flagpanel-actions { display: flex; flex-wrap: wrap; gap: 8px; padding-top: 4px; }
.bq-flagpanel-actions .bq-btn-outline { min-height: 44px; }
@media (max-width: 767.98px) { .bq-flagpanel-actions { width: 100%; } .bq-flagpanel-actions .bq-btn-outline { flex: 1 1 0; } }

/* Safety and labour they left out (Task 96c item 3): a room of its own under
   the amber band, one 56 px row a suggestion -- the item with its money line
   and its state on the left, the "?" and the two answers on the right (every
   target 44 px); on a phone the answers take the row's whole width. The
   working behind the figure lives in the row's "?", with the why. */
.bq-suggest-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; min-height: 56px; padding: 6px 16px; }
.bq-suggest-text { flex: 1 1 240px; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 12px; row-gap: 2px; }
.bq-suggest-text > b { font-size: 15px; font-weight: 600; color: rgb(var(--ink)); line-height: 1.3; }
/* The row's title and its "?" on one line (Task 129b item 3): the "?" follows
   the words it explains instead of standing alone at the row's other end. */
.bq-suggest-title { display: inline-flex; align-items: center; gap: 4px; min-width: 0; }
.bq-suggest-title > b { min-width: 0; }
.bq-suggest-why { display: inline-grid; place-items: center; flex: none; width: 44px; height: 44px; margin: -12px -12px -12px -6px; border: 0; border-radius: var(--r-pill); background: none; color: rgb(var(--muted)); cursor: pointer; }
.bq-suggest-why svg { width: 16px; height: 16px; }
.bq-suggest-why:hover { background: rgb(var(--ink) / .08); color: rgb(var(--ink)); }
.bq-suggest-text > small { font-size: 13px; color: rgb(var(--muted)); }
.bq-suggest-text .bq-line-flags { margin-top: 0; }
.bq-suggest-actions { flex: none; display: flex; align-items: center; gap: 8px; margin-left: auto; }
.bq-suggest-actions .bq-btn-outline { min-height: 44px; }
.bq-suggest-wrap.is-not-needed .bq-suggest-text b { color: rgb(var(--muted)); text-decoration: line-through; }
/* The rule's pill ("Required by law · OSHA 29 CFR 1926.501(b)(13) and 1926.503")
   wraps inside the row like a line's flag does, never clipped at the card's edge. */
.bq-suggest-text .bq-pill { flex: 0 1 auto; max-width: 100%; height: auto; min-height: 24px; padding-top: 2px; padding-bottom: 2px; white-space: normal; line-height: 1.25; }
/* A phone's band says its whole name on two lines rather than an ellipsis. */
@media (max-width: 767.98px) { .bq-room-band { white-space: normal; line-height: 1.2; } }
@media (max-width: 767.98px) { .bq-suggest-actions { width: 100%; margin-left: 0; } .bq-suggest-actions .bq-btn-outline { flex: 1 1 0; } }

/* The band a claim's group is read under: steel words for a room and its
   pages, red for money behind their totals page, amber for work left out. */
.bq-room-band { flex: 1 1 auto; max-width: none; }
.bq-room-bar.is-red { background: rgb(var(--pill-red)); }
.bq-room-bar.is-red .bq-room-band, .bq-room-bar.is-red .bq-room-total { color: rgb(var(--pill-red-ink)); }
.bq-room-bar.is-amber { background: rgb(var(--pill-amber)); }
.bq-room-bar.is-amber .bq-room-band, .bq-room-bar.is-amber .bq-room-total { color: rgb(var(--pill-amber-ink)); }

/* The editor's Their price on a claim: a read-only box like the total's, in
   the claim's own number row (see the two-row editor above, Task 129d). */

/* The foot's walkthrough on a claim. */
.bq-work-talk { gap: 8px; }

/* The panel's adjuster fold, under the buttons. */
.bq-pays-adjuster { margin: 0 16px 16px; padding: 12px; border-radius: var(--r-input); background: rgb(var(--page)); border: 1px solid rgb(var(--line)); }
.bq-pays-adjuster .bq-btn-outline, .bq-pays-adjuster .bq-btn-dark { width: 100%; }
.bq-pays-adjuster a.bq-btn-outline { text-decoration: none; }
/* The reply-by-email word (Task 128d item 2): "Their reply came by email? Add
   it" was cut off at the card's right edge, which is why it now says "Reply by
   email? Attach it" -- and its own rule lets it wrap rather than clip. */
.bq-pays-reply { width: 100%; margin-top: 4px; justify-content: flex-start; gap: 6px; text-align: left; white-space: normal; }

/* They wanted vs you found: two columns of 20 px figures, one line under. */
.bq-found { padding: 16px 20px; }
.bq-found-cols { margin-top: 12px; }
.bq-found-cols small { display: block; font-size: 13px; color: rgb(var(--muted)); }
.bq-found-cols b { display: block; margin-top: 2px; font-family: var(--font-display); font-size: var(--fs-card); font-weight: 700; color: rgb(var(--muted)); letter-spacing: -.01em; white-space: nowrap; }
/* The money column is 260 px from xl (Task 122b), so the box's card is 218 px:
   Task 128d put each label on its own line and the two figures in the head's own
   96 px columns, where "$125,044.03" at 15 px is ~88 px and fits on one line. */
@media (min-width: 1280px) {
  .bq-qb-grid.has-side .bq-found-cols b { font-size: 15px; }
}
.bq-found-cols b.is-steel { color: rgb(var(--brand2-text)); }
.bq-found-line { margin: 12px 0 0; font-size: 13px; font-weight: 700; color: rgb(var(--muted)); }
.bq-found-line.is-up { color: rgb(var(--money-ink)); }
.bq-found-line.is-down { color: rgb(var(--danger)); }

/* ------------------------------------------------------------------ */
/* Task 114: Settings, built to Glenn's approved design                */
/* (`.ai/design/app/Settings-laptop.png`, `-laptop-proposal.png`,      */
/* `-phone.png` and `-phone-getpaid.png`, 17 Oct 2026). Flat rules on  */
/* the tokens, like the rest of the house stylesheet.                  */
/* ------------------------------------------------------------------ */

/* The page owns its own edges: the white header band and the 240 px menu run
   from the rail to the right edge, so the shell's gutters and 1200 px ceiling
   come off `main` here and the page puts them back inside its content column.
   Sideways overflow is left visible so the proposal preview can stick under
   the top bar (an overflow on `main` would make it the sticky container);
   the browser test walks every element for a right edge past the viewport. */
.bq-shell--settings .bq-main { max-width: none; padding: 0; overflow-x: visible; }
.bq-set { display: flex; flex-direction: column; min-height: 100%; }
/* The page took the shell's gutters off `main`, so it puts the phone's tab-bar
   clearance back itself (Task 115: the list's last row sat under the bar). */
.bq-set { padding-bottom: calc(var(--tabbar-h) + 16px + env(safe-area-inset-bottom, 0px)); }
.bq-set.has-bar { padding-bottom: max(96px, calc(var(--tabbar-h) + 24px + env(safe-area-inset-bottom, 0px))); }
@media (min-width: 768px) { .bq-set { padding-bottom: 0; } .bq-set.has-bar { padding-bottom: 72px; } }

/* The header band: the title over the search on a phone (44 + 48, 12 apart,
   16 px gutters), one 72 px row from md: with the 320 px box on the right. */
.bq-set-head { background: rgb(var(--surface)); border-bottom: 1px solid rgb(var(--line)); }
.bq-set-head-row { display: flex; flex-direction: column; gap: 12px; padding: 16px; }
.bq-set-head-row .bq-h1 { display: flex; align-items: center; min-height: 44px; flex: 1; }
@media (min-width: 768px) { .bq-set-head-row { flex-direction: row; align-items: center; gap: 16px; height: 72px; padding: 0 24px; } }
@media (min-width: 768px) { .bq-set-head-row .bq-h1 { min-height: 0; } }
.bq-set-find { position: relative; min-width: 0; }
.bq-set-find .bq-search { width: 100%; }
@media (min-width: 768px) { .bq-set-find { width: 320px; flex: none; } }
.bq-set-find-list { position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 35; max-height: 320px; overflow-y: auto; padding: 4px; box-shadow: 0 12px 32px -16px rgb(0 0 0 / .35); }
.bq-set-find-item { display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; min-height: 48px; padding: 0 12px; border: 0; border-radius: var(--r-input); background: none; text-align: left; cursor: pointer; }
.bq-set-find-item:hover, .bq-set-find-item.is-active { background: rgb(var(--mist)); }
.bq-set-find-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; font-weight: 600; color: rgb(var(--ink)); }
.bq-set-find-where { flex: none; font-size: 12px; font-weight: 700; color: rgb(var(--eyebrow)); white-space: nowrap; }
.bq-set-find-none { position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 35; margin: 0; padding: 12px; border: 1px solid rgb(var(--line)); border-radius: var(--r-card); background: rgb(var(--surface)); font-size: 14px; color: rgb(var(--muted)); }

/* A phone's section header: steel, like a job page's, with the way back. */
.bq-set-steel { background: rgb(var(--brand2)); color: rgb(var(--on-steel-sub)); padding: 12px 16px 16px; }
.bq-set-steel .bq-h1 { color: rgb(var(--rail-active)); margin-top: 8px; }
.bq-set-steel .bq-steel-line { margin: 4px 0 0; font-size: 14px; color: rgb(var(--on-steel-sub)); }
.bq-set-back { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; padding: 0 8px 0 0; border: 0; background: none; color: rgb(var(--rail-active)); font-size: 14px; font-weight: 700; cursor: pointer; }
.bq-set-back:hover { text-decoration: underline; text-underline-offset: 2px; }
@media (min-width: 768px) { .bq-set-steel { display: none !important; } }

/* The body: the 240 px menu beside the content from md: up. */
.bq-set-body { display: flex; flex: 1; align-items: stretch; min-width: 0; }
.bq-set-menu { display: none; }
@media (min-width: 768px) { .bq-set-menu { display: block; width: 240px; flex: none; padding: 8px 12px 24px; border-right: 1px solid rgb(var(--line)); background: rgb(var(--surface)); } }
.bq-set-menu .bq-eyebrow { display: flex; align-items: center; gap: 8px; margin: 16px 12px 6px; }
.bq-set-menu .bq-eyebrow svg { width: 14px; height: 14px; }
.bq-set-menu-item { display: flex; align-items: center; width: 100%; min-height: 40px; padding: 0 12px; border: 0; border-radius: var(--r-input); background: none; color: rgb(var(--ink)); font-size: 14px; font-weight: 500; text-align: left; cursor: pointer; transition: background .15s ease, transform .08s ease; }
.bq-set-menu-item:hover { background: rgb(var(--mist) / .5); }
.bq-set-menu-item:active { transform: scale(.98); }
.bq-set-menu-item.is-active { background: rgb(var(--mist)); color: rgb(var(--brand2-text)); font-weight: 700; box-shadow: inset 3px 0 0 rgb(var(--brand2)); }
.bq-set-content { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 12px; padding: 16px; }
@media (min-width: 768px) { .bq-set-content { gap: 16px; padding: 24px; } }

/* The phone's list: an eyebrow 8 px over its card, groups 12 apart. */
.bq-set-list { display: flex; flex-direction: column; gap: 12px; }
.bq-set-list-group { display: flex; flex-direction: column; gap: 8px; }
.bq-set-list .bq-eyebrow { display: flex; align-items: center; gap: 8px; }
.bq-set-list .bq-eyebrow svg { width: 14px; height: 14px; }
.bq-set-list .bq-row { color: rgb(var(--ink)); }

/* Sections and cards: a title (18 px from md:), one line of purpose, then the
   fields two to a row from md: up. */
.bq-set-section { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
@media (min-width: 768px) { .bq-set-section { gap: 16px; } }
.bq-set-card { display: flex; flex-direction: column; gap: 12px; padding: 16px; min-width: 0; }
@media (min-width: 768px) { .bq-set-card { gap: 16px; padding: 20px 24px; } }
.bq-set-card-head { display: flex; align-items: flex-start; gap: 12px; }
.bq-set-card-head > div:first-child { flex: 1; min-width: 0; }
.bq-set-card .bq-h2 { font-size: 17px; }
@media (min-width: 768px) { .bq-set-card .bq-h2 { font-size: 18px; } }
.bq-set-why { margin: 2px 0 0; font-size: 13px; color: rgb(var(--muted)); }
@media (min-width: 768px) { .bq-set-why { font-size: 14px; } }
/* Task 115b: on a phone the steel header above the card already says the
   section's name and what it is for, so the card under it does not say it a
   second time. `data-dup-title` marks the repeating title-and-purpose block --
   or the whole head, when the title is all the head holds and an empty one
   would leave a gap. A head that also holds a pill or a button keeps it, on the
   right edge where it sits on a tablet and a laptop. Tablet and laptop have no
   steel header, so the card keeps its own title there. */
@media (max-width: 767.98px) {
  .bq-set-section [data-dup-title] { display: none; }
  .bq-set-section .bq-set-card-head { justify-content: flex-end; }
}
.bq-set-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
@media (min-width: 768px) { .bq-set-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; } }
.bq-set-grid .is-wide { grid-column: 1 / -1; }
.bq-set-field { min-width: 0; }
.bq-set-label { display: block; margin: 0 0 4px; font-size: 12px; font-weight: 700; color: rgb(var(--muted)); }
.bq-set .bq-input { min-height: 48px; font-size: 15px; }
@media (max-width: 767.98px) { .bq-set .bq-input { font-size: var(--fs-body); } }
.bq-set-hint { margin: 4px 0 0; font-size: 12px; color: rgb(var(--muted)); }
.bq-set-error { margin: 4px 0 0; font-size: 12px; font-weight: 600; color: rgb(var(--danger)); }
.bq-set-ok { margin: 0; font-size: 13px; font-weight: 600; color: rgb(var(--money)); }

/* A row with its switch on the right: 44 px, a hairline over each. The
   switch's label stays the house 44 px target (clinerules section 3). */
.bq-set-rows { display: flex; flex-direction: column; }
.bq-set-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 44px; border-top: 1px solid rgb(var(--divider)); }
.bq-set-row-text { display: flex; flex-direction: column; min-width: 0; font-size: 14px; color: rgb(var(--body)); }
.bq-set-row-text b { color: rgb(var(--ink)); font-weight: 600; }
.bq-set-row-text small { font-size: 12px; color: rgb(var(--muted)); }
/* A row's title and its "?" on one line (Task 129b item 3): the "?" follows the
   words it explains, never alone at the other end of the row. */
.bq-set-row-title { display: flex; align-items: center; gap: 4px; min-width: 0; }
.bq-set-row-title > b { min-width: 0; }
.bq-set-why-btn { display: inline-grid; place-items: center; flex: none; width: 44px; height: 44px; margin: -12px -12px -12px -6px; border: 0; border-radius: var(--r-pill); background: none; color: rgb(var(--muted)); cursor: pointer; }
.bq-set-why-btn svg { width: 16px; height: 16px; }
.bq-set-why-btn:hover { background: rgb(var(--ink) / .08); color: rgb(var(--ink)); }
.bq-set-row-right { display: flex; align-items: center; gap: 12px; flex: none; }

/* A payment method: its name and switch on one row (44 px, the switch's
   own target), the box under it. */
.bq-set-method { display: flex; flex-direction: column; gap: 4px; padding-top: 8px; border-top: 1px solid rgb(var(--divider)); }
.bq-set-method-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 44px; }
.bq-set-method-head b { color: rgb(var(--ink)); font-size: 14px; }

/* The logo tile: 96 px, a dashed edge, the picture inside. */
.bq-set-logo-row { display: flex; align-items: center; gap: 16px; }
.bq-set-logo { display: grid; place-items: center; width: 96px; height: 96px; flex: none; overflow: hidden; padding: 6px; border: 1px dashed rgb(var(--edge)); border-radius: var(--r-card); background: rgb(var(--page)); color: rgb(var(--brand2-text)); font-size: 12px; font-weight: 700; text-align: center; cursor: pointer; }
.bq-set-logo img { max-width: 100%; max-height: 100%; object-fit: contain; }
.bq-set-logo-row > div { display: flex; flex-direction: column; gap: 8px; min-width: 0; }

/* The segmented control in these pictures: one bordered box, equal segments,
   the chosen one steel. `.bq-seg--steel` on top of the house `.bq-seg`;
   `.bq-seg--thirds` lets a long list (the six layouts) wrap three to a row. */
.bq-seg--steel { gap: 0; padding: 0; border: 1px solid rgb(var(--edge)); border-radius: var(--r-btn); background: rgb(var(--surface)); overflow: hidden; flex-wrap: wrap; }
.bq-seg--steel > button { flex: 1 1 0; min-width: 0; min-height: 42px; border-radius: 0; color: rgb(var(--brand2-text)); font-size: 14px; }
.bq-seg--steel > button[aria-pressed="true"], .bq-seg--steel > button[aria-checked="true"] { background: rgb(var(--brand2)); color: rgb(var(--rail-active)); box-shadow: none; }
.bq-seg--thirds > button { flex: 1 1 30%; }

/* Task 115b: a segmented control whose labels are long (the Display card's
   Light / Dark / Match my phone). Equal segments, and the control grows to the
   longest label instead of squeezing three fixed thirds and cutting "Match my
   phone" off at the edge. From lg: up that is one row of three; below lg: the
   card is narrower than three full labels, so the control takes the field's
   whole width and that one label wraps onto a second line -- every segment
   still the same width, and 52 px tall (a 48 px target plus the border). */
.bq-seg--fit {
  display: inline-grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  width: max-content;
  max-width: 100%;
}
.bq-seg--fit > button { min-width: 0; }
@media (max-width: 1023.98px) {
  .bq-seg--fit { display: grid; width: 100%; }
  .bq-seg--fit > button { white-space: normal; line-height: 1.15; padding: 0 6px; min-height: 52px; }
  .bq-seg--fit > button svg { flex-shrink: 0; }
}

/* Colour swatches: 44 px, the chosen one ringed in steel. */
.bq-set-swatches { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.bq-set-swatch { width: 44px; height: 44px; flex: none; border: 0; border-radius: var(--r-btn); cursor: pointer; transition: transform .08s ease; }
.bq-set-swatch:active { transform: scale(.96); }
.bq-set-swatch[aria-checked="true"] { box-shadow: 0 0 0 3px rgb(var(--surface)), 0 0 0 5px rgb(var(--brand2)); }
.bq-set-swatch:focus-visible { outline: none; box-shadow: 0 0 0 2px rgb(var(--surface)), 0 0 0 4px rgb(var(--accent)); }
.bq-set-logo-strip { display: flex; align-items: center; gap: 12px; padding: 12px; border: 1px solid rgb(var(--line)); border-radius: var(--r-card); background: rgb(var(--page)); }
.bq-set-logo-strip img { width: 80px; height: 48px; flex: none; object-fit: contain; }

/* The proposal look: the controls with the live preview beside them from lg:
   (under them before that), the preview sticking under the top bar. */
.bq-set-proposal { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; align-items: start; }
@media (min-width: 768px) { .bq-set-proposal { gap: 16px; } }
@media (min-width: 1024px) { .bq-set-proposal { grid-template-columns: minmax(0, 1fr) 420px; } }
.bq-set-proposal-main { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
@media (min-width: 768px) { .bq-set-proposal-main { gap: 16px; } }
.bq-set-preview { padding: 16px; background: rgb(var(--mist)); border-color: rgb(var(--mist)); min-width: 0; }
@media (min-width: 1024px) { .bq-set-preview { position: sticky; top: calc(var(--topbar-h-lg) + 16px); } }
.bq-set-preview .bq-eyebrow { margin: 0 0 8px; }
/* Task 128c item 4: the preview is the renderer's own 816 px Letter document,
   drawn at that width and scaled down to the card -- before this it was redrawn
   388 px wide and the right edge of the page was cut off. `--bq-preview-scale`
   is measured by fitPreview(); the height inverts the scale so the card keeps
   the same height and shows more of the page, not a letterboxed slice. */
.bq-set-preview-frame-wrap { position: relative; width: 100%; height: 44rem; overflow: hidden; border-radius: var(--r-input); background: rgb(var(--surface)); box-shadow: 0 10px 30px -15px rgb(0 0 0 / .35); }
.bq-set-preview-frame { position: absolute; top: 0; left: 0; width: 816px; height: calc(44rem / var(--bq-preview-scale, .5)); border: 0; border-radius: var(--r-input); background: rgb(var(--surface)); transform-origin: top left; transform: scale(var(--bq-preview-scale, .5)); }

/* Finish setting up: the amber card, its bar and the six steps. */
.bq-set-setup { gap: 12px; background: rgb(var(--warn-tint)); border-color: rgb(var(--warn-edge)); }
.bq-set-setup-row { display: flex; align-items: center; gap: 12px; min-height: 32px; }
.bq-set-setup-row > b { flex: 1; min-width: 0; color: rgb(var(--ink)); font-size: 14px; }
.bq-set-setup-next { flex: none; min-height: 44px; margin: -6px 0; padding: 0 4px; border: 0; background: none; color: rgb(var(--brand2-text)); font-size: 14px; font-weight: 700; cursor: pointer; }
.bq-set-setup-next:hover { text-decoration: underline; text-underline-offset: 2px; }
.bq-set-setup .bq-icon-quiet { display: none; margin: -6px -12px -6px 0; }
@media (min-width: 768px) { .bq-set-setup .bq-icon-quiet { display: inline-grid; } }
.bq-set-progress { height: 6px; border-radius: 3px; background: rgb(var(--accent) / .25); overflow: hidden; }
.bq-set-progress > div { height: 100%; border-radius: 3px; background: rgb(var(--accent)); transition: width .2s ease; }
.bq-set-setup-pills { display: none; flex-wrap: wrap; gap: 8px; }
@media (min-width: 768px) { .bq-set-setup-pills { display: flex; } }
.bq-set-setup-pill { height: 32px; border: 0; cursor: pointer; }
.bq-set-setup-pill:not(.is-done) svg { display: none; }

/* The pinned save bar: only there with unsaved changes. Fixed across the
   bottom (over the phone's tab bar), from the menu's right edge from md: up. */
.bq-set-savebar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 45; display: flex; align-items: center; gap: 12px; padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px)); background: rgb(var(--surface)); border-top: 1px solid rgb(var(--line)); }
.bq-set-savebar .bq-btn-outline { flex: 1; }
.bq-set-savebar .bq-btn { flex: 2; justify-content: center; }
.bq-set-unsaved { display: none; }
@media (min-width: 768px) { .bq-set-savebar { left: calc(var(--rail-w) + 240px); height: 72px; padding: 0 24px; } }
/* Both of its buttons are the main action's size (48 px): the outline's own
   44 px minimum comes later in this file, so it is said again here. */
.bq-set-savebar .bq-btn-outline, .bq-set-savebar .bq-btn { min-height: 48px; }
@media (min-width: 768px) { .bq-set-savebar .bq-btn-outline, .bq-set-savebar .bq-btn { flex: none; } }
@media (min-width: 768px) { .bq-set-unsaved { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; color: rgb(var(--warn-ink)); font-size: 14px; font-weight: 600; } }

/* Display: each choice with a small live sample beside its switch. The dark
   sample is dark whichever look is on, so it reads the always-dark token. */
.bq-set-sample { display: inline-flex; align-items: center; justify-content: center; gap: 4px; min-width: 56px; height: 32px; padding: 0 8px; border: 1px solid rgb(var(--line)); border-radius: var(--r-input); background: rgb(var(--surface)); color: rgb(var(--ink)); font-size: 14px; font-weight: 700; white-space: nowrap; }
.bq-set-sample--dark { background: rgb(var(--totalbar)); color: rgb(var(--rail-active)); border-color: rgb(var(--totalbar)); }
.bq-set-sample--large { font-size: 18px; }
.bq-set-sample--dyslexia { font-family: 'OpenDyslexic', 'Lexend', var(--font-sans); letter-spacing: .03em; }
.bq-set-sample-dot { width: 10px; height: 10px; border-radius: 50%; background: rgb(var(--accent)); }
.bq-set-sample .bq-pill { height: 20px; padding: 0 8px; font-size: 11px; }

/* A crew role: its name, who is in it, what it costs an hour. */
.bq-set-role { display: flex; flex-direction: column; gap: 8px; padding: 12px; border: 1px solid rgb(var(--line)); border-radius: var(--r-card); }
.bq-set-role-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px; }
.bq-set-role-row .bq-set-field { flex: 1 1 160px; }
.bq-set-role-row .bq-set-field.is-rate { flex: 0 1 128px; }

/* The contract's quick tags and the two drop zones. */
.bq-set-tags { display: flex; flex-wrap: wrap; gap: 8px; }
.bq-set-tag { min-height: 36px; padding: 0 10px; border: 1px solid rgb(var(--edge)); border-radius: var(--r-chip); background: rgb(var(--page)); color: rgb(var(--ink)); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; cursor: pointer; }
.bq-set-tag:hover { border-color: rgb(var(--brand2)); }
.bq-set-drop { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; padding: 24px 16px; border: 2px dashed rgb(var(--edge)); border-radius: var(--r-card); background: rgb(var(--page)); text-align: center; cursor: pointer; }
.bq-set-drop:hover { border-color: rgb(var(--brand2)); }
.bq-set-drop p { margin: 0; font-size: 13px; color: rgb(var(--muted)); }
.bq-set-drop p.is-title { font-size: 14px; font-weight: 600; color: rgb(var(--ink)); }
.bq-set-drop svg { color: rgb(var(--brand2-text)); }

/* The plan picker's three cards. */
.bq-set-plans { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
@media (min-width: 768px) { .bq-set-plans { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; } }
.bq-set-plan { display: flex; flex-direction: column; gap: 8px; padding: 16px; border: 1px solid rgb(var(--line)); border-radius: var(--r-card); background: rgb(var(--surface)); }
.bq-set-plan.is-current { border-color: rgb(var(--brand2)); background: rgb(var(--mist) / .5); }
.bq-set-plan-price { display: flex; align-items: baseline; gap: 6px; font-family: var(--font-display); font-size: 24px; font-weight: 700; color: rgb(var(--ink)); font-variant-numeric: tabular-nums; }
.bq-set-plan-price small { font-size: 12px; font-weight: 500; color: rgb(var(--muted)); }
.bq-set-plan ul { display: flex; flex-direction: column; gap: 6px; flex: 1; margin: 0; padding: 0; list-style: none; font-size: 13px; color: rgb(var(--body)); }
.bq-set-plan li { display: flex; align-items: flex-start; gap: 6px; }
.bq-set-plan li svg { width: 14px; height: 14px; flex: none; margin-top: 2px; color: rgb(var(--brand2-text)); }

/* Notes, empty states, skeletons and the actions row. */
.bq-set-note { padding: 12px 16px; border: 1px solid rgb(var(--line)); border-radius: var(--r-card); background: rgb(var(--page)); font-size: 13px; color: rgb(var(--body)); }
.bq-set-note p { margin: 0; }
.bq-set-note p + p { margin-top: 4px; }
.bq-set-note.is-danger { border-color: rgb(var(--danger) / .4); background: rgb(var(--danger-tint)); color: rgb(var(--danger)); }
.bq-set-note.is-warn { border-color: rgb(var(--warn-edge)); background: rgb(var(--warn-tint)); color: rgb(var(--ink)); }
.bq-set-note.is-steel { border-color: rgb(var(--brand2) / .4); background: rgb(var(--mist) / .6); color: rgb(var(--ink)); }
.bq-set-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.bq-set-empty { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 24px 16px; border: 1px solid rgb(var(--line)); border-radius: var(--r-card); background: rgb(var(--page)); text-align: center; font-size: 13px; color: rgb(var(--muted)); }
.bq-set-empty svg { color: rgb(var(--brand2-text)); }
.bq-set-empty b { font-size: 15px; color: rgb(var(--ink)); }
.bq-set-skel { height: 64px; border-radius: var(--r-card); }
.bq-set-list-cards { display: flex; flex-direction: column; gap: 8px; }
.bq-set-list-cards .bq-row { border: 1px solid rgb(var(--line)); border-radius: var(--r-card); }

/* ------------------------------------------------------------------ */
/* Task 115: Settings -> Account (sign-in and security, download your  */
/* data, close your account). Same tokens, same 4/8/16/24 steps.       */
/* ------------------------------------------------------------------ */

/* A form that opens under its row: page tint, 12 px inside, 12 px apart. */
.bq-set-panel { display: flex; flex-direction: column; gap: 12px; padding: 12px 16px; border: 1px solid rgb(var(--line)); border-radius: var(--r-card); background: rgb(var(--page)); }
.bq-set-row .bq-set-row-right .bq-btn-outline { min-height: 44px; }
.bq-set-row-text small .bq-pill { height: 20px; padding: 0 8px; font-size: 11px; vertical-align: middle; }
.text-warn-ink { color: rgb(var(--warn-ink)); }

/* The password meter: four bars, the reading in words beside them. Never
   colour alone -- the word is the meaning, the bars are the picture. */
.bq-set-meter { display: flex; gap: 4px; margin-top: 8px; }
.bq-set-meter span { flex: 1; height: 6px; border-radius: 3px; background: rgb(var(--mist)); }
.bq-set-meter.is-1 span:nth-child(-n+1) { background: rgb(var(--danger)); }
.bq-set-meter.is-2 span:nth-child(-n+2) { background: rgb(var(--accent)); }
.bq-set-meter.is-3 span:nth-child(-n+3) { background: rgb(var(--brand2)); }
.bq-set-meter.is-4 span:nth-child(-n+4) { background: rgb(var(--money)); }

/* Two-step: the QR beside the steps from md:, under them on a phone. */
.bq-set-twostep { display: flex; flex-direction: column; gap: 16px; }
@media (min-width: 768px) { .bq-set-twostep { flex-direction: row; align-items: flex-start; } }
.bq-set-qr { width: 192px; height: 192px; flex: none; padding: 8px; border: 1px solid rgb(var(--line)); border-radius: var(--r-card); background: rgb(var(--surface)); }
.bq-set-key { margin: 4px 0 0; padding: 8px 12px; border: 1px dashed rgb(var(--edge)); border-radius: var(--r-input); background: rgb(var(--surface)); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 14px; letter-spacing: .06em; color: rgb(var(--ink)); word-break: break-all; }
.bq-set-code-input { max-width: 220px; font-family: var(--font-display); font-size: 22px; font-weight: 700; letter-spacing: .25em; text-align: center; font-variant-numeric: tabular-nums; }
.bq-set-codes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 12px; }
@media (min-width: 768px) { .bq-set-codes { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
.bq-set-codes span { display: flex; align-items: center; justify-content: center; min-height: 44px; border: 1px solid rgb(var(--line)); border-radius: var(--r-input); background: rgb(var(--surface)); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 15px; font-weight: 700; letter-spacing: .04em; color: rgb(var(--ink)); }

/* The one danger-edged card on the page, and its quiet danger button. The
   confirm itself is .bq-btn-danger, inside the opened panel only. */
.bq-set-danger-card { border-color: rgb(var(--danger) / .6); }
.bq-btn-outline.is-danger { color: rgb(var(--danger)); border-color: rgb(var(--danger) / .6); }
.bq-btn-outline.is-danger:hover { background: rgb(var(--danger-tint)); }
.bq-set .bq-btn-danger { min-height: 44px; padding: 0 16px; font-weight: 700; }
.bq-set .bq-btn-strong { min-height: 44px; padding: 0 16px; font-size: .875rem; font-weight: 700; }
.bq-set .bq-set-note .bq-link { font-weight: 700; }

/* The sign-in history on a phone: the moment goes under the words instead of
   squeezing "Signed in" to one letter (seen in the Task 115 screenshots). */
@media (max-width: 767.98px) {
  .bq-set-list-cards .bq-row { flex-wrap: wrap; row-gap: 4px; }
  .bq-set-when { flex-basis: 100%; padding-left: 0; }
}

/* ------------------------------------------------------------------ */
/* Task 96d: the right-hand panel and the found-vs-theirs box.         */
/* The money column stays in view while the work scrolls (sticky under */
/* the top bar from lg:); on a phone the panel is a sheet opened from  */
/* the Your numbers row, and the found box sits under the lines with   */
/* its rows behind one tap. Tokens only, as every rule above.          */
/* ------------------------------------------------------------------ */
@media (min-width: 1280px) {
  /* Task 128a item 8: the money column is `sticky` 16 px under the top bar
     (top-4) and starts at the top of its grid area, so the work scrolls beside
     a column that stays where it is. A height cap with its own scrollbar was
     tried and taken back out: it made the panel's own buttons unreachable to a
     real click (the browser suite's "intercepts pointer events"). */
  .bq-qb-grid.is-workbench .bq-qb-side {
    position: sticky;
    top: calc(var(--topbar-h-lg) + 16px);
    align-self: start;
  }
}
@media (min-width: 1024px) {
  /* The quote page is the one page with `bq-shell--no-tabbar` (its own bar
     at the foot). Its sideways overflow is left visible so the money column
     can stick under the top bar -- an `overflow-x: hidden` on `main` makes
     main the sticky container (the Settings page's rule above says the
     same); the browser test asserts `scrollWidth <= viewport` at every width. */
  .bq-shell--no-tabbar .bq-main { overflow-x: visible; }
}
/* The phone's Your numbers row: drawn below md on a claim only. */
.bq-numbers-row { display: none; overflow: hidden; }
@media (max-width: 767px) { .bq-qb-grid.is-workbench .bq-numbers-row { display: block; } }
.bq-numbers-row .bq-row { border-top: 0; }
/* The panel as a phone's sheet: hidden in the flow, full screen when open,
   with its own head (the name and a 44 px close). */
.bq-pays-sheet-head { display: none; }
@media (max-width: 767px) {
  .bq-qb-grid.is-workbench .bq-pays-card.is-sheet { display: none; }
  /* Under the thumb bar (z-index 40): the bar keeps the total and the one
     gold Send on screen over the sheet, and the sheet's last control stays
     clear of it. */
  .bq-qb-grid.is-workbench .bq-pays-card.is-sheet.is-open { display: block; position: fixed; inset: 0; z-index: 35; overflow-y: auto; border-radius: 0; border: 0; padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
  .bq-pays-card.is-sheet.is-open .bq-pays-sheet-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 56px; padding: 8px 8px 8px 16px; border-bottom: 1px solid rgb(var(--divider)); background: rgb(var(--surface)); }
}
/* The found box's rows: one row an item, their figure and ours on it (Task 128a
   item 6). A row is the same three columns every time -- the item, "They
   wanted", "You found" -- so the two money columns line up from row to row
   without two lists being read against each other, and a side with no figure is
   blank rather than a lone dash. */
.bq-found-rows { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.bq-found-row { display: grid; grid-template-columns: minmax(0, 1fr) 96px 96px; align-items: baseline; gap: 1px 8px; font-size: 13px; line-height: 1.3; color: rgb(var(--muted)); }
.bq-found-label { min-width: 0; }
.bq-found-row small { display: block; font-size: 12px; color: rgb(var(--eyebrow)); }
.bq-found-row b { font-size: 15px; font-weight: 600; color: rgb(var(--ink)); white-space: nowrap; text-align: right; }
.bq-found-row.is-outside b { color: rgb(var(--muted)); }
.bq-found-row--head { margin-top: 0; }
.bq-found-row--head small { font-size: 12px; font-weight: 700; color: rgb(var(--eyebrow)); text-align: right; }
.bq-found-row--total { margin-top: 2px; }
.bq-found-row--total small { font-size: 13px; font-weight: 700; color: rgb(var(--muted)); }
/* A phone has ~110 px a money column; the labels wrap above their figure. */
@media (max-width: 767px) {
  .bq-found-row { grid-template-columns: minmax(0, 1fr) 84px 84px; }
  .bq-found-row b { font-size: 14px; }
}
/* From xl the box lives in the money column: 260 px of column, 218 px of card.
   Two 96 px money columns plus the 8 px gaps leave the label 10 px -- it was
   laid out one word a line ("Items / left / out / 4 / items / at / $0.00") and
   "Total" printed over its figure (Task 128d item 1, seen in
   `.ai/t128a-workbench-1366.png`). So the label takes a line of its own across
   the whole card -- a name and its note ("4 items at $0.00") read full width on
   one or two lines -- and the two figures sit on the next line in the same two
   columns the head words name, right-aligned and tabular so they still line up
   from row to row. Everywhere the card is the page's full width (below xl) the
   three columns stay side by side. */
@media (min-width: 1280px) {
  .bq-found-row > .bq-found-label { grid-column: 1 / -1; grid-row: 1; }
  .bq-found-row > .bq-found-money { grid-row: 2; }
  .bq-found-row > .bq-found-money--theirs { grid-column: 2; }
  .bq-found-row > .bq-found-money--yours { grid-column: 3; }
  /* The head words keep the two money columns and nothing else: no empty first
     line above them. */
  .bq-found-row--head > .bq-found-label { display: none; }
  .bq-found-row--head > .bq-found-money { grid-row: 1; }
}
.bq-found-years { margin: 4px 0 0; font-size: 13px; font-weight: 700; color: rgb(var(--money-ink)); }
.bq-found-toggle { display: none; }
@media (max-width: 767px) {
  .bq-found-cols { gap: 16px; }
  .bq-found:not(.is-open) .bq-found-rows { display: none; }
  .bq-found-toggle { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; margin-top: 4px; padding: 0 4px; }
}
/* ---- Walkthrough review rows (Task 124) --------------------------------
   One row per line from md: up, every row on ONE grid, so Service,
   Description, Qty, Unit, Price and Room line up from row to row; a card per
   line on a phone, Service and Description on top, the numbers in one row and
   the room under them. Fields are 44 px with 16 px type on a phone (a gloved
   thumb, and iOS never zooms into a field) and compact from md: up. The room
   is the group heading; a row's own room is the Move button, so no select ever
   cuts "Primary bathroom" down to "Primary bat". */
.bq-review-line {
  display: grid;
  gap: 8px;
  align-items: center;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  grid-template-areas:
    "check service service service service service"
    "desc  desc    desc    desc    desc    desc"
    "qty   qty     unit    unit    price   price"
    "room  room    room    room    room    room"
    "flags flags   flags   flags   flags   flags";
  margin-top: 8px;
  padding: 10px;
  border: 1px solid rgb(var(--line));
  border-radius: var(--r-card);
  background: rgb(var(--surface));
}
.bq-review-check {
  grid-area: check; align-self: center; justify-self: center;
  width: 24px; height: 44px; margin: 0; accent-color: rgb(var(--accent));
}
.bq-review-field {
  width: 100%; min-width: 0; height: 44px; padding: 0 10px;
  border: 1px solid rgb(var(--input)); border-radius: var(--r-input);
  background: rgb(var(--surface)); color: rgb(var(--ink));
  font-family: inherit; font-size: 16px;
}
.bq-review-field:focus {
  outline: none; border-color: rgb(var(--accent));
  box-shadow: 0 0 0 2px rgb(var(--accent) / .35);
}
.bq-review-field.is-amber {
  border-color: rgb(var(--accent-edge) / .55); background: rgb(var(--warn-tint));
}
.bq-review-service { grid-area: service; }
.bq-review-desc { grid-area: desc; }
.bq-review-qty { grid-area: qty; text-align: right; font-variant-numeric: tabular-nums; }
.bq-review-unit { grid-area: unit; padding: 0 4px; }
.bq-review-price { grid-area: price; text-align: right; font-variant-numeric: tabular-nums; }
/* No step spinners on a quantity or a price: the spinner drew over the figure
   in the narrow money column, and a mis-tap on one changes what a client pays. */
.bq-review-qty, .bq-review-price { appearance: textfield; -moz-appearance: textfield; }
.bq-review-qty::-webkit-outer-spin-button, .bq-review-qty::-webkit-inner-spin-button,
.bq-review-price::-webkit-outer-spin-button, .bq-review-price::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0;
}
.bq-review-room {
  grid-area: room; display: inline-flex; align-items: center; justify-content: center;
  gap: 6px; width: 100%; min-width: 0; min-height: 44px; padding: 0 8px;
  border: 1px solid rgb(var(--input)); border-radius: var(--r-input);
  background: rgb(var(--surface)); color: rgb(var(--body));
  font-family: inherit; font-size: 14px; cursor: pointer;
}
.bq-review-room:hover { background: rgb(var(--mist)); }
.bq-review-room:focus-visible { outline: 2px solid rgb(var(--accent)); outline-offset: 2px; }
.bq-review-room-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bq-review-mover { grid-area: room; }
.bq-review-flags {
  grid-area: flags; display: flex; flex-wrap: wrap; align-items: center;
  gap: 6px; min-width: 0;
}
.bq-review-note {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12px; color: rgb(var(--muted));
}
.bq-review-chip {
  display: inline-flex; align-items: center; height: 24px; padding: 0 8px;
  border-radius: var(--r-pill); background: rgb(var(--accent) / .18);
  color: rgb(var(--ink)); font-size: 11px; font-weight: 700; white-space: nowrap;
}
.bq-review-cols { display: none; }
@media (min-width: 768px) {
  .bq-review-line {
    grid-template-columns: 1.5rem 7rem minmax(0, 1fr) 4rem 4.5rem 6.5rem 9rem;
    grid-template-areas:
      "check service desc  qty  unit  price room"
      ".     flags   flags flags flags flags flags";
    margin-top: 0;
    padding: 6px 0;
    border: 0;
    border-bottom: 1px solid rgb(var(--line));
    border-radius: 0;
    background: none;
  }
  .bq-review-check { width: 14px; height: 14px; }
  .bq-review-field { height: 28px; padding: 0 6px; border-radius: var(--r-chip); font-size: 12px; }
  .bq-review-unit { padding: 0 2px; }
  .bq-review-room { min-height: 28px; padding: 0 6px; font-size: 12px; }
  .bq-review-cols {
    display: grid; align-items: center; gap: 8px;
    grid-template-columns: 1.5rem 7rem minmax(0, 1fr) 4rem 4.5rem 6.5rem 9rem;
    padding: 4px 0;
    border-bottom: 1px solid rgb(var(--line));
    font-size: 11px; font-weight: 700; letter-spacing: .04em;
    text-transform: uppercase; color: rgb(var(--muted));
  }
  .bq-review-cols .is-num { text-align: right; }
}
/* The take itself, under the actions (Task 124 item 5): one small fold. */
.bq-review-recording > summary {
  display: flex; align-items: center; gap: 6px;
  min-height: 44px; padding: 0 2px;
  font-size: 12px; font-weight: 700; color: rgb(var(--muted)); cursor: pointer;
}
.bq-review-recording-caret { transition: transform .15s ease; }
.bq-review-recording[open] .bq-review-recording-caret { transform: rotate(90deg); }
.bq-review-recording > summary:focus-visible { outline: 2px solid rgb(var(--accent)); outline-offset: 2px; }

/* ---- "Walk with me" (Task 133a): the room chips and the mic ---------------
   A chip here is 44 px tall because it is a tap target for a thumb in a glove;
   the page's own .bq-chip is 22 px, which is right beside a line and wrong for
   a control. The room being walked is GOLD as a FILL with ink on it -- yellow
   is never text on a light background (clinerules section 1 rule 1) -- and a
   finished room is ticked and dashed, so the chip says what it is without
   colour alone. */
.bq-walk-chip {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  flex: 0 0 auto;
  min-height: 44px;
  padding: 0 .875rem;
  border: 1px solid rgb(var(--input));
  border-radius: var(--r-btn);
  background: rgb(var(--surface));
  color: rgb(var(--ink));
  font-size: .875rem;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, transform .08s ease;
}
.bq-walk-chip:hover { background: rgb(var(--mist)); }
.bq-walk-chip:active { transform: scale(.97); }
.bq-walk-chip:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent));
}
.bq-walk-chip[data-current="true"] {
  background: rgb(var(--accent));
  border-color: rgb(var(--accent-edge));
  color: rgb(var(--on-accent));
}
.bq-walk-chip[data-current="true"]:hover { filter: brightness(1.06); }
.bq-walk-chip[data-closed="true"] { border-style: dashed; color: rgb(var(--body)); }
.bq-walk-chip[data-closed="true"][data-current="true"] {
  border-style: solid;
  color: rgb(var(--on-accent));
}
.bq-walk-chip--add { border-style: dashed; color: rgb(var(--body)); }

/* The chips on the walk's own question cards (Task 133b): the same 44 px tap
   target as a room chip and the review window's answer chips, because a thumb
   in a glove does not change size between two cards. The label may wrap: "Add
   to master bathroom" is a sentence, not a word. */
.bq-walk-answer {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 .875rem;
  font-weight: 600;
  text-align: left;
  white-space: normal;             /* "Add to master bathroom" wraps */
  max-width: 100%;
}
.bq-walk-answer:active { transform: scale(.97); }
.bq-walk-answer:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgb(var(--surface)), 0 0 0 4px rgb(var(--accent));
}

/* The mic: the one gold control on this screen, full width and 60 px tall, so a
   gloved thumb cannot miss it and the word on it is read at arm's length. While
   it is listening it is PRESSED IN with a red dot beside the word, so the state
   is never colour alone (clinerules section 1 rule 3) -- the fill stays gold
   because it is still the same button in the same place. */
.bq-walk-mic {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  width: 100%;
  min-height: 60px;
  border: 1px solid rgb(var(--accent-edge));
  border-radius: var(--r-btn);
  background: rgb(var(--accent));
  color: rgb(var(--on-accent));
  font-size: 1rem;
  font-weight: 700;
  box-shadow: 0 2px 0 rgb(var(--accent-edge));
  cursor: pointer;
  transition: filter .15s ease, transform .08s ease, box-shadow .1s ease;
  touch-action: none;                 /* a hold is a hold, not a scroll */
  -webkit-user-select: none;
  user-select: none;
}
.bq-walk-mic:hover { filter: brightness(1.08); }
.bq-walk-mic:active { transform: scale(.98); }
.bq-walk-mic:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent));
}
.bq-walk-mic[data-state="recording"] {
  box-shadow: inset 0 2px 6px rgb(var(--accent-edge) / .55);
}
.bq-walk-mic[data-state="sending"],
.bq-walk-mic[data-state="reading"] { opacity: .7; cursor: progress; }

/* Hands-free (Task 133c): the mic stays pressed in while the room is being
   listened to and a slow ring goes out from it, so "it is still on" is visible
   from across a room. The red dot beside the word and the label's own words say
   the same thing -- the ring is never the only sign. */
.bq-walk-mic[data-state="recording"][data-handsfree="true"] {
  animation: bq-walk-listening 2.4s ease-out infinite;
}
@keyframes bq-walk-listening {
  0% { box-shadow: inset 0 2px 6px rgb(var(--accent-edge) / .55), 0 0 0 0 rgb(var(--accent) / .45); }
  70% { box-shadow: inset 0 2px 6px rgb(var(--accent-edge) / .55), 0 0 0 12px rgb(var(--accent) / 0); }
  100% { box-shadow: inset 0 2px 6px rgb(var(--accent-edge) / .55), 0 0 0 0 rgb(var(--accent) / 0); }
}
[data-motion="reduce"] .bq-walk-mic[data-state="recording"][data-handsfree="true"] {
  animation: none;
}

/* The camera beside the mic (Task 136 item 4): 60 px square -- the mic's own
   height -- and an OUTLINE rather than a second gold fill, because a screen has
   one gold control and on this screen it is the mic. Gold is a fill or a line,
   so the icon wears the ink. It opens the phone's camera or a desk's file
   picker, and a photo it takes is filed under the room being walked. */
.bq-walk-photo-row { display: flex; align-items: stretch; gap: 8px; }
.bq-walk-photo-row .bq-walk-mic { flex: 1 1 auto; width: auto; min-width: 0; }
.bq-walk-camera {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 60px;
  width: 60px;
  min-height: 60px;
  padding: 0;
  gap: 0;
  border: 1px solid rgb(var(--input));
  border-radius: var(--r-btn);
  background: rgb(var(--surface));
  color: rgb(var(--ink));
  cursor: pointer;
  touch-action: manipulation;
  transition: background .15s ease, transform .08s ease;
}
.bq-walk-camera:hover { background: rgb(var(--mist)); }
.bq-walk-camera:active { transform: scale(.97); }
.bq-walk-camera:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px rgb(var(--page)), 0 0 0 4px rgb(var(--accent));
}
.bq-walk-camera[aria-disabled="true"] { opacity: .6; cursor: progress; }

/* What the camera took in a room: four 44 px thumbs on the room's card, beside
   the "N lines · M photos" count, so the card says what the contractor saw
   there without becoming a gallery of its own. */
.bq-walk-photos { display: flex; align-items: center; gap: 6px; margin-top: .5rem; }
.bq-walk-photo {
  width: 44px;
  height: 44px;
  border: 1px solid rgb(var(--line));
  border-radius: 6px;
  background: rgb(var(--mist));
  object-fit: cover;
}

/* ---- Clavoz Sites: the builder's four steps (Task 54, re-cut in 54b) ------
   The steps sit at the TOP of the form, above the panes, and each one is its
   own pill -- never joined into a segmented control (clinerules: buttons keep
   their own edge) -- 44px tall because a thumb on a jobsite picks them. The
   step open now is a gold FILL carrying ink on it -- yellow is a fill, never
   text (clinerules rule 1) -- and says so with aria-selected as well, so the
   state is never colour alone. */
.bq-site-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  padding: .5rem;
  border-bottom: 1px solid rgb(var(--line));
}
.bq-site-tab {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 .75rem;
  border: 1px solid rgb(var(--line));
  border-radius: 999px;
  background: rgb(var(--surface));
  color: rgb(var(--body));
  font-size: .8125rem;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
}
.bq-site-tab:hover { background: rgb(var(--mist)); }
.bq-site-tab:focus-visible { outline: 2px solid rgb(var(--accent)); outline-offset: 2px; }
.bq-site-tab[aria-selected="true"] {
  background: rgb(var(--accent));
  border-color: rgb(var(--accent-edge));
  color: rgb(var(--on-accent));
}

/* The panes scroll UNDER the pills, so the steps never leave the screen, and
   the preview keeps a real height whether or not a Tailwind build has run
   (Task 54b: `h-[70vh]` was missing from the built sheet, so the iframe fell
   back to the browser's own 150px and the preview was a sliver). */
.bq-site-panes { max-height: 70vh; overflow-y: auto; padding: 1rem; }
.bq-site-frame { height: 70vh; min-height: 420px; }

/* `hidden` must actually hide (Task 54b). The browser's own `[hidden]` rule is
   one author `display: grid` or `display: inline-flex` away from losing, and
   the builder's skeleton is a .grid while its buttons are .bq-btn -- so a
   state that had been switched off kept drawing under the live one, and every
   screenshot showed the loading skeleton. Scoped to this page only. */
#site-builder [hidden] { display: none !important; }

