/* =====================================================================================================
   PolyJacks public doors - instant.css (S2-T8, contract S2 6.2-6.7; LIGHT REDESIGN, owner live 2026-10-04)
   The customer's Instant Price flow, the self-book flow, the token pages and the agent pages. Layered ON TOP
   of the shared design system (ds/tokens.css + ds/components.css, never edited from here - the private app
   shares them): this sheet maps the DS semantic --c-* names to the PUBLIC LIGHT SET below, so every DS
   component (.btn, .input, .field-label, .paper) reads right without knowing it is on a public page.

   OWNER (live, 2026-10-04): "99% of all our traffic will be from people's cell phones ... super super easy
   to work on a phone"; "having all those pages so dark in that navy blue is really ... ugly"; "learn from
   our websites". So the language is the website's (POLYJACKS_Website_Upgrade/04_BUILD/_shell.css, "Foam
   Amber"): a CREAM page (#fff7ed), WHITE cards with a hairline (#e5e7eb) and a soft navy-tinted shadow,
   NAVY ink (#0f172a), navy as an ACCENT in measured doses (the slim top bar, the thumb-reach action bar on
   a phone, the price total plate, the icon badges, the footer), the amber gradient pill for the one primary
   action (#c2410c -> #9a3412, white text 5.18:1 at its lightest stop), the gentle green trust pills, radii
   10 / 14 / 20 / 26.

   SYSTEM
   - Type: system faces only (ds --font-ui / --font-display), never a fixed-width face. Body 16 px / 1.6,
     inputs 17 px (no iOS zoom), labels 15 px semibold, H1 28 px phone -> 34 px desktop, weight 800.
   - Space: the DS 4 px rhythm (--sp-*); a 16 px side gutter on a phone; the column is 560 px max.
   - Touch: every control 48 px or taller; the primary pill 56 px; 8 px or more between targets.
   - Contrast (WCAG 2.x, on white / on cream): ink 17.9 / 17.0; text-2 #334155 10.4 / 9.8; text-3 #475569
     7.6 / 7.2; link #c2410c 5.18 / 4.88; amber-800 #9a3412 7.3 / 6.9; danger #b91c1c 6.5; good #15803d
     5.0; white on the amber pill 5.18-7.32; control edge #7c8aa0 3.5 / 3.3; on navy #0f172a: white 17.9,
     #e2e8f0 14.5, #cbd5e1 12.0, the amber ink #fdba74 10.5.
   - Motion: the DS durations (zeroed under prefers-reduced-motion by tokens.css); transform/opacity only.
   ===================================================================================================== */

/* ---------- the public light set: the DS semantic names, re-pointed for every public page ---------- */
body.pub,
body.pub .paper {
  color-scheme: light;
  --c-canvas: #fff7ed;
  --c-surface: #ffffff;
  --c-surface-2: #fff7ed;
  --c-column: #f1f5f9;
  --c-column-line: #e5e7eb;
  --c-line: #e5e7eb;
  --c-line-strong: #7c8aa0; /* a control edge: 3.5:1 on white */
  --c-hover: rgba(15, 23, 42, .05);
  --c-text: #0f172a;
  --c-text-2: #334155;
  --c-text-3: #475569;
  --c-placeholder: #64748b; /* 4.76:1 on white */
  --c-link: #c2410c;
  --c-focus: #c2410c;
  --c-accent-line: #ea580c;
  --c-primary: #c2410c;
  --c-primary-hover: #9a3412;
  --c-primary-press: #9a3412;
  --c-on-primary: #ffffff;
  --c-good-text: #15803d;
  --c-good-fill: #16a34a;
  --c-good-bg: #f0fdf4;
  --c-good-line: #bbf7d0;
  --c-warn-text: #9a3412;
  --c-warn-fill: #f97316;
  --c-warn-bg: #fff7ed;
  --c-warn-line: #fed7aa;
  --c-danger-text: #b91c1c;
  --c-danger-fill: #dc2626;
  --c-danger-bg: #fef2f2;
  --c-danger-line: #fecaca;
  --c-on-danger: #ffffff;
  --c-info-text: #9a3412;
  --c-info-bg: #fff7ed;
  --c-info-line: #fed7aa;
  --c-chip: #f1f5f9;
  --c-chip-text: #334155;
  --c-scrim: rgba(15, 23, 42, .55);
  --chevron: var(--l-chevron);
  --icon-alert: var(--l-icon-alert);
  --c-paper: #ffffff;
  --c-paper-text: #0f172a;
  --c-paper-muted: #475569;
  --c-paper-link: #c2410c;
  --c-paper-line: #e5e7eb;

  /* the website's own primitives (new public names, never an S0a redefinition) */
  --pj-navy: #0f172a;
  --pj-navy-2: #1e293b;
  --pj-amber: #f97316;
  --pj-amber-l: #fb923c;
  --pj-amber-d: #ea580c;
  --pj-amber-700: #c2410c;
  --pj-amber-800: #9a3412;
  --pj-on-navy: #ffffff;
  --pj-on-navy-2: #e2e8f0;
  --pj-on-navy-3: #cbd5e1;
  --pj-amber-ink: #fdba74; /* the amber INK on navy, 10.5:1 */
  --pj-mint-bg: #f1faf5;
  --pj-mint-line: #bee6d2;
  --pj-mint-text: #1f5f42; /* 7.2:1 on its pill */
  --pj-tint: rgba(249, 115, 22, .08); /* a picked tile */
  --pj-ring: rgba(249, 115, 22, .22); /* the focus halo around an input */
  --pj-pill: linear-gradient(135deg, #c2410c, #9a3412);
  --pj-navy-plate: linear-gradient(160deg, #0f172a, #1e293b);
  --pj-tex-dots: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='26'%3E%3Ccircle cx='2' cy='2' r='1.3' fill='%230f172a' fill-opacity='.07'/%3E%3C/svg%3E");
  --pj-tex-topo-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='64'%3E%3Cpath d='M0 16 Q 27.5 6 55 16 T 110 16 T 165 16 T 220 16' stroke='%23fff7ed' stroke-opacity='.06' stroke-width='1.4' fill='none'/%3E%3Cpath d='M0 38 Q 27.5 28 55 38 T 110 38 T 165 38 T 220 38' stroke='%23fff7ed' stroke-opacity='.045' stroke-width='1.4' fill='none'/%3E%3Cpath d='M0 55 Q 27.5 47 55 55 T 110 55 T 165 55 T 220 55' stroke='%23f97316' stroke-opacity='.12' stroke-width='1.4' fill='none'/%3E%3C/svg%3E");
  --pj-check-white: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 13l4 4 10-11'/%3E%3C/svg%3E");
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, .06), 0 2px 6px rgba(15, 23, 42, .05);
  --shadow-1: 0 2px 6px rgba(15, 23, 42, .06), 0 18px 40px -12px rgba(15, 23, 42, .22);
  --shadow-3: 0 10px 20px rgba(15, 23, 42, .11), 0 30px 60px -18px rgba(15, 23, 42, .30);
  --shadow-paper: var(--shadow-1);
  --shadow-amber: 0 1px 0 rgba(255, 255, 255, .4) inset, 0 10px 24px rgba(249, 115, 22, .38), 0 3px 8px rgba(249, 115, 22, .26);
  --pj-tap: 48px;
  --pj-col: 560px;
  --pj-gutter: 16px;
}

:root:has(> body.pub) {
  color-scheme: light;
  background: #fff7ed;
}

/* ---------- the shell: the bar, one centred column, the footer pinned to the foot (vis-10) ---------- */
body.pub {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--c-canvas) var(--pj-tex-dots);
  color: var(--c-text);
  font-size: 16px;
  line-height: 1.6;
  -webkit-tap-highlight-color: transparent;
}

body.pub :focus-visible {
  outline: 2.5px solid var(--pj-amber-d);
  outline-offset: 3px;
}

/* the top bar, matched to the website's phone bar (NEO-418): cream, a hairline, the dark-lettered logo and
   the plain bold number. It scrolls away with the page - the phone action bar carries Call at the thumb. */
.pub-topbar {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 56px;
  padding: var(--sp-1) max(var(--pj-gutter), env(safe-area-inset-right)) var(--sp-1) max(var(--pj-gutter), env(safe-area-inset-left));
  background: var(--c-canvas);
  border-bottom: 1px solid var(--c-line);
}

/* the real logo.webp (Wave 8 BRAND), dark lettering for the cream bar */
.pub-logo {
  display: block;
  height: 30px;
  width: auto;
  flex-shrink: 0;
}

/* the human fallback: the number itself, bold navy (17.0:1 on cream), a 44 px tap height */
.pub-call {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  margin-left: auto;
  color: var(--pj-navy);
  font-size: 15px;
  font-weight: 800;
  text-decoration: none;
  white-space: nowrap;
}

.pub-call::before {
  content: "";
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  background: var(--pj-amber-700);
  -webkit-mask: var(--glyph-phone) center / contain no-repeat;
  mask: var(--glyph-phone) center / contain no-repeat;
}

.pub-call:hover {
  color: var(--pj-amber-800);
}

.pub-main {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: var(--pj-col);
  flex: 1 1 auto;
  margin: 0 auto;
  padding: var(--sp-4) max(var(--pj-gutter), env(safe-area-inset-left)) var(--sp-8) max(var(--pj-gutter), env(safe-area-inset-right));
}

/* NEO-412: a field the keyboard opens on lands near the top of the screen, clear of any bar. NEO-778: clear of
   the pinned consent bar's MEASURED height (--pj-bar, written by instant.js) plus a field-error line - the
   bar is 152-182 px on phones, so a fixed 120px put the Tab/Next target under it */
body.pub .input {
  scroll-margin-top: var(--sp-3);
  scroll-margin-bottom: calc(var(--pj-bar, 160px) + 40px);
}

/* ---------- type ---------- */
.pub-h1 {
  color: var(--c-text);
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -.025em;
  line-height: 1.15;
  text-wrap: balance;
}

.pub-h2 {
  margin-top: var(--sp-6);
  color: var(--c-text);
  font-family: var(--font-display);
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -.015em;
  line-height: 1.2;
}

.pub-sub {
  margin-top: var(--sp-2);
  color: var(--c-text-2);
  font-size: 17px;
  line-height: 1.55;
}

.pub-note {
  color: var(--c-text-3);
  font-size: 15px;
}

:where(.pub-main > section) > :is(p, ul) {
  margin-top: var(--sp-3);
}

/* the gentle green trust pills (the website's, owner 2026-09-10) */
.trust-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: var(--sp-1) 0 0;
  padding: 0;
  list-style: none;
}

.trust-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border: 1px solid var(--pj-mint-line);
  border-radius: var(--r-pill);
  background: var(--pj-mint-bg);
  color: var(--pj-mint-text);
  font-size: 14px;
  font-weight: 650;
  line-height: 1.3;
}

