/* pricegap
   Split from the single v22 stylesheet. Everything here is scoped to
   .card.pricegap and this form's own class prefix (rule 14: a change made for one
   card form is scoped to that form, by class). */
/* ------------------------------------------------------------------ *
   The Price Gap — the thing, here, then the number it costs there.

   Every class here is `.pg-` or hangs off `.card.pricegap`, per AGENTS.md
   rule 14. Same hard rule as The Price, on a second store instead of a
   national figure: the answer -- Location B's price -- is never written
   into the markup. It is held in a JS property on the card element and
   reaches the DOM only after a guess is locked in. Location A's price is
   the premise and is safe to print at any time -- the headline already
   names it -- so `.pg-anchor` may carry it before the lock; nothing else
   here may carry B's price, the dollar difference or the percentage gap
   before the lock.

   The reveal's hierarchy, which is what this form is for: two places, two
   prices, and the distance between them set larger than either. The
   reader's own accuracy is a note under it, not the headline of it. Before
   the reveal there was one size for everything that arrived at the lock --
   a 54px answer, a 19px grade, a 14px sentence and a 13px sentence, four
   groups all saying two numbers -- and the frame read as a list rather
   than as a comparison.

   Reuses `priceMoney`, `priceDiff` and `railLabelShift` rather than
   redeclaring them: one instrument, one set of helpers, not a second copy
   per form the ticker happens to belong to. `gradeGuess` is new -- The
   Price grades on a single national figure and Price Gap grades on the
   gap between two stores, so the two payloads carry different band field
   names (`max_relative_error` against `max_guess_relative_error`) by
   design (see `session/pricegap.mjs`) and cannot share one function.
 * ------------------------------------------------------------------ */
/* 12/12 rather than 16/14. The panel is a fixed --panelq and the photograph
   is the only thing in it that can take slack, so six pixels of padding are
   six pixels of product. */
.card.pricegap .vizsec{padding:12px 0 12px}
/* lane-image-floor: same defect as The Price, worse -- the box rendered 1px
   tall at 430x743, on the live site (reviewer: "...and tacobell"). Same fix,
   same reasoning as price.css's own note above `.pr-shot`: `.pg-shot` gets a
   floor (68px -- lower than The Price's 96, see the note on `.pg-shot`
   below for why), `.pg-foot` and `.pg-scale` give first (highest
   flex-shrink), and the row gap drops from 11 to 1 because six gaps of
   pure whitespace at the old value were competing with the floor as much
   as any row was. */
.pricegapviz{display:flex;flex-direction:column;width:100%;height:100%;min-height:0;
  padding:0 15px;gap:1px}

/* 1 - the thing being priced: its name, its picture, and what it costs at
       Location A.

       This is the stack's `setup` slot, and on this form it is three things
       rather than one. The name leads, because the photograph says "a Taco
       Bell box" and does not say which box, and the item is the subject of
       the question about to be asked. It used to be the last line of the
       panel, in footnote grey under the button, purely because it shared an
       element with the footnote.

       The comparison value used to be readable only in the headline and again
       down there -- and a reader guessing California's price had to look past
       the control they were using to find Nevada's. It is the premise of the
       question, so it sits with the premise, and it stands down at the lock
       because the comparison then states it in full.

       The wrapper is what makes it one slot: the stack orders the form root's
       own children, and a form needing three elements in one position groups
       them rather than claiming three slots (which would put them at an order
       the stack does not define). `.pg-shot` keeps the flex inside it, so the
       photograph is still what gives when the panel is tight -- and after the
       restructure below it is what GAINS when the panel is not. */
/* lane-image-floor: `min-height:115px`, not 0. `.pg-setup` is the `setup`
   slot (shell.css: `flex-grow:1;flex-basis:0%`) and its own `min-height:0`
   let the OUTER algorithm assign it a box shorter than `.pg-name` +
   `.pg-shot`'s floor + `.pg-anchor` need -- and since this wrapper has no
   `overflow:hidden` of its own, the overflow bled downward into `.pg-ask`,
   printing the anchor price on top of the guess figure (measured at
   430x743: "$5.99 in Vegas" over "$7.00"). The floor is this row's own
   three children at their own floor: 18.75 (name) + 4 (gap) + 68 (the shot
   floor) + 4 (gap) + 23.39 (anchor), rounded up, plus a few px of slack
   proven against `review/foldcheck.mjs`'s own panel-overflow measurement
   rather than against the DOM-only arithmetic here (the two did not agree
   to the pixel -- see this form's floor note on `.pg-shot` below). */
