/* UNSCRW — Estimator Modern theme + Classic View density toggle.
   Executive View (default) = Modern: airy, surfaces the financial wins.
   Classic View (.classic) = mimics CCC ONE density for zero-friction
   regional-team onboarding. Same data, presentation-density switch. */

:root {
  --u-ink:        #1A1A1A;
  --u-steel:      #185FA5;   /* primary steel blue */
  --u-steel-600:  #0C447C;
  --u-steel-050:  #E6F1FB;
  --u-line:       #D3D1C7;
  --u-line-soft:  #ECEAE3;
  --u-paper:      #F7F7F4;
  --u-white:      #FFFFFF;
  --u-slate:      #5F5E5A;
  --u-green:      #0F6E56;
  --u-green-050:  #E1F5EE;
  --u-amber-050:  #FAEEDA;
  --u-amber-700:  #854F0B;

  --u-radius:     10px;
  --u-pad:        16px;
  --u-row:        1;         /* density multiplier, overridden by Classic */
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: 'Inter', -apple-system, Segoe UI, Roboto, sans-serif;
  color: var(--u-ink);
  background: var(--u-paper);
  font-size: 15px;
  line-height: 1.5;
}

a { color: var(--u-steel); text-decoration: none; }

/* ---- Top bar --------------------------------------------------------- */
.u-topbar {
  background: var(--u-steel);
  color: var(--u-white);
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 12px 22px;
}
.u-brand { display: flex; align-items: center; gap: 9px; font-weight: 700;
  font-family: 'Space Grotesk', 'Inter', sans-serif; letter-spacing: .5px; font-size: 18px; }
.u-screw {
  width: 20px; height: 20px; border-radius: 50%;
  border: 2px solid var(--u-white); position: relative; display: inline-block;
}
.u-screw::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 11px; height: 2px; background: var(--u-white);
  transform: translate(-50%, -50%) rotate(45deg);
}
.u-nav { display: flex; gap: 6px; margin-left: 8px; }
.u-nav a {
  color: #CFE2F6; padding: 6px 12px; border-radius: 6px; font-size: 14px;
}
.u-nav a.active { color: var(--u-white); background: rgba(255,255,255,.14); }
.u-topbar .u-right { margin-left: auto; display: flex; align-items: center; gap: 14px; }

/* ---- Site footer ----------------------------------------------------- */
.u-foot { background: var(--u-steel-600); color: var(--u-steel-050); margin-top: 56px; }
.u-foot-inner {
  max-width: 720px; margin: 0 auto; padding: 40px 22px 24px;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px;
}
.u-foot-inner h4 {
  font-family: 'Space Grotesk', 'Inter', sans-serif;
  font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--u-white); margin: 0 0 12px; font-weight: 700;
}
.u-foot-inner a {
  display: block; color: var(--u-steel-050); font-size: 14px;
  margin-bottom: 9px; opacity: .9; word-break: break-word;
}
.u-foot-inner a:hover { opacity: 1; text-decoration: underline; }
.u-foot-bottom {
  border-top: 1px solid rgba(255,255,255,.15); padding: 16px 22px;
  text-align: center; font-size: 12px; color: var(--u-steel-050); opacity: .7;
}
@media (max-width: 560px) { .u-foot-inner { grid-template-columns: repeat(2, 1fr); } }

/* ---- View toggle ----------------------------------------------------- */
.u-toggle {
  display: inline-flex; background: rgba(255,255,255,.15);
  border-radius: 999px; padding: 3px; font-size: 13px;
}
.u-toggle button {
  border: 0; background: transparent; color: #CFE2F6; cursor: pointer;
  padding: 5px 12px; border-radius: 999px; font: inherit;
}
.u-toggle button.on { background: var(--u-white); color: var(--u-steel-600); font-weight: 500; }

/* ---- Layout ---------------------------------------------------------- */
.u-wrap { max-width: 980px; margin: 26px auto; padding: 0 22px; }
.u-h1 { font-family: 'Space Grotesk','Inter',sans-serif; font-weight: 700;
  font-size: 24px; margin: 0 0 4px; }
.u-sub { color: var(--u-slate); margin: 0 0 22px; }