.trust-chip::before {
  content: "";
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  background: currentColor;
  -webkit-mask: var(--glyph-check) center / contain no-repeat;
  mask: var(--glyph-check) center / contain no-repeat;
}

/* ---------- the stepper: a line of labelled dots that fills as they go - on a phone too (owner 2026-10-04:
   "I liked the little stages before... every time you progress, that line moves"; a bare "1/8" read as a
   wall of pages). ---------- */
.stepper {
  display: block;                       /* NEO-441: the shared DS .stepper is a grid - not here */
  background: var(--c-surface);
  border-bottom: 1px solid var(--c-line);
}

.stepper-inner {
  max-width: var(--pj-col);
  margin: 0 auto;
  padding: var(--sp-3) max(var(--pj-gutter), env(safe-area-inset-right)) var(--sp-3) max(var(--pj-gutter), env(safe-area-inset-left));
}

.stepper-track {
  --step-count: 3;
  display: flex;
  position: relative;
  margin: 0;
  padding: 0;
  list-style: none;
}

.stepper-track[data-of="2"] { --step-count: 2; }

/* the grey line and the amber fill both run dot-centre to dot-centre; the fill's length comes from the page's
   own stage (data-at), so it is right with or without a script, and it grows in on every page load */
.stepper-track::before,
.stepper-track::after {
  content: "";
  position: absolute;
  top: 8px;
  left: calc(100% / var(--step-count) / 2);
  height: 3px;
  border-radius: 3px;
}

.stepper-track::before {
  right: calc(100% / var(--step-count) / 2);
  background: var(--c-line);
}

.stepper-track::after {
  width: 0;
  background: linear-gradient(90deg, var(--pj-amber-l), var(--pj-amber-d));
  animation: stepper-grow var(--dur-4) var(--ease);
}

.stepper-track[data-of="3"][data-at="1"]::after { width: calc(100% / 3); }
.stepper-track[data-of="3"][data-at="2"]::after,
.stepper-track[data-of="3"][data-at="3"]::after { width: calc(200% / 3); }
.stepper-track[data-of="2"][data-at="1"]::after,
.stepper-track[data-of="2"][data-at="2"]::after { width: 50%; }

@keyframes stepper-grow {
  from { width: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .stepper-track::after { animation: none; }
}

.stepper-step {
  display: grid;
  flex: 1 1 0;
  justify-items: center;
  gap: 5px;
  min-width: 0;
  position: relative;
  z-index: var(--z-raised);
}

.stepper-dot {
  width: 19px;
  height: 19px;
  border: 2px solid var(--c-line-strong);
  border-radius: 50%;
  background: var(--c-surface);
  transition: background-color var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease);
}

.stepper-step[data-state="done"] .stepper-dot {
  border-color: var(--pj-amber-700);
  background: var(--pj-amber-700) var(--pj-check-white) center / 11px 11px no-repeat;
}

.stepper-step[data-state="current"] .stepper-dot {
  border-color: var(--pj-amber-700);
  background: var(--c-surface);
  box-shadow: 0 0 0 4px var(--pj-ring);
}

.stepper-label {
  max-width: 100%;
  color: var(--c-text-3);
  font-size: 13px;
  white-space: nowrap;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
}

.stepper-step[data-state="current"] .stepper-label {
  color: var(--c-text);
  font-weight: 750;
}

@media (min-width: 640px) {
  .stepper-inner {
    padding-block: var(--sp-4);
  }
}

/* ---------- the form: one column, a steady rhythm; each question is a white card ---------- */
.pub-form {
  display: grid;
  gap: var(--sp-4);
}

.pub-form > .pub-sub {
  margin-top: calc(-1 * var(--sp-2));
}

.form-note {
  margin: 0;
  color: var(--c-text-3);
  font-size: 14px;
}

.field {
  gap: var(--sp-2);
}

.field-label {
  color: var(--c-text);
  font-size: 15px;
  font-weight: 650;
}

.field-req {
  color: var(--c-danger-text);
  font-weight: 800;
}

.field-opt {
  color: var(--c-text-3);
  font-weight: 500;
}

.field-hint {
  margin: calc(-1 * var(--sp-2)) 0 0;
  color: var(--c-text-3);
  font-size: 14px;
}

.field .field-hint {
  margin-top: 0;
}

.field-error {
  margin: 0;
  color: var(--c-danger-text);
  font-size: 15px;
  font-weight: 650;
}

body.pub .input {
  min-height: 52px;
  padding: 12px 14px;
  border: 1.5px solid var(--c-line-strong);
  border-radius: var(--r-md);
  background-color: var(--c-surface);
  color: var(--c-text);
  font-size: 17px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, .04);
}

body.pub .input:focus-visible {
  border-color: var(--pj-amber-d);
  outline: none;
  box-shadow: 0 0 0 4px var(--pj-ring);
}

body.pub .input[aria-invalid="true"] {
  border-color: var(--c-danger-fill);
  box-shadow: 0 0 0 4px var(--c-danger-bg);
}

body.pub select.input {
  padding-right: 42px;
}

/* a question card: the fieldset is the card, its legend the card title (floated so it sits inside). Every
   card is display:block - WebKit ignores a legend's float inside a grid fieldset and sets it on the border
   (NEO-422) - and spaces its children itself. */
.tile-group,
.drop-group,
.when-picker {
  display: block;
  min-width: 0;
  margin: 0;
  padding: var(--sp-4);
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow: var(--shadow-sm);
}

.pub-form legend.field-label,
.photo-card-title,
.day-head {
  float: left;
  width: 100%;
  margin: 0 0 var(--sp-3);
  padding: 0;
  color: var(--c-text);
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 750;
  line-height: 1.3;
}

.pub-form legend + *,
.photo-card-title + *,
.day-head + * {
  clear: both;
}

.tile-group > .chip-pick + .chip-pick {
  margin-top: var(--sp-2);
}

/* ---------- pickers, matched to the website's diagnose picker (NEO-418): ONE column of white rows, a thin
   line icon, the words; a picked row takes the amber edge, a warm tint and a check (never colour alone) ---------- */
.tiles {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-2);
}

.tile {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 58px;
  padding: var(--sp-2) 44px var(--sp-2) var(--sp-4);
  border: 1.5px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface);
  color: var(--c-text);
  cursor: pointer;
  touch-action: manipulation;
  transition: border-color var(--dur-2) var(--ease), background-color var(--dur-2) var(--ease),
    box-shadow var(--dur-2) var(--ease), transform var(--dur-1) var(--ease);
}

.tile:hover {
  border-color: var(--c-line-strong);
}

.tile:active {
  transform: scale(.985);
}

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

.tile:has(.tile-input:checked) {
  border-color: var(--pj-amber-d);
  background: var(--pj-tint);
  box-shadow: 0 0 0 1px var(--pj-amber-d), 0 6px 16px -10px rgba(249, 115, 22, .55);
}

/* the check badge on a picked row */
.tile:has(.tile-input:checked)::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 12px;
  width: 22px;
  height: 22px;
  margin-top: -11px;
  border-radius: 50%;
  background: var(--pj-amber-700) var(--pj-check-white) center / 13px 13px no-repeat;
  animation: pj-pop var(--dur-2) var(--ease);
}

.tile:has(.tile-input:focus-visible),
.chip-pick:has(input:focus-visible),
.time-chip:has(input:focus-visible) {
  outline: 2.5px solid var(--pj-amber-d);
  outline-offset: 2px;
}

/* the surface line icons (navy strokes, one amber accent), the website's thin-icon size */
.tile-icon {
  width: 30px;
  height: 30px;
  flex-shrink: 0;
}

.tile-label {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.3;
}

/* the small drop picker (Door 2): thumb-size chips, three or four to a row */
.tiles--drop {
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: var(--sp-2);
}

.tile--sm {
  justify-content: center;
  min-height: 52px;
  padding: var(--sp-2);
  text-align: center;
}

.tile--sm .tile-label {
  font-size: 15px;
  font-weight: 650;
}

.tile--sm:has(.tile-input:checked)::after {
  top: 4px;
  right: 4px;
  width: 18px;
  height: 18px;
  margin-top: 0;
  background-size: 11px 11px;
}

/* ---------- radio / checkbox rows: the whole row is the 48 px target ---------- */
.chip-pick {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--pj-tap);
  padding: var(--sp-3) var(--sp-4);
  border: 1.5px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface);
  font-weight: 600;
  line-height: 1.35;
  cursor: pointer;
  touch-action: manipulation;
  transition: border-color var(--dur-2) var(--ease), background-color var(--dur-2) var(--ease);
}

.chip-pick:has(input:checked) {
  border-color: var(--pj-amber-d);
  background: var(--pj-tint);
  box-shadow: inset 0 0 0 1px var(--pj-amber-d);
}

.chip-pick input:not(.sr-only) {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  margin: 0;
  accent-color: var(--pj-amber-700);
}

/* ---------- the time picker (NEO-417): a swipeable day strip, then the picked day's times as chips ---------- */
.when-picker {
  padding: var(--sp-3);
}

.day-strip {
  display: flex;
  gap: var(--sp-2);
  margin: 0 calc(-1 * var(--sp-3)) var(--sp-3);
  padding: var(--sp-1) var(--sp-3) var(--sp-2);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}

.day-strip::-webkit-scrollbar {
  display: none;
}

.day-pill {
  display: grid;
  justify-items: center;
  align-content: center;
  flex: 0 0 auto;
  min-width: 62px;
  min-height: 74px;
  padding: var(--sp-1) var(--sp-2);
  border: 1.5px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface);
  color: var(--c-text);
  font: inherit;
  line-height: 1.15;
  cursor: pointer;
  scroll-snap-align: start;
  touch-action: manipulation;
}

.day-pill-dow,
.day-pill-mon {
  color: var(--c-text-3);
  font-size: 13px;
  font-weight: 700;
}

.day-pill-dom {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 800;
}

.day-pill-word {
  max-width: 120px;
  font-size: 14px;
  font-weight: 750;
  white-space: normal;
}

/* the picked day: the amber pill, white words (5.18:1 at the lighter stop) */
.day-pill[aria-pressed="true"] {
  border-color: transparent;
  background: var(--pj-pill);
  color: #ffffff;
  box-shadow: var(--shadow-amber);
}

.day-pill[aria-pressed="true"] .day-pill-dow,
.day-pill[aria-pressed="true"] .day-pill-mon {
  color: #ffffff;
}

