/* price
   Split from the single v22 stylesheet. Everything here is scoped to
   .card.price 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 — the thing, then the number you think it costs.

   Every class here is `.pr-` or hangs off `.card.price`, per AGENTS.md rule
   14. The form is the only one on the feed whose payload must not reach the
   DOM: the answer is what the reader is being asked for, so it is held in a
   JS property on the card element and written into the panel only after a
   guess is locked in. Nothing below may reintroduce it -- no reserved width
   measured from it, no `content:` that spells it, and no rule that positions
   anything from it.

   The rail carries a mark at the answer's position AFTER the lock, and that
   is the one thing here that has to be read carefully: `.pr-track` ships
   empty, `.pr-mark` exists only as a style, and both marks are written by
   initPrice from the closure when a guess is locked in. A `left:` in this
   stylesheet, a `--pos` custom property or a marker in `visualPrice` would
   each put the answer back in the served document.
 * ------------------------------------------------------------------ */
/* No --panelq override. The Habit buys its picture down to 488 because it
   carries a three-line headline AND a live caption; this form leaves `.sub`
   empty, so the default 427 balances out at roughly 154px of photograph over
   a 51px ask, a 60px rail+scale and a 46px button -- measured in the frame,
   not budgeted on paper. */
/* lane-face-fit-width: same shape as The Close's fix, on this mode's own
   selector -- Price resolves `prompt_first`, so the shell fixes the panel at
   `.card.solo[data-layout="prompt_first"]:not(.open) .vizsec{height:
   var(--panelq)}`, not --panelh, and a shorter face clipped or overlapped the
   bottom of that unless the panel could give. Unlike The Close, `.pr-shot`
   -- the photograph -- is already `flex:1;min-height:0` INSIDE this panel, so
   letting the panel itself flex too just chains one flexible box into
   another: the picture is the one thing in the column with give, `.pr-ask`,
   `.pr-slot` and `.pr-lock` all keep their own content-sized height, and
   nothing has to be measured and pinned to a number the way The Close's fixed
   result rows did. `max-height:var(--panelq)` is still load-bearing for the
   same reason it was there (this file's byte-identity check at 393x852 caught
   its absence the same way).

   620px, tried first, was too low and not caught by eye until measured: at
   430x743 (679px, the width-bound height there) the panel got only 271px,
   which the fixed ask+rail+lock rows (190px) plus the panel's own 30px of
   padding already exceed, so `.pr-shot` -- the one flexible row -- was
   squeezed to 0 and the photograph disappeared. This mode puts the headline
   ABOVE the panel rather than below it (unlike The Close), so the space
   outside the panel is ~408px here, not ~266px, and the floor has to clear
   that before the panel gets anything. 760px is the shortest floor that
   leaves `.pr-shot` a visible photograph at 430x743 and 375x667 (measured:
   panel 353px there, shot ~106px, against 154px at 852) with the ask, rail
   and lock rows still full size and nothing overlapping. */
.card.price[data-layout="prompt_first"]:not(.open) .vizsec{
  flex:1;height:auto;min-height:0;max-height:var(--panelq);
}
.card.price .vizsec{padding:16px 0 14px}
.priceviz{display:flex;flex-direction:column;width:100%;height:100%;min-height:0;
  padding:0 15px;gap:11px}

/* 1 - the thing. It is the premise, so it leads and it is allowed to be big;
       `contain` rather than `cover` because a gallon jug cropped at the
       shoulders stops being recognisable in the two seconds the card has. */
.pr-shot{flex:1;min-height:0;display:flex;align-items:center;justify-content:center}
.pr-img{max-height:100%;max-width:60%;width:auto;height:auto;object-fit:contain;
  filter:drop-shadow(0 20px 34px rgba(0,0,0,.6))}

/* 2 - the ask */
.pr-ask{display:flex;flex-direction:column;align-items:center;gap:5px}
/* No type of its own -- it is the stack's `question` slot and the layout
   block sets it. What stays here is the box: centred under the photograph,
   which is this form's own composition (rule 14). */
