/* ═══════════════════════════════════════════════════════════════════
   Cart, checkout and account.

   Phase 1 keeps the cart in localStorage; Phase 2 swaps the store for
   the WooCommerce Store API cart without touching this file.

   MOBILE FIRST. Everything outside a media query is the phone layout
   and every @media is min-width. The three surfaces share one form
   language — .fld / .field-in for entry, .acct-sec for a disclosure,
   .cart-sum for a summary — so the cart, the checkout and the account
   page read as one shop (§9.1).

   §9.9 — nothing decorative above the first real control. .cart-page
   and .acct-page therefore open on var(--sp-4) of padding and a single
   heading line: no band, no rule, no hero.
   ═══════════════════════════════════════════════════════════════════ */

/* ── Cart ───────────────────────────────────────────────────────── */
.cart-page{padding-block:var(--sp-4) var(--sp-10)}
.cart-head{display:flex;align-items:baseline;gap:var(--sp-3);
  flex-wrap:wrap;margin-bottom:var(--sp-4)}
.cart-head h1{font-size:1.5rem;font-weight:800;letter-spacing:-.01em}
.cart-n{font-size:.9375rem;color:var(--ink-3);font-variant-numeric:tabular-nums}

.cart-list{display:flex;flex-direction:column;gap:var(--sp-2)}
.cart-row{display:grid;grid-template-columns:76px minmax(0,1fr);gap:var(--sp-3);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:var(--sp-3)}
.cart-row .media{aspect-ratio:1/1;border-radius:var(--r-sm);overflow:hidden}
.cart-row .info{min-width:0;display:flex;flex-direction:column;gap:var(--sp-1)}
.cart-row .nm{font-size:1rem;font-weight:600;color:var(--ink);
  overflow-wrap:anywhere;line-height:1.3}
.cart-row .unit{font-size:.9375rem;color:var(--ink-3);font-variant-numeric:tabular-nums}

.cart-ctl{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;
  margin-top:var(--sp-1)}
/* Steppers are full 44px targets and keyboard-operable buttons — the
   minus disables at 1 rather than silently deleting the line. */
.cart-qty{display:flex;align-items:center;border:1px solid var(--line);
  border-radius:var(--r);background:var(--surface)}
.cart-qty button{width:var(--tap);height:var(--tap);display:flex;
  align-items:center;justify-content:center;color:var(--ink)}
.cart-qty button .ico{width:22px;height:22px}
.cart-qty button:hover:not([disabled]){color:var(--brand-ink)}
.cart-qty button[disabled]{color:var(--ink-3);cursor:not-allowed}
.qty-v{min-width:2.5ch;text-align:center;font-size:1.0625rem;font-weight:700;
  color:var(--ink);font-variant-numeric:tabular-nums}
.line-total{margin-left:auto;font-size:1.0625rem;font-weight:800;
  color:var(--ink);font-variant-numeric:tabular-nums;white-space:nowrap}
.cart-remove{display:inline-flex;align-items:center;gap:var(--sp-2);
  align-self:flex-start;min-height:var(--tap);font-size:1rem;font-weight:600;
  color:var(--ink-3)}
.cart-remove .ico{width:22px;height:22px}                    /* §9.3 */
.cart-remove:hover{color:var(--red)}

/* §9.10 — a long cart shows a first batch. The extra rows stay in the
   DOM; only their layout changes. display:none rather than the
   max-height clip used on the account page because a zero-height flex
   child still claims its gap, which would leave phantom space in the
   list — and a cart is per-customer localStorage, so unlike page copy
   there is nothing here for a crawler to miss. Same pattern as
   .chip.is-extra in shop.css. */
.cart-row.is-extra{display:none}
.cart-list.show-all .cart-row.is-extra{display:grid}
.disclose[hidden]{display:none}

.cart-sum{margin-top:var(--sp-4);padding:var(--sp-4);background:var(--surface-2);
  border:1px solid var(--line);border-radius:var(--r);
  display:flex;flex-direction:column;gap:var(--sp-3)}
.cart-sum h2{font-size:1.125rem;font-weight:800}
.sum-row{display:flex;justify-content:space-between;align-items:baseline;
  gap:var(--sp-3);font-size:1rem;color:var(--ink-2)}
.sum-row .v{font-size:1.5rem;font-weight:800;color:var(--ink);
  font-variant-numeric:tabular-nums}
.sum-row .q{color:var(--ink-3);text-align:right}
.sum-note{font-size:1rem;color:var(--ink-3);line-height:1.5;max-width:60ch}

/* ── Empty cart ─────────────────────────────────────────────────── */
.cart-empty-act{display:flex;flex-wrap:wrap;gap:var(--sp-3);justify-content:center}
.cart-cats{margin-top:var(--sp-8)}
.cart-cats h2{font-size:1.125rem;font-weight:800;text-align:center;
  margin-bottom:var(--sp-3)}