.window-group {
  display: block;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.window-group + .window-group {
  margin-top: var(--sp-5);
}

.has-strip .window-group + .window-group {
  margin-top: 0;
}

/* with the strip, the strip names the day: the heading stays for screen readers only */
.has-strip .day-head {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* a two-hour window chip ("12:30-2:30 PM", owner ruling 2026-10-13) sits two to a row on a phone, three on
   the full column */
.time-chips {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--sp-2);
}

.time-chip {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: var(--sp-2) var(--sp-3);
  border: 1.5px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface);
  font-weight: 700;
  line-height: 1.3;
  text-align: center;
  cursor: pointer;
  touch-action: manipulation;
}

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

/* the picked time: white on navy (17.9:1) */
.time-chip:has(input:checked) {
  border-color: transparent;
  background: var(--pj-navy);
  color: #ffffff;
}

/* the hold countdown: an amber note with the clock in tabular figures */
.hold-countdown {
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--c-warn-line);
  border-radius: var(--r-md);
  background: var(--c-warn-bg);
  color: var(--c-warn-text);
  font-weight: 650;
}

.hold-clock {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.hold-countdown[data-low="true"] {
  border-color: var(--c-danger-line);
  background: var(--c-danger-bg);
  color: var(--c-danger-text);
}

/* ---------- consent (FLOW_SPEC section 1): the box's ONE sentence (p.consent-line) ---------- */
.consent-line {
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface);
  color: var(--c-text-2);
  font-size: 15px;
  line-height: 1.5;
}

.consent-line a {
  color: var(--c-link);
  font-weight: 700;
  white-space: nowrap;
}

.addr-more > summary {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;
  color: var(--c-link);
  font-size: 15px;
  font-weight: 650;
  cursor: pointer;
  list-style: none;
}

.addr-more > summary::after {
  content: "";
  width: 16px;
  height: 16px;
  background: currentColor;
  -webkit-mask: var(--glyph-chevron) center / contain no-repeat;
  mask: var(--glyph-chevron) center / contain no-repeat;
  transform: rotate(90deg);
  transition: transform var(--dur-2) var(--ease);
}

.addr-more[open] > summary::after {
  transform: rotate(-90deg);
}

.addr-more > summary::-webkit-details-marker { display: none; }

.addr-more[open] > summary { margin-bottom: var(--sp-2); }

/* 2026-10-14: city, state and ZIP sit OPEN under the address (most visitors get no suggestion and type them), in
   ONE row so the contact screen still fits a 390 x 844 phone above Continue (owner 2026-10-05). State and ZIP
   take what "Missouri" and five digits need, the city the rest; the row's boxes pad a little tighter. */
.addr-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 7.5em 5.4em;
  column-gap: var(--sp-2);
}

body.pub .addr-row .input { padding-right: 10px; padding-left: 10px; }
body.pub .addr-row select.input { padding-right: 30px; background-position: right 10px center; }

/* 2026-10-14: the contact screen carries the open city / state / ZIP row and must still fit a 390 x 844 phone
   with no scrolling (owner 2026-10-05) - its fields and labels sit a little tighter there; the inputs keep their
   full height */
body.pub .pub-main[data-step="contact"] .field { margin-bottom: 5px; gap: 4px; }
body.pub .pub-main[data-step="contact"] .field-label { margin-bottom: 1px; line-height: 1.25; }

/* ---------- the contact form's human check (mc_public/humancheck.py): a field no person meets. Off the
   page, out of the flow, one pixel - so it adds no row, no gap and no scroll at any width. Never
   display:none: a program that skips hidden fields would skip it too. ---------- */
.field-aside {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---------- the address suggestions under the street field ---------- */
.addr-list {
  margin: var(--sp-1) 0 0;
  padding: var(--sp-1);
  list-style: none;
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface);
  box-shadow: var(--shadow-1);
}

.addr-option {
  display: flex;
  align-items: center;
  min-height: var(--pj-tap);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  cursor: pointer;
}

.addr-option[aria-selected="true"],
.addr-option:hover { background: var(--pj-tint); }

.area-hint {
  margin: 0;
  color: var(--c-text-2);
  font-size: 15px;
}

/* ---------- buttons on light: the website's pill voices ---------- */
body.pub .btn {
  min-height: var(--pj-tap);
  border-radius: var(--r-pill);
  font-weight: 750;
}

/* the website's glowing amber pill (.btn-primary + --shadow-amber), white words 5.18:1 at the lighter stop */
body.pub .btn-primary {
  border: 0;
  background: var(--pj-pill);
  color: #ffffff;
  box-shadow: var(--shadow-amber);
}

body.pub .btn-primary:hover {
  filter: brightness(1.05);
}

/* the ghost voice (the website's .btn-ghost): white, a navy edge */
body.pub .btn-secondary {
  min-height: 52px;
  border: 1.5px solid var(--pj-navy);
  background: var(--c-surface);
  color: var(--pj-navy);
  font-size: 16px;
  box-shadow: 0 2px 8px rgba(15, 23, 42, .07);
}

body.pub .btn-secondary:hover {
  background: var(--pj-navy);
  color: #ffffff;
}

body.pub .btn-lg {
  min-height: 54px;
  padding: 0 var(--sp-5);
  font-size: 17px;
  font-weight: 800;
}

body.pub .btn-primary:disabled,
body.pub .btn-primary[aria-disabled="true"] {
  opacity: 1;
  background: #e2e8f0;
  color: #475569;
  box-shadow: none;
  filter: none;
  cursor: not-allowed;
}

/* ---------- the thumb-reach action bar, the website's phone bar exactly (NEO-418): a navy strip with the
   amber pill and the white Call pill side by side, ONE slim row (NEO-416). From 900 px it sits in the
   column and the Call pill folds away (the top bar shows the number). A bar inside a card (state, error,
   done) always sits in its card. ---------- */
.action-bar {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: var(--z-sticky);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  padding: 10px max(12px, env(safe-area-inset-right)) calc(10px + env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left));
  background: linear-gradient(180deg, var(--pj-navy-2), var(--pj-navy));
  border-top: 1px solid rgba(249, 115, 22, .35);
  box-shadow: 0 -10px 26px rgba(15, 23, 42, .35);
  transition: transform var(--dur-3) var(--ease);
}

.action-bar .btn-primary {
  width: 100%;
  padding: 0 var(--sp-3);
}

/* the white Call pill: navy words on white (17.9:1), the phone glyph */
body.pub .call-pill {
  gap: var(--sp-2);
  min-height: 54px;
  min-width: 112px;
  padding: 0 var(--sp-5);
  border: 0;
  background: #ffffff;
  color: var(--pj-navy);
  font-size: 17px;
  font-weight: 800;
  box-shadow: 0 8px 18px rgba(0, 0, 0, .25);
}

.call-pill::before {
  content: "";
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  background: currentColor;
  -webkit-mask: var(--glyph-phone) center / contain no-repeat;
  mask: var(--glyph-phone) center / contain no-repeat;
}

/* on the navy bar a disabled pill is a quiet slate shape with legible words (8.1:1), not a muddy amber */
.action-bar .btn-primary:disabled,
.action-bar .btn-primary[aria-disabled="true"] {
  background: rgba(255, 255, 255, .12);
  color: var(--pj-on-navy-3);
}

/* NEO-412: only while the address suggestions are open does the bar step out of the way. It used to hide
   whenever a field had focus - so on a phone, typing, the Continue button was never there (owner 2026-10-04). */
@media (pointer: coarse) and (max-width: 899px) {
  body.pub:has(.addr-list:not([hidden])) .action-bar {
    transform: translateY(120%);
  }
}

/* the cancel note and the secondary link live in the page, just above the bar (NEO-416) */
.action-more {
  display: grid;
  justify-items: center;
  gap: var(--sp-1);
  text-align: center;
}

.action-note {
  margin: 0;
  color: var(--c-text-2);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.45;
}

.action-secondary {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--sp-3);
  border: 0;
  background: transparent;
  color: var(--c-link);
  font: inherit;
  font-size: 16px;
  font-weight: 700;
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 4px;
  cursor: pointer;
}

/* FB restart 2026-10-15: the measuring screens' release valve - a full-width button under the instruction */
body.pub .measure-for-me {
  width: 100%;
  margin: var(--sp-3) 0 var(--sp-1);
  white-space: normal;
  text-align: center;
  line-height: 1.25;
}

/* owner 2026-10-16: the valve is a gentle green that stands out (dark green on soft green, 6.4:1) */
body.pub .btn-secondary.measure-for-me {
  border: 2px solid #3fa36b;
  background: #d9f2e3;
  color: #1f5f42;
  box-shadow: 0 2px 10px rgba(31, 95, 66, .16);
}

body.pub .btn-secondary.measure-for-me:hover {
  background: #c8ebd7;
  color: #1f5f42;
}

body.pub .measure-for-me-note {
  margin: 0 0 var(--sp-4);
  text-align: center;
}

.action-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--sp-2) var(--sp-5);
  margin: 0;
  font-size: 15px;
}

.action-links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--c-link);
  font-weight: 700;
}

/* a link only a desktop visitor needs ("text me a link to finish on your phone" - NEO-423) */
@media (pointer: coarse) {
  .on-desktop {
    display: none;
  }
}

/* inside a card the bar is part of the card (the error, state and done cards) */
.state-card .action-bar,
.error-card .action-bar,
.done-card .action-bar {
  position: static;
  grid-template-columns: minmax(0, 1fr);
  margin-top: var(--sp-5);
  padding: 0;
  background: none;
  border: 0;
  box-shadow: none;
}

/* NEO-72 / NEO-79: the footer reserves the bar's real height (one 54 px row + 20 px) ONLY while a FIXED bar
   shows */
body.pub:has(.action-bar:not([hidden]):not(:is(.state-card, .error-card, .done-card) .action-bar)) {
  --pj-bar: 76px;
}

@media (min-width: 900px) {
  .action-bar {
    position: static;
    grid-template-columns: minmax(0, 1fr);
    margin-top: var(--sp-2);
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
  }

  body.pub .action-bar .call-pill {
    display: none;
  }

  .pub-footer {
    padding-bottom: calc(var(--sp-6) + env(safe-area-inset-bottom));
  }
}

/* ---------- the footer: the website's navy foot with its amber seam ---------- */
.pub-footer {
  position: relative;
  margin-top: auto;
  padding: var(--sp-8) var(--pj-gutter) calc(var(--sp-6) + var(--pj-bar, 0px) + env(safe-area-inset-bottom));
  background-color: var(--pj-navy);
  background-image: var(--pj-tex-topo-dark), linear-gradient(195deg, var(--pj-navy-2), var(--pj-navy) 55%);
  color: var(--pj-on-navy-3);
  font-size: 15px;
  text-align: center;
}

.pub-footer::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  height: 3px;
  background: linear-gradient(90deg, transparent, var(--pj-amber) 25%, var(--pj-amber-l) 50%, var(--pj-amber) 75%, transparent);
}