.pg-setup{display:flex;flex-direction:column;min-height:115px;gap:4px}
.pg-name{flex:none;text-align:center;font-size:var(--fs-15);line-height:1.25;font-weight:600;
  letter-spacing:var(--ls-n01);color:var(--muted);text-transform:none}
/* lane-image-floor: the box rendered 1px tall at 430x743 -- this row was the
   only flexible thing in its own wrapper and in the panel, so it gave
   everything (see the note above `.priceviz` in price.css for the fuller
   argument, identical here). `min-height:68px` is the floor; it never gives
   past that.

   Lower than The Price's 96px, on the same card, in the same panel shape,
   for two reasons. First, this row's own wrapper (`.pg-setup`) carries two
   more rigid rows around the picture -- the product name and the Location A
   anchor -- that The Price's `.pr-shot` does not, so less of the shared
   budget is left over once those and the give-first rows (`.pg-foot`,
   `.pg-scale`) are spent. Second, this particular card (`2026-09-03-
   pricegap`) carries no footnote at all -- `visualPriceGap` omits `.pg-foot`
   entirely when the payload has none -- so the give-first pool this card
   actually has is `.pg-scale` alone. 96 does not fit that pool at 430x743;
   68 is the highest floor proven, against `review/foldcheck.mjs`'s own
   panel-overflow measurement, not to overflow `.vizsec` on this card. A
   payload that does carry a footnote has more give and would clear a higher
   floor, but the floor is set for the tightest card this form can produce,
   not the easiest one. */
.pg-shot{flex:1;min-height:68px;display:flex;align-items:center;justify-content:center}
.pg-anchor{flex:none;text-align:center;font-size:var(--fs-14);line-height:1.3;
  color:var(--dim);font-variant-numeric:tabular-nums}
.pg-anchor b{color:var(--muted);font-size:18px;font-weight:700;letter-spacing:var(--ls-n01)}
/* 88%, not 60%. The photograph is a cut-out on black with nothing around it
   to crowd, and the height is what binds in this panel -- so the width cap
   exists only to stop a wide product running to the panel's edges, and 60%
   was capping it well before the height did. */
.pg-img{max-height:100%;max-width:88%;width:auto;height:auto;object-fit:contain;
  filter:drop-shadow(0 20px 34px rgba(0,0,0,.6))}
/* At the lock the premise is restated in full by the comparison, one line
   below -- but `.pg-anchor` used to go `display:none` there, and the room it
   freed went to `.pg-shot` (`flex:1`, the one flexible child in this slot),
   which is exactly the class of move `review/formcheck.mjs`'s
   answer-stability check now catches by name (session 42, the reviewer:
   "before the guess/answer should be similar to after the guess ...
   (identical really) with the extra stuff appearing"). Session 20 already
   taught this lesson on The Price -- "the picture is the card; it does not
   shrink because a question was answered" (`forms/price.css`, `.pr-rail`'s
   own comment) -- and this form re-learned it independently. `.pg-anchor`
   stays drawn, unchanged, in both states now; saying Location A's price
   twice (once here, once in the comparison) is a smaller cost than the
   photograph resizing under the reader. */

/* 2 - the ask, and then the answer in the box the ask was in */
/* Never gives -- the guess figure, same reasoning as `.pr-ask` in price.css. */
.pg-ask{flex:none;display:flex;flex-direction:column;align-items:center;gap:5px}
/* No type of its own -- the stack's `question` slot, set in the layout
   block with the other three forms' questions. */
.pg-prompt{display:block;text-align:center}
.pg-guess{font-size:var(--fs-guess);font-weight:700;line-height:1;
  letter-spacing:-.03em;font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;
  color:var(--ink);min-width:4.6ch;text-align:center;white-space:nowrap;
  transition:transform .16s cubic-bezier(.22,.9,.3,1)}
.pricegapviz.adjusting .pg-guess{transform:scale(1.03)}

.pg-head{display:none;flex-direction:column;align-items:stretch;gap:9px;width:100%;
  opacity:0;transform:translateY(6px);
  transition:opacity .3s ease-out,transform .34s cubic-bezier(.22,.9,.3,1)}
.pricegapviz.locked .pg-head{display:flex}
.pricegapviz.settled .pg-head{opacity:1;transform:none}
/* The guess goes; the question stays, for the reason set out over the
   equivalent rule in The Price's section -- one instrument, one behaviour. */
.pricegapviz.locked .pg-guess{display:none}

/* --- the comparison, which is what the card is about ---------------- *
   Two places, balanced, and the distance between them. The hairline is the
   comparison: two centred columns with nothing between them read as two
   unrelated facts, and a border is one pixel against an arrow's twelve.
   Location B carries the full ink because it is the answer; Location A is
   muted because the reader was told it before they were asked. */
