/* ============================================================
   public_mirror.components.css — Public Value Mirror
   Ported from Claude Design handoff docs/design/handoff_out/public_value_mirror/
   (prototype public_value_mirror.html + design_notes_public_mirror.md).

   Scope: the value-communication layer around the ALREADY-SHIPPED public Spine
   map — NOT a map redesign. Two new blocks only:
     · .pvm-hero .ph-*   → the ◆ official wholesale-price hero above the map
     · .pvm-lanes .ln-*  → the 3-lane mirror that REPLACES .publicbar

   Everything else the prototype drew (the cells, legend, ramp and season
   overlays) is the live map's own CSS in supply.components.css — deliberately
   NOT re-added here (design notes §1: "provenance material reused, never
   re-encoded").
   NOTE: no glob patterns in these comments. A literal star-slash inside a CSS
   comment closes it early; the stray text then runs on as a selector until the
   next "{" and silently eats the rule that follows.

   Mints nothing: every colour/size/space is an existing token from
   supply.tokens.css. Loaded AFTER shell.chrome.css so .publicbar's retirement
   and these additions land in the shipped cascade order.
   ============================================================ */

/* ============================================================
   PUBLIC DOOR SHELL — hero (full width) → [map | panel] → lanes
   ============================================================ */
/* The shipped `.content` IS the map|panel row. The public door needs a band
   ABOVE that row, so on this door .content becomes the COLUMN and `.pvm-row`
   takes over its old job.
   Why it matters: with the hero inside .stage, the hero pushed the MAP down
   while the sibling panel column stayed at the top — click a cell and its panel
   floated ~360px above the map it describes (measured on prod: map.top 422 vs
   panel.top 59). Hero above the row keeps map.top == panel.top.
   Scoped to the logged-out door — the authed layout is untouched. */
.content.pvm-door{ flex-direction:column; overflow-y:auto; }
.content.pvm-door > *{ flex:0 0 auto; }
.pvm-row{ display:flex; min-height:0; }
.pvm-row > .stage{ flex:1; min-width:0; }

/* MEASURED, NOT GUESSED — why the map is NOT height-capped here (2026-07-17).
   The 3-lane mirror sits ~900px below the fold, so the obvious move was to cap
   the map (its ~711px height is an accident: the svg is `width:100%;height:100%`
   and simply took its viewBox aspect in this column layout). Tried
   `max-height:44vh; width:auto` and measured:
     · the map shrank exactly as asked — svg 595 → 352px at 1280 wide
     · the lanes did NOT move: top=1113 both ways at 1280 (fold 800). Under ~90px
       at 1440. The cap bought ZERO where it mattered.
   Because .pvm-row is a flex row: its height is the TALLER of stage and panel —
   and measured on prod with flex-stretch disabled, the two are TWINS:
   stage 696px vs panel 712px at 1280. So shrinking EITHER side alone is futile:
   the map → 0px (panel holds the row open), the panel → ~16px (the stage does).
   Only shrinking BOTH, or breaking them out of one row, moves the fold. On mobile
   they stack instead of compete (514 + 707 = 1221), so there one side does help.
   Do not read this as "the panel is the wall" — that was the first, wrong reading.
   And the map got WORSE: aspect ratio must hold, so a shorter map is also a
   NARROWER map — a ~350px thumbnail floating in ~550px of dead space with
   unreadable province labels. Keeping full width at a shorter height would mean
   CROPPING the geography, which is a design decision, not a CSS tweak.
   So: don't re-try the cap alone. The lever is the intro panel (or moving the
   ask above the row). Left here so the next person doesn't spend the same hour. */

/* ============================================================
   HERO — ราคาขายส่งวันนี้ (public, above the map)
   ============================================================ */
.pvm-hero{border:1px solid var(--line); border-radius:var(--r-lg); background:var(--surface); box-shadow:var(--sh-md); overflow:hidden; position:relative}
.pvm-hero .ph-accent{position:absolute; inset:0 auto 0 0; width:5px; background:linear-gradient(180deg,var(--brand),var(--brand2))}
/* stale/empty are NOT edge cases here — prod's dit_price feed runs days behind,
   so these states are the common truth. Both re-tint the accent so the state
   reads before any number does. */
