/* lot-extra.css — HAND-EDITED, and that is the whole reason it exists.
   ---------------------------------------------------------------------------
   `lot.css` is BUILT from `site/src/lot.src.css` by `npm run css`, so a rule
   written into it is lost on the next build. This sheet is the hand-editable
   layer that loads AFTER it and carries only what a later pass added on top of
   the built one. Load order is load-bearing: site.css, lot.css, then this.

   HOUSE LAW, OBSERVED HERE AS EVERYWHERE:
   - Borderless. Nothing below writes a `border`, a resting `outline`, or a
     `box-shadow` under 3px of spread. Separation is fill and spacing.
   - Tokens, not literals. Every colour and every rung is a `var(--lp-*)` that
     site.css already declares.
   - One accent, one meaning. Amber is "LotPost is waiting for you". It is the
     right hue for a QUEUE, which is a page-length picture of waiting, and it
     is not used below to mean anything else.
   - No type size is written as a literal px. The one exception is the mobile
     HEIGHT of a drawn cell, which is a picture's dimension and not type.

   Sections touched: #queue, #price.
   -------------------------------------------------------------------------- */


/* =========================================================== #queue, ground

   THE PATTERN IS THE SUBJECT DRAWN AT PAGE SCALE. #queue is about a lot of
   cars standing in line for a slot, and the section behind them is a lined
   sheet: an amber hairline grid on the true-black ground at 4% and 3%, the
   same hue the day cells are lit in, so the pattern and the instrument on top
   of it are plainly the same picture.

   IT IS A ::before AND NOT A background ON THE SECTION for two reasons: the
   mask that fades it out at the edges would otherwise fade the section's own
   fill, and a pattern that tiles hard into the neighbouring section reads as a
   seam. `isolation: isolate` keeps the layer under the content without a
   z-index race. */
#queue {
  position: relative;
  isolation: isolate;
}

#queue::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    repeating-linear-gradient(90deg, rgba(242, 169, 59, 0.055) 0 1px, transparent 1px 88px),
    repeating-linear-gradient(0deg,  rgba(242, 169, 59, 0.035) 0 1px, transparent 1px 88px);
  /* Faded on every side, so the grid belongs to this section rather than
     running under the price cards below it. */
  -webkit-mask-image: radial-gradient(120% 90% at 50% 40%, #000 35%, transparent 78%);
  mask-image: radial-gradient(120% 90% at 50% 40%, #000 35%, transparent 78%);
  pointer-events: none;
}

/* The 88px cell is the desktop rhythm. On a phone it lands as four lines
   across the whole viewport, which reads as a ruled page rather than a
   texture, so the grid tightens with the column. */
@media (max-width: 767px) {
  #queue::before {
    background-image:
      repeating-linear-gradient(90deg, rgba(242, 169, 59, 0.05) 0 1px, transparent 1px 44px),
      repeating-linear-gradient(0deg,  rgba(242, 169, 59, 0.03) 0 1px, transparent 1px 44px);
  }
}

@media (prefers-reduced-motion: no-preference) {
  /* Nothing moves. The pattern is static on purpose: a drifting background
     behind a chart of posting times is a thing to read through, not with. */
}


/* ====================================================== #queue, on a phone

   THE TWO INSTRUMENTS ARE DRAWINGS WITH FIXED CELL HEIGHTS, and both were cut
   for a 1024px column. At 360 the clock's twenty-four cells come out about
   12px wide against a 44px height, which is a picket fence, and the two cards
   carry --lp-m6 of padding each on a 328px measure. Both are fixed by making
   the cell heights fluid rather than by hiding anything: every hour a dealer
   can pick is still on the strip. */