.pr-prompt{display:block;text-align:center}
/* Tabular figures and a reserved width. $2.50 and $8.95 carry the same number
   of glyphs and not the same width in proportional figures, so without
   `tnum` the readout twitches under the thumb and reads as the card
   stuttering rather than as the value changing. min-width holds the box at
   its widest form so the centre never walks either. */
.pr-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)}
/* The only feedback the control gives while it is being used. Deliberately
   not a colour: colour on this figure would be read as hot/cold against the
   answer, which is the one thing the card must not say before the lock. */
.priceviz.adjusting .pr-guess{transform:scale(1.03)}

/* The answer lands in the box the guess was standing in, at the same size and
   the same place. The reader spent the whole interaction watching one figure
   above the rail change under their thumb; the reveal is that figure settling
   on the true one, not a new number appearing somewhere else. Empty until the
   lock -- initPrice writes it. */
.pr-head{display:none;flex-direction:column;align-items:center;gap:4px}
.priceviz.locked .pr-head{display:flex}
/* The guess goes; the QUESTION stays. It used to go with it, which left the
   revealed card leading with a photograph and a number and no statement of
   what the number answered -- and it made the answered state a different
   composition from the unanswered one, so the panel's rows moved under the
   reader at the moment they were reading it. The stack's rule is that
   revealing rewrites a row IN PLACE: `.pr-guess` becomes `.pr-head` inside
   the `answer` slot, and everything above and below it holds still. */
.priceviz.locked .pr-guess{display:none}

/* 3 - the rail. A native range: it is the only control that arrives with
       pointer, touch and keyboard already working, announces itself as a
       slider, and carries its own current-value semantics. 160 steps of
       $0.05 across the frame is about 2px a step, and the ±5% band that
       earns the top grade is four steps wide, so a thumb can reach it. */
.pr-slot{display:flex;flex-direction:column;gap:1px}
/* The rail the reader drags IS the result bar. It does not vanish and get
   replaced by a chart: the control stays on the page, on the same scale, and
   the answer arrives on it beside the mark the reader left. `.pr-rail` is the
   shared coordinate space -- the input and the track it is drawn on are the
   same 44px box, so a mark at any value and the thumb sitting on that value
   are always the same place on it. Written without a worked figure on
   purpose: a live example here is a live number in served CSS, and this file
   draws every card built to this rail, not just the one open when the
   comment was written (rule 4). Adapted from the rail in The Reveal's own
   section, deliberately: a reader who meets both cards in one feed should
   recognise one instrument. */
.pr-rail{position:relative;height:44px}
/* The rail's own surface, which the marks hang on. The input draws an
   identical 8px track over it, so nothing changes visually at the lock --
   the input fades out and this is already underneath it. */
.pr-track{position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);
  height:8px;border-radius:4px;background:var(--line)}
.pr-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;
  /* a drag on the rail must not take the feed with it */
  touch-action:none}
.pr-range:active{cursor:grabbing}
.pr-range::-webkit-slider-runnable-track{height:8px;border-radius:4px;background:var(--line)}
.pr-range::-moz-range-track{height:8px;border-radius:4px;background:var(--line)}
/* 34px of thumb inside a 44px band: the target is the whole height of the
   control, not the circle drawn in it. */
.pr-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)}
.pr-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)}
.pr-range:focus-visible{outline:2px solid var(--muted);outline-offset:4px;border-radius:8px}
/* The ends of the range, and -- while the question is open -- nothing between
   them. A tick, a midpoint or a "typical" band would each be the card
   narrowing the field toward its own answer.

   The midpoint arrives with the answer, not before it. Once the guess is
   locked the axis has a third label so the gap between the two marks can be
   measured by eye against a scale rather than trusted; before the lock it is
   an anchor, and an anchor is a hint. It is the arithmetic middle of the two
   ends and carries no information about the answer, which is why it is safe
   to show at all. `<i>`, not a third `<span>`: the ends are the scale the
   payload declares and are checked as a pair.  */