.pvm-hero.is-stale .ph-accent{background:linear-gradient(180deg,var(--pv-stale-ln),var(--pv-stale))}
.pvm-hero.is-empty .ph-accent{background:var(--line2)}
.ph-body{padding:var(--s5) var(--s5) var(--s5) calc(var(--s5) + 5px)}
.ph-top{display:flex; align-items:flex-start; justify-content:space-between; gap:var(--s4); flex-wrap:wrap}
.ph-eyebrow{display:flex; align-items:center; gap:.5rem}
.ph-eyebrow .sun{color:var(--brand); font-size:1rem}
.ph-src{font-size:var(--fs-xs); color:var(--muted); text-align:right; max-width:24ch; line-height:1.4}
.ph-figs{display:flex; align-items:flex-end; gap:var(--s6); flex-wrap:wrap; margin-top:var(--s3)}
.ph-fig{display:flex; flex-direction:column; gap:.3rem}
.ph-fig .ph-var{font-size:var(--fs-sm); font-weight:var(--fw-semi); color:var(--ink2)}
.ph-num{font-family:var(--mono); font-variant-numeric:tabular-nums; font-size:var(--fs-3xl); font-weight:var(--fw-x); line-height:1; letter-spacing:-.02em; color:var(--ink)}
.ph-num .u{font-size:1.1rem; color:var(--muted); font-weight:var(--fw-semi); letter-spacing:0; margin-left:.35rem}
/* greying the figure is load-bearing: a stale price must not read as today's */
.pvm-hero.is-stale .ph-num{color:var(--muted)}
.ph-fig.sec .ph-num{font-size:var(--fs-xl); color:var(--ink2)}
.ph-when{display:flex; align-items:center; gap:.5rem; margin-top:var(--s4); flex-wrap:wrap}
.ph-when .date{font-family:var(--mono); font-size:var(--fs-sm); color:var(--ink2); font-weight:var(--fw-semi)}
.ph-honest{margin-top:var(--s3); font-size:var(--fs-xs); color:var(--muted); line-height:1.5; max-width:70ch}
.ph-honest b{color:var(--ink2); font-weight:var(--fw-semi)}
.ph-empty{display:flex; align-items:center; gap:.6rem; margin-top:var(--s4); font-size:var(--fs-sm); color:var(--muted)}

/* ============================================================
   3-LANE VALUE MIRROR — replaces .publicbar (generic banner)
   proof (free, real) → labeled 🔒 wall → CTA
   ============================================================ */
.pvm-lanetitle{display:flex; align-items:baseline; gap:.6rem; flex-wrap:wrap}
.pvm-lanetitle h2{font-size:var(--fs-lg); font-weight:var(--fw-x); letter-spacing:-.01em; margin:0}
.pvm-lanetitle .psub{margin:0}
.pvm-lanes{display:grid; grid-template-columns:repeat(3,1fr); gap:var(--s4)}
.lane{display:flex; flex-direction:column; border:1px solid var(--line); border-radius:var(--r-lg); background:var(--surface); box-shadow:var(--sh-sm); overflow:hidden}
/* the primary persona (grower) gets a 1px brand ring — visual weighting only; the
   "🌳 ชาวสวน" label carries the meaning, so the ring is decoration (Q2). */
.lane.spot{border-color:var(--brand); box-shadow:0 0 0 1px var(--brand), var(--sh-md)}
/* MOBILE persona picker (Q1) — a compact chooser; CSS reveals it ≤880px (below).
   Names all 3 personas (label-level mirror) then shows the chosen lane's detail. */
.pvm-picker{display:none; gap:.4rem; background:var(--surface); border:1px solid var(--line); border-radius:var(--r-pill); padding:4px; box-shadow:var(--sh-sm); margin-bottom:var(--s4)}
.pvm-picker button{flex:1; display:flex; flex-direction:column; align-items:center; gap:2px; border:0; background:transparent; color:var(--ink2); cursor:pointer; font:inherit; border-radius:var(--r-pill); padding:.5rem .3rem; min-height:52px; line-height:1.1}
.pvm-picker button .pe{font-size:1.15rem}
.pvm-picker button .pl{font-size:var(--fs-2xs); font-weight:var(--fw-semi)}
.pvm-picker button[aria-pressed="true"]{background:var(--brand-soft); color:var(--brand-ink); font-weight:var(--fw-bold)}
.ln-hd{display:flex; align-items:center; gap:.65rem; padding:var(--s3) var(--s4) var(--s2)}
.ln-emoji{width:38px; height:38px; flex:0 0 38px; border-radius:10px; display:grid; place-items:center; background:var(--brand-soft); font-size:1.25rem}
.ln-who{flex:1; min-width:0}
.ln-who b{display:block; font-size:var(--fs-md); font-weight:var(--fw-bold); letter-spacing:-.01em}
.ln-who span{font-size:var(--fs-xs); color:var(--muted)}
/* login-entry (Claude Design login_entry): the persona head is a real <button>
   that opens the door — the spot all 3 sim personas tapped to log in. .ln-signin
   pill puts "เข้าสู่ระบบ" where the eye lands. token-bound, mints nothing. */