.u-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px,1fr)); gap: 16px; }
.u-card {
  background: var(--u-white); border: 1px solid var(--u-line);
  border-radius: var(--u-radius); padding: 20px;
}
.u-card h3 { margin: 0 0 4px; font-size: 17px; }
.u-tag { display: inline-block; font-size: 12px; color: var(--u-steel-600);
  background: var(--u-steel-050); padding: 2px 9px; border-radius: 6px; margin-bottom: 10px; }
.u-price { color: var(--u-slate); font-size: 13px; }
.u-btn {
  display: inline-block; margin-top: 14px; background: var(--u-steel); color: #fff;
  padding: 9px 16px; border-radius: 8px; font-size: 14px; border: 0; cursor: pointer;
}
.u-btn.ghost { background: transparent; color: var(--u-steel); border: 1px solid var(--u-line); }

/* ---- Metric row ------------------------------------------------------ */
.u-metrics { display: grid; grid-template-columns: repeat(auto-fit,minmax(150px,1fr));
  gap: 12px; margin: 0 0 22px; }
.u-metric { background: var(--u-white); border: 1px solid var(--u-line);
  border-radius: var(--u-radius); padding: 14px 16px; }
.u-metric .k { font-size: 13px; color: var(--u-slate); }
.u-metric .v { font-size: 26px; font-weight: 500; }

/* ---- Estimate table -------------------------------------------------- */
.u-table { width: 100%; border-collapse: collapse; background: var(--u-white);
  border: 1px solid var(--u-line); border-radius: var(--u-radius); overflow: hidden; font-size: 14px; }
.u-table th { text-align: left; background: var(--u-line-soft); color: var(--u-slate);
  font-weight: 500; padding: 11px 14px; }
.u-table td { padding: 12px 14px; border-top: 1px solid var(--u-line-soft); }

.u-panel-title { font-size: 13px; text-transform: uppercase; letter-spacing: .5px;
  color: var(--u-slate); margin: 26px 0 10px; }

/* =====================================================================
   CLASSIC VIEW — CCC ONE-style density. Tighter rows, banded tables,
   squarer corners, smaller type. Deliberately utilitarian.
   ===================================================================== */
