/* ==========================================================
   Sawgrass Product Development Request — public stylesheet

   Brand colours are MEASURED from clients/logos/snl-logo.jpg, not
   guessed: the wordmark's bright green samples at #72B41F and the
   "NUTRA LABS" dark green at #22581E. Everything else is derived
   from those two.

   This file is standalone ON PURPOSE. It imports nothing from
   clients/css/, because the public application must be deployable
   without the internal client and must never inherit an internal
   administrative look (instruction 6, 12).
   ========================================================== */

:root {
  --brand-green:        #72B41F;
  --brand-green-dark:   #5E9619;
  --brand-green-darker: #4A7714;
  --brand-forest:       #22581E;
  --brand-forest-deep:  #163C14;
  --brand-tint:         #F2F8EA;
  --brand-tint-edge:    #DCEBC6;

  --ink:        #1B2419;
  --ink-soft:   #4C5A48;
  --ink-faint:  #6E7B6B;
  --line:       #DFE4DC;
  --line-soft:  #EDF0EB;
  --surface:    #FFFFFF;
  --canvas:     #F7F9F5;
  --danger:     #B3261E;
  --danger-bg:  #FCEEED;

  --radius:     14px;
  --radius-sm:  10px;
  --shadow:     0 1px 2px rgba(22,60,20,.05), 0 8px 24px rgba(22,60,20,.07);
  --shadow-lift:0 2px 4px rgba(22,60,20,.07), 0 14px 34px rgba(22,60,20,.11);

  --font-head: "Montserrat", "Segoe UI", -apple-system, BlinkMacSystemFont, Arial, sans-serif;
  --font-body: "Open Sans", "Segoe UI", -apple-system, BlinkMacSystemFont, Arial, sans-serif;
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
}

/* TWO WIDTHS, DELIBERATELY.
   The FORM stays at a readable measure -- a 1100px-wide input row is
   harder to complete, not easier. The frame around it (header, hero,
   footer) uses the screen, which is where "stronger use of horizontal
   space" actually belongs. */
/* The two widths are kept CLOSE on purpose. Rendering them at 760 and
   1080 put the headline's left edge ~160px outside the card's, which
   read as a misalignment rather than as a deliberate inset. 880 and
   1080 leaves a gentle ~80px shoulder that looks intended -- and the
   wider card is itself "stronger use of horizontal space". */
.wrap {
  width: 100%;
  max-width: 880px;
  margin: 0 auto;
  padding: 0 20px;
}

.wrap-wide {
  width: 100%;
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 20px;
}

@media (max-width: 620px) {
  .wrap, .wrap-wide { padding: 0 16px; }
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--brand-forest);
  color: #fff;
  padding: 10px 16px;
  z-index: 100;
  border-radius: 0 0 var(--radius-sm) 0;
}
.skip-link:focus { left: 0; }

/* ── header ─────────────────────────────────────────────── */

.site-header {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
/* Identifies Sawgrass; does not behave like a marketing nav bar.
   72px -> 52px, logo 38px -> 28px. */
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 52px;
}
.logo {
  height: 28px;
  width: auto;
  display: block;
}
.header-phone {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 15px;
  color: var(--brand-forest);
  text-decoration: none;
  white-space: nowrap;
}
.header-phone:hover { color: var(--brand-green-darker); }

/* ── hero ───────────────────────────────────────────────── */

/* COMPRESSED ~37%: 309px -> ~195px at 1280px, MEASURED in a browser
   rather than estimated from the numbers below. The point is that
   Step 1 begins above the fold on a normal laptop, so a reviewer sees
   the form rather than a banner.

   Typography, colours, copy and hierarchy are deliberately unchanged.
   Only padding, margins and the headline's DESKTOP CEILING move -- the
   mobile floor stays where it was so small screens keep their
   proportions. */
.hero {
  background: linear-gradient(160deg, var(--brand-forest) 0%, var(--brand-forest-deep) 100%);
  color: #fff;
  padding: 20px 0 22px;
}