@media (max-width: 767px) {
  .lp-qrun,
  .lp-clock {
    padding: var(--lp-m5);
    gap: var(--lp-m3);
  }

  .lp-clock-bar {
    gap: 1px;
  }

  .lp-clock-bar i {
    height: clamp(26px, 7.5vw, 44px);
    border-radius: 3px;
  }

  .lp-clock-bar i.is-quiet {
    height: clamp(15px, 4.4vw, 26px);
  }

  /* The scale's three words are the only labels on the strip and they must not
     wrap: "midnight noon midnight" at 13px is 196px, which fits 328. */
  .lp-clock-scale {
    white-space: nowrap;
  }

  .lp-qday-cells i {
    height: clamp(22px, 6.5vw, 30px);
  }
}

/* The whole point of the pair at 360 is that it is ONE column of two cards and
   neither is scaled down to meet the other. Stated rather than inherited, so a
   later grid change upstream cannot quietly put them side by side at 400. */
@media (max-width: 1023px) {
  .lp-qpair {
    grid-template-columns: minmax(0, 1fr);
  }
}


/* ============================================================== #get, bento

   THE SECTION'S OWN HEADING IS "Three things it does. Three it will not." and
   until this pass the grid did not draw that sentence: the six cards ran a,b /
   c(full) / d,e / f(full), so the two groups were interleaved down four rows
   and the reader had to collect them by reading each card's tag. Measured at
   924px the section stood 1490px tall, and the two full-width cards were the
   two tallest things in it.

   THREE COLUMNS, TWO ROWS. Row one is the three It does, row two is the three
   It will not, which is the heading rendered as a layout. It also takes the
   section from four card rows to two.

   The full-bleed spans are released rather than re-tuned: `grid-column: auto`
   on all six, and the two cards that split into text-beside-drawing at 1024
   and 1280 stack their children again, because a two-column split inside a
   270px card is not a split. Source order is what wins here -- this sheet
   loads after lot.css and the selectors score the same, so the media queries
   in the built sheet do not need matching breakpoint for breakpoint. */
@media (min-width: 768px) and (max-width: 899px) {
  .lp-b-c,
  .lp-b-f {
    grid-column: auto;
  }
}