.pub-footer-inner {
  display: grid;
  gap: var(--sp-1);
  max-width: var(--pj-col);
  margin: 0 auto;
}

.pub-footer-brand {
  color: var(--pj-on-navy);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.pub-footer a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--pj-on-navy-2);
  font-weight: 650;
  text-decoration: none;
}

.pub-footer a:hover {
  color: var(--pj-amber-ink);
  text-decoration: underline;
}

.pub-footer-legal {
  margin-top: var(--sp-2);
  padding-top: var(--sp-2);
  border-top: 1px solid rgba(255, 255, 255, .14);
}

/* ---------- cards: plain, state, error, done, token pages ---------- */
.pub-card {
  min-width: 0;
  margin-top: var(--sp-4);
  padding: var(--sp-5);
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow: var(--shadow-1);
}

.pub-card .chips,
.token-page .chips {
  display: grid;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}

.state-card,
.error-card,
.done-card {
  margin-top: var(--sp-5);
  padding: var(--sp-8) var(--sp-5) var(--sp-6);
  border: 1px solid var(--c-line);
  border-radius: var(--r-xl);
  background: var(--c-surface);
  box-shadow: var(--shadow-1);
  text-align: center;
}

.state-card h2 {
  color: var(--c-text);
  font-size: 21px;
  font-weight: 800;
}

.state-card p {
  margin-top: var(--sp-3);
  color: var(--c-text-2);
}

.error-card .pub-sub,
.done-card .pub-sub { margin-top: var(--sp-3); }

.error-card .pub-note,
.done-card .pub-note { margin-top: var(--sp-4); }

/* vis-13: a lone state card (session expired, closed, error) centres in the viewport's free space. */
.pub-main > .state-card:last-child {
  margin-top: auto;
  margin-bottom: auto;
}

/* the done check: a green disc with a white tick, popped in */
.done-check {
  display: block;
  width: 64px;
  height: 64px;
  margin: 0 auto var(--sp-4);
  border-radius: 50%;
  background: var(--c-good-fill) var(--pj-check-white) center / 34px 34px no-repeat;
  box-shadow: 0 0 0 8px var(--c-good-bg), 0 12px 24px -8px rgba(22, 163, 74, .5);
  animation: pj-pop var(--dur-4) var(--ease);
}

.done-next {
  display: grid;
  gap: var(--sp-2);
  margin: var(--sp-5) 0 0;
  padding: var(--sp-4);
  border-radius: var(--r-md);
  background: var(--c-surface-2);
  list-style: none;
  text-align: left;
}

.done-next li {
  display: flex;
  gap: var(--sp-2);
  color: var(--c-text-2);
}

.done-next li::before {
  content: "";
  width: 18px;
  height: 18px;
  margin-top: 3px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--c-good-fill) var(--pj-check-white) center / 11px 11px no-repeat;
}

.token-page {
  display: grid;
  gap: var(--sp-4);
}

.token-windows {
  display: grid;
  gap: var(--sp-4);
}

.pub-card > .chip-pick + .chip-pick {
  margin-top: var(--sp-2);
}

.token-loading,
.token-current {
  margin: 0;
  color: var(--c-text-2);
}

.token-current:empty {
  display: none;
}

/* the honest "needs a quick look" card on the price step */
.needs-look {
  padding: var(--sp-6) var(--sp-5);
  border: 1px solid var(--c-line);
  border-radius: var(--r-xl);
  background: var(--c-surface);
  box-shadow: var(--shadow-1);
}

.needs-look > p {
  margin-top: var(--sp-3);
  color: var(--c-text-2);
}

/* the error banner above a form */
.mc-banner {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  font-weight: 650;
}

.mc-banner--error {
  border: 1px solid var(--c-danger-line);
  background: var(--c-danger-bg);
  color: var(--c-danger-text);
}

/* the offline bar (instant.js toggles [hidden]) */
.offline-bar {
  position: sticky;
  top: 56px;
  z-index: var(--z-sticky);
  margin-bottom: var(--sp-3);
  padding: 10px var(--sp-4);
  border: 1px solid var(--c-info-line);
  border-radius: var(--r-md);
  background: var(--c-info-bg);
  color: var(--c-info-text);
  font-size: 14px;
  font-weight: 650;
  text-align: center;
}

/* ---------- confirm: the three facts in one card ---------- */
.confirm-lines {
  display: grid;
  gap: var(--sp-3);
  margin: 0;
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow: var(--shadow-sm);
}

.confirm-lines > .pub-note {
  font-weight: 650;
}

.confirm-line {
  display: grid;
  grid-template-columns: 64px 1fr;
  gap: var(--sp-3);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--c-line);
}

.confirm-line:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

.confirm-line dt {
  color: var(--c-text-3);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}

.confirm-line dd {
  margin: 0;
  color: var(--c-text);
  font-weight: 650;
}

/* ---------- the decide timeline: the website's numbered steps ---------- */
.timeline {
  display: grid;
  gap: var(--sp-3);
  margin: var(--sp-4) 0 0;
  padding: 0;
  list-style: none;
  counter-reset: pj-step;
}

.timeline li {
  position: relative;
  padding: var(--sp-3) var(--sp-4) var(--sp-3) 56px;
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface);
  box-shadow: var(--shadow-sm);
  color: var(--c-text-2);
  counter-increment: pj-step;
}

.timeline li::before {
  content: counter(pj-step);
  position: absolute;
  top: var(--sp-3);
  left: var(--sp-3);
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--pj-amber-l), var(--pj-amber-d));
  color: var(--pj-navy); /* 8.0:1 on the lighter stop, 5.0:1 on the darker */
  font-weight: 900;
  font-size: 15px;
}

/* ---------- the two-slot photo card (contract 6.7; owner 2026-10-04 "pictures are key"): two tiles side
   by side - the guide well (the thumbnail once taken), the shot's name and how to take it, then the two big
   ways in: [Take photo] (amber) and [Choose from gallery] (white). minmax(0, 1fr) + min-width 0 keep a
   390 px phone from overflowing ---------- */
.photo-card {
  display: block;
  min-width: 0;
  margin: 0;
  padding: var(--sp-4);
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow: var(--shadow-sm);
}

.photo-slots {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3);
}

.photo-slot {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  gap: var(--sp-2);
  min-width: 0;
}

/* the navy viewfinder well: the guide reads on it; camera.js lands the thumbnail inside */
.photo-shot {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--r-md);
  background: var(--pj-navy-plate);
}

.photo-guide {
  width: 88%;
  height: auto;
  pointer-events: none;
}

.photo-slot[data-state="filled"] .photo-shot {
  box-shadow: inset 0 0 0 2px var(--c-good-fill);
}

/* a slot the server already holds: the check shows without a local thumbnail */
.photo-slot.is-filled .photo-shot::after {
  content: "";
  position: absolute;
  right: 6px;
  bottom: 6px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--c-good-fill) var(--pj-check-white) center / 14px 14px no-repeat;
}

.photo-slot.is-filled .photo-guide {
  opacity: .4;
}

.photo-slot-body {
  display: grid;
  gap: 6px;
  min-width: 0;
}

.photo-slot-label {
  color: var(--c-text);
  font-family: var(--font-display);
  overflow-wrap: anywhere;
  font-size: 15px;
  font-weight: 750;
  line-height: 1.25;
}

.photo-slot-hint {
  color: var(--c-text-3);
  overflow-wrap: anywhere;
  font-size: 13px;
  line-height: 1.35;
}

/* the two ways in: both full-width pills, 48 px, 8 px apart */
body.pub .photo-take,
body.pub .photo-pick {
  width: 100%;
  min-height: var(--pj-tap);
  padding: 0 var(--sp-3);
  font-size: 15px;
  font-weight: 750;
  white-space: normal;
  text-align: center;
  line-height: 1.2;
}

body.pub .photo-take {
  border: 0;
  background: var(--pj-pill);
  color: #ffffff;
  box-shadow: var(--shadow-amber);
}

body.pub .photo-pick {
  border: 1.5px solid var(--c-line-strong);
  background: var(--c-surface);
  color: var(--pj-navy);
}

/* once a shot is in, Retake / Replace step back to quiet white pills */
body.pub .photo-slot[data-state="filled"] .photo-take {
  border: 1.5px solid var(--c-line-strong);
  background: var(--c-surface);
  color: var(--pj-navy);
  box-shadow: none;
}

/* the native file inputs stay reachable (keyboard, no-JS) but take no room */
.photo-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  overflow: hidden;
}

.photo-slot:has(.photo-input[data-file]:focus-visible) .photo-take,
.photo-slot:has(.photo-input[data-library]:focus-visible) .photo-pick {
  outline: 2.5px solid var(--pj-amber-d);
  outline-offset: 2px;
}

/* a picked photo still decoding, or one that would not open (camera.js sets data-state) */
.photo-slot[data-state="loading"] .photo-shot {
  box-shadow: inset 0 0 0 2px var(--pj-amber);
}

.photo-wait {
  position: absolute;
  inset: auto 6px 6px;
  padding: 4px 6px;
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, .92);
  color: var(--c-text-2);
  font-size: var(--fs-1);
  font-weight: 700;
  line-height: 1.25;
  text-align: center;
}

.photo-slot[data-state="unreadable"] .photo-shot {
  box-shadow: inset 0 0 0 2px var(--c-danger-fill);
}

.photo-slot[data-state="unreadable"] .photo-wait {
  color: var(--c-danger-text);
}

/* the captured thumbnail, flown in from the shutter (camera.js sets --thumb from a blob: URL) */
.photo-thumb {
  position: absolute;
  inset: 0;
  background: var(--thumb) center / cover no-repeat, var(--pj-navy);
}

.photo-check {
  position: absolute;
  right: 6px;
  bottom: 6px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--c-good-fill) var(--pj-check-white) center / 14px 14px no-repeat;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .4);
  animation: pj-pop var(--dur-2) var(--ease);
}