/* THE SPACE COMES FROM LAYOUT, NOT FROM SHRINKING TYPE. The two short
   facts move BESIDE the headline instead of under it, which removes a
   whole stacked block from the page height while the headline keeps its
   size and weight. */
.hero-inner {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 32px;
  text-align: left;
}
.hero-lead { min-width: 0; }

.hero-facts {
  flex: 0 0 auto;
  list-style: none;
  margin: 0;
  padding: 0 0 2px;
  text-align: right;
}
.hero-facts li {
  font-size: 12.5px;
  font-weight: 600;
  color: #9FCB74;
  white-space: nowrap;
}
.hero-facts li + li { margin-top: 3px; }

.eyebrow {
  margin: 0 0 5px;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #A8D77A;
}
.hero h1 {
  margin: 0 0 8px;
  font-family: var(--font-head);
  font-weight: 800;
  /* The FLOOR is unchanged, so mobile keeps its proportions; only the
     desktop ceiling comes down, 52px -> 40px. */
  font-size: clamp(30px, 4.6vw, 40px);
  line-height: 1.08;
  letter-spacing: -.02em;
}
.hero-sub {
  margin: 0;
  max-width: 46em;
  font-size: 15.5px;
  line-height: 1.45;
  color: #DCE9D2;
}

/* PHONE: one column, centred, and the two facts sit inline under the
   copy rather than being forced into a right-hand rail that would be
   a cramped column on a 375px screen. */
@media (max-width: 720px) {
  .hero { padding: 18px 0 20px; }
  .hero-inner {
    display: block;
    text-align: center;
  }
  .hero-sub { margin: 0 auto; max-width: 34em; }
  .hero-facts {
    display: flex;
    justify-content: center;
    gap: 14px;
    margin-top: 10px;
    padding: 0;
    text-align: center;
  }
  .hero-facts li + li { margin-top: 0; }
  .hero-facts li + li::before {
    content: "·";
    margin-right: 14px;
    opacity: .65;
  }
}

/* ── main / card ────────────────────────────────────────── */

main {
  flex: 1 0 auto;
  padding-bottom: 64px;
}

.loading {
  margin: 40px auto;
  text-align: center;
  color: var(--ink-faint);
}

.fatal {
  margin: 30px auto 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 4px solid var(--danger);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 28px;
  text-align: center;
}
.fatal h2 {
  margin: 0 0 10px;
  font-family: var(--font-head);
  font-size: 20px;
}
.fatal p { margin: 0 0 18px; color: var(--ink-soft); }

/* ── step rail ──────────────────────────────────────────── */

/* The rail sits BELOW the hero, on the light canvas.
   It originally used `margin-top: -30px` to tuck under the hero's edge.
   Rendering the page showed why that was wrong: the rail's labels are
   --ink-faint, and the current one is --brand-forest, so pulling the rail
   onto the dark-green hero put dark grey and dark green on dark green.
   Every assertion still passed -- the markup, the states and the colours
   were all exactly as specified -- and the step names were, in practice,
   unreadable. CM-90G, found by looking at it. */
.steps {
  display: flex;
  gap: 6px;
  list-style: none;
  margin: 30px 0 0;
  padding: 0;
  position: relative;
  z-index: 2;
}
.steps li {
  flex: 1 1 0;
  min-width: 0;
}
.steps .bar {
  display: block;
  height: 5px;
  border-radius: 3px;
  background: #CBD8C2;
  transition: background .25s ease;
}
.steps li[data-state="done"] .bar,
.steps li[data-state="current"] .bar { background: var(--brand-green); }
.steps .name {
  display: block;
  margin-top: 8px;
  font-family: var(--font-head);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.steps li[data-state="current"] .name { color: var(--brand-forest); }

@media (max-width: 620px) {
  .steps .name { display: none; }
}

/* ── form ───────────────────────────────────────────────── */

#form {
  margin-top: 22px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 34px;
}

@media (max-width: 620px) {
  #form { padding: 22px 18px; border-radius: var(--radius-sm); }
}