@media (min-width: 900px) {
  .lp-bento {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .lp-b-a,
  .lp-b-b,
  .lp-b-c,
  .lp-b-d,
  .lp-b-e,
  .lp-b-f {
    grid-column: auto;
  }

  .lp-b-a,
  .lp-b-c {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    align-items: start;
  }

  .lp-b-c .lp-bpanel,
  .lp-b-a .lp-bpanel {
    grid-area: auto;
  }

  /* THE PANEL HEAD IS A ROW ONLY WHEN THE ROW FITS. `.lp-bptop` is a flex pair
     -- a label and a count -- cut for the 400px+ form of .lp-b-a; in a 272px
     card its two children measure 116 + 12 + 58 = 186 against a 218px content
     box with no slack, so both wrap at max-content and the head reads
     "EVERY BOX / FILLED" beside "18 OF / 18". A machine-face figure split
     mid-value is the "Qu" defect this page's own notes record.
     Stacked, not nowrapped: nowrap keeps the count whole and leaves the label
     wrapping, which is half a fix. */
  .lp-bptop {
    display: grid;
    justify-items: start;
    gap: 2px;
  }

  .lp-bptop b {
    white-space: nowrap;
  }

  .lp-bcard {
    padding: var(--lp-m5);
  }

  /* THE CHIP ROW'S NOWRAP WAS SAFE ONLY BECAUSE THE CARD WAS 871px WIDE.
     lot.css sets `.lp-bchips` to `flex-wrap: nowrap` from 768 for the
     full-bleed form of .lp-b-c; three of core/pace.mjs's cap chips measure
     370px, so in a 272px card the row sized its parent's auto track to
     max-content and painted 98px past .lp-wrap -- real bleed behind
     `overflow-x: clip`, which is proof/typeset.mjs check 1's whole subject and
     the trap this card's own comment quotes.
     The narrow form lot.css already ships below 768 is the right one here: a
     STACK, not a wrapped row, because Law 9 bans a chip row that wraps. */
  .lp-bchips {
    display: grid;
    justify-items: start;
  }

  /* And the belt to that braces: a grid item's `min-width` is auto, so any
     max-content child can blow the track again. Zero means the card's own
     width wins whatever lands inside it. */
  .lp-bcard-txt,
  .lp-bcard > * {
    min-width: 0;
  }
}

/* THE TWO HALVES ARE TWO FILLS, WHICH IS WHAT MAKES THE GROUPING READABLE
   WITHOUT A LABEL. Every card was --lp-surface, so "does" and "will not" were
   distinguished only by the words in the tag. The refusals step DOWN the
   surface ladder to the recessed rung -- a thing the product holds back is
   quieter than a thing it performs -- and their tag and their drawn rows step
   up to --lp-surface-3 so the ladder inside the card is preserved rather than
   flattened. Fill and spacing, never a rim. */
.lp-bcard-not {
  background: var(--lp-surface-2);
}

/* ONLY THE GLYPH TILE STEPS UP, NEVER THE LABEL. lot.css gives that tile
   --lp-surface-2, which is now the card's own fill, so the mark had nothing to
   sit on; the fix is the next rung of the ladder under the 34px tile and
   nothing behind the words. A fill behind "IT WILL NOT" is the light grey slab
   this repo's own stylesheets warn about twice -- two words wearing a chip
   read as a control nobody can press. */
.lp-bcard-not .lp-btag-i {
  background: var(--lp-surface-3);
}

.lp-bcard-not .lp-bnot-r {
  background: var(--lp-surface-3);
}

/* The drawings were cut for a card half the page wide. At a third of it they
   are the same pictures at the same proportions, three rungs shorter. */
.lp-bcells i {
  height: 14px;
}

.lp-bday-bars i {
  height: 24px;
}

.lp-bnot-r {
  min-height: 34px;
}

.lp-bform,
.lp-bday {
  padding: var(--lp-m4);
}


/* ==================================================== section headings, ink

   FLAT INK, 2026-09-18. The design shipped these h2s as a top-lit wash --
   `background-clip: text` over an ink-to-ink-2 gradient with `color:
   transparent` under it. It came out on arrival. Clipped text computes its
   colour as `transparent`, so site/proof.mjs's contrast probe reads every one
   of these headings at 1:1 against the black ground and fails it, nine pairs
   in each scheme. The wash's own comment called gradient text a flat ban in
   this house and then made an exception for itself; the ban wins. One token,
   the same one the h1 is set in. */
.lp-sec .lp-h2 { color: var(--lp-ink); }


/* ==================================================== #studio, the job chips

   THE CHIPS ARE PRESSABLE NOW, so they have to look it. They were drawn as
   labels inside an aria-hidden picture; each one loads a different gallery
   behind the stage, which makes them controls, and a control with no hover and
   no focus ring is a control a keyboard cannot find.

   Fill on hover, a 3px halo on focus. Both are the house's own devices: the
   halo is never under 3px of spread (see DESIGN.md, The Halo Not a Rim Rule)
   and the at-rest state gains nothing at all. */
.lp-edit-job {
  transition: background-color 180ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .lp-edit-job {
    transition-duration: 0ms;
  }
}

@media (hover: hover) {
  .lp-edit-job:not(.is-on):hover {
    background: var(--lp-surface-3);
  }
}

.lp-edit-job:focus-visible {
  outline: 0;
  box-shadow: 0 0 0 3px var(--lp-accent-60);
}

/* The section is the fourth on the page now rather than the fifth, which puts
   the modal in front of a reader who has just been told what the product does
   and has not yet been told the price. It carries the page's heaviest drawing,
   so the stage gets the top of the lift ladder and its own contained ground --
   a picture of a modal wants to look like it is over something. */
.lp-edit {
  box-shadow: var(--lp-lift-3);
}


/* ============================================================ #price, cards

   THE THREE BUTTONS LINE UP. That is the single change that makes a price
   table read as priced rather than assembled: the cards carry 4, 4 and 5
   feature lines, so before this the calls to action sat at three different
   heights and the eye read the middle one as a different KIND of thing rather
   than the recommended one. The slack goes into the list's row, which is the
   only row on the card whose length is content and not design. */
.lp-plan {
  display: grid;
  grid-template-rows: auto auto auto auto 1fr auto;
  align-content: start;
}

.lp-plan-list {
  align-self: start;
}

/* MONEY IN TABULAR FIGURES. Archivo was chosen for this product's numbers
   specifically because its tabular-nums measured 0.00px of spread (see
   DESIGN.md, Typography), and a price is the one figure on the page a reader
   compares down a column. $49 / $99 / $149 with proportional digits do not
   align on the dollar sign. */
.lp-plan-fig b,
.lp-matrix .lp-val {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.lp-plan-fig b {
  letter-spacing: -0.02em;
}

/* THE LEAD CARD IS LIT, NOT RIMMED. An accent wash pooled behind its head,
   drawn as a radial stop on the card's own background so it is a fill and not
   an edge, plus the next rung of the lift ladder so it sits above its two
   neighbours in the same plane they share. */
.lp-plan-lead {
  background-image: radial-gradient(120% 70% at 50% 0%, var(--lp-accent-12) 0%, transparent 62%);
  box-shadow: var(--lp-lift-2);
}

/* The date under each figure is a qualifier and reads as one: quiet, and on
   the same line rhythm in all three cards so the feature lists start level. */
.lp-plan-when {
  color: var(--lp-muted);
  min-height: 1.6em;
}

@media (max-width: 767px) {
  .lp-plan {
    padding: var(--lp-m5);
  }
}


/* =========================================================== #price, matrix

   A COMPARISON TABLE IS READ ACROSS, so the row label has to stay in front of
   the answer when the table is wider than the reading column. The label column
   is stuck to the inline start and carries the surface fill it sits on, which
   is what stops the yes/no marks scrolling under a transparent cell.
   The wrap is the scroller; the table itself is untouched. */
.lp-matrix-wrap {
  overflow-x: auto;
  overscroll-behavior-inline: contain;
}

.lp-matrix th[scope="row"] {
  position: sticky;
  inset-inline-start: 0;
  background: var(--lp-surface);
  z-index: 1;
}

.lp-matrix thead th {
  font-variant-numeric: tabular-nums;
}

/* The caption is the table's own title and was set at the same weight as its
   headers, which made the first row read as part of the head. */
.lp-matrix-cap {
  color: var(--lp-ink-2);
  text-align: start;
}


/* ================================================== #price, matrix on a phone

   THE TABLE IS NO LONGER HIDDEN UNDER 768. lot.css sets `.lp-matrix-wrap` to
   display:none there and the reasoning in index.html is sound about one thing
   -- a twelve-row four-column grid at 360 is a table people pinch, not read.
   So it is not shown as a table: each row becomes its own small card, the row
   label is its heading, and the three answers sit under it as label-and-value
   pairs. The plan names come from the `data-c` attribute the markup already
   carries on every cell, which is what that attribute was put there for.

   NOTHING IS RE-WORDED AND NO FIGURE ARRIVES. The yes/no marks keep their
   .lp-vh text, so a screen reader reads "Pro, yes" here exactly as it reads
   "Pro, yes" from the desktop table. */
@media (max-width: 767px) {
  .lp-matrix-wrap {
    display: block;
    margin-block-start: var(--lp-m7);
  }

  .lp-matrix,
  .lp-matrix thead,
  .lp-matrix tbody,
  .lp-matrix tr,
  .lp-matrix th,
  .lp-matrix td {
    display: block;
    width: auto;
  }

  /* The head row is three plan names with no row label to sit against; the
     cards below name their own plans. */
  .lp-matrix thead {
    display: none;
  }

  .lp-matrix tbody tr {
    margin-block-end: var(--lp-m3);
    padding: var(--lp-m4);
    border-radius: var(--lp-r-in);
    background: var(--lp-surface);
  }

  /* The zebra and the lit Pro column are both desktop devices for reading
     across a wide row. Down here every card is one row, so they only muddy
     which plan is which. */
  .lp-matrix tbody tr:nth-child(odd) th,
  .lp-matrix tbody tr:nth-child(odd) td,
  .lp-matrix td.is-lead {
    background: transparent !important;
  }

  .lp-matrix tbody th[scope="row"] {
    position: static;
    padding: 0 0 var(--lp-m3);
    color: var(--lp-ink);
    font-weight: 600;
  }

  .lp-matrix tbody td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--lp-m3);
    min-height: 34px;
    padding: 0;
    text-align: start;
  }

  .lp-matrix tbody td::before {
    content: attr(data-c);
    color: var(--lp-muted);
    font-size: var(--lp-mt-small);
    letter-spacing: var(--lp-track-label);
  }

  /* Pro is still the recommended rung; down here it is said with the accent
     ink on its own name rather than with a lit column. */
  .lp-matrix tbody td.is-lead::before {
    color: var(--lp-accent-ink);
    font-weight: 700;
  }
}