body.classic { font-size: 13px; background: #EDEBE4; }
body.classic .u-wrap { max-width: 1120px; margin: 14px auto; }
body.classic .u-h1 { font-size: 19px; }
body.classic .u-sub { margin-bottom: 12px; }
body.classic .u-card,
body.classic .u-metric,
body.classic .u-table { border-radius: 3px; }
body.classic .u-card { padding: 12px 14px; }
body.classic .u-metric { padding: 8px 12px; }
body.classic .u-metric .v { font-size: 20px; }
body.classic .u-cards,
body.classic .u-metrics { gap: 8px; }
body.classic .u-table th { padding: 6px 10px; }
body.classic .u-table td { padding: 6px 10px; }
body.classic .u-table tbody tr:nth-child(even) td,
body.classic .u-table tr:nth-child(even) td { background: #F4F2EC; }
body.classic .u-btn { border-radius: 3px; padding: 6px 12px; }
body.classic .u-topbar { padding: 7px 16px; }

/* ---- Executive vs Classic layout fork (genuine, not just density) ---- */
.classic-only { display: none; }
body.classic .exec-only { display: none; }
body.classic .classic-only { display: block; }

/* form grid */
.u-form { display: grid; grid-template-columns: repeat(auto-fit,minmax(150px,1fr));
  gap: 12px; align-items: end; }
.u-field label { display: block; font-size: 13px; color: var(--u-slate); margin-bottom: 5px; }
.u-field input, .u-field select {
  width: 100%; padding: 9px 10px; border: 1px solid var(--u-line);
  border-radius: 8px; font: inherit; background: #fff; }
body.classic .u-field input, body.classic .u-field select { border-radius: 3px; padding: 6px 8px; }

/* result banners */
.u-banner { border-radius: var(--u-radius); padding: 14px 16px; margin: 4px 0 18px; font-size: 15px; }
.u-banner.win { background: var(--u-green-050); color: var(--u-green); border: 1px solid #5DCAA5; }
.u-banner.warn { background: var(--u-amber-050); color: var(--u-amber-700); border: 1px solid #FAC775; }
.u-banner.flat { background: #EFEEE8; color: var(--u-slate); border: 1px solid var(--u-line); }
body.classic .u-banner { border-radius: 3px; }

/* before/after compare cards */
.u-compare { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.u-side { border: 1px solid var(--u-line); border-radius: var(--u-radius); padding: 14px 16px; background: #fff; }
.u-side h4 { margin: 0 0 8px; font-size: 13px; text-transform: uppercase; letter-spacing: .5px; color: var(--u-slate); }
.u-pill { display: inline-block; font-size: 12px; padding: 3px 10px; border-radius: 999px; }
.u-pill.total { background: #FCEBEB; color: #A32D2D; }
.u-pill.ok { background: var(--u-green-050); color: var(--u-green); }
.u-bar { height: 8px; background: var(--u-line-soft); border-radius: 999px; overflow: hidden; margin: 8px 0; }
.u-bar span { display: block; height: 100%; }

/* ---- Hero result (visual-hierarchy pass, 2026-07-07 — one focal point,
   everything else demoted; see All Engines Studio/VISUAL_DESIGN_PRINCIPLES.md) */
.u-hero { border-radius: 14px; padding: 26px 28px; margin: 4px 0 20px; }
.u-hero.win  { background: var(--u-green-050); border: 1px solid #5DCAA5; }
.u-hero.warn { background: var(--u-amber-050); border: 1px solid #FAC775; }
.u-hero.flat { background: #EFEEE8; border: 1px solid var(--u-line); }
.u-hero .eyebrow { font-size: 12px; text-transform: uppercase; letter-spacing: .6px; opacity: .7; }
.u-hero .stat { font-family: 'Space Grotesk','Inter',sans-serif; font-weight: 700;
  font-size: 44px; line-height: 1.08; margin: 4px 0 8px; }
.u-hero.win .stat  { color: var(--u-green); }
.u-hero.warn .stat { color: var(--u-amber-700); }
.u-hero.flat .stat { color: var(--u-ink); }
.u-hero .sub { font-size: 15px; color: var(--u-ink); opacity: .82; margin: 0; max-width: 62ch; }
body.classic .u-hero { border-radius: 3px; padding: 14px 16px; margin-bottom: 12px; }
body.classic .u-hero .stat { font-size: 26px; margin: 2px 0 4px; }

/* ---- Supporting-evidence band (Gestalt common region: everything below
   the hero reads as one demoted "backup material" group, not equal peers) */
.u-evidence { background: #EFEEE8; border-radius: 14px; padding: 20px 22px 22px; }
.u-evidence .u-panel-title:first-child { margin-top: 0; }
body.classic .u-evidence { background: transparent; border-radius: 0; padding: 0; }

/* metrics grid, demoted (smaller than the hero stat on purpose) */
.u-metrics.ambient .u-metric .v { font-size: 19px; font-weight: 500; }

/* ---- value tease (preview before paid unlock) ---- */
.u-tease { border: 2px solid var(--u-steel); border-radius: 12px; padding: 20px 22px;
  background: var(--u-steel-050); margin: 4px 0 18px; }
body.classic .u-tease { border-radius: 3px; padding: 14px 16px; }
.u-tease .eyebrow { font-size: 12px; text-transform: uppercase; letter-spacing: .5px; color: var(--u-steel-600); }
.u-tease h3 { margin: 6px 0 8px; font-size: 20px; }
.u-lock-note { font-size: 12px; color: var(--u-slate); margin-top: 10px; }
.report-body.teased { filter: blur(6px); pointer-events: none; user-select: none; opacity: .9; }

/* ---- Unlock reveal (2026-07-16) — .u-reveal only ever renders on the
   hero/banner markup shown right after a paid unlock (see total_loss.html /
   repair.html), so this animation always means "just cleared the paywall,"
   not "revisiting an old report." JS (base.html) adds .is-in one frame after
   load so the transition actually fires instead of snapping in. */
.u-reveal {
  opacity: 0;
  transform: translateY(22px) scale(.94);
  transition: opacity .5s ease, transform .6s cubic-bezier(.22,1.35,.36,1);
}
.u-reveal.is-in { opacity: 1; transform: translateY(0) scale(1); }

@keyframes u-pulse-green { 0% { box-shadow: 0 3px 6px rgba(11,64,49,.25), 0 18px 44px rgba(15,110,86,.35), 0 0 0 0 rgba(15,110,86,.55); } 65% { box-shadow: 0 3px 6px rgba(11,64,49,.25), 0 18px 44px rgba(15,110,86,.35), 0 0 0 30px rgba(15,110,86,0); } 100% { box-shadow: 0 3px 6px rgba(11,64,49,.25), 0 18px 44px rgba(15,110,86,.35), 0 0 0 0 rgba(15,110,86,0); } }
@keyframes u-pulse-amber { 0% { box-shadow: 0 3px 6px rgba(84,50,7,.25), 0 18px 44px rgba(133,79,11,.32), 0 0 0 0 rgba(133,79,11,.5); } 65% { box-shadow: 0 3px 6px rgba(84,50,7,.25), 0 18px 44px rgba(133,79,11,.32), 0 0 0 30px rgba(133,79,11,0); } 100% { box-shadow: 0 3px 6px rgba(84,50,7,.25), 0 18px 44px rgba(133,79,11,.32), 0 0 0 0 rgba(133,79,11,0); } }
@keyframes u-pulse-slate { 0% { box-shadow: 0 2px 5px rgba(60,59,56,.22), 0 14px 36px rgba(95,94,90,.26), 0 0 0 0 rgba(95,94,90,.4); } 65% { box-shadow: 0 2px 5px rgba(60,59,56,.22), 0 14px 36px rgba(95,94,90,.26), 0 0 0 24px rgba(95,94,90,0); } 100% { box-shadow: 0 2px 5px rgba(60,59,56,.22), 0 14px 36px rgba(95,94,90,.26), 0 0 0 0 rgba(95,94,90,0); } }
.u-reveal.is-in.u-hero.win,  .u-reveal.is-in.u-banner.win  { animation: u-pulse-green 1.5s ease-out .5s 1; }
.u-reveal.is-in.u-hero.warn { animation: u-pulse-amber 1.5s ease-out .5s 1; }
.u-reveal.is-in.u-hero.flat { animation: u-pulse-slate 1.5s ease-out .5s 1; }

/* ---- Persistent result accent (2026-07-16, 2nd pass) ----
   The pulse above fades to nothing after ~1.5s and leaves the card looking
   identical to every other card on the page (confirmed live: Golz demo,
   nobody could tell the answer from the rest of the UI once the pulse
   passed). This block is NOT tied to animation/JS at all — it's a permanent
   thick accent border + lifted shadow so the result reads as "different"
   whether or not anyone caught the reveal moment. Declared after .u-hero/
   .u-banner win/warn/flat so the border-left here wins the cascade. */
.u-reveal.win  { border-left: 10px solid var(--u-green);     border-color: rgba(15,110,86,.5); border-left-color: var(--u-green);
  background: linear-gradient(180deg, rgba(15,110,86,.04), rgba(15,110,86,.13)), var(--u-green-050);
  box-shadow: 0 3px 6px rgba(11,64,49,.25), 0 18px 44px rgba(15,110,86,.35); }
.u-reveal.warn { border-left: 10px solid var(--u-amber-700); border-color: rgba(133,79,11,.5); border-left-color: var(--u-amber-700);
  background: linear-gradient(180deg, rgba(133,79,11,.04), rgba(133,79,11,.11)), var(--u-amber-050);
  box-shadow: 0 3px 6px rgba(84,50,7,.25), 0 18px 44px rgba(133,79,11,.32); }
.u-reveal.flat { border-left: 10px solid var(--u-slate);     border-color: rgba(95,94,90,.5); border-left-color: var(--u-slate);
  box-shadow: 0 2px 5px rgba(60,59,56,.22), 0 14px 36px rgba(95,94,90,.26); }
/* Parked Crease v2 advisory, swept 2026-07-28: this override reset the width,
   the shadow and the background image but NOT the colour — so the three
   non-accent sides kept the outcome tint that `.u-reveal.win/.warn/.flat` set
   via the `border-color` shorthand above, and the shop-floor view rendered a
   green- or amber-boxed card in a palette that has no other tinted borders.
   Only the three sides are reset, deliberately: setting the `border-color`
   shorthand here would win the cascade over `.u-reveal.win`'s
   `border-left-color` too and take the left accent — the whole point of the
   block — with it. */
body.classic .u-reveal {
  border-left-width: 4px; box-shadow: none; background-image: none;
  border-top-color: var(--u-line);
  border-right-color: var(--u-line);
  border-bottom-color: var(--u-line);
}

/* ---- Persistent accent, extended down the page (2026-07-16, 3rd pass) ----
   Atul: the hero/banner border alone reads as an isolated box, not a
   consistent "this whole result is the product" indicator. Same treatment
   on .u-evidence (total-loss's tables/metrics card, and repair's now-wrapped
   equivalent — see repair.html) so the accent repeats down the page instead
   of stopping after the first card. */
.u-evidence.win  { border-left: 10px solid var(--u-green);     box-shadow: 0 2px 5px rgba(11,64,49,.16), 0 12px 30px rgba(15,110,86,.20); }
.u-evidence.warn { border-left: 10px solid var(--u-amber-700); box-shadow: 0 2px 5px rgba(84,50,7,.16), 0 12px 30px rgba(133,79,11,.18); }
.u-evidence.flat { border-left: 10px solid var(--u-slate);     box-shadow: 0 2px 5px rgba(60,59,56,.14), 0 12px 30px rgba(95,94,90,.16); }
body.classic .u-evidence.win, body.classic .u-evidence.warn, body.classic .u-evidence.flat {
  border-left-width: 4px; box-shadow: none;
}

/* ---- Form -> RESULT divider (2026-07-25) — Atul: nothing visually separates
   the input form from the output; the answer must read as a RESULT. Labeled
   full-width rule rendered directly above the verdict hero/banner, tinted by
   outcome on total-loss, green on repair's fresh unlock, neutral on reopen. */
.u-result-divider {
  display: flex; align-items: center; gap: 14px; margin: 36px 0 16px;
  font-size: 12px; font-weight: 700; letter-spacing: .22em; text-transform: uppercase;
  color: var(--u-slate);
}
.u-result-divider::before, .u-result-divider::after {
  content: ""; flex: 1; height: 2px; background: var(--u-line); border-radius: 1px;
}
.u-result-divider.win  { color: var(--u-green); }
.u-result-divider.win::before,  .u-result-divider.win::after  { background: rgba(15,110,86,.35); }
.u-result-divider.warn { color: var(--u-amber-700); }
.u-result-divider.warn::before, .u-result-divider.warn::after { background: rgba(133,79,11,.35); }
.u-result-divider.flat { color: var(--u-slate); } /* explicit — total_loss emits 'flat' */
body.classic .u-result-divider { letter-spacing: .12em; }
body.classic .u-result-divider::before, body.classic .u-result-divider::after { height: 1px; }

/* ---- The Crease (2026-07-25 v3) — physics moved to JS (base.html). CSS
   proximity snap was tried first (v2) and felt too weak: browser-defined
   thresholds are tuned for light trackpad flicks, and Atul's spec is shop
   hands — "mechanics, not neurosurgeons." The JS version makes the one-
   viewport span around the divider bistable (rest with input filling the
   screen, or result filling the screen — never straddling the crease) with
   the commit decided at the midpoint. No scroll-snap-type here on purpose:
   CSS snap would fight the JS smooth-scroll settle. */

/* ---- Scoped print (2026-07-25 v2) — the ONE print-isolation mechanism on the
   site; used by both Export Letter (PDF) and Print Parts List. printScoped()
   (base.html) clones the target block into a .print-clone wrapper appended to
   <body>, then adds .print-scoped to <body>.

   `display: none`, NOT `visibility: hidden`: v1 used visibility, which keeps
   every hidden box's layout — so the hidden report body still generated ~7
   blank pages after the letter. display:none is what actually removes them,
   and it only works because the clone is a direct child of <body> rather than
   nested inside the subtree being hidden. Also no position:absolute here (v1
   had it): absolutely-positioned print content taller than one sheet clips
   instead of flowing onto page 2. */
.print-clone { display: none; }
@media print {
  body.print-scoped > *:not(.print-clone) { display: none !important; }
  body.print-scoped .print-clone { display: block; }
}

/* ---- Insurer letter export (2026-07-25) — hidden on screen; printLetter()
   prints this block alone via printScoped() above. Save-as-PDF = email
   attachment / portal upload; paper = fax. Serif + letterhead on purpose:
   adjusters treat a formal letter as a negotiation artifact, an app
   screenshot as noise. */
.letter-print { display: none; }
/* Name left, contact right, sharing one baseline — the approved mockup's
   header (2026-07-28).

   Corrected in gate round 3: this comment used to say the contact block "is
   allowed to wrap onto a second right-aligned line… wrapping is better than
   clipping." That is no longer the design. Each contact ROW is now atomic
   (.lp-sub white-space: nowrap, see below), so a row never wraps internally at
   any width; what happens instead is that the whole block DROPS to its own
   full-width line beneath the name. That is deliberate — an internally wrapped
   row is what stranded a "·" at a line end on the first two attempts.
   Consequence worth stating: a row wider than the space it lands in would now
   overflow rather than wrap. Not reachable with the seeded letterheads (Gölz
   rows ≈2.6in; Riverside drops to a full 6.7in line), but it becomes live the
   day shop contact details are editable — at which point the honest fix is to
   shrink the font or truncate, not to re-allow the wrap. */
/* flex-wrap + a real flex-basis on .lp-contact (2026-07-28, gate P1).
   The first version was sized to the one name that had been PDF-verified,
   "Gölz Motors". Rendered against Riverside Collision (Demo) — the letter a
   PROSPECT sees — the 20pt name ate ~4.1in of the 6.7in printable width, the
   contact block was squeezed below what its own nowrap segments need, and the
   two deterministic rows became FOUR with a dangling "·" stranded at the end of
   two of them: exactly the defect letterhead_lines() exists to prevent, undone
   by the header geometry. Now the contact block keeps its flex-basis (3.5in, see below) and simply
   drops to its own full-width right-aligned line when the name won't leave room
   — short names keep the mockup's shared baseline, long names degrade to a
   stacked header instead of a mangled one. */
/* column-gap, NOT gap (gate round 3). `gap` was written when this container
   could not wrap, so only its column component ever applied. Adding flex-wrap
   in the previous commit silently promoted it to a ROW gap as well, dropping
   0.3in (21.6pt) of dead vertical space between the shop name and the contact
   block on exactly the letter the wrap exists for — Riverside — and growing the
   header by ~0.3in on a document that @page and page-break-inside tune to
   exactly one sheet, and that has already spilled onto a second sheet twice. */
.letter-print .lp-head { display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; column-gap: 0.3in; }
/* nowrap + flex-shrink:0 — the first generated PDF broke "Gölz Motors" across
   two lines, which also dropped the contact block off the shared baseline the
   approved mockup calls for. A shop name is a proper noun; it does not wrap. */
.letter-print .lp-shop { font-size: 20pt; font-weight: 700; letter-spacing: .02em;
  flex: 0 0 auto; white-space: nowrap; }
/* The contact block is ONE flex item wrapping N lines. Each line was its own
   element at first, which made every line a sibling flex item laid out
   side-by-side across the header instead of stacked under it.
   min-width:0 is load-bearing, not tidying: a flex item defaults to
   min-width:auto and refuses to shrink below min-content, and with nowrap
   segments inside, min-content is the longest segment. */
.letter-print .lp-contact { flex: 1 1 3.5in; min-width: 0; text-align: right; }
/* Each ROW is atomic. The earlier fix only moved the wrap threshold, so a shop
   name in the ~3.0-3.4in band still left the contact block just narrow enough
   for a row to break at the space after a "·" — the stranded separator, latent
   rather than fixed (gate, 2026-07-28). A nowrap row cannot break internally at
   any width, so the dangling separator is structurally impossible instead of
   merely improbable; if a row will not fit beside the name, flex-wrap drops the
   whole block to its own full-width line. The 3.5in basis is sized above the
   longest seeded row (Riverside's phone+email, ~3.3in) so the drop happens
   before a row would ever overflow. */
.letter-print .lp-sub { font-size: 10pt; color: #444; white-space: nowrap; }
/* Each contact segment is atomic. Breaks fall BETWEEN segments (the plain
   spaces around the "·") and never inside one — the first PDF split Gölz's
   phone as "(847) 317-" / "9880" because the separator was non-breaking and
   the only remaining break opportunity was mid-number. */
.letter-print .lp-seg { white-space: nowrap; }
.letter-print .lp-rule { border: none; border-top: 2px solid #111; margin: 8px 0 0; }
.letter-print .lp-rule-thin { border: none; border-top: 1px solid #999; margin: 2px 0 20px; }
/* Ruled fill-in blanks. Replaces [bracketed] tokens — a bracket reads as
   unfinished software to an adjuster; a ruled line reads as a form. */
.letter-print .lp-fill { display: inline-block; min-width: 2.05in;
  border-bottom: 1px solid #444; }
.letter-print .lp-fill.lp-fill-wide { min-width: 3.1in; }
.letter-print .lp-date, .letter-print .lp-block, .letter-print .lp-re { margin-bottom: 18px; }
.letter-print p { margin: 0 0 14px; }
/* ~46pt of clear space above the signature rule, per the approved mockup —
   room to actually sign. */
.letter-print .lp-sig { margin-top: 46pt; }
.letter-print .lp-sig-rule { border-top: 1px solid #444; width: 3.1in; margin-bottom: 4px; }
.letter-print .lp-sig-label { font-size: 10.5pt; color: #333; }
.letter-print .lp-enc { margin-top: 26px; font-size: 10.5pt; color: #333; }

/* 🚨 @page is DOCUMENT-GLOBAL — CSS gives no way to scope it to one printed
   block, so this governs the Print Parts List export as well as the letter.
   Both were re-verified as single-sheet against generated PDFs before shipping
   (2026-07-28); if you change these margins, re-check BOTH artifacts.
   Before this rule existed there was no @page at all, so the browser's own
   margin applied and the letter's 0.4in/0.5in padding stacked on top of it —
   which is why identical code fit on one page on 7/25 and spilled onto a second
   on 7/26. Output depended on the reader's print-dialog margin setting. */
@page { size: letter; margin: 0.85in 0.9in; }

@media print {
  body.print-scoped .print-clone .letter-print {
    display: block; width: 100%;
    font-family: Georgia, 'Times New Roman', serif; color: #111;
    /* 12.5pt/1.6 was larger than a business letter and sat a few lines from
       overflow on its own. Padding is gone — @page owns the margins now, and
       keeping both stacked them. */
    font-size: 11.75pt; line-height: 1.46; box-sizing: border-box;
  }
  /* Nothing prevented the signature being orphaned onto a blank second sheet,
     which is exactly what 7/26's export did. */
  body.print-scoped .print-clone .letter-print,
  body.print-scoped .print-clone .letter-print .lp-sig,
  body.print-scoped .print-clone .letter-print .lp-enc {
    page-break-inside: avoid; break-inside: avoid;
  }
}

/* ---- Demo-mode indicator (session-sticky ?demo=1) ---- */
.u-demo-badge {
  background: var(--u-amber-050); color: var(--u-amber-700); font-size: 11px;
  font-weight: 700; letter-spacing: .4px; padding: 3px 9px; border-radius: 999px;
  border: 1px solid #FAC775;
}

/* ---- Classic-view milestone counter (2026-07-25) ---------------------
   The shop-floor view shows a celebration rung ("Over $15,000") instead of the
   exact billings figure — see milestone() in app.py. Read as one object, the
   way a dealership sign reads: "OVER" is set in the same face, size, weight and
   color as the number, not as a demoted label (Atul, 2026-07-25). Tabular
   numerals so the digits don't reflow while the roll-up runs. After the roll
   lands there's a single pop, then a slow breathe that never stops — the number
   stays alive on the wall instead of going inert three seconds after login.
   Executive never renders any of these classes. */
.u-milestone { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }
.u-milestone .ms-pre { font-size: 1em; font-weight: inherit; color: inherit;
  letter-spacing: .01em; margin-right: .3em; text-transform: uppercase; }
.u-milestone .ms-num { display: inline-block; }

/* The landing beat: one pop on the number... */
.u-milestone.is-landed .ms-num { animation: u-ms-pop .5s cubic-bezier(.22,1,.36,1) 1; }
@keyframes u-ms-pop {
  0%   { transform: scale(1); }
  38%  { transform: scale(1.055); }
  100% { transform: scale(1); }
}
/* ...then the whole line breathes, slowly, forever. Scaled from the left so
   the figure doesn't drift on its baseline, and shallow enough (2.2%) to read
   as a heartbeat rather than a bounce. */
.u-milestone.is-landed { display: inline-block; transform-origin: left center;
  animation: u-ms-breathe 3.4s ease-in-out .55s infinite; }
@keyframes u-ms-breathe {
  0%, 100% { transform: scale(1);     opacity: 1; }
  50%      { transform: scale(1.022); opacity: .93; }
}

/* The metric tile's rung is static — no roll, no breathe (two counters moving
   on one screen reads as a slot machine) — but "OVER" matches there too. */
.u-metric .ms-pre { font-size: 1em; font-weight: inherit; color: inherit;
  letter-spacing: .01em; margin-right: .3em; text-transform: uppercase; }

@media (prefers-reduced-motion: reduce) {
  .u-milestone.is-landed,
  .u-milestone.is-landed .ms-num { animation: none; }
}