.step {
  border: 0;
  margin: 0;
  padding: 0;
}
.step[hidden] { display: none; }

.step-title {
  padding: 0;
  margin: 0 0 6px;
  font-family: var(--font-head);
  font-weight: 800;
  font-size: 26px;
  letter-spacing: -.01em;
  color: var(--ink);
}
.step-hint {
  margin: 0 0 26px;
  color: var(--ink-faint);
  font-size: 15px;
}
.sub-hint {
  margin: -4px 0 12px;
  font-size: 13px;
  color: var(--ink-faint);
}

.grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 20px;
}
@media (max-width: 620px) {
  .grid-2 { grid-template-columns: 1fr; }
}

.field { margin-bottom: 22px; }

/* THE CHILD COMBINATOR IS LOad-BEARING. This was written as
   `.field label`, which is specificity (0,1,1) and therefore BEATS
   `.choice` at (0,1,0) -- so every choice card, which is itself a
   <label> nested inside a .field, silently computed `display: block`
   instead of `display: flex`. The card still had its padding, border,
   background and min-height from the same rule that lost only its
   display, so it looked almost right; what actually happened is that
   the radio indicator stopped being a flex item, `width: 18px` was
   ignored as it is on any inline box, and the dot rendered as a 4px
   sliver with no gap beside the text.
   Measured, not guessed: getComputedStyle on the real page reported
   display=inline, width=18px, rect=4.0x22.0, parentDisplay=block.
   Keep this a CHILD selector so a nested label is never captured. */
.field > label,
.label-as-legend {
  display: block;
  margin-bottom: 8px;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 14px;
  color: var(--ink);
}

.req { color: var(--brand-green-darker); }
.opt {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 12px;
  color: var(--ink-faint);
  text-transform: none;
  letter-spacing: 0;
}

/* PUBREQ-2A added `url`, and its absence here was invisible to every
   assertion: the markup was right, the label was right, the class was
   right, and the field rendered as a bare 180px browser default beside
   four full-width siblings. Only looking at the page found it (CM-90G).
   An enumerated type list is exactly the whitelist Release 108 warns
   about; it stays enumerated because `input` alone would capture the
   radio and file inputs, but every type the form uses must be in it. */
input[type="text"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="number"],
textarea {
  width: 100%;
  padding: 12px 14px;
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--ink);
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  transition: border-color .15s ease, box-shadow .15s ease;
}
textarea { resize: vertical; min-height: 96px; }

input:hover, textarea:hover { border-color: #C5CFBF; }

input:focus, textarea:focus {
  outline: none;
  border-color: var(--brand-green);
  box-shadow: 0 0 0 3px rgba(114,180,31,.20);
}

input[aria-invalid="true"],
textarea[aria-invalid="true"] {
  border-color: var(--danger);
  background: var(--danger-bg);
}

.counter {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--ink-faint);
  text-align: right;
}

/* ── choice cards ───────────────────────────────────────── */

.choice-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px;
  align-items: stretch;
}
.choice-grid-compact {
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
}

.choice {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 58px;
  padding: 13px 15px;
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
}
.choice:hover {
  border-color: var(--brand-green);
  background: var(--brand-tint);
}
.choice input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  margin: 0;
}

/* A plain radio indicator. No per-code icon -- see app.js. */
.choice .dot {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid #BFCCB6;
  background: var(--surface);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.choice:hover .dot { border-color: var(--brand-green); }
.choice[data-selected="true"] .dot {
  border-color: var(--brand-green);
  background: var(--brand-green);
  box-shadow: inset 0 0 0 3px #fff;
}

.choice .text {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 14px;
  color: var(--ink);
  line-height: 1.25;
}
.choice[data-selected="true"] {
  border-color: var(--brand-green);
  background: var(--brand-tint);
  box-shadow: inset 0 0 0 1px var(--brand-green);
}
.choice:focus-within {
  outline: none;
  box-shadow: 0 0 0 3px rgba(114,180,31,.28);
  border-color: var(--brand-green);
}

/* ── errors ─────────────────────────────────────────────── */

.err {
  margin: 6px 0 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--danger);
}
.err:empty { display: none; }