/* ============================================ the hero headline, three states

   THE DESIGN SHIPPED A ROTATOR WITH NOTHING TO DRIVE IT, 2026-09-18. The h1
   carries three `.lp-h1-line` variants, one of them marked `is-on`, and
   `lp-h1-line`, `lp-h1-half`, `lp-h1-em` and `lp-h1-lit` appear in no sheet
   and no script in this repo. So all three painted at once, stacked: ten lines
   at 360 against a cap of four, and a hero column the deck could not sit under.
   The bundle's own brief says why -- interactions prototyped in the design copy
   are stripped on export because the repo page has no script for them. This is
   that script's sheet half.

   ONE GRID CELL, NOT ABSOLUTE POSITIONING. All three variants share row 1 /
   column 1, so the h1 reserves the height of the TALLEST variant and the deck
   under it never moves when the headline turns. Absolute children would
   collapse the h1 to zero and put the deck through it.

   `visibility`, NOT OPACITY ALONE. An opacity-0 variant is still in the
   accessibility tree and still in `innerText`, which would hand a screen
   reader and site/seo-proof.mjs three different headlines joined end to end.
   Hidden means hidden; the delay on the way out is what lets the crossfade
   finish first. */
.lp-h1 {
  display: grid;
  /* minmax(0, 1fr), NOT the default `auto`. An auto grid column is at least
     its widest item's min-content, and the variants carry `inline-size: 100%`
     halves whose percentage resolves against an indefinite column -- which
     pushed the whole hero column to 384px inside a 360px phone and took eleven
     boxes over the edge with it. A zero floor lets the column be the viewport. */
  grid-template-columns: minmax(0, 1fr);
}
.lp-h1-line {
  grid-area: 1 / 1;
  min-inline-size: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.6s ease, visibility 0s linear 0.6s;
}
.lp-h1-line.is-on {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.6s ease, visibility 0s linear 0s;
}