/* the background upload progress ring (camera.js sets --ring 0deg..360deg) */
.photo-progress {
  position: absolute;
  top: 6px;
  left: 6px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: conic-gradient(var(--pj-amber) var(--ring, 0deg), rgba(255, 255, 255, .3) 0);
  -webkit-mask: radial-gradient(circle 7px at center, transparent 98%, #000 100%);
  mask: radial-gradient(circle 7px at center, transparent 98%, #000 100%);
}

/* NEO-411: an upload the server refused - the thumbnail dims, a red note and a Retry button say so */
.photo-slot[data-state="failed"] .photo-shot {
  box-shadow: inset 0 0 0 2px var(--c-danger-fill);
}

.photo-slot[data-state="failed"] .photo-thumb {
  opacity: .45;
}

.photo-advice,
.photo-failed {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-2);
  grid-column: 1 / -1;
  margin: 0;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  font-size: 15px;
  font-weight: 600;
}

.photo-advice {
  border: 1px solid var(--c-warn-line);
  background: var(--c-warn-bg);
  color: var(--c-warn-text);
}

.photo-failed {
  border: 1px solid var(--c-danger-line);
  background: var(--c-danger-bg);
  color: var(--c-danger-text);
}

/* camera.js's small text buttons inside those notes (Retake, Use it, Retry) */
.actionbar-secondary {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--sp-2);
  border: 0;
  background: transparent;
  color: var(--c-link);
  font: inherit;
  font-weight: 750;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.photo-failed .actionbar-secondary {
  color: var(--c-danger-text);
}

.photo-count {
  margin: 0;
  color: var(--c-text);
  font-size: 16px;
  font-weight: 700;
  text-align: center;
}

.photo-count:empty {
  display: none;
}

/* ---------- the in-page camera (camera.js; getUserMedia environment camera) - black, always ---------- */
.camera {
  position: fixed;
  inset: 0;
  z-index: var(--z-ghost);
  display: grid;
  grid-template-rows: 1fr auto;
  background: #000000;
}

.camera-view {
  position: relative;
  overflow: hidden;
}

.camera-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* the SAME line illustration as a live overlay at 40 % (contract 6.7) */
.camera-overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
}

.camera-overlay img {
  width: min(70%, 320px);
  height: auto;
  opacity: .4;
}

.camera-instruction {
  position: absolute;
  right: 0;
  bottom: var(--sp-4);
  left: 0;
  padding: 0 var(--sp-4);
  color: #ffffff;
  font-size: 18px;
  font-weight: 650;
  text-align: center;
  text-shadow: 0 1px 6px rgba(0, 0, 0, .8);
}

.camera-flash {
  position: absolute;
  inset: 0;
  background: #ffffff;
  opacity: 0;
  pointer-events: none;
}

.camera-flash[data-fire] {
  animation: pj-flash 180ms var(--ease);
}

.camera-bar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5) calc(var(--sp-4) + env(safe-area-inset-bottom));
  background: #000000;
}

.camera-shutter {
  justify-self: center;
  width: 72px;
  height: 72px;
  border: 4px solid #ffffff;
  border-radius: 50%;
  background: #ffffff;
  box-shadow: 0 0 0 4px rgba(255, 255, 255, .25);
  cursor: pointer;
}

.camera-shutter:active {
  transform: scale(.94);
}

.camera-cancel {
  min-height: 48px;
  border: 0;
  background: transparent;
  color: #ffffff;
  font: inherit;
  font-weight: 650;
  cursor: pointer;
}

/* ---------- THE REVEAL: the white paper receipt, a perforated top edge, the total on a navy plate ---------- */
body.pub .receipt {
  position: relative;
  max-width: none;
  margin-top: var(--sp-5);
  padding: calc(var(--sp-6) + 8px) var(--sp-5) var(--sp-5);
  border: 0;
  border-radius: 0 0 var(--r-lg) var(--r-lg);
  background: var(--c-paper);
  color: var(--c-paper-text);
  font-size: 16px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, .06), 0 22px 40px -16px rgba(15, 23, 42, .28);
}

/* the perforated top edge: page-cream half-circles bitten out of the paper's top (the receipt always sits on
   the cream column). Drawn, not masked, so the paper keeps its shadow. */
.receipt-perf {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  height: 8px;
  background: radial-gradient(circle 8px at 8px 0, var(--c-canvas) 0 7px, transparent 7.5px) 0 0 / 16px 16px repeat-x;
}

.receipt-lines {
  display: grid;
  gap: var(--sp-3);
  margin: 0;
}

.receipt-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-bottom: var(--sp-3);
  border-bottom: 1px dashed var(--c-line);
}

.receipt-line dt {
  color: var(--c-text);
  font-weight: 600;
}

.receipt-line dd {
  margin: 0;
  font-weight: 750;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.receipt-line--sub dt,
.receipt-line--sub dd {
  color: var(--c-text-2);
  font-size: 15px;
}

/* each line prints in: translateY 6 px -> 0 + fade, staggered by receipt.js via --i */
.receipt-line,
.receipt-total,
.receipt-checklist {
  animation: pj-line-in var(--dur-3) var(--ease) both;
  animation-delay: calc(var(--i, 0) * 70ms);
}

.receipt-total {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin: var(--sp-4) calc(-1 * var(--sp-2)) 0;
  padding: var(--sp-4) var(--sp-4);
  overflow: hidden;
  border-radius: var(--r-md);
  background-color: var(--pj-navy);
  background-image: var(--pj-tex-topo-dark), var(--pj-navy-plate);
  color: var(--pj-on-navy);
  box-shadow: 0 14px 30px -12px rgba(15, 23, 42, .55);
}

.receipt-total-label {
  color: var(--pj-on-navy-3);
  font-size: 14px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.receipt-total-figure {
  display: grid;
  justify-items: end;
}

.receipt-total-amount {
  color: var(--pj-on-navy);
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  /* receipt.js reserves the final width so the count-up never shifts the layout */
}

/* the amber underline grows under the total, with one soft amber glow */
.receipt-underline {
  display: block;
  width: 0;
  height: 4px;
  margin-top: 6px;
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--pj-amber-l), var(--pj-amber-d));
  box-shadow: 0 4px 12px -2px rgba(249, 115, 22, .6);
}

.receipt-underline[data-grown] {
  width: 100%;
  transition: width var(--dur-4) var(--ease);
}

.receipt .receipt-note {
  margin: var(--sp-2) 0 0;
  color: var(--c-text-3);
  font-size: 14px;
}

.receipt .receipt-checklist {
  display: grid;
  gap: var(--sp-2);
  margin: var(--sp-4) 0 0;
  padding: var(--sp-4);
  border: 1px solid var(--pj-mint-line);
  border-radius: var(--r-md);
  background: var(--pj-mint-bg);
  list-style: none;
}

.receipt .receipt-checklist li {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  color: var(--pj-mint-text);
  font-weight: 600;
}

.receipt .receipt-checklist li::before {
  content: "";
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin-top: 2px;
  border-radius: 50%;
  background: var(--c-good-fill) var(--pj-check-white) center / 12px 12px no-repeat;
}

.receipt .receipt-lock {
  margin: var(--sp-4) 0 0;
  color: var(--c-text-2);
  font-size: 15px;
}

.receipt .receipt-held {
  display: inline-block;
  margin: var(--sp-3) 0 0;
  padding: 4px 12px;
  border: 1px solid var(--c-warn-line);
  border-radius: var(--r-pill);
  background: var(--c-warn-bg);
  color: var(--c-warn-text);
  font-size: 14px;
  font-weight: 700;
}

.receipt .receipt-lockid {
  margin: var(--sp-2) 0 0;
  color: var(--c-text-3);
  font-size: 13px;
}


/* ---------- objection chips (a tap expands its factual answer in place) - the website's FAQ ---------- */
.objections {
  display: grid;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
}

.objection {
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition: border-color var(--dur-2) var(--ease);
}

.objection[open] {
  border-color: rgba(249, 115, 22, .45);
}

.objection > summary { list-style: none; }
.objection > summary::-webkit-details-marker { display: none; }

.objection-q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  min-height: 52px;
  padding: var(--sp-2) var(--sp-4);
  color: var(--c-text);
  font-weight: 700;
  cursor: pointer;
}

.objection-q::after {
  content: "+";
  display: grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgba(249, 115, 22, .12);
  color: var(--pj-amber-800);
  font-size: 18px;
  font-weight: 900;
  transition: transform var(--dur-3) var(--ease), background-color var(--dur-2) var(--ease);
}

.objection[open] .objection-q::after {
  content: "\2013";
  background: var(--pj-navy);
  color: var(--pj-amber-ink);
  transform: rotate(180deg);
}

.objection-a {
  padding: 0 var(--sp-4) var(--sp-4);
  color: var(--c-text-2);
  font-size: 15px;
}

/* ---------- agent pages (gen/pages.py bodies) and the price preview ---------- */
.pub-main article,
.preview {
  padding: var(--sp-5);
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow: var(--shadow-sm);
  overflow-wrap: break-word;
}

.pub-main article h1 {
  color: var(--c-text);
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -.02em;
  line-height: 1.2;
}

.pub-main article h2 {
  margin-top: var(--sp-6);
  color: var(--c-text);
  font-size: 20px;
  font-weight: 800;
}

.pub-main article p,
.pub-main article ul,
.pub-main article ol,
.preview ul,
.preview p {
  margin-top: var(--sp-3);
  color: var(--c-text-2);
}

.pub-main article ul,
.pub-main article ol,
.preview ul {
  padding-left: 1.3em;
}

.pub-main article li + li,
.preview li + li {
  margin-top: var(--sp-1);
}

.lede {
  color: var(--c-text-2);
  font-size: 17px;
}

.page-meta {
  color: var(--c-text-3);
  font-size: 14px;
}

.preview-estimate {
  color: var(--c-text);
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 800;
}

/* example blocks: line breaks kept, the body's own font - never <pre> */
.snippet {
  margin-top: var(--sp-4);
  padding: var(--sp-4);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface-2);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* agent-page tables (problems, limits): fit a phone - long codes and fix sentences wrap inside their cell,
   and a table still wider than the column scrolls inside itself */
article > table {
  display: block;
  max-width: 100%;
  margin-top: var(--sp-4);
  overflow-x: auto;
  border-collapse: collapse;
}

article > table th,
article > table td {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--c-line);
  overflow-wrap: break-word;
  text-align: left;
  vertical-align: top;
}

article > table th {
  color: var(--c-text);
  font-size: 14px;
}

@media (max-width: 560px) {
  article > table td:first-child {
    overflow-wrap: anywhere; /* phones: the long snake_case code may break mid-word */
  }
}

/* ---------- round 3: one screen per stage (owner 2026-10-04 "they just stay on the same screen") ---------- */
/* a part of a long page: a quiet heading with air above it, so the page reads as sections, not a chore */
.form-section {
  margin-top: var(--sp-4);
  scroll-margin-top: var(--sp-4);
}

.price-part {
  scroll-margin-top: var(--sp-3);
}

/* the price before the photo gate passes: a calm placeholder where the number will appear */
.price-locked {
  margin-top: var(--sp-5);
  padding: var(--sp-5);
  border: 1.5px dashed var(--c-line-strong);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  text-align: center;
}

.price-locked-title {
  margin: 0 0 var(--sp-1);
  color: var(--c-text);
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 750;
}

/* the photos once the price shows: folded to one line, open to change a shot */
.photos-done {
  padding: 0 var(--sp-4);
  border: 1px solid var(--c-good-line);
  border-radius: var(--r-md);
  background: var(--c-good-bg);
}