.form-err {
  margin: 0 0 16px;
  padding: 12px 14px;
  background: var(--danger-bg);
  border: 1px solid #F0C9C6;
  border-radius: var(--radius-sm);
}

/* ── review block ───────────────────────────────────────── */

.review {
  margin: 0 0 22px;
  padding: 18px 20px;
  background: var(--brand-tint);
  border: 1px solid var(--brand-tint-edge);
  border-radius: var(--radius-sm);
}
.review:empty { display: none; }
.review h3 {
  margin: 0 0 12px;
  font-family: var(--font-head);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brand-forest);
}
.review dl {
  margin: 0;
  display: grid;
  grid-template-columns: minmax(120px, auto) 1fr;
  gap: 6px 16px;
}
.review dt {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-faint);
}
.review dd {
  margin: 0;
  font-size: 14px;
  color: var(--ink);
  overflow-wrap: anywhere;
}

/* ── turnstile ──────────────────────────────────────────── */

.turnstile-slot { margin: 0 0 6px; min-height: 0; }
.turnstile-slot:not(:empty) { margin-bottom: 18px; }

.consent {
  margin: 18px 0 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-faint);
}

/* ── nav row ────────────────────────────────────────────── */

.nav-row {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-top: 30px;
  padding-top: 24px;
  border-top: 1px solid var(--line-soft);
}

.btn {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 15px;
  padding: 13px 26px;
  border-radius: var(--radius-sm);
  border: 1.5px solid transparent;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, transform .06s ease;
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(114,180,31,.35);
}
.btn[hidden] { display: none; }
.btn:disabled { opacity: .55; cursor: not-allowed; }

.btn-primary {
  background: var(--brand-green);
  color: #fff;
  margin-left: auto;
  box-shadow: 0 1px 2px rgba(74,119,20,.25);
}
.btn-primary:hover:not(:disabled) { background: var(--brand-green-dark); }

.btn-secondary {
  background: var(--surface);
  color: var(--brand-forest);
  border-color: var(--line);
}
.btn-secondary:hover:not(:disabled) {
  border-color: var(--brand-forest);
  background: var(--brand-tint);
}
.btn-secondary[hidden] { display: none; }

/* ── confirmation ───────────────────────────────────────── */

.done {
  margin-top: 26px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 5px solid var(--brand-green);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lift);
  padding: 44px 34px;
  text-align: center;
}
.done-tick {
  width: 58px;
  height: 58px;
  margin: 0 auto 18px;
  border-radius: 50%;
  background: var(--brand-tint);
  color: var(--brand-green-darker);
  font-size: 28px;
  line-height: 58px;
  font-weight: 700;
}
.done h2 {
  margin: 0 0 14px;
  font-family: var(--font-head);
  font-weight: 800;
  font-size: 27px;
  letter-spacing: -.01em;
}
.done p { margin: 0 auto 12px; max-width: 34em; color: var(--ink-soft); }
.done-code {
  font-size: 18px !important;
  color: var(--ink) !important;
}
.done-code strong {
  font-family: var(--font-head);
  font-weight: 800;
  letter-spacing: .04em;
  color: var(--brand-forest);
}
.done-foot { font-size: 14px; }

/* ── footer ─────────────────────────────────────────────── */

.site-footer {
  flex: 0 0 auto;
  background: var(--brand-forest-deep);
  color: #B7CDAE;
  padding: 30px 0;
  text-align: center;
}
/* HORIZONTAL on desktop: Sawgrass and its line on the left, the
   platform attribution on the right. Stacks on a phone. */
.footer-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  text-align: left;
}

.foot-brand {
  margin: 0;
  font-family: var(--font-head);
  font-weight: 800;
  font-size: 15px;
  letter-spacing: .04em;
  color: #fff;
}
.foot-line {
  display: block;
  margin-top: 3px;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 13px;
  letter-spacing: 0;
  color: #B7CDAE;
}