.pg-pair{display:flex;align-items:flex-start;gap:0}
.pg-loc{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;gap:2px;
  text-align:center;padding:0 6px}
.pg-loc + .pg-loc{border-left:1px solid var(--line)}
.pg-where{font-size:var(--fs-12-5);line-height:1.25;font-weight:500;color:var(--dim);
  letter-spacing:0;text-transform:none}
.pg-price{font-size:27px;font-weight:700;line-height:1.1;letter-spacing:-.025em;
  color:var(--muted);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.pg-far .pg-price{color:var(--ink)}

/* There used to be a third row here, `.pg-gapfig` -- the dollar difference
   and the percentage, in type larger than the grade. The reviewer put this
   card next to The Price and asked for it gone (session 24); pricegap.js's
   `lock()` no longer writes it and this rule is gone with it, rather than
   left declared and unused (rule 17's trap runs the other way too -- a rule
   nothing still writes into is exactly as easy to mis-trust as a duplicate
   one). What it cost: the store gap was the one place it was spoken as
   arithmetic rather than left for the reader to subtract `.pg-pair`'s two
   figures themselves. */

/* 3 - the rail. Adapted from The Price's, deliberately: a reader who meets
       both cards in one feed should recognise one instrument -- including
       The Price's own lesson (session 20, `forms/price.css`'s `.pr-rail`
       comment) that the rail keeps the margins and the track keeps the
       thickness it was drawn with, in both states. This form used to demote
       it at the lock -- a thinner track, smaller marks, no end labels,
       "subordinate to the comparison above" -- and that demotion was itself
       a move on three elements the reader had just been looking at
       (`.pg-rail`, `.pg-track`, `.pg-scale`), which is exactly what session
       42's answer-stability standard forbids. The marks still shrink in
       their OWN styling (`.pg-mark.pg-real` below) -- that is not a box any
       element existing before the lock is measured against -- only the
       rail's, the track's and the scale's own containers no longer do. */
/* lane-image-floor: same shape as `.pr-slot` in price.css -- `.pg-rail`
   never gives (it is the control), `.pg-scale` gives second (after
   `.pg-foot`), and this row's own floor (45px) protects the rail from being
   pushed under it by the outer shrink pass. */
.pg-slot{display:flex;flex-direction:column;gap:1px;flex:0 3 auto;min-height:45px}
.pg-rail{position:relative;height:44px;flex:none}
.pg-track{position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);
  height:8px;border-radius:var(--radius-xs);background:var(--line);
  transition:height .28s ease-out}
.pg-range{position:absolute;left:0;right:0;top:0;width:100%;height:44px;margin:0;
  z-index:2;-webkit-appearance:none;
  appearance:none;background:none;cursor:grab;
  touch-action:none}
.pg-range:active{cursor:grabbing}
.pg-range::-webkit-slider-runnable-track{height:8px;border-radius:var(--radius-xs);background:var(--line)}
.pg-range::-moz-range-track{height:8px;border-radius:var(--radius-xs);background:var(--line)}
.pg-range::-webkit-slider-thumb{-webkit-appearance:none;width:34px;height:34px;
  border-radius:50%;background:var(--ink);border:0;margin-top:-13px;
  box-shadow:0 2px 12px rgba(0,0,0,.55)}
.pg-range::-moz-range-thumb{width:34px;height:34px;border-radius:50%;
  background:var(--ink);border:0;box-shadow:0 2px 12px rgba(0,0,0,.55)}
.pg-range:focus-visible{outline:2px solid var(--muted);outline-offset:4px;border-radius:var(--radius-sm)}
/* lane-image-floor: the second thing to give, after `.pg-foot` -- same
   reasoning as `.pr-scale` in price.css. */
.pg-scale{display:flex;justify-content:space-between;font-size:var(--fs-12);color:var(--dim);
  letter-spacing:0;text-transform:none;font-variant-numeric:tabular-nums;
  flex:0 2 auto;min-height:0;overflow:hidden}

/* --- the reveal, on the rail -------------------------------------- */
.pg-mark{position:absolute;top:50%;transform:translate(-50%,-50%);opacity:0;
  pointer-events:none;transition:opacity .3s ease-out}
.pg-mark i{display:block;width:10px;height:10px;border-radius:50%;
  background:var(--dim);margin:0 auto}
.pg-mark em{position:absolute;left:50%;top:-23px;white-space:nowrap;font-style:normal;
  font-size:var(--fs-11-5);font-weight:600;letter-spacing:0;text-transform:none;
  color:var(--dim);font-variant-numeric:tabular-nums}