.pr-scale{display:flex;justify-content:space-between;font-size:12px;color:var(--dim);
  letter-spacing:0;text-transform:none;font-variant-numeric:tabular-nums}
.pr-mid{display:none;font-style:normal}
.priceviz.locked .pr-mid{display:block}

/* --- the reveal, on the rail -------------------------------------- */
/* Two marks on one axis, and the distance between them is the error -- seen,
   rather than converted back from a sentence. Both are written by initPrice
   at lock time; the track ships empty.

   Never coloured by direction, for the same reason `.pr-grade` is not: a
   green mark for a good guess and a red one for a bad one turns the card into
   a scoreboard, and being wrong about the price of milk is not a loss. The
   answer is --ink because it is the thing the reader came back for; the
   reader's own mark is --muted and stays on the rail, because it is theirs
   and it is what makes the card personal. */
.pr-mark{position:absolute;top:50%;transform:translate(-50%,-50%);opacity:0;
  pointer-events:none;transition:opacity .3s ease-out}
/* The reader's mark is a pin, not a second rule: a dot where the thumb was,
   so when a good guess and the answer land on the same spot the answer's rule
   crosses the pin instead of covering it. Both stay legible at the one
   position on the rail where it matters most that they do. */
.pr-mark i{display:block;width:13px;height:13px;border-radius:50%;
  background:var(--muted);margin:0 auto}
.pr-mark em{position:absolute;left:50%;top:-27px;white-space:nowrap;font-style:normal;
  font-size:12.5px;font-weight:600;letter-spacing:0;text-transform:none;
  color:var(--muted);font-variant-numeric:tabular-nums}
/* `.pr-mine`, not `.pr-you`: `.pr-you` is the sentence under the rail, and a
   mark sharing its class made `querySelector(".pr-you")` return whichever came
   first in the document. The renderer has one flat namespace and that is the
   `data-count` collision again -- formcheck caught it in the same run it was
   written in. */
.pr-mark.pr-real i{width:4px;height:30px;background:var(--ink)}
.pr-mark.pr-real em{top:29px;color:var(--ink);font-weight:700}
/* An answer the rail cannot reach. The contract forbids it -- the payload's
   answer must be reachable on the control the card offers -- so this is the
   renderer refusing to lie if one ever gets through: the mark stops at the
   end it ran past and says so, rather than being drawn inside a window it
   does not belong to. The bar never rescales to swallow it, because a bar
   that quietly restretches makes a wild guess look close. */
.pr-mark.beyond i{width:0;height:0;border-radius:0;background:none;
  border-top:8px solid transparent;border-bottom:8px solid transparent}
.pr-mark.beyond.hi i{border-left:11px solid var(--ink);margin-left:auto;margin-right:0}
.pr-mark.beyond.lo i{border-right:11px solid var(--ink);margin-left:0;margin-right:auto}
/* The error itself, drawn. --edge sits between the track and the marks, so it
   reads as the span between two things rather than as a value of its own.
   The delay is the beat: the answer's mark lands beside the pin the reader
   left, and only then does the distance between them draw. Fired together
   they read as one blob appearing; a fifth of a second apart they read as a
   sentence -- here it is, and here is how far off you were. */
.pr-gap{position:absolute;top:50%;transform:translateY(-50%);height:10px;
  border-radius:5px;background:var(--edge);width:0;
  transition:width .5s cubic-bezier(.16,1,.3,1) .18s,
             left .5s cubic-bezier(.16,1,.3,1) .18s}
.priceviz.locked .pr-mark{opacity:1;transition-delay:.12s}
/* The control steps aside; the rail it drew on stays. */
.priceviz.locked .pr-range{opacity:0;pointer-events:none}
/* The rail keeps the margins it was drawn with. It used to gain 28px above
   and 30px below at lock -- room for a label over each mark -- and the marks
   are absolutely positioned inside the track, so that was visual breathing
   room rather than containment. Measured, it cost 58px that `.pr-shot` is
   `flex:1` and therefore paid: the milk jug went 153.9px -> 72.2px, a 53% drop,
   the instant the reader answered. The picture is the card; it does not shrink
   because a question was answered. */