/* PLATFORM ATTRIBUTION, and the styling is the argument.
   Sawgrass stays dominant: 15px, weight 800, pure white. This is 10.5px,
   weight 400, and a dimmer green than the footer's own body text -- set
   apart by a hairline rule so it reads as a footnote about the
   infrastructure rather than as a second brand competing with the
   first. It is inline-block so the rule is only as wide as the words. */
/* VISIBLE, AND STILL SUBORDINATE. The previous version was legible in
   isolation but sat below the fold under a hairline, and in practice
   nobody saw it. It now sits on the footer's right edge on desktop, at
   a size that reads -- while staying a third smaller than the Sawgrass
   line, unbolded at the block level, and in a quieter green than the
   white brand beside it. */
.foot-platform {
  flex: 0 0 auto;
  margin: 0;
  font-size: 11.5px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: #94B189;
  white-space: nowrap;
}
.foot-platform span {
  font-family: var(--font-head);
  font-weight: 700;
  letter-spacing: .1em;
  color: #C3DAB9;
}

@media (max-width: 620px) {
  .footer-inner {
    display: block;
    text-align: center;
  }
  /* On a phone the hairline comes back, because a stacked attribution
     with nothing separating it reads as a third line of the brand
     block rather than as a footnote about the platform. */
  .foot-platform {
    display: inline-block;
    margin-top: 14px;
    padding-top: 11px;
    border-top: 1px solid rgba(255, 255, 255, .14);
  }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}

/* ── request summary: what happens next ─────────────────── */

.review-next-head {
  margin: 18px 0 6px !important;
  font-family: var(--font-head);
  font-size: 13px !important;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brand-forest);
}
.review-next {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-soft);
}

/* ── preview mode ───────────────────────────────────────── */

/* A standing banner, not a dismissible toast: the reviewer must not be
   able to lose the one piece of context that stops a walkthrough being
   mistaken for a real submission. Deliberately above the header and
   outside the card, so it frames the page without altering the
   experience being reviewed. */
.preview-banner {
  background: var(--brand-forest);
  color: #fff;
  text-align: center;
  padding: 9px 20px;
  font-family: var(--font-head);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .04em;
  border-bottom: 3px solid var(--brand-green);
}
.preview-banner span {
  font-family: var(--font-body);
  font-weight: 400;
  opacity: .88;
}

.done-preview {
  font-size: 15px !important;
  line-height: 1.6;
  color: var(--ink-soft) !important;
  max-width: 34em;
  margin: 0 auto !important;
}

/* ══════════════════════════════════════════════════════════
   PHONE
   ══════════════════════════════════════════════════════════
   A real share of these requests will be completed on a phone, so
   this is a first-class layout rather than a fallback. Everything
   below is spacing and sizing only -- no separate mobile page, no
   fixed positioning, one responsive implementation.
   ══════════════════════════════════════════════════════════ */

@media (max-width: 620px) {

  /* The card takes nearly the screen, with margins that still read as
     a card rather than a full-bleed page. */
  #form { padding: 20px 16px; }
  main { padding-bottom: 40px; }

  .step-title { font-size: 22px; }
  .step-hint  { margin-bottom: 20px; font-size: 14.5px; }

  /* 16px is the floor: below it iOS zooms the viewport on focus, which
     reads to the customer as the page jumping. */
  input[type="text"], input[type="email"], input[type="tel"],
  input[type="url"], input[type="number"], textarea {
    font-size: 16px;
    padding: 13px 14px;
  }

  /* Comfortable thumb targets. */
  .choice { min-height: 56px; padding: 14px; }
  .choice .text { font-size: 15px; }

  /* Back and Continue share the row and stay easy to reach. */
  .nav-row { gap: 10px; }
  .btn { padding: 14px 20px; font-size: 15px; }
  .btn-primary, .btn-secondary { flex: 1 1 0; }

  .review { padding: 16px; }
  .review dl { grid-template-columns: 1fr; gap: 2px 0; }
  .review dt { margin-top: 8px; }
  .review dd { margin-bottom: 2px; }

  .done { padding: 32px 20px; }
  .done h2 { font-size: 23px; }

  .site-footer { padding: 24px 0; }
}