.pg-mark.pg-real i{width:3px;height:22px;border-radius:var(--radius-xs);background:var(--muted)}
.pg-mark.pg-real em{top:23px;color:var(--muted);font-weight:700}
.pg-mark.beyond i{width:0;height:0;border-radius:0;background:none;
  border-top:7px solid transparent;border-bottom:7px solid transparent}
.pg-mark.beyond.hi i{border-left:10px solid var(--muted);margin-left:auto;margin-right:0}
.pg-mark.beyond.lo i{border-right:10px solid var(--muted);margin-left:0;margin-right:auto}
.pg-gap{position:absolute;top:50%;transform:translateY(-50%);height:6px;
  border-radius:var(--radius-xs);background:var(--edge);width:0;
  transition:width .5s cubic-bezier(.16,1,.3,1) .18s,
             left .5s cubic-bezier(.16,1,.3,1) .18s}
.pricegapviz.locked .pg-mark{opacity:1;transition-delay:.12s}
.pricegapviz.locked .pg-range{opacity:0;pointer-events:none}
/* `.pg-rail`, `.pg-track` and `.pg-scale` used to shrink or disappear here --
   session 20 found the identical shape of defect on The Price (`.pr-shot`,
   `flex:1`, paying for a reveal that was "additive": 153.9px to 72.2px) and
   fixed it by making the rail keep its own margins; this form's own rail
   getting shorter (44 -> 26px) and its scale vanishing was the same defect
   wearing a different shape -- room freed on elements the reader had just
   been looking at, spent on `.pg-shot` growing underneath the photograph.
   `review/formcheck.mjs`'s answer-stability check (session 42) is what
   finally named it on three elements at once rather than one. Nothing here
   demotes any more; `js/forms/pricegap.js`'s `reserveAskHeight()` is what
   makes room for the comparison instead, and it comes from `.pg-ask`'s own
   reserved height, never from the rail. */

/* Never gives -- see the lane-image-floor note above `.pg-shot`. */
.pg-lock{appearance:none;-webkit-appearance:none;width:100%;padding:15px 16px;border:0;
  border-radius:var(--radius-md);background:var(--ink);color:var(--lock-ink);cursor:pointer;
  font:700 16px/1 "IBM Plex Sans",system-ui,sans-serif;letter-spacing:var(--ls-n01);
  transition:transform .12s ease-out,opacity .18s ease-out;flex:none}
.pg-lock:hover{opacity:.9}
.pg-lock:active{transform:scale(.985)}

/* 4 - how the reader did. `.pg-lock` stays on the card at the lock rather
       than being hidden for a result block: pricegap.js writes the grade and
       the distance into the button's own text, exactly the way price.js's
       `lockBtn.textContent` does for The Price -- same box, same place the
       reader's hand already was. `.pg-result` still gets the same two lines
       written into it (kept for the reason `.pr-result` is, in price.css)
       but is never shown; the button already said this. */
.pg-result{display:none;flex-direction:column;align-items:center;text-align:center;gap:3px;
  opacity:0;transform:translateY(6px);
  transition:opacity .32s ease-out .1s,transform .32s cubic-bezier(.22,.9,.3,1) .1s}
.pg-grade{font-size:var(--fs-14);font-weight:700;line-height:1.2;letter-spacing:var(--ls-n01);
  color:var(--muted)}
.pg-you{font-size:var(--fs-13);line-height:1.3;font-weight:500;color:var(--dim);
  font-variant-numeric:tabular-nums;letter-spacing:0;text-transform:none}

/* the footnote, in both states -- and only when the payload has one. The
   product name used to fall in here when it did not, which is how the thing
   being priced ended up at the bottom of the panel in footnote grey.
   lane-image-floor: the first thing to give -- same reasoning as `.pr-foot`
   in price.css. */
.pg-foot{padding-top:11px;border-top:1px solid var(--line);font-size:var(--fs-12-5);
  color:var(--dim);letter-spacing:0;text-transform:none;
  flex:0 20 auto;min-height:0;overflow:hidden}

/* --- the honest failure ------------------------------------------- */
.pg-fail{display:flex;flex-direction:column;gap:6px;justify-content:center;width:100%;
  min-height:0;padding:15px;border:1px solid var(--edge);border-radius:var(--radius-md);
  letter-spacing:0;text-transform:none}
.pg-fail b{font-size:var(--fs-15);font-weight:700;color:var(--muted)}
.pg-fail span{font-size:var(--fs-12-5);line-height:1.5;color:var(--dim)}

@media (prefers-reduced-motion:reduce){
  .pg-guess,.pg-lock{transition:none}
  .pricegapviz.adjusting .pg-guess{transform:none}
  .pg-head,.pg-result{transition:none}
  .pg-track,.pg-mark,.pg-gap{transition:none}
}