/* The two emphasis inks the design set per variant. Accent on the word that
   carries the promise, ink on the word that names the reader. Flat tokens: the
   h1 is the page's one searchable sentence and gradient text is banned here. */
.lp-h1-em  { color: var(--lp-accent-ink); }
.lp-h1-lit { color: var(--lp-ink); }

/* Reduce stops the turn outright -- lot.js never starts the timer -- so the
   transition has nothing to run and is cut here too, which is what
   site/proof.mjs reads when it asks for a 0s longest transition. */
@media (prefers-reduced-motion: reduce) {
  .lp-h1-line, .lp-h1-line.is-on { transition: none; }
}


/* ================================================ the hero eyebrow, at 360

   `.lp-hero-who` is set `white-space: nowrap` so the line and its glyph read
   as one pill. A nowrap line has a min-content as wide as the sentence, and at
   360 that pushed `.lp-hero-in` to 384px and took the whole hero column --
   eleven boxes, h1 to art -- past the viewport edge. The pill keeps its one
   line everywhere it fits and is allowed to wrap on the narrowest phones,
   which is the only width where it cannot. */
@media (max-width: 480px) {
  .lp-hero-who { white-space: normal; text-align: start; }
}

/* THE MARK DOES NOT GROW WITH THE LINE. `.lp-who-mk` carries no width of its
   own, and an inline SVG with no width fills the box it is given: once the
   pill was allowed to wrap to three lines at 360 the glyph stretched to 120px
   square beside them. It is an 18px mark at every width, and `flex: none` so
   the wrapped text never pulls on it again. */