.photos-done > summary {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--pj-tap);
  color: var(--c-good-text);
  font-weight: 700;
  cursor: pointer;
  list-style: none;
}

.photos-done > summary::-webkit-details-marker {
  display: none;
}

.photos-done > summary::before {
  content: "";
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--c-good-fill) var(--pj-check-white) center / 12px 12px no-repeat;
}

.photos-done[open] {
  padding-bottom: var(--sp-4);
}

/* a re-priced page says what changed, in words */
.pub-notice {
  margin: var(--sp-3) 0 0;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--c-warn-line);
  border-radius: var(--r-md);
  background: var(--c-warn-bg);
  color: var(--c-warn-text);
  font-weight: 650;
}

/* ---------- round 2 pieces ---------- */
/* NEO-416: the price restated right under the sign step's headline */
.decide-total {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-1) var(--sp-3);
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  background-color: var(--pj-navy);
  background-image: var(--pj-tex-topo-dark), var(--pj-navy-plate);
  color: var(--pj-on-navy-3);
  font-weight: 700;
}

.decide-total-amount {
  color: var(--pj-on-navy);
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.decide-total-held {
  flex-basis: 100%;
  color: var(--pj-amber-ink);
  font-size: 14px;
}

/* The booked screen's photo ask (FLOW_SPEC 2.5, gate 2026-10-18_photo-ask): optional, below the booking card;
   up to 6 thumbnails in a 3-wide grid, each with what happened to it. */
.photo-ask {
  margin-top: var(--sp-5);
  padding: var(--sp-5) var(--sp-4);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface-2);
}

.photo-ask[hidden],
.photo-ask-add[hidden],
.photo-ask-count[hidden],
.photo-ask-limit[hidden],
.photo-ask-retry[hidden],
.photo-ask-all[hidden] {
  display: none;
}

.photo-ask-lead {
  color: var(--c-text);
  font-size: 16px;
}

.photo-ask-tip {
  margin-top: var(--sp-2);
  color: var(--c-text-2);
  font-size: 15px;
}

.photo-ask-add {
  position: relative;
  width: 100%;
  margin-top: var(--sp-4);
}

.photo-ask-add:has(.photo-input:focus-visible) {
  outline: 2.5px solid var(--pj-amber-d);
  outline-offset: 2px;
}

.photo-ask-thumbs {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-3);
  margin: var(--sp-4) 0 0;
  padding: 0;
  list-style: none;
}

.photo-ask-thumbs:empty {
  display: none;
}

.photo-ask-thumb {
  display: grid;
  gap: var(--sp-1);
  justify-items: center;
  color: var(--c-text-2);
  font-size: 13px;
  line-height: 1.3;
}

.photo-ask-thumb img {
  width: 100%;
  aspect-ratio: 1;
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  object-fit: cover;
}

.photo-ask-thumb[data-state="added"] .photo-ask-note {
  color: var(--c-good-text);
  font-weight: 700;
}

.photo-ask-thumb[data-state="failed"] .photo-ask-note,
.photo-ask-thumb[data-state="refused"] .photo-ask-note {
  color: var(--c-danger-text);
  font-weight: 700;
}

.photo-ask-retry {
  min-height: 44px;
  padding: 0 var(--sp-3);
  font-size: 14px;
}

.photo-ask-count {
  margin-top: var(--sp-4);
  color: var(--c-text);
  font-weight: 700;
}

.photo-ask-limit {
  margin-top: var(--sp-2);
  color: var(--c-text-2);
  font-size: 14px;
}

.photo-ask-done {
  width: 100%;
  margin-top: var(--sp-4);
}

.photo-ask-all:focus {
  outline: none;
}

.photo-ask-all:focus-visible {
  outline: 2.5px solid var(--pj-amber-d);
  outline-offset: 4px;
}

.photo-ask-thanks,
.photo-ask-all {
  margin-top: var(--sp-4);
  color: var(--c-text);
  font-weight: 650;
}

/* the done pages: a short headline, the booking itself in its own card (NEO-426) */
.done-detail {
  margin: var(--sp-4) 0 0;
  padding: var(--sp-4);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface-2);
  color: var(--c-text);
  font-size: 17px;
  font-weight: 650;
  text-align: left;
}

/* the token pages opened without their link (NEO-424): a calm card, never an alarm */
.state-card h2 {
  text-wrap: balance;
}

/* ---------- keyframes (all neutralised to ~instant under prefers-reduced-motion by tokens.css) ---------- */
@keyframes pj-line-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes pj-pop {
  from { transform: scale(.6); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

@keyframes pj-flash {
  from { opacity: .9; }
  to { opacity: 0; }
}

/* ---------- small phones (320-374 px): the bar and the type tighten, nothing scrolls sideways ---------- */
@media (max-width: 374px) {
  body.pub {
    --pj-gutter: 12px;
  }

  .pub-logo {
    height: 26px;
  }

  .pub-call {
    font-size: 14px;
  }

  .pub-h1 {
    font-size: 24px;
  }

  .receipt-total-amount {
    font-size: 34px;
  }

  body.pub .call-pill {
    min-width: 96px;
    padding: 0 var(--sp-4);
  }
}

/* ---------- desktop: the same column, more air (the phone stays the lead design) ---------- */
@media (min-width: 640px) {
  .pub-main {
    padding-top: var(--sp-10);
    padding-bottom: var(--sp-12);
  }

  .pub-h1 {
    font-size: 34px;
  }

  .pub-logo {
    height: 34px;
  }

  .tile-group,
  .drop-group,
  .photo-card {
    padding: var(--sp-5);
  }
}

/* ---------- Door 1's count and area screens (owner 2026-10-04; FINAL_FLOW_v4): the big 1 / 2 / 3 / 4+ tiles,
   the kind chips, the length x width steppers, and the "Area i of N" tag. The tilting slab is slab.css. ---------- */
.hint {
  margin: 0 0 var(--sp-2);
  color: var(--c-text-3);
  font-size: 14px;
  line-height: 1.4;
}

.h1-tag {
  display: inline-block;
  margin-left: 8px;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--pj-tint);
  color: var(--pj-amber-700);
  font-size: var(--fs-1);
  font-weight: 800;
  letter-spacing: .03em;
  vertical-align: middle;
}

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

.big-pick {
  aspect-ratio: 1;
  min-width: 0;
  border: 1.5px solid var(--c-line-strong);
  border-radius: 18px;
  background: var(--c-surface);
  box-shadow: var(--shadow-sm);
  color: var(--pj-navy);
  font: 900 30px var(--font-display);
  cursor: pointer;
}

.big-pick:hover,
.big-pick:focus-visible {
  border-color: var(--pj-amber);
  background: var(--pj-tint);
  color: var(--pj-amber-700);
  box-shadow: 0 0 0 3px var(--pj-ring);
}

.kinds {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  margin: 6px 0 2px;
}

.kind {
  position: relative;
  display: grid;
  place-items: center;
  min-width: 0;
  min-height: 44px;
  padding: 8px 2px;
  border: 1.5px solid var(--c-line-strong);
  border-radius: 12px;
  background: var(--c-surface);
  color: var(--c-text);
  font-size: 15px;
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  cursor: pointer;
}

.kind:has(.kind-input:checked) {
  border-color: var(--pj-amber);
  background: var(--pj-tint);
  color: var(--pj-amber-700);
  font-weight: 800;
}

.kind:has(.kind-input:focus-visible) {
  outline: 2.5px solid var(--pj-amber-d);
  outline-offset: 2px;
}

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

.name-row {
  margin: 6px 0 2px;
}

.dims {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-top: 8px;
}

.dim {
  min-width: 0;
}

.dim-cap {
  display: block;
  margin-top: 3px;
  color: var(--c-text-3);
  font-size: var(--fs-1);
  text-align: center;
}

.stepper-ctl {
  display: flex;
  align-items: center;
  overflow: hidden;
  border: 1.5px solid var(--c-line-strong);
  border-radius: 12px;
  background: var(--c-surface);
}

.stepper-btn {
  flex: 0 0 46px;
  height: 50px;
  border: 0;
  background: var(--c-column);
  color: var(--pj-navy);
  font: 900 22px var(--font-ui);
  cursor: pointer;
}

.stepper-btn[hidden] {
  display: none;
}

.stepper-num {
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--c-text);
  font: 800 19px var(--font-ui);
  text-align: center;
  appearance: textfield;
}

/* the minus and plus are the steppers: the browser's own tiny arrows inside the box only crowd the number */
.stepper-num::-webkit-outer-spin-button,
.stepper-num::-webkit-inner-spin-button {
  margin: 0;
  appearance: none;
}

/* ---------- the area screen for a first-timer (2026-10-13): the one instruction, the size presets for a
   homeowner who does not know their square feet, and a minus / number / plus under the picture for each
   corner (slab.js keeps them and the picture in step) ---------- */
body.pub .area-how {
  margin: 0 0 10px;
  padding: 10px 12px;
  border-left: 4px solid var(--pj-amber);
  border-radius: 10px;
  background: var(--pj-tint);
  color: var(--c-text);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.4;
}

.presets {
  margin: 10px 0 2px;
}

.presets[hidden] {
  display: none;
}

.presets-cap,
.chips-cap {
  margin: 0 0 6px;
  color: var(--c-text-2);
  font-size: 15px;
  font-weight: 700;
}

.preset-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px;
}

.preset {
  display: grid;
  gap: 2px;
  min-width: 0;
  min-height: 52px;
  padding: 8px 6px;
  border: 1.5px solid var(--c-line-strong);
  border-radius: 12px;
  background: var(--c-surface);
  color: var(--c-text);
  font: 700 15px/1.2 var(--font-ui);
  text-align: center;
  cursor: pointer;
}

.preset:hover,
.preset:focus-visible {
  border-color: var(--pj-amber);
  background: var(--pj-tint);
  color: var(--pj-amber-700);
}

.preset-size {
  color: var(--c-text-3);
  font-size: 14px;
  font-weight: 600;
}

.corner-field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

body.pub .deeper-pick {
  margin-top: 8px;
  font-size: 15px;
}

.saved-line {
  margin: var(--sp-3) 0;
  padding: 10px 12px;
  border-radius: 12px;
  background: var(--pj-tint);
  color: var(--c-text);
  font-size: 16px;
  line-height: 1.4;
}

.slab-card {
  margin: 8px 0;
  padding: 8px 10px;
  border: 1px solid var(--c-line);
  border-radius: 16px;
  background: var(--c-surface);
}

.slab-hint {
  margin: 0 0 6px;
  color: var(--c-text);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
}

.corner-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-top: 8px;
}