/* Very small phones (375x667 and narrower). */
@media (max-width: 400px) {
  .header-phone { font-size: 14px; }
  .logo { height: 25px; }
  .hero h1 { font-size: 29px; }
  .choice-grid, .choice-grid-compact { grid-template-columns: 1fr; }
}

/* ══════════════════════════════════════════════════════════
   PUBREQ-2A — the classifier, the uploader, the progress bar

   Everything here is additive. No existing rule is changed, so the
   New Product path renders exactly as it rendered before Transfer
   existed — which is the property the regression assertion in the
   suite is actually about.
   ══════════════════════════════════════════════════════════ */

/* ── the two big choices ────────────────────────────────── */

/* WIDER THAN A NORMAL CHOICE GRID because these two cards carry a
   second line of copy each. At the default 160px minimum they wrap
   into a column of very tall cards on a laptop; at 260px they sit
   side by side, which is what makes them read as two alternatives
   rather than a list of one thing and then another. */
.choice-grid-wide {
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 14px;
}

/* A card carrying a hint stacks: indicator and title on one line, the
   explanation under them, indented past the indicator so the two lines
   of text align with each other rather than with the dot. */
.choice-grid-wide .choice {
  display: grid;
  grid-template-columns: 18px 1fr;
  grid-template-rows: auto auto;
  gap: 4px 12px;
  align-items: start;
  min-height: 92px;
  padding: 18px;
}
.choice-grid-wide .choice .dot { margin-top: 2px; }
.choice-grid-wide .choice .text { font-size: 16px; }

.choice-hint {
  grid-column: 2;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--ink-soft);
}

/* ── the uploader ───────────────────────────────────────── */

/* A LABEL WRAPPING THE FILE INPUT, not a button that clicks one. The
   whole tile is therefore a native tap target: on a phone it opens the
   OS sheet with Take Photo, Photo Library and Browse, with no
   JavaScript involved at all, and it keeps working if a script fails.
   `capture` is deliberately absent from the input — it would force the
   camera and remove the other two choices. */
/* `.field > label.uploader`, NOT `.uploader`, and the reason is
   measured rather than guessed. `.field > label` above sets
   `display: block` at specificity (0,1,1); a bare `.uploader` is
   (0,1,0) and LOSES, so the icon and the two lines of copy sat on one
   row instead of stacking. The rule that beat it carries a comment
   saying "keep this a CHILD selector so a nested label is never
   captured" -- and PUBREQ-2A introduced a direct-child label that is
   not a field label at all, which is the same hazard one level out.
   Nothing in the markup, the class names or any string assertion showed
   this; looking at the rendered page did (CM-90G). */
.field > label.uploader,
.uploader {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 132px;
  padding: 22px 18px;
  text-align: center;
  background: var(--brand-tint);
  border: 2px dashed var(--brand-tint-edge);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.uploader:hover { border-color: var(--brand-green); background: #EAF4DC; }
.uploader:focus-within {
  outline: none;
  border-color: var(--brand-green);
  box-shadow: 0 0 0 3px rgba(114,180,31,.28);
}

/* Visually hidden, NOT display:none. A display:none input is
   unreachable by keyboard and by assistive technology; this one keeps
   its focus ring through :focus-within on the tile above. */
.uploader input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.uploader-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  margin-bottom: 4px;
  font-size: 24px;
  font-weight: 700;
  line-height: 1;
  color: #fff;
  background: var(--brand-green);
  border-radius: 50%;
}
.uploader-main {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 16px;
  color: var(--ink);
}
.uploader-sub {
  font-size: 13px;
  color: var(--ink-soft);
}

/* ── what has been attached ─────────────────────────────── */

.ev-list {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.ev-list:empty { display: none; }

.ev-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--radius-sm);
}