.ln-enter{width:100%; text-align:left; border:0; background:transparent; font:inherit; color:inherit; cursor:pointer; min-height:56px; border-bottom:1px solid transparent; border-radius:var(--r-lg) var(--r-lg) 0 0; transition:background .12s, box-shadow .12s}
.ln-enter:hover{background:var(--surface2)}
.ln-enter:hover .ln-signin{background:var(--brand); color:#fff; border-color:var(--brand)}
.ln-enter:hover .ln-emoji{box-shadow:0 0 0 2px var(--brand-soft)}
.ln-enter:focus-visible{outline:2px solid var(--ring); outline-offset:-2px}
.ln-signin{display:inline-flex; align-items:center; gap:.2rem; flex:0 0 auto; font-size:var(--fs-xs); font-weight:var(--fw-bold); color:var(--brand-ink); background:var(--brand-soft); border:1px solid var(--brand-soft); border-radius:var(--r-pill); padding:.32rem .6rem; white-space:nowrap; transition:background .12s, color .12s, border-color .12s}
.ln-signin .go{font-weight:var(--fw-bold)}
/* header entry — reads "เข้าสู่ระบบ" in brand, not LINE-green (Q2). reuses .btn.secondary */
.entry-signin{gap:.45rem}
.entry-signin .eic{width:17px; height:17px; display:inline-flex; color:var(--brand2)}
.entry-signin .eic svg{width:100%; height:100%; display:block}
.entry-signin:hover .eic{color:var(--brand-ink)}

/* free proof block — the "taste of the real thing" (public/k-anon data only) */
.ln-proof{margin:0 var(--s4); padding:var(--s4); border-radius:var(--r); background:var(--surface2); border:1px solid var(--line)}
.ln-plabel{display:flex; align-items:center; gap:.4rem; font-size:var(--fs-2xs); text-transform:uppercase; letter-spacing:.08em; color:var(--pv-verified); font-weight:var(--fw-bold)}
.ln-plabel .dot{width:7px; height:7px; border-radius:50%; background:var(--pv-verified); box-shadow:0 0 0 3px var(--pv-verified-bg)}
.ln-pfig{font-family:var(--mono); font-variant-numeric:tabular-nums; font-size:1.5rem; font-weight:var(--fw-bold); line-height:1.1; margin-top:.4rem; letter-spacing:-.01em}
.ln-pfig .tilde{color:var(--pv-est)}
.ln-pfig .u{font-size:.8rem; color:var(--muted); font-weight:var(--fw-semi)}
.ln-psub{font-size:var(--fs-xs); color:var(--muted); margin-top:.3rem; line-height:1.45}
.ln-pchips{display:flex; gap:.35rem; flex-wrap:wrap; margin-top:.5rem}
.ln-spark{display:flex; align-items:flex-end; gap:3px; height:34px; margin-top:.5rem}
.ln-spark i{flex:1; border-radius:2px 2px 0 0; min-width:4px}

/* labeled 🔒 wall — now COLLAPSIBLE (<details>) so proof + CTA clear the fold, and
   every locked row is a <button> that routes to the CTA (bug §3b: the old always-
   open <li> wall read as buttons but did nothing). Reuses the shipped .gate/.stub
   grammar (dashed --line2 + striped surface2). */
.ln-more{margin:var(--s3) var(--s4) 0; border:1.5px dashed var(--line2); border-radius:var(--r); background:repeating-linear-gradient(135deg,var(--surface2) 0 9px, transparent 9px 18px)}
.ln-more[open]{background:var(--surface)}
.ln-summary{list-style:none; display:flex; align-items:center; gap:.5rem; cursor:pointer; padding:.6rem .7rem; font-size:var(--fs-sm); font-weight:var(--fw-semi); color:var(--ink); min-height:44px}
.ln-summary::-webkit-details-marker{display:none}
.ln-summary .lk{font-size:1rem}
.ln-summary .caret{margin-left:auto; color:var(--muted); transition:transform .16s}
.ln-more[open] .ln-summary .caret{transform:rotate(90deg)}
.ln-wlist{margin:0; padding:0 .5rem .5rem; list-style:none; display:flex; flex-direction:column; gap:.35rem}
.ln-wlist button{display:flex; gap:.5rem; align-items:flex-start; width:100%; text-align:left; cursor:pointer; font:inherit; border:1px solid var(--line); background:var(--surface); border-radius:var(--r-sm); padding:.5rem .6rem; font-size:var(--fs-xs); color:var(--ink2); line-height:1.4; min-height:44px; transition:border-color .12s, background .12s}
.ln-wlist button:hover{border-color:var(--pv-private-ln); background:var(--pv-private-bg)}
.ln-wlist button .c{color:var(--pv-private); font-weight:var(--fw-bold); flex:0 0 auto}
.ln-wlist button .go{margin-left:auto; color:var(--pv-private); flex:0 0 auto}
.ln-why{margin:0 .7rem .6rem; font-size:var(--fs-2xs); color:var(--muted); line-height:1.5}
.ln-why .ic{color:var(--pv-private); font-weight:var(--fw-bold)}
.ln-cta{padding:var(--s4); margin-top:auto}
.ln-cta .btn{width:100%}
.ln-ctahint{text-align:center; font-size:var(--fs-2xs); color:var(--muted); margin-top:.5rem}

/* COMPACT INTRO PANEL (Q3) — the public panel's 7-row ranked list is deferred
   behind a <details>; the rows themselves keep their shipped inline styling. */
.pvm-door .iranked{margin-top:var(--s3); border:1px solid var(--line); border-radius:var(--r); background:var(--surface)}
.pvm-door .iranked > summary{list-style:none; cursor:pointer; padding:.6rem .7rem; font-size:var(--fs-sm); font-weight:var(--fw-semi); display:flex; align-items:center; gap:.4rem; min-height:44px}
.pvm-door .iranked > summary::-webkit-details-marker{display:none}
.pvm-door .iranked > summary .caret{margin-left:auto; color:var(--muted); transition:transform .16s}
.pvm-door .iranked[open] > summary .caret{transform:rotate(90deg)}
.pvm-door .iranked > button{margin:0 !important; border-radius:0 !important; border-left:0 !important; border-right:0 !important; border-bottom:0 !important}

/* ---- RESPONSIVE ---- */
/* 880px = the shell's OWN breakpoint (shell.chrome.css flips .content to a
   column there). .pvm-row follows it exactly so the door never disagrees with
   the shell about what "mobile" means. */
@media (max-width:880px){
  .pvm-row{flex-direction:column}

  /* Q1 — the persona PICKER replaces the 3-up grid on a phone: 3 full lanes
     stacked can't clear the fold. Show the picker; show only the chosen lane
     (data-lane, flipped by setLaneView without a re-render). Desktop keeps the
     grid — the picker's default display:none simply never gets overridden. */
  .pvm-picker{display:flex}
  .pvm-lanes{grid-template-columns:1fr}
  .pvm-lanes[data-lane] > .lane{display:none}
  .pvm-lanes[data-lane="grower"] > .lane[data-persona="grower"],
  .pvm-lanes[data-lane="consolidator"] > .lane[data-persona="consolidator"],
  .pvm-lanes[data-lane="exporter"] > .lane[data-persona="exporter"]{display:flex}

  /* Q2 — compact the hero so the grower price never eats the small fold for the
     other two personas. The load-bearing rule is nowrap: both figures on ONE row
     (monthong beside chanee) instead of stacked — that alone is what pulls the
     hero from ~424 back toward the ~262 the design measured. */
  .pvm-hero .ph-figs{flex-wrap:nowrap; gap:var(--s5); margin-top:var(--s1)}
  .ph-num{font-size:var(--fs-xl)}
  .ph-num .u{font-size:.8rem; margin-left:.2rem}
  .ph-fig.sec .ph-num{font-size:var(--fs-lg)}
  .pvm-hero .ph-src{font-size:var(--fs-2xs); max-width:18ch}
  .ph-body{padding:var(--s4) var(--s4) var(--s4) calc(var(--s4) + 5px)}
  .ph-honest{font-size:var(--fs-2xs); margin-top:var(--s2); line-height:1.45}
  .ph-when{margin-top:var(--s3)}
}
@media (pointer:coarse){ .ln-cta .btn{min-height:44px} }
@media (prefers-reduced-motion:reduce){ .ln-summary .caret, .iranked > summary .caret{transition:none} }