.cart-cat-row{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-2)}
.cart-cat{display:flex;align-items:center;gap:var(--sp-3);min-width:0;
  min-height:var(--tap);padding:var(--sp-2) var(--sp-3);background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r);
  color:var(--ink);font-size:1rem;font-weight:600;line-height:1.25}
.cart-cat .ico{width:26px;height:26px;color:var(--brand-ink)}   /* §9.3 */
.cart-cat:hover{border-color:var(--brand)}

/* ── Checkout ───────────────────────────────────────────────────── */
.co-page{padding-bottom:var(--sp-10)}
.co-note{margin:var(--sp-3) 0 var(--sp-5);padding:var(--sp-4);
  background:var(--brand-xlight);border:1px solid var(--brand-light);
  border-left:4px solid var(--brand);border-radius:0 var(--r) var(--r) 0}
.co-note b{display:block;font-size:var(--fs-pair-head);color:var(--ink);margin-bottom:var(--sp-1)}
/* NOT --fs-pair-sub. These two are running body copy — three lines
   explaining how to order, not the one-line label that sits under a
   heading — and §9.2's 16px floor is for exactly that. The pair still
   reads: 17px extra-bold over 16px regular, and the paragraph's own
   length does the rest. scripts/check-account-cart.mjs asserts it. */
.co-note p{font-size:1rem;color:var(--ink-2);max-width:62ch}
.co-h2{font-size:1.125rem;font-weight:800;margin-bottom:var(--sp-3)}
.co-lines{background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r);overflow:hidden}
.co-line{display:grid;grid-template-columns:auto minmax(0,1fr) auto;
  gap:var(--sp-3);align-items:baseline;padding:var(--sp-3);
  border-bottom:1px solid var(--line-soft);font-size:1rem}
.co-line:last-child{border-bottom:0}
.co-line .q{font-weight:700;color:var(--ink-3);font-variant-numeric:tabular-nums}
.co-line .n{color:var(--ink);overflow-wrap:anywhere}
.co-line .t{font-weight:700;color:var(--ink);white-space:nowrap;
  font-variant-numeric:tabular-nums}
.co-line.is-extra{display:none}
.co-lines.show-all .co-line.is-extra{display:grid}
.co-details{margin-top:var(--sp-4)}

/* ── Account ────────────────────────────────────────────────────── */
.acct-page{padding-block:var(--sp-4) var(--sp-10)}
.acct-h1{font-size:1.5rem;font-weight:800;letter-spacing:-.01em;
  margin-bottom:var(--sp-4)}
.acct-grid{display:flex;flex-direction:column;gap:var(--sp-3)}
.acct-sec{background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r)}

/* §9.10 — a real disclosure: ≥44px, ≥16px label, and the label NAMES
   what it opens. The panel is clipped with max-height, never
   display:none and never [hidden], so the copy stays in the DOM. */
.acct-toggle{display:flex;align-items:center;gap:var(--sp-3);width:100%;
  min-height:var(--tap);padding:var(--sp-3);text-align:left;
  font-size:1rem;font-weight:700;color:var(--ink)}
.acct-toggle>.ico:first-child{width:26px;height:26px;color:var(--brand-ink)}
.acct-toggle>span{flex:1 1 auto;min-width:0}
.acct-toggle>.ico:last-child{width:22px;height:22px;color:var(--ink-3);
  transition:transform .18s ease}
.acct-toggle[aria-expanded="true"]>.ico:last-child{transform:rotate(90deg)}
.acct-panel{max-height:0;overflow:hidden;visibility:hidden;
  padding-inline:var(--sp-3);
  transition:max-height .24s ease,visibility 0s linear .24s}
.acct-toggle[aria-expanded="true"]+.acct-panel{max-height:1600px;visibility:visible;
  padding-bottom:var(--sp-4);transition:max-height .28s ease,visibility 0s}

.acct-form{display:flex;flex-direction:column}
.fld{display:flex;flex-direction:column;gap:var(--sp-1);margin-bottom:var(--sp-3)}
/* 16px, so the label is body copy (§9.2) and the field it points at
   never triggers the iOS focus zoom. */
.fld-l{font-size:1rem;font-weight:600;color:var(--ink)}
textarea.field-in{min-height:92px;line-height:1.5;resize:vertical}

.acct-p{font-size:1rem;color:var(--ink-2);max-width:62ch;margin-bottom:var(--sp-3)}
.acct-soon b{display:block;font-size:var(--fs-pair-head);color:var(--ink);margin-bottom:var(--sp-1)}
/* 16px for the same reason as .co-note p above. */
.acct-soon p{font-size:1rem;color:var(--ink-2);max-width:62ch;margin-bottom:var(--sp-3)}
.acct-status{margin-top:var(--sp-3);padding:var(--sp-3);font-size:1rem;
  color:var(--ink-2);background:var(--brand-xlight);
  border:1px solid var(--brand-light);border-left:4px solid var(--brand);
  border-radius:0 var(--r) var(--r) 0}
.acct-status b{display:block;font-size:var(--fs-pair-head);color:var(--ink);margin-bottom:var(--sp-1)}
.acct-status .btn{margin-top:var(--sp-3)}