.pr-lock{appearance:none;-webkit-appearance:none;width:100%;padding:15px 16px;border:0;
  border-radius:14px;background:var(--ink);color:var(--lock-ink);cursor:pointer;
  font:700 16px/1 "IBM Plex Sans",system-ui,sans-serif;letter-spacing:-.01em;
  transition:transform .12s ease-out,opacity .18s ease-out}
.pr-lock:hover{opacity:.9}
.pr-lock:active{transform:scale(.985)}

/* 4 - the payoff, in one beat, and it is now spread over three places rather
       than stacked in one: the answer in the box the guess was in, the two
       marks on the rail, and this block under it. The answer still leads and
       the reader's error is still second -- a card that opens with how wrong
       you were is a card about the reader, and the reader is not the story --
       but the error is a distance on a bar before it is a sentence, and the
       sentence confirms what the bar already showed. */
.pr-result{display:none;flex-direction:column;align-items:center;text-align:center;gap:6px;
  opacity:0;transform:translateY(6px);
  transition:opacity .32s ease-out,transform .32s cubic-bezier(.22,.9,.3,1)}
/* Not drawn on the face in either state: the answer is the figure, the error
   is the button, and the distance is the gap on the rail. The five-year
   comparison is a second story about a different month and belongs to Read
   more, which already prints it. Kept in the markup for the detail view. */
/* `.pr-ask`, `.pr-slot` and the button all survive the lock. Nothing goes.
   The button used to be replaced by `.pr-result`, 69.7px of block where 46px
   of button had been, and the difference came out of the picture along with
   the rail's new margins. The button asked for a guess and now reports how it
   went, in the same box, at the same size, under the reader's own thumb. */
.pr-actual{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)}
/* The verdict is its own row, and the largest thing after the answer: it is
   the beat the reader came back for. Never coloured by direction -- a green
   "Nailed it" and a red "Way off" would turn a price card into a scoreboard,
   and being wrong about the price of milk is not a loss. */
.pr-grade{font-size:19px;font-weight:700;line-height:1.1;letter-spacing:-.015em;color:var(--ink)}
.pr-you{font-size:14px;font-weight:500;color:var(--muted);font-variant-numeric:tabular-nums}
.pr-ctx{font-size:13px;line-height:1.45;color:var(--dim);font-variant-numeric:tabular-nums}
.pr-ctx b{color:var(--muted);font-weight:600}

/* the credit line, in both states */
.pr-foot{padding-top:11px;border-top:1px solid var(--line);font-size:12.5px;
  color:var(--dim);letter-spacing:0;text-transform:none}

/* --- the honest failure ------------------------------------------- */
/* A payload this renderer cannot vouch for gets a card with no number on it
   at all. The premise survives -- the picture is still the thing being priced
   -- but there is no rail to move and no button to press, because an
   interaction whose payoff does not exist is worse than a card that says so.
   AGENTS.md rule 4, in the renderer. */
.pr-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:12px;
  letter-spacing:0;text-transform:none}
.pr-fail b{font-size:15px;font-weight:700;color:var(--muted)}
.pr-fail span{font-size:12.5px;line-height:1.5;color:var(--dim)}

/* Reduced motion keeps the interaction and drops the decoration: the guess
   stops springing under the thumb and the result arrives without a rise.
   Nothing here reveals anything -- the reader still has to lock a guess in. */
@media (prefers-reduced-motion:reduce){
  .pr-guess,.pr-lock{transition:none}
  .priceviz.adjusting .pr-guess{transform:none}
  .pr-result{opacity:1;transform:none;transition:none}
  /* The marks and the span between them are the reveal, so they still arrive
     -- they just arrive placed rather than travelling. initPrice skips the
     two-frame grow for the same reason. */
  .pr-mark,.pr-gap{transition:none}
}