.lp-who-mk {
  inline-size: 18px;
  block-size: 18px;
  flex: none;
}


/* ============================================ the hover lift, under reduce

   The four tilted panels declare `transition: transform .45s` in their own
   inline style, which no sheet can lower, so site/proof.mjs read 0.45s as the
   page's longest transition under `prefers-reduced-motion: reduce`. The
   selector is the attribute that marks exactly those elements: site/lot.js
   wires no hover at all under reduce, so there is nothing left for the
   transition to carry and it comes to 0s here. */
@media (prefers-reduced-motion: reduce) {
  [style-hover] { transition: none !important; }
}


/* ==================================================== #how, the phone stack

   AT 360 THE PAGE WAS 16,578 CSS px TALL and site/proof.mjs could not capture
   it: a texture tops out at 16,384, so the check that reads the full-page slice
   was measuring a page it could not see whole. `#how` alone was 4,042 of those
   pixels, three step rows that each keep their desktop air on a phone.

   The air comes off the joins, not off the copy: the gap between rows and the
   lead-in above each one. `!important` because both values are inline on the
   elements the design exported, and an inline declaration is the one thing a
   sheet cannot outrank any other way. */
@media (max-width: 480px) {
  .lp-howrows { gap: var(--lp-m4) !important; }
  .lp-howrows > div { padding-block-start: var(--lp-m3) !important; }
}


/* ======================================== #how, the step facts and the ghost

   THE ICONS WERE RENDERING AT 200px SQUARE. `.lp-stepfact`, `.lp-stepfact-i`,
   `.lp-stepfact-t` and `.lp-stepcopy-ghost` are four of the twenty-five classes
   the design's markup uses that arrived with no rule in any sheet -- the export
   shipped the new markup against the previous page's hand sheet. An inline SVG
   with no width and no height is 300x150 by default, so each fact chip's glyph
   filled its own row: a 676px stack of three chips that should be 80px, three
   times over, and the white shape standing where a 16px icon belongs.

   THE CHIP IS A FILL, NOT A RIM. Borderless law: separation comes from the
   plate, never from a hairline around it.

   THE GHOST IS NOT PAINTED, and the rule below says why. */