.ev-thumb {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  overflow: hidden;
  background: var(--canvas);
  border: 1px solid var(--line-soft);
  border-radius: 8px;
}
.ev-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* A PDF or a HEIC gets a plain badge. Inventing a preview for a file
   the browser cannot draw would mean either a broken image or a
   decoder this page has no business carrying. */
.ev-thumb-doc {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: .04em;
  color: var(--brand-forest);
  background: var(--brand-tint);
  border-color: var(--brand-tint-edge);
}

.ev-meta {
  flex: 1 1 auto;
  /* Without this a long filename stretches the row and the card
     scrolls sideways on a phone. */
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.ev-name {
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ev-size { font-size: 12px; color: var(--ink-faint); }

/* THE CUSTOMER SAYS WHAT EACH FILE IS. A guess of ours from a filename
   would put our guess into the one field whose entire meaning is what
   THEY said it was. */
.ev-kind {
  margin-top: 2px;
  width: 100%;
  max-width: 260px;
  padding: 7px 9px;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--ink);
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: 8px;
}
.ev-kind:focus {
  outline: none;
  border-color: var(--brand-green);
  box-shadow: 0 0 0 3px rgba(114,180,31,.22);
}

.ev-remove {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  font-size: 20px;
  line-height: 1;
  color: var(--ink-faint);
  background: transparent;
  border: 1.5px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
  transition: color .15s ease, border-color .15s ease, background .15s ease;
}
.ev-remove:hover {
  color: var(--danger);
  border-color: var(--danger);
  background: var(--danger-bg);
}
.ev-remove:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(114,180,31,.28);
}

.ev-budget {
  margin: 10px 0 0;
  font-size: 12.5px;
  color: var(--ink-faint);
}

/* ── upload progress ────────────────────────────────────── */

/* A 15 MB upload over cellular takes long enough that a page with no
   progress reads as a page that has frozen, and the customer's next
   move is to press the button again. This is why sendWithFiles() uses
   XHR: fetch has no upload-progress event. */
.progress { margin: 4px 0 16px; }
.progress[hidden] { display: none; }
.progress-bar {
  height: 8px;
  background: var(--line-soft);
  border-radius: 999px;
  overflow: hidden;
}
.progress-fill {
  display: block;
  width: 0;
  height: 100%;
  background: var(--brand-green);
  border-radius: 999px;
  transition: width .2s ease;
}
.progress-text {
  margin: 8px 0 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-soft);
}

/* ── the confirmation's file line ───────────────────────── */

/* AMBER, BOXED, AND NOT ONE SHADE OF TEXT. CM-90G is in CLAUDE.md
   because a warning rendered as amber text beside black text of the
   same size and weight was invisible to everyone who looked at it.
   This carries a background, a border and padding, so it is
   distinguishable at a glance from the plain confirmation lines it
   sits between. */
.done-warn {
  max-width: 34em;
  margin: 0 auto 12px;
  padding: 12px 16px;
  font-size: 14px;
  font-weight: 600;
  color: #7A4A05;
  background: #FEF6E7;
  border: 1.5px solid #F2CE87;
  border-radius: var(--radius-sm);
}

/* The pool is a holding area, never a rendered one. Groups are moved
   OUT of it into their step; anything still inside is a question this
   path does not ask. */
#pool[hidden] { display: none; }

/* ── phones ─────────────────────────────────────────────── */

@media (max-width: 620px) {
  .choice-grid-wide { grid-template-columns: 1fr; }
  .choice-grid-wide .choice { min-height: 84px; padding: 16px; }

  .uploader { min-height: 120px; padding: 20px 14px; }
  .uploader-main { font-size: 15px; }

  /* The row stays legible rather than squeezing a 52px thumbnail off
     the edge. */
  .ev-item { align-items: flex-start; }
  .ev-kind { max-width: none; font-size: 16px; }   /* 16px: no iOS zoom */
  .ev-thumb { width: 46px; height: 46px; }
}