/* ---------- the price screen's finish (owner 2026-10-04; FINAL_FLOW_v4): the lift picture, the replacement
   anchor and the saving pill, the warranty card and badges, and the upgrades screen. receipt.js plays the lift
   and the roll; with no JS the server's final state is already on the page. ---------- */
.lift {
  position: relative;
  margin-top: var(--sp-4);
  padding: var(--sp-3);
  overflow: hidden;
  text-align: center;
}

.lift[hidden] {
  display: none;
}

.lift-svg {
  display: block;
  width: 100%;
  height: auto;
  max-height: 210px;
}

.lift-cap {
  margin: 0 0 var(--sp-1);
  color: var(--pj-navy);
  font-size: 15px;
  font-weight: 800;
}

.lift-cap.is-done {
  color: var(--c-good-text);
}

.lift-skip {
  display: block;
  margin: var(--sp-1) auto 0;
  padding: 6px 12px;
  font-size: 13px;
}

.confetti {
  position: fixed;
  inset: 0;
  z-index: 60;
  overflow: hidden;
  pointer-events: none;
}

.confetti span {
  position: absolute;
  width: 10px;
  height: 14px;
  border-radius: 2px;
  background: var(--c, var(--pj-amber));
  animation: pj-burst 2s cubic-bezier(.15, .7, .3, 1) forwards;
}

@keyframes pj-burst {
  to {
    opacity: 0;
    transform: translate(var(--x), var(--y)) rotate(var(--r));
  }
}

.receipt .receipt-was {
  margin: var(--sp-3) 0 0;
  color: var(--c-text-2);
  font-size: 15px;
  line-height: 1.45;
}

.receipt-was b {
  color: var(--c-text);
}

.receipt-was.is-struck b {
  text-decoration: line-through;
  text-decoration-thickness: 2px;
}

.linkish {
  color: var(--c-link);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.receipt .receipt-save {
  display: inline-block;
  margin: var(--sp-2) 0 0;
  padding: 5px 14px;
  border: 1px solid var(--c-good-line);
  border-radius: var(--r-pill);
  background: var(--c-good-bg);
  color: var(--c-good-text);
  font-size: 15px;
  font-weight: 800;
}

.receipt .receipt-save[hidden] {
  display: none;
}

.receipt-save.is-in {
  animation: pj-save-in var(--dur-3) var(--ease);
}

@keyframes pj-save-in {
  from {
    opacity: 0;
    transform: scale(.92);
  }
}

.trust-card {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  margin-top: var(--sp-4);
  padding: var(--sp-4);
  border: 1px solid var(--c-good-line);
  border-radius: var(--r-md);
  background: var(--c-good-bg);
}

.trust-card-icon {
  flex: 0 0 auto;
  color: var(--c-good-fill);
}

.trust-card-title {
  margin: 0;
  color: var(--c-text);
  font-size: 16px;
  font-weight: 800;
}

.trust-card-text {
  margin: var(--sp-1) 0 0;
  color: var(--c-text-2);
  font-size: 14px;
  line-height: 1.4;
}

.trust-badges {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-2);
  margin: var(--sp-3) 0 0;
  padding: 0;
  list-style: none;
}

.trust-badge {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  background: var(--c-surface);
  color: var(--c-text);
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.25;
}

.trust-badge svg {
  flex: 0 0 auto;
  color: var(--c-good-fill);
}

.up-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 150px;
  align-items: center;
  gap: var(--sp-1) var(--sp-3);
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
}

.up-text .hint {
  margin: 2px 0 0;
}

.up-unit {
  grid-column: 2;
  margin: 0;
  color: var(--c-text-3);
  font-size: var(--fs-1);
  text-align: center;
}

.up-total {
  margin: 0 0 var(--sp-3);
  color: var(--pj-navy);
  font-size: 32px;
  font-weight: 900;
}

@media (prefers-reduced-motion: reduce) {
  .confetti span,
  .receipt-save.is-in {
    animation: none;
  }
}

/* owner 2026-10-05: the price leads the receipt (FINAL_FLOW_v4); the breakdown follows under a hairline */
.receipt .receipt-was + .receipt-total {
  margin-top: var(--sp-3);
}

.receipt > .receipt-total:first-of-type {
  margin-top: 0;
}

.receipt .receipt-lines {
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px dashed var(--c-line);
}

.receipt .lift {
  margin: var(--sp-4) 0 0;
}

.decide-measure {
  margin: var(--sp-6) 0 var(--sp-2);
  text-align: center;
}

.decide-visit {
  width: 100%;
}

/* ===== FINAL_FLOW_v4 "tighter phone layout", copied from the approved demo (owner 2026-10-04: "scrolls too
   much... a lot of empty space"; 2026-10-05: "why you couldn't just copy it") - these rules win ===== */
body.pub .pub-main { padding-top: 6px; padding-bottom: 0; }
/* r33 (owner 2026-10-06, "you can't scroll to the whole page"): with the footer gone, nothing reserved room under the
   FIXED phone action bar - the page's last lines sat behind Continue/Call. The column now reserves it itself. */
@media (max-width: 899px) {
  body.pub .pub-main { padding-bottom: calc(var(--pj-bar, 0px) + 16px + env(safe-area-inset-bottom)); }
}
body.pub .stepper { padding-top: 2px; padding-bottom: 0; min-height: 0; }
body.pub .stepper-inner { padding-top: 4px; padding-bottom: 4px; }
body.pub .pub-h1 { font-size: 25px; line-height: 1.2; margin: 0 0 4px; }
body.pub .field { margin: 0 0 8px; }
body.pub .field-label { margin-bottom: 3px; font-size: 14px; }
body.pub .input { min-height: 46px; padding-top: 9px; padding-bottom: 9px; }
body.pub .hint { margin: 0 0 8px; font-size: 14px; line-height: 1.4; color: var(--c-text-3); }
body.pub .pub-form { gap: 0; }
/* the consent sentence: small, grey, no box of its own */
body.pub .consent-line { font-size: 14px; line-height: 1.45; color: var(--c-text-3); margin: 0; padding: 0; border: 0; background: none; text-wrap: pretty; }
body.pub .consent-line a { font-weight: 400; }
body.pub .consent-line a { color: inherit; }
/* the optional apt/unit stays one quiet line until opened */
body.pub .addr-more { margin: -4px 0 6px; }
body.pub .addr-more > summary { font-size: var(--fs-1); min-height: 48px; padding: 0; scroll-margin-bottom: calc(var(--pj-bar, 160px) + 40px); }

/* ===== FINAL_FLOW_v4 photos: per area a small label, then two dashed tap-boxes; the whole box takes the photo,
   a small chip picks from the gallery; a filled box shows the photo with a green edge ===== */