.lp-stepfacts { align-items: center; }
.lp-stepfact {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 11px;
  border-radius: var(--lp-r-pill);
  background-color: #ffffff0d;
  font-size: 13px;
  line-height: 1.25;
  color: var(--lp-ink-2);
}
.lp-stepfact-i {
  display: grid;
  place-items: center;
  inline-size: 16px;
  block-size: 16px;
  flex: none;
  color: var(--lp-accent-ink);
}
.lp-stepfact-i svg {
  inline-size: 16px;
  block-size: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.lp-stepfact-t { white-space: nowrap; }

.lp-stepcopy { position: relative; }
.lp-stepcopy-ghost {
  /* NOT PAINTED. Drawn as a watermark it read 1.06:1 against the ground and
     site/proof.mjs fails every painted text node under 4.5:1 -- and a numeral
     lifted to 4.5:1 is not a watermark any more, it is a second heading
     competing with the one beside it. The step number is not lost: the
     "Step 01" label directly under this sits in ink that passes, which is
     where a reader was going to read it anyway. */
  display: none;
}


/* ================================================= the guarantee strip, #guard

   THE WHOLE BAND ARRIVED UNSTYLED. `lp-vow3grid`, `lp-vow3`, `lp-vow3-top`,
   `lp-vow3-num`, `lp-vow3-tile`, `lp-vow3-head`, `lp-vow3-say` and `lp-rise`
   are eight more of the classes the design's markup names and no sheet in this
   repo declares, so the three guarantees rendered as a single column of plain
   text under icons at 300x150 -- the browser's default for an inline SVG with
   no size. It measured 3,911px at 1280 and the design gates scored it 1 out of
   1000 against this page's own median band, which is what a third of a page
   carrying nothing scores.

   THREE UP, BREAKING STRAIGHT TO ONE. The page's own comment above the markup
   asks for exactly that and says why: at minmax(200px) three columns never
   pass through a row of two over a widow.

   NO ICON TILE. A glyph in a rounded plate stacked over a heading is the
   generated-page tell the finish checklist names, and the borderless law wants
   the plate gone anyway. The mark is a bare glyph, nothing under it.

   CENTRED, NUMERALS OFF, GLYPH ON TOP AND LARGER, 2026-09-20, his call. The
   ordinals numbered a set that is not a sequence, so they read as steps the
   reader has to take in order; the three promises are simultaneous and always
   true. With the numeral gone the glyph has the line to itself, which is the
   only reason it can be set at 30px without crowding the head beside it, and
   each cell centres on its own column. Law 8 wants a heading block centred in
   its band and this is three of them.

   THE HUE IS THE ACCENT PAIR, reversing the success pair the band was rebuilt
   in on 2026-09-14. The ticks in the listing cards directly above this are
   already --lp-accent-ink, so the strip now answers in the colour the page
   owns rather than in a second one. */
.lp-vow3grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--lp-m5);
}
.lp-vow3 {
  display: grid;
  gap: 9px;
  align-content: start;
  justify-items: center;
  text-align: center;
}
.lp-vow3-top {
  display: flex;
  align-items: center;
  justify-content: center;
}
.lp-vow3-tile {
  display: grid;
  place-items: center;
  inline-size: 30px;
  block-size: 30px;
  flex: none;
  color: var(--lp-accent-ink);
}
.lp-vow3-tile svg {
  inline-size: 30px;
  block-size: 30px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.lp-vow3-head {
  font-size: var(--lp-mt-h3);
  font-weight: 600;
  line-height: 1.18;
  letter-spacing: -0.02em;
  text-wrap: balance;
  color: var(--lp-ink);
}
/* The second half of each promise is the half that names what is refused. */
.lp-vow3-head span { color: var(--lp-accent-ink); }
.lp-vow3-say {
  font-size: var(--lp-mt-small);
  line-height: 1.45;
  color: var(--lp-ink-2);
}


/* ============================================ the hero card title, descenders

   `.lp-card2-title` is a two-line `-webkit-line-clamp` over `overflow: hidden`,
   and the clip box is exactly two line boxes tall. That held while the titles
   were short ("2020 BMW X5 xDrive40i"). The design made them full listing
   lines -- "2020 BMW X5 xDrive40i | 69,117 km | Won't Last Long" -- which fill
   both lines, and a descender on the second one is then cut by the box.
   proof/typeset.mjs check 2 reads the ink, not the layout box, which is why a
   scrollWidth probe calls this clean: the glyph is clipped, not overflowing.

   The pair grows the CLIP box without moving anything under it. */
.lp-card2-title {
  padding-block-end: 0.16em;
  margin-block-end: -0.16em;
}

/* Two lines cannot hold a full listing title on a phone, and the clamp then
   cuts the last glyph rather than ending on one. A third line at the widths
   where the card is narrowest; the desktop card still clamps at two. */
@media (max-width: 480px) {
  .lp-card2-title { -webkit-line-clamp: 3; }
}
/* The lead card is the narrowest of the three on a phone and carries the
   longest title, so three lines still ended on a cut glyph at 360 and 390. */
@media (max-width: 400px) {
  .lp-card2-first .lp-card2-title { -webkit-line-clamp: 4; }
}