/* ═══ ≥640 — a little more room ═════════════════════════════════ */
@media (min-width:640px){
  .cart-row{grid-template-columns:96px minmax(0,1fr)}
  .cart-head h1,.acct-h1{font-size:1.75rem}
  .cart-cat-row{grid-template-columns:repeat(3,minmax(0,1fr))}
}

/* ═══ ≥768 — the account lays out two-up ════════════════════════
   The sections open by default from here (set in account.js, so
   aria-expanded stays truthful) and sit side by side. Same content,
   same markup, different form factor — never a reduced set (§9.1). */
@media (min-width:768px){
  .acct-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
    gap:var(--sp-4);align-items:start}
  .acct-toggle{font-size:1.0625rem}
}

/* ═══ ≥900 — cart and summary side by side ══════════════════════
   With a column of its own the summary is on screen from the first
   line item, so the batch disclosure has nothing left to do. */
@media (min-width:900px){
  .cart-layout{display:grid;grid-template-columns:minmax(0,1fr) 340px;
    gap:var(--sp-6);align-items:start}
  .cart-sum{margin-top:0}
  .cart-row.is-extra{display:grid}
  [data-cart-more],[data-co-more]{display:none}
  .cart-cat-row{grid-template-columns:repeat(6,minmax(0,1fr))}
  .co-line.is-extra{display:grid}
}

/* ── Checkout: real order form ──────────────────────────────────────
   The fields, the gateway radios and the confirmation. Reuses .fld /
   .field-in / .cart-sum / .sum-row rather than inventing a second
   vocabulary for the same job (§9.1). */
.co-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--sp-3);
  margin-bottom:var(--sp-6)}
/* Two across only where there is genuinely room. Names and city/state
   pair naturally; an address line never shares a row. */
@media (min-width:560px){
  .co-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .co-grid .fld:nth-child(4),
  .co-grid .fld:nth-child(5),
  .co-grid .fld:nth-child(6){grid-column:1 / -1}
}
.fld-req{font-weight:400;color:var(--ink-3);font-size:var(--fs-pair-sub)}
/* 1rem, not --fs-pair-sub. A hint under a field is running copy a
   customer reads, and §9.2's 16px floor applies to it — the same call
   already made for .co-note p and .acct-soon p. --fs-pair-sub is for a
   description paired UNDER A HEADING, which this is not. */
.fld-hint{margin-top:var(--sp-1);font-size:1rem;line-height:1.5;color:var(--ink-2)}
.co-loading{font-size:1rem;color:var(--ink-2);padding:var(--sp-2) 0}

/* A gateway choice is a REAL radio (§9.14): native semantics, native
   keyboard, and the dot reads as a dot. The input is visually replaced,
   never removed, so it stays in the accessibility tree. */
.co-methods{display:grid;gap:var(--sp-2);margin-bottom:var(--sp-6)}
.co-method{display:flex;align-items:flex-start;gap:var(--sp-3);
  min-height:var(--tap);padding:var(--sp-3) var(--sp-4);
  border:1px solid var(--line);border-radius:var(--r);
  background:var(--surface);cursor:pointer}
.co-method input{flex:0 0 auto;width:22px;height:22px;margin-top:2px;
  accent-color:var(--brand)}
.co-method-body{display:flex;flex-direction:column;gap:2px;min-width:0}
.co-method-body b{font-size:var(--fs-pair-head);font-weight:700;color:var(--ink)}
.co-method-body .d{font-size:var(--fs-pair-sub);line-height:var(--lh-pair-sub);
  color:var(--ink-2)}
/* Selected state carries a border and a tint, never colour alone — and
   the radio dot itself is the primary signal, which is the point: even
   with NO selected styling at all the choice is still legible, because
   the control is a real radio. So `.is-on` is set from JS and :has() is
   never the only thing showing a state (§10.7). */
.co-method:hover{border-color:var(--brand)}
.co-method.is-on{border-color:var(--brand);background:var(--brand-xlight)}
.co-method:focus-within{outline:2px solid var(--brand);outline-offset:2px}

.sum-row.is-total{border-top:1px solid var(--line);margin-top:var(--sp-2);
  padding-top:var(--sp-3)}
.sum-row.is-total span:first-child{font-weight:700;color:var(--ink)}

/* ── Confirmation ─────────────────────────────────────────────────── */
.co-done{text-align:center;padding:var(--sp-8) var(--sp-4) var(--sp-4)}
.co-done .ico{width:56px;height:56px;color:var(--green);stroke-width:2.2;
  margin:0 auto var(--sp-3)}
.co-done h1{font-size:1.5rem;font-weight:800;margin-bottom:var(--sp-2)}
.co-done-num{font-size:1rem;line-height:1.55;color:var(--ink-2);max-width:52ch;
  margin-inline:auto}
.co-done-sum{max-width:520px;margin-inline:auto}
.co-done-sum h2{margin-top:var(--sp-4)}
.co-done-sum h2:first-child{margin-top:0}