body.pub .photo-card { margin: 4px 0 8px; padding: 0; border: 0; background: none; box-shadow: none; }
body.pub .photo-card-title { padding: 0; margin: 0 0 4px; font-size: 15px; font-weight: 800; }
body.pub .photo-slots { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
body.pub .photo-slot { position: relative; aspect-ratio: 4 / 5; min-width: 0; padding: 0; overflow: hidden;
  border: 2px dashed var(--c-line-strong); border-radius: 14px; background: var(--c-surface); box-shadow: none; }
body.pub .photo-slot.is-filled, body.pub .photo-slot[data-state="filled"] { border: 2px solid var(--c-good-fill); }
body.pub .photo-slot[data-state="failed"] { border-color: var(--c-danger-fill); }
body.pub .photo-shot { position: absolute; inset: 0; margin: 0; border-radius: 12px; background: none; aspect-ratio: auto; }
body.pub .photo-guide { display: none; }
body.pub .photo-slot-body { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 2px; padding: 54px 8px 8px; text-align: center; }
body.pub .photo-slot-label { font-size: 15px; font-weight: 800; color: var(--c-text); line-height: 1.25; }
body.pub .photo-slot-hint { font-size: 14px; color: var(--c-text-3); line-height: 1.3; }
body.pub .photo-slot.is-filled .photo-slot-label, body.pub .photo-slot.is-filled .photo-slot-hint,
body.pub .photo-slot[data-state="filled"] .photo-slot-label,
body.pub .photo-slot[data-state="filled"] .photo-slot-hint { visibility: hidden; }
/* the whole box is the camera button; its words stay for screen readers */
body.pub .photo-take { position: absolute; inset: 0; z-index: 1; margin: 0; min-height: 0; border: 0; border-radius: 12px;
  background: none; box-shadow: none; color: transparent; font-size: 1px; }
/* NEO-925: a filled box shows its photo. The older "quiet white Retake pill" rule for a filled slot is more
   specific than the label rule above, so it painted this whole-box label white over the thumbnail and a taken
   photo looked like an empty white box. In this layout the label stays see-through in every state. */
body.pub .photo-slot[data-state="filled"] .photo-take { border: 0; background: none; box-shadow: none;
  color: transparent; }
body.pub .photo-take:focus-visible { outline: 3px solid var(--pj-amber); outline-offset: -3px; }
body.pub .photo-pick { position: absolute; top: 6px; right: 6px; left: 6px; z-index: 2; min-height: 44px; margin: 0;
  padding: 0 8px; border: 1px solid var(--c-line-strong); border-radius: 999px; background: #fff;
  color: var(--c-text-2); font: 700 14px var(--font-ui); box-shadow: none; width: auto; }
/* NEO-923: an upload the server refused. camera.js appends the failure box to the slot; left in flow it painted
   UNDER the take label (z-index 1, a full-box layer) and the pill (z-index 2), so Retry could not be tapped, and
   it sat on the slot's own title. It is now a layer above both (z-index 3), held to the bottom of the box below
   the pill's row (6 + 44 px) so the gallery pill stays tappable, with Retry as its own full-width 44 px row. The
   title and hint step aside while it shows, as they do once the box is filled.
   The quality advice ("Looks a little dark - retake?", Retake / Use it) was the same unpositioned in-flow block
   with the same cause, so it is the same layer: one rule for both notes. Its two buttons sit side by side in
   their own row (each at least 54 px wide, so the pair fits the 136 px slot of a 320 px phone) and the row wraps
   to a column only if a slot is narrower still; the words shrink first, the 44 px buttons never do. */
body.pub .photo-slot[data-state="failed"] .photo-slot-label,
body.pub .photo-slot[data-state="failed"] .photo-slot-hint { visibility: hidden; }
body.pub .photo-slot:has(.photo-advice) .photo-slot-label,
body.pub .photo-slot:has(.photo-advice) .photo-slot-hint { visibility: hidden; }
body.pub .photo-advice,
body.pub .photo-failed { position: absolute; z-index: 3; right: 6px; bottom: 6px; left: 6px; box-sizing: border-box;
  max-height: calc(100% - 56px); overflow: hidden; flex-direction: column; flex-wrap: nowrap; align-items: stretch;
  gap: 4px; padding: 6px 8px; font-size: 14px; line-height: 1.25; text-align: center; }
body.pub .photo-advice > span,
body.pub .photo-failed > span { min-height: 0; overflow: hidden; }
body.pub .photo-advice { padding: 6px 4px; }
body.pub .photo-failed .actionbar-secondary { width: 100%; }
body.pub .photo-advice .actionbar-secondary,
body.pub .photo-failed .actionbar-secondary { flex: none; justify-content: center;
  border: 1.5px solid currentColor; border-radius: 999px; background: var(--c-surface); text-decoration: none; }
body.pub .photo-advice-actions { display: flex; flex: none; flex-wrap: wrap; gap: 4px; }
body.pub .photo-advice-actions .actionbar-secondary { flex: 1 1 54px; min-width: 54px; padding: 0; white-space: nowrap; }
body.pub .photo-count:empty { display: none; }
body.pub .photo-count { margin: 4px 0; font-size: 15px; }

/* the locked-price placeholder card is not in the demo: the grey See-my-price button already says it */
body.pub .price-locked { display: none; }

/* ===== FINAL_FLOW_v4 area screen: the surface tiles sit on the page (no box), dimension captions under the
   steppers. The corner instruction is SHOWN, above the picture (2026-10-13: it was clipped to 1 px, and the
   only words left sat under the phone's bottom bar) ===== */
body.pub .kinds-group { margin: 6px 0 2px; padding: 0; border: 0; }
body.pub .kinds-group > legend { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
/* Door 2 "How much needs lifting?" (2026-10-15): a visible question over two columns of the same tiles */
body.pub .sizes-group { margin: 14px 0 2px; padding: 0; border: 0; min-width: 0; }
body.pub .sizes-group > legend { padding: 0; margin: 0 0 4px; }
body.pub .kinds.sizes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
body.pub .dim { display: flex; flex-direction: column-reverse; gap: 3px; }
body.pub .dim-cap { font-size: 15px; color: var(--c-text-2); text-align: center; font-weight: 600; }

/* ===== FINAL_FLOW_v4 price screen: the price is a big plain number on the page (no paper, no navy band),
   then the lift picture, then the lines in one small card ending in Total ===== */
body.pub .receipt { margin: 2px 0 0; padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none; }
body.pub .receipt::before, body.pub .receipt::after, body.pub .receipt-perf { display: none; }
body.pub .receipt .receipt-was { margin: 2px 0 0; font-size: 14px; line-height: 1.4; color: var(--c-text-3); }
body.pub .receipt-total { display: block; margin: 2px 0; padding: 0; background: none; border: 0; box-shadow: none;
  border-radius: 0; animation: none; }
body.pub .receipt-total::before, body.pub .receipt-total::after { display: none; }
body.pub .receipt-total-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
body.pub .receipt-total-figure { display: block; }
body.pub .receipt-total-amount { color: var(--pj-navy); font: 900 46px/1.08 var(--font-display); letter-spacing: -.01em; }
body.pub .receipt-underline { display: none; }
body.pub .receipt .receipt-save { margin: 0 0 6px; font-size: 15px; padding: 5px 12px; }
body.pub .receipt .receipt-note { margin: 0 0 8px; font-size: 14px; line-height: 1.4; color: var(--c-text-3); }
body.pub .receipt .lift { margin: 0 0 8px; padding: 6px; border: 1px solid var(--c-line); border-radius: 16px;
  background: var(--c-surface); box-shadow: none; }
body.pub .receipt .receipt-lines { margin: 8px 0; padding: 8px 10px; gap: 0; border: 1px solid var(--c-line);
  border-radius: 16px; background: var(--c-surface); }
body.pub .receipt .receipt-line { padding: 6px 0; border-bottom: 1px dashed var(--c-line); font-size: 14.5px; animation: none; }
body.pub .receipt .receipt-line dt, body.pub .receipt .receipt-line dd { font-size: 14.5px; }
body.pub .receipt .receipt-line--total { border: 0; }
body.pub .receipt .receipt-line--total dt, body.pub .receipt .receipt-line--total dd { font-weight: 900; font-size: 18px;
  color: var(--pj-navy); }
body.pub .receipt .receipt-lock { margin: 0; font-size: var(--fs-1); line-height: 1.4; color: var(--c-text-3); }
body.pub .receipt .receipt-lockid { display: none; }
/* the trust card and badges at the demo's size */
body.pub .trust-card { margin: 8px 0; padding: 8px 10px; }
body.pub .trust-badges { gap: 6px; margin: 8px 0; }
body.pub .trust-badge { padding: 8px; font-size: 13px; }
body.pub .decide-measure { margin: 8px 0 4px; text-align: left; }
body.pub .decide-visit { width: auto; }
/* "Your photos are in - change one": one quiet line, not a green panel */
body.pub .photos-done { margin: 0 0 4px; padding: 0; border: 0; background: none; }
body.pub .photos-done > summary { min-height: 0; padding: 0; font-size: 13px; font-weight: 700; color: var(--c-good-text);
  background: none; border: 0; }

/* DEL-6: a tapped submit button reads as working (slots.js sets aria-busy while the server answers). */
body.pub [aria-busy="true"] { opacity: 0.7; cursor: progress; }

/* ---------- the contact steps' pinned bar (macros.consent_bar): the box and its ONE sentence above Continue / Call
   (white on navy), the Terms line under them. From 900 px the bar is static in the column and the text reads dark. */
body.pub .action-bar--consent .consent-line {
  grid-column: 1 / -1;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--pj-on-navy);
  font-size: 14px;
  line-height: 1.4;
}

body.pub .action-bar--consent .consent-line a {
  display: inline;
  min-height: 0;
  color: var(--pj-amber-l);
  font-weight: 700;
  text-decoration: underline;
  white-space: normal;
}

/* The consent step: the bar stays PINNED on a phone (Continue must be there while typing - owner 2026-10-04). Its
   real height is measured by instant.js into --pj-bar (safe-area inset included); this value is only the no-script
   fallback, sized for the v4 bar (the box's three lines + Continue + the Terms line measure 152 px). */
@media (max-width: 899px) {
  body.pub:has(.action-bar.action-bar--consent:not([hidden]):not(:is(.state-card, .error-card, .done-card) .action-bar)) {
    --pj-bar: 160px;
  }
}

@media (min-width: 900px) {
  body.pub .action-bar--consent .consent-line {
    color: var(--c-text-2);
  }

  body.pub .action-bar--consent .consent-line a {
    color: var(--c-link);
  }
}

/* ---------- the relaunch first screens (FLOW_SPEC section 1, A1, A3, A6) ---------- */
/* the hero photo (the foam injection) under the heading and the one line, on both first screens */
.job-photo { display: block; width: 100%; height: auto; aspect-ratio: 900 / 331; border-radius: var(--r-md); margin: 0 0 10px; }

/* the optional text box (macros.text_box): the box at the left of ONE sentence. textbox.js shakes it once when
   Continue is pressed unticked (a flash of the outline with reduced motion) and pops it when ticked. */
body.pub .textbox { display: flex; gap: 9px; align-items: center; margin: 0; padding: 4px 6px; border: 2px solid transparent; border-radius: 10px; cursor: pointer; }
body.pub .textbox input { width: 22px; height: 22px; flex: 0 0 22px; margin: 1px 0 0; accent-color: #f97316; }
body.pub .textbox label { cursor: pointer; }
body.pub .textbox--asked { border-color: #f59e0b; background: rgba(245, 158, 11, .14); }
body.pub .textbox--shake { animation: textbox-shake .65s ease-in-out 1; }
body.pub .textbox--flash { animation: textbox-flash .8s linear 1; }
body.pub .textbox--ticked { animation: textbox-glow .7s ease-out 1; }
body.pub .textbox--ticked input { animation: textbox-pop .32s cubic-bezier(.3,1.6,.5,1) 1; }
@keyframes textbox-shake { 0%,100% { transform: translateX(0) } 12% { transform: translateX(-13px) } 26% { transform: translateX(12px) } 40% { transform: translateX(-10px) } 54% { transform: translateX(8px) } 68% { transform: translateX(-5px) } 82% { transform: translateX(3px) } }
@keyframes textbox-flash { 0%,50%,100% { border-color: #f59e0b } 25%,75% { border-color: transparent } }
@keyframes textbox-glow { 0% { box-shadow: 0 0 0 0 rgba(34,197,94,.55) } 100% { box-shadow: 0 0 0 12px rgba(34,197,94,0) } }
@keyframes textbox-pop { 0% { transform: scale(1) } 45% { transform: scale(1.35) } 100% { transform: scale(1) } }
body.pub .action-bar--consent .textbox { grid-column: 1 / -1; }
body.pub .action-bar--consent .textbox .consent-line { font-size: 13px; line-height: 1.4; }

/* "Continuing accepts our Terms & Privacy.": small, under the buttons (the 13 px floor of DEL-1 holds) */
body.pub .terms-line { margin: 4px 0 0; font-size: 13px; line-height: 1.4; color: var(--c-text-3); }
body.pub .terms-line a { color: inherit; text-decoration: underline; }
body.pub .action-bar--consent .terms-line { grid-column: 1 / -1; margin: 2px 0 0; text-align: center; }
@media (max-width: 899px) {
  body.pub .action-bar--consent .terms-line { color: #94a3b8; }
}

/* no footer on the door steps (the number is in the header, Terms and Privacy in the consent): the bar's room is
   reserved once, by .pub-main's padding. The legal and token pages are not flow steps and keep it. */
body.pub:has(.pub-main[data-flow]) .pub-footer { display: none; }

/* ---------- the polyjacks.com booking widget (/embed/book, gate 2026-10-17_pj-widget): the same pages inside a frame
   on a site page. frame.js sizes the frame to the PAGE, so nothing here may size itself to the frame's own viewport
   (a 100vh body would pin the frame at its tallest step), and the Continue bar sits at the end of the form - a bar
   pinned to the bottom of a frame as tall as its page would sit at the page's foot anyway, off the phone's screen.
   No top bar and no footer: the site page around the frame has both, and its phone number. ---------- */
body.pub.pub-embed {
  min-height: 0;
}

body.pub.pub-embed .pub-main {
  padding-top: var(--sp-3);
  padding-bottom: var(--sp-4);
}

/* two rules, not one list: a browser without :has() (iOS < 15.4) drops a whole selector list it cannot parse,
   and would leave the bar fixed over the frame's last screen (G5 review F1) */
body.pub.pub-embed .action-bar {
  position: static;
  transform: none;
  margin-top: var(--sp-3);
  border-radius: var(--r-lg);
  box-shadow: none;
}

body.pub.pub-embed:has(.addr-list:not([hidden])) .action-bar {
  transform: none;
}

body.pub.pub-embed .offline-bar {
  top: 0;
}
