/*!
 * ll-promo.css  [LEAD-CARDS 2026-09-12]
 *
 * Promotional lead cards mixed into dealer inventory and Vehicle Finder
 * results, plus the lightbox they open.
 *
 * WHY THE ART IS DRAWN RATHER THAN PHOTOGRAPHED
 * These cards sit in a grid of vehicle photographs. A stock photo of a car
 * next to real inventory reads as filler and the eye slides straight past it.
 * Drawn artwork is the thing that makes a shopper stop, it tints itself to
 * whichever dealership is hosting the page, it costs no image requests on a
 * page already carrying forty photos, and there is no licence attached to any
 * of it. Every motif is built from the store's own theme colour.
 *
 * THIRTEEN SKINS. The renderer never places two of the same skin next to each
 * other, which is what stops a long scroll feeling repetitive.
 *
 * Everything is scoped under .llp- so nothing here can touch the host page,
 * and the cards inherit the host page's font on purpose so they read as part
 * of the site rather than as an advert bolted on.
 */

.llp-card,
.llp-card * { box-sizing: border-box; }

/* ---------------------------------------------------------------- the card */

.llp-card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  width: 100%;
  min-height: 380px;
  /* A CEILING AS WELL AS A FLOOR.
     The grid stretches every card in a row to match the tallest one, and a row
     of vehicle cards with long spec lists can run past 650 pixels. A promo
     card carries a headline, a sentence and a button: past about five hundred
     it stops looking generous and starts looking empty. It takes the ceiling
     and sits at the top of its cell, which reads as deliberate. */
  max-height: 640px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 16px;
  text-align: left;
  font: inherit;
  color: #0f172a;
  background: #fff;
  cursor: pointer;
  isolation: isolate;
  -webkit-tap-highlight-color: transparent;
  box-shadow: 0 2px 14px -3px rgba(15, 23, 42, 0.16), 0 1.5px 4px rgba(15, 23, 42, 0.08);
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
/* The dealer grid rounds its own cards a touch more than the finder does, so
   the promo card follows whichever grid it landed in and never looks pasted in
   from somewhere else. */
#inventory-grid .llp-card { border-radius: 1.12em; }

.llp-card:focus-visible {
  outline: 3px solid var(--llp-primary, #005c90);
  outline-offset: 3px;
}
@media (hover: hover) and (pointer: fine) {
  .llp-card:hover { transform: translateY(-3px); box-shadow: 0 16px 34px -10px rgba(15, 23, 42, 0.3); }
  .llp-card:hover .llp-cta-arrow { transform: translateX(4px); }
}
.llp-card:active { transform: translateY(-1px); }

/* Everything below the collage: the skin's surface, its drawing and the words.
   Wrapping them means the artwork fills exactly the copy area rather than
   running on underneath the photographs.

   ON A CARD CARRYING A COLLAGE THIS TAKES EXACTLY ITS CONTENT HEIGHT and the
   collage absorbs whatever the grid row hands over. The other way round, with
   the words flexible, a tall headline over a long sentence gets squeezed and
   the button is clipped off the bottom of the card, silently, on exactly the
   cards whose copy is working hardest. */
.llp-face {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
.llp-has-shot .llp-face { flex: 0 0 auto; }
.llp-has-shot .llp-copy { flex: 0 0 auto; }

/* ------------------------------------------------------------- the collage
   A band of real vehicles across the head of the card, in as many colours and
   body styles as the lot allows. Tiles are separated by a hairline of the card
   behind them, which is what makes it read as a deliberate grid rather than as
   one wide photograph somebody chopped up. */

/* The band absorbs spare card height, so a tall row gets a bigger collage
   rather than a bigger gap. */
.llp-shot {
  position: relative;
  flex: 1 1 196px;
  min-height: 176px;
  max-height: 276px;
  display: grid;
  gap: 2px;
  overflow: hidden;
  background: #dfe5ec;
}
.llp-tile { position: relative; overflow: hidden; background: #eef2f6; }
.llp-tile img {
  width: 100%; height: 100%;
  object-fit: cover;
  /* A MUCH TIGHTER CROP THAN IT LOOKS LIKE IT NEEDS, AND IT DOES TWO JOBS.
     These are lot photographs. At a gentle crop you can read the selling
     store's name off the building behind the car and, on some of them, their
     phone number off the plate frame: Springfield Acura, Larson Ford, and so
     on, on a page belonging to somebody else entirely. Cropping in until the
     car body fills the tile puts all of that outside the frame.
     It also happens to be what makes the collage work. The point of these
     photographs is colour, and a tile filled with paint reads as colour from
     across a room while a tile containing a whole small car on a forecourt
     reads as grey. Biased below centre because forecourt signage sits high. */
  /* Manufacturer photography is framed by somebody who was paid to frame it,
     so it is barely cropped: just enough to fill the tile and to take a stray
     press watermark off a corner. */
  /* Barely cropped. Every photograph that reaches a card now comes from a
     manufacturer or press source, vetted by where the scraper got it rather
     than by looking at it, so there is no watermark to crop away and the whole
     car can be in frame the way it should be. */
  object-position: center 50%;
  transform: scale(1.06);
  filter: saturate(1.1) contrast(1.03);
  display: block;
}
/* A FORECOURT PHOTOGRAPH IS A DIFFERENT ANIMAL. The selling store's name is on
   the building behind the car, so this crops in until the car body fills the
   tile and the background is outside the frame, and it biases low because
   forecourt signage sits high. Used only when the manufacturer library covers
   nothing this store sells. */
.llp-tile-lot img {
  object-position: center 64%;
  transform: scale(1.95);
  filter: saturate(1.16) contrast(1.05);
}
/* The small tiles in a layout crop a little harder than the big one either
   way. They are too small for the extra zoom to cost any recognisable shape,
   and the big tile is where the car is meant to read. */
.llp-shot-hero .llp-tile:not(:first-child) img,
.llp-shot-mosaic .llp-tile:not(:first-child) img { transform: scale(1.16); }
.llp-shot-hero .llp-tile-lot:not(:first-child) img,
.llp-shot-mosaic .llp-tile-lot:not(:first-child) img { transform: scale(2.2); }
/* A tile whose photo never arrived collapses to the card's own colour rather
   than leaving a grey rectangle in the middle of the grid. */
.llp-tile-out { background: var(--llp-primary-wash, #eef5fa); }
.llp-tile-out img { display: none; }

.llp-shot-quad   { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
.llp-shot-strip  { grid-template-columns: repeat(3, 1fr); }
.llp-shot-wide   { grid-template-columns: 1.35fr 1fr; }
.llp-shot-six    { grid-template-columns: repeat(3, 1fr); grid-template-rows: 1fr 1fr; }
.llp-shot-hero   { grid-template-columns: 1.5fr 1fr; grid-template-rows: 1fr 1fr; }
.llp-shot-hero .llp-tile:first-child { grid-row: span 2; }
/* A hero tile down the left and three stacked beside it. THE CELL COUNT HAS TO
   MATCH THE TILE COUNT: this was three columns by two rows with the first tile
   spanning two by two, which leaves two free cells for three tiles. The fourth
   pushed itself onto an implicit third row, the fixed height squeezed all three
   rows, and the collage came out with a grey hole in it. */
.llp-shot-mosaic { grid-template-columns: 1.7fr 1fr; grid-template-rows: 1fr 1fr 1fr; }
.llp-shot-mosaic .llp-tile:first-child { grid-row: span 3; }

/* [SCENES 2026-09-13] One photograph instead of a grid of them, for the cards
   about one thing rather than about vehicles. No tiles, no hairlines, no line
   of copy across the foot: the picture is the whole band. Framed a little
   above centre because that is where the faces are. */
.llp-shot-one { display: block; background: #e3e8ee; }
.llp-shot-one img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 38%;
  transform: none;
  filter: saturate(1.04) contrast(1.02);
  display: block;
}

/* Our own line along the foot of the collage. It says what the pictures mean
   and it covers the strip where a lot photo's watermark sits. */
.llp-shot-tag {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  display: flex; align-items: center; gap: 0.34rem;
  padding: 1.5rem 0.8rem 0.5rem;
  font-size: 0.715rem; font-weight: 700; color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
  background: linear-gradient(to top, rgba(6, 10, 18, 0.8) 0%, rgba(6, 10, 18, 0.55) 40%, rgba(6, 10, 18, 0) 100%);
  pointer-events: none;
}
.llp-shot-tag svg { flex: none; }

/* A card carrying a collage has less room underneath it, so the copy tightens
   up rather than the card growing past its ceiling. */
.llp-has-shot .llp-inner { padding-top: 1rem; }
.llp-has-shot .llp-copy { padding: 0.3rem 0 0.95rem; }
.llp-has-shot .llp-title { font-size: 1.42rem; }

/* The drawn layer. Always behind the copy, never interactive. */
.llp-art {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
/* Each motif says where it lives rather than being stretched to the card. A
   promo card's height is set by the tallest vehicle in its grid row, so one
   scaled viewBox would crop the drawing somewhere different on every page. */
.llp-art svg { position: absolute; display: block; }
.llp-art svg.llp-a-full { inset: 0; width: 100%; height: 100%; }
.llp-art svg.llp-a-corner { top: -52px; right: -62px; width: 340px; height: 340px; }
.llp-art svg.llp-a-top { top: 0; left: 0; width: 100%; height: 200px; }
/* The bottom band stops at the foot of the card. It used to reach far enough
   up that a dashed route line ran straight through the supporting sentence,
   which is the one thing artwork may never do. */
.llp-art svg.llp-a-bottom { bottom: -2px; left: 0; width: 100%; height: 168px; }
.llp-art svg.llp-a-seal { top: -34px; left: 50%; margin-left: -104px; width: 208px; height: 208px; }
/* With a collage above it the face starts lower, so the seal comes back down
   into the card instead of half of it being cropped by the photographs. */
.llp-has-shot .llp-art svg.llp-a-seal { top: 2px; width: 168px; height: 168px; margin-left: -84px; }

/* [ART-FIT 2026-09-20] ARTWORK MAY NEVER RUN THROUGH THE WORDS.
   The art layer lives inside the face, under the copy. On a card with a
   photograph the face is nothing but copy (eyebrow, headline, sentence,
   button), so a corner piece, a seal or a band pinned to the face lands on
   the headline every time: the owner saw a clock through "Come in today" and
   a sunburst through "We turn down far more". Those motifs only exist for
   the open space a tall drawn card has between its eyebrow and its headline.
   A photo card keeps its wash (the full bleed pattern) and nothing else. A
   (Reversed the same day: the veil under the copy does this job now.) */
/* [QUIET-ART round 2, 2026-09-20] The motifs are back on every card. What
   keeps them off the words now is the blurred veil under the copy (see the
   QUIET-ART block at the end of this file), not switching them off: the
   owner wants the colour and texture there, softened, on every card. */

.llp-inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 0.55rem;
  padding: 1.2rem 1.25rem 1.1rem;
}
/* THREE ZONES, BECAUSE THE HEIGHT IS NOT OURS TO CHOOSE.
   A promo card is a grid child, so it stretches to the height of the tallest
   vehicle card in its row: anywhere from 330 to 850 pixels. Left to itself
   everything bunches at the top of a tall empty box. So the eyebrow holds the
   head of the card, the headline and its supporting line take the middle and
   center themselves in whatever space is left, and the button stays on the
   floor where a thumb expects to find it. The card reads as composed at every
   height instead of as one that happened to be stretched. */
.llp-copy {
  display: flex;
  flex-direction: column;
  /* The copy settles just above the button rather than floating in the middle.
     The space that opens up sits between the eyebrow and the headline, which
     is where the artwork lives, so a tall card fills with drawing instead of
     with nothing. A poster reads the same way: mark at the top, art, then the
     line you are meant to remember sitting right above the call to action. */
  justify-content: flex-end;
  flex: 1;
  min-height: 0;
  gap: 0.5rem;
  padding: 0.45rem 0 1.15rem;
}

.llp-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.42rem;
  align-self: flex-start;
  font-size: 0.73rem;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  line-height: 1;
  padding: 0.44rem 0.68rem 0.44rem 0.56rem;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.07);
  color: #334155;
}
.llp-eyebrow svg { width: 15px; height: 15px; flex: none; }

.llp-title {
  margin: 0.15rem 0 0;
  font-size: 1.5rem;
  line-height: 1.15;
  font-weight: 800;
  letter-spacing: -0.018em;
  color: inherit;
}
.llp-sub {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.45;
  font-weight: 500;
  color: #415167;
}

.llp-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.88rem 1rem;
  border-radius: 11px;
  font-size: 1.02rem;
  font-weight: 800;
  line-height: 1.2;
  color: #fff;
  background: var(--llp-primary, #005c90);
  box-shadow: 0 6px 16px -6px var(--llp-primary-glow, rgba(0, 92, 144, 0.7));
}
.llp-cta-arrow { display: block; flex: none; transition: transform 0.18s ease; }
.llp-cta-arrow svg { width: 17px; height: 17px; display: block; }

/* A quiet line under the button. It answers "what happens if I tap this"
   before a shopper has to wonder, which is most of why people do not tap. */
.llp-foot {
  margin: 0;
  font-size: 0.755rem;
  font-weight: 600;
  line-height: 1.38;
  text-align: center;
  /* Measured, not chosen. At #94a3b8 and again at #64748b this line came in
     under 4.5 to 1 once the artwork behind it was taken into account, which is
     the only measurement that counts. See gates/contrast.js. */
  color: #556477;
}

/* ------------------------------------------------------------------- skins */

/* 1. MIDNIGHT. The card that stops a scroll on a white page. */
.llp-skin-midnight { background: #0b1120; color: #f8fafc; }
.llp-skin-midnight .llp-eyebrow { background: rgba(255, 255, 255, 0.1); color: #cbd5e1; }
.llp-skin-midnight .llp-sub { color: #b6c2d4; }
.llp-skin-midnight .llp-foot { color: #8794a8; }
.llp-skin-midnight .llp-cta { background: var(--llp-accent, #38bdf8); color: var(--llp-accent-ink, #04121f); box-shadow: none; }

/* 2. AURORA. Soft light mesh, the friendliest of the set. */
.llp-skin-aurora { background: #fdfdff; }
.llp-skin-aurora .llp-eyebrow { background: var(--llp-primary-soft, rgba(0, 92, 144, 0.12)); color: var(--llp-primary-dark, #004466); }

/* 3. TICKET. A voucher. Perforated edge and a torn stub. */
.llp-skin-ticket {
  background: #fff;
  border: 2px dashed var(--llp-primary-line, rgba(0, 92, 144, 0.4));
}
/* Two punched holes and a tear line across the card. The holes are filled
   with whatever the page behind them is, which is what makes them read as
   holes rather than as circles drawn on a card. */
.llp-skin-ticket::before,
.llp-skin-ticket::after {
  content: '';
  position: absolute;
  bottom: 86px;
  left: -13px;
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--llp-page-bg, #f4f6f9);
  border: 2px dashed var(--llp-primary-line, rgba(0, 92, 144, 0.4));
  z-index: 3;
}
.llp-skin-ticket::after { left: auto; right: -13px; }
.llp-skin-ticket .llp-art::after {
  content: '';
  position: absolute;
  bottom: 97px;
  left: 13px; right: 13px;
  border-top: 2px dashed var(--llp-primary-line, rgba(0, 92, 144, 0.3));
}
/* The stub below the tear is the part somebody hands over, so the button sits
   in it with a little air rather than crowding the perforation. */
.llp-skin-ticket .llp-copy { padding-bottom: 1.8rem; }
.llp-skin-ticket .llp-cta { margin-top: 0; }
.llp-skin-ticket .llp-eyebrow {
  background: var(--llp-primary, #005c90); color: #fff;
}
.llp-skin-ticket .llp-inner { padding-top: 1.15rem; }

/* 4. STAT. One oversized mark behind the words. */
.llp-skin-stat { background: linear-gradient(168deg, var(--llp-primary-wash, #eef5fa) 0%, #ffffff 58%); }
.llp-skin-stat .llp-eyebrow { background: #fff; color: var(--llp-primary-dark, #004466); box-shadow: 0 1px 3px rgba(15, 23, 42, 0.1); }

/* 5. PAPER. Editorial. Cream, a heavy rule, quiet confidence. */
.llp-skin-paper { background: #fbfaf6; }
.llp-skin-paper .llp-inner { padding-top: 1.5rem; }
.llp-skin-paper .llp-eyebrow {
  background: none; padding-left: 0; border-radius: 0;
  color: var(--llp-primary-dark, #004466);
  border-bottom: 3px solid var(--llp-primary, #005c90);
  padding-bottom: 0.5rem;
}
.llp-skin-paper .llp-title { font-size: 1.34rem; letter-spacing: -0.02em; }
.llp-skin-paper .llp-cta { background: #111827; box-shadow: none; }

/* 6. SPOTLIGHT. Dark, with the light coming from above. */
.llp-skin-spotlight { background: radial-gradient(120% 90% at 50% -12%, #1c1c24 0%, #0a0a0d 62%); color: #f4f4f5; }
.llp-skin-spotlight .llp-eyebrow { background: rgba(255, 255, 255, 0.09); color: #d4d4d8; }
.llp-skin-spotlight .llp-sub { color: #b8b8c0; }
.llp-skin-spotlight .llp-foot { color: #8b8b96; }
.llp-skin-spotlight .llp-cta { background: #fff; color: #0d0d12; box-shadow: none; }

/* 7. GRID. Drafting paper. Reads as precise, which is the point. */
.llp-skin-grid { background: #ffffff; }
.llp-skin-grid .llp-eyebrow { background: #0f172a; color: #fff; }

/* 8. WAVE. Full colour. The loudest card in the deck. */
.llp-skin-wave {
  background: linear-gradient(150deg, var(--llp-primary, #005c90) 0%, var(--llp-primary-far, #004466) 100%);
  color: #fff;
}
.llp-skin-wave .llp-eyebrow { background: rgba(255, 255, 255, 0.2); color: #fff; }
.llp-skin-wave .llp-sub { color: #fff; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.32); }
.llp-skin-wave .llp-foot { color: #fff; text-shadow: 0 1px 4px rgba(0, 0, 0, 0.62); }
.llp-skin-wave .llp-cta { background: #fff; color: var(--llp-primary-dark, #004466); box-shadow: none; }

/* 9. EMBLEM. Centred, ceremonial, like a seal on a document. */
.llp-skin-emblem { background: #fcfbf8; }
.llp-skin-emblem .llp-inner { align-items: center; text-align: center; padding-top: 1.5rem; }
.llp-skin-emblem .llp-copy { align-items: center; width: 100%; }
.llp-skin-emblem .llp-eyebrow { align-self: center; background: none; color: #7d725e; letter-spacing: 0.18em; padding: 0; }
.llp-skin-emblem .llp-sub { text-align: center; }
.llp-skin-emblem .llp-cta { background: #1c1917; box-shadow: none; }

/* 10. PULSE. Something on this card is moving. Used for timing offers. */
.llp-skin-pulse { background: #0f172a; color: #f1f5f9; }
.llp-skin-pulse .llp-eyebrow { background: rgba(248, 113, 113, 0.18); color: #fca5a5; }
.llp-skin-pulse .llp-sub { color: #b9c4d4; }
.llp-skin-pulse .llp-foot { color: #8794a8; }
.llp-skin-pulse .llp-cta { background: #f8fafc; color: #0f172a; box-shadow: none; }

/* 11. STRIPE. Workwear. Belongs on trucks, credit and in house finance. */
.llp-skin-stripe { background: #fff; padding-top: 10px; }
.llp-skin-stripe .llp-foot { color: #52627a; }
.llp-skin-stripe .llp-eyebrow { background: #111827; color: #fde047; }

/* 12. GLASS. A frosted panel floating on colour. */
.llp-skin-glass {
  background: linear-gradient(155deg, var(--llp-primary-far, #004466) 0%, #0b1120 100%);
  color: #f8fafc;
}
.llp-skin-glass .llp-inner {
  margin: 0.65rem;
  padding: 1.05rem 1rem 1rem;
  border-radius: 13px;
  background: rgba(255, 255, 255, 0.13);
  border: 1px solid rgba(255, 255, 255, 0.28);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 10px 30px -14px rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
}
.llp-skin-glass .llp-eyebrow { background: rgba(255, 255, 255, 0.16); color: #e2e8f0; }
.llp-skin-glass .llp-sub { color: rgba(248, 250, 252, 0.85); }
.llp-skin-glass .llp-foot { color: rgba(248, 250, 252, 0.75); }
.llp-skin-glass .llp-cta { background: #fff; color: var(--llp-primary-dark, #004466); box-shadow: none; }

/* ------------------------------------------------- 13. the manufacturer offer

   This one is not written by us. It is a live factory program pulled from the
   store's own incentive feed, so it is laid out like a rate board rather than
   an advert: the money first, the vehicle under it, the deadline where a
   shopper expects a deadline to be. Nothing about it is invented.

   THE PHOTOGRAPH IS THE TOP OF THE CARD. It ran under a white header bar at
   first, which put a strip of nothing above the picture on the card whose
   whole job is to be the most eye catching thing in the grid. The badges float
   on the picture now, on a scrim dark enough to read them against anything. */

.llp-skin-offer { background: #fff; border: 1px solid #e6e9ee; }
.llp-skin-offer .llp-inner { padding: 0; gap: 0; }

.llp-off-top {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 2;
  display: flex; align-items: center; gap: 0.55rem;
  padding: 0.7rem 0.85rem 1.6rem;
  background: linear-gradient(to bottom, rgba(6, 10, 18, 0.72) 0%, rgba(6, 10, 18, 0.42) 46%, rgba(6, 10, 18, 0) 100%);
  pointer-events: none;
}
.llp-off-mark {
  width: 32px; height: 32px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 8px; background: #fff; overflow: hidden;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.3);
}
.llp-off-mark img { width: 100%; height: auto; display: block; }
.llp-off-mark span { font-size: 0.85rem; font-weight: 900; color: #475569; }
.llp-off-brand {
  font-size: 0.92rem; font-weight: 800; color: #fff; line-height: 1.15;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
}
.llp-off-live {
  display: inline-flex; align-items: center; gap: 0.34rem;
  margin-left: auto;
  font-size: 0.64rem; font-weight: 800;
  letter-spacing: 0.08em; text-transform: uppercase; color: #fff;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
}
/* THE LIVE DOT, ANIMATED ON THE COMPOSITOR.
   The obvious way to write this pulse is an expanding box-shadow, and that is
   how it started. box-shadow spread cannot be composited, so every frame
   repaints the element, and the Offers page can carry sixty offer cards at
   once: sixty elements repainting forever, on a phone, for decoration. A ring
   drawn once on a pseudo element and animated with transform and opacity costs
   the compositor alone and looks identical. */
.llp-off-live i {
  position: relative;
  width: 7px; height: 7px; border-radius: 50%; background: #4ade80;
}
.llp-off-live i::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: rgba(74, 222, 128, 0.55);
  animation: llp-live 2.4s ease-out infinite;
  will-change: transform, opacity;
}
@keyframes llp-live {
  0%   { transform: scale(1);   opacity: 0.65; }
  70%  { transform: scale(3.2); opacity: 0; }
  100% { transform: scale(3.2); opacity: 0; }
}

/* The picture fills the head of the card and grows into any height the grid
   hands over, so a taller card gets a bigger photograph rather than a gap. */
.llp-off-photo,
.llp-off-panel {
  position: relative;
  flex: 1 1 210px;
  min-height: 200px;
  max-height: 340px;
  overflow: hidden;
  background: #f1f5f9;
}
/* A LOT PHOTOGRAPH, cropped and biased low. This one comes out of the
   dealership's own new car feed, and the selling store's sign is on the
   building behind the car, high in the frame. Same reasoning as the collage
   tiles. Never an uneven scale: the car keeps its proportions. */
.llp-off-photo img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 60%;
  transform: scale(1.32);
  display: block;
}
/* A manufacturer shot carries no forecourt, so it is shown whole. */
.llp-off-photo.llp-off-clean img {
  transform: none;
  object-position: center center;
}
.llp-off-panel {
  background: linear-gradient(150deg, var(--llp-primary, #005c90) 0%, var(--llp-primary-far, #004466) 100%);
}
.llp-off-panel svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.llp-off-panel > span {
  position: absolute; left: 0.85rem; bottom: 0.6rem;
  font-size: 0.715rem; font-weight: 700; color: rgba(255, 255, 255, 0.94);
}
.llp-off-scrim {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  display: flex; align-items: flex-end; gap: 0.4rem;
  padding: 1.6rem 0.85rem 0.55rem;
  font-size: 0.715rem; font-weight: 700; color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  background: linear-gradient(to top, rgba(6, 10, 18, 0.82) 0%, rgba(6, 10, 18, 0.6) 42%, rgba(6, 10, 18, 0) 100%);
}

/* NOTHING IN AN OFFER CARD MAY SHRINK PAST ITS CONTENT. A flex child allowed
   to shrink below what it holds slides under the next one, which puts the
   footnote through the middle of the button. Only the photo gives. */
.llp-off-body {
  display: flex; flex-direction: column; flex: 0 0 auto;
  gap: 0.3rem; padding: 0.95rem 1rem 1rem;
}
.llp-off-kind {
  font-size: 0.68rem; font-weight: 800; letter-spacing: 0.1em;
  text-transform: uppercase; color: #5b6b80;
}
.llp-off-figure {
  display: flex; align-items: baseline; gap: 0.28rem;
  font-size: 2.3rem; font-weight: 900; line-height: 1; letter-spacing: -0.03em;
  color: var(--llp-primary-dark, #004466);
}
.llp-off-figure small { font-size: 0.98rem; font-weight: 800; letter-spacing: 0; color: #415167; }
.llp-off-model { font-size: 1.02rem; font-weight: 700; color: #0f172a; line-height: 1.3; }
.llp-off-meta { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.15rem; }
.llp-off-chip {
  font-size: 0.74rem; font-weight: 700; color: #415167;
  background: #f1f5f9; border-radius: 6px; padding: 0.24rem 0.5rem;
}
.llp-off-chip.llp-off-soon { background: #fef2f2; color: #b91c1c; }
.llp-skin-offer .llp-cta { margin-top: 0.7rem; }
.llp-skin-offer .llp-foot { flex: 0 0 auto; padding: 0.55rem 0 0; }

/* The empty state. One card under the store's own "nothing found" line, in a
   single column so it reads as an offer of help rather than as a result. */
#llp-empty {
  max-width: 380px;
  margin: 0.4rem auto 2.4rem;
  padding: 0 1rem;
}
#llp-empty .llp-card { min-height: 300px; max-height: none; }

/* ------------------------------------------------- the Offers menu item

   Adding a sixth link to the desktop bar pushed it past the viewport at
   exactly 768px, which is where the bar appears and the hamburger disappears,
   so there was nowhere else to reach it from. Rather than hide the new item at
   the one width that has no fallback, the bar tightens up through the narrow
   desktop range and goes back to the host's own spacing above it. Only the
   horizontal padding moves: the type, the colour and the hover all stay the
   page's own.                                                              */
/* ------------------------------------------------- the Offers menu item

   A sixth link in a bar built for five. Two things had to be dealt with.

   ONE, IT DID NOT FIT AT 768. That is exactly where the bar appears and the
   hamburger disappears, so there was nowhere else to reach it from. The bar
   tightens its horizontal padding and type through the whole narrow desktop
   range and goes back to the host's own spacing above 1340.

   TWO, THE LOGO WAS BEING SHRUNK TO NOTHING. It sits in a flex row with the
   nav, and with six links the browser took the space out of the picture rather
   than out of the words, so at several widths the header rendered with an
   empty space where the dealership's mark should be. It is held open here.
   Height is set and width is auto, so the mark is never distorted.

   Wrapping is deliberately NOT suppressed. Below about a thousand pixels the
   links do take two lines, which is what this bar has always done and what
   makes it fit at all; forcing them onto one line pushed the whole header off
   the side of the page.                                                     */
@media (min-width: 768px) and (max-width: 1339px) {
  nav .desktop-nav-btn-link { padding: 0 0.5rem !important; font-size: 0.9rem; }
  #navigation nav[aria-label="Main navigation"] { margin-left: 0.8rem !important; }
  /* The mark sits two levels down, inside a flex-1 min-w-0 wrapper. That pair
     of Tailwind classes is an explicit licence to collapse to nothing, and
     with six links in the bar the browser took it. Both levels are held open
     or neither is. */
  #navigation div:has(> .business-logo-section),
  #navigation .flex.flex-row.items-center.min-w-0.flex-1 {
    flex: 0 0 auto !important;
    min-width: auto !important;
  }
  #navigation .business-logo-section { flex: 0 0 auto !important; }
  /* WHICHEVER MARK IS SHOWING, not just the desktop one. At exactly 768 the
     page shows the desktop nav (Tailwind md is min-width 768) and the MOBILE
     logo (the host's rule is max-width 768), so the two overlap on that single
     pixel and the mark that was being squeezed there was the mobile one. */
  #navigation .business-logo { flex: none !important; }
  #navigation .business-logo.desktop-logo {
    height: 40px;
    width: auto;
    max-width: 132px;
  }
  /* Only ever visible at exactly 768, where the host's max-width:768 logo rule
     and Tailwind's min-width:768 nav rule both apply. The tall mobile mark is
     180px wide there, which is wider than the bar has left. */
  #navigation .business-logo.mobile-logo {
    height: 40px;
    width: auto;
    max-width: 118px;
  }
}

/* THE HEADER WAS BEING HIDDEN OUTRIGHT BETWEEN 1000 AND 1200 PIXELS.
   A rule already on every dealer page reads:

       @media (min-width:1000px) and (max-width:1200px) {
           header.sticky-bar { display: none; }
       }

   There is only one header on these pages, so in that band a shopper had no
   logo, no phone, no hamburger and no menu at all: no Schedule a Visit, no
   trade-in, no financing, no Vehicle Finder, no Contact Me. Two hundred pixels
   of extremely ordinary laptop and half-screen window widths with every route
   to a lead switched off, and it predates the promotional cards entirely. It
   was also the one band the new Offers item could not be reached from, which
   is how it came to light. The bar is given back. */
@media (min-width: 1000px) and (max-width: 1200px) {
  header#navigation.sticky-bar { display: block !important; }
}

/* ------------------------------------------------- CRM samples [2026-09-14]

   The lead form opened from a sample card inside the LeadLocate CRM. Every
   control is disabled by the script; this draws the whole ask greyed out so
   nobody mistakes it for a working form, with one note above it saying so. */

.llp-lb.llp-sample form {
  opacity: 0.5;
  pointer-events: none;
  filter: grayscale(1);
}
.llp-sample-note {
  margin: 0 0 0.95rem;
  padding: 0.7rem 0.85rem;
  border-radius: 10px;
  background: #fff7df;
  border: 1px solid #f0d98c;
  color: #6b4e00;
  font-size: 0.86rem;
  line-height: 1.45;
}
.llp-sample-note b { font-weight: 800; }

/* ----------------------------------------------------------- Offers page

   A full screen page reached from the main menu, carrying every manufacturer
   program this store can sell and every offer written for its kind of
   business. It takes the whole screen rather than floating in a dialog for the
   same reason the Vehicle Finder does: this is a destination, not an
   interruption, and a shopper who lands on it should be looking at nothing
   else.                                                                     */

.llo-overlay {
  position: fixed;
  inset: 0;
  z-index: 2147482000;
  display: flex;
  flex-direction: column;
  background: #f2f5f9;
  opacity: 0;
  transition: opacity 0.2s ease;
  font: inherit;
  color: #0f172a;
}
.llo-overlay.llp-on { opacity: 1; }

.llo-head {
  flex: none;
  color: #fff;
  background: linear-gradient(135deg, var(--llp-primary, #005c90) 0%, var(--llp-primary-far, #004466) 100%);
  box-shadow: 0 2px 18px rgba(8, 13, 24, 0.22);
}
.llo-head-inner {
  max-width: 1320px;
  margin: 0 auto;
  padding: 1rem 1.15rem 1.05rem;
  display: flex;
  align-items: center;
  gap: 1rem;
}
.llo-head h2 {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
}
.llo-head p {
  margin: 0.22rem 0 0;
  font-size: 0.88rem;
  line-height: 1.35;
  color: rgba(255, 255, 255, 0.88);
}
.llo-close {
  margin-left: auto;
  flex: none;
  width: 42px; height: 42px;
  display: flex; align-items: center; justify-content: center;
  padding: 0; cursor: pointer;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
}
.llo-close:hover { background: rgba(255, 255, 255, 0.26); }

.llo-scroll { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.llo-inner { max-width: 1320px; margin: 0 auto; padding: 1.4rem 1.15rem 3rem; }

.llo-lead { margin-bottom: 1.3rem; max-width: 760px; }
.llo-lead h3 {
  margin: 0 0 0.35rem;
  font-size: 1.22rem;
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: -0.014em;
  color: #0f172a;
}
.llo-lead p { margin: 0; font-size: 0.95rem; line-height: 1.5; color: #415167; }

.llo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(288px, 1fr));
  column-gap: 1.15rem;
  row-gap: 0;
  align-items: start;
}
.llo-grid > * { margin-bottom: 1.15rem; }
/* Nothing is stretching these to match a neighbour here, so they keep their
   own natural height and the ceiling never comes into it. */
.llo-grid .llp-card { max-height: none; }

.llo-skel {
  min-height: 380px;
  border-radius: 16px;
  background: linear-gradient(90deg, #e6ebf1 25%, #eef2f7 37%, #e6ebf1 63%);
  background-size: 400% 100%;
  animation: llo-shimmer 1.3s ease infinite;
}
@keyframes llo-shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }

.llo-empty {
  padding: 3rem 1rem;
  text-align: center;
  font-size: 1rem;
  color: #415167;
}

.llo-foot {
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid #dde3ea;
  text-align: center;
}
.llo-foot p { margin: 0 0 0.5rem; font-size: 0.95rem; color: #415167; }
.llo-call {
  display: inline-block;
  font-size: 1.15rem;
  font-weight: 800;
  color: var(--llp-primary, #005c90);
  text-decoration: none;
}

@media (max-width: 560px) {
  .llo-head-inner { padding: 0.85rem 1rem 0.9rem; }
  .llo-head h2 { font-size: 1.28rem; }
  .llo-head p { font-size: 0.82rem; }
  .llo-inner { padding: 1.1rem 0.9rem 2.4rem; }
  .llo-grid { grid-template-columns: 1fr; gap: 1rem; }
}

/* --------------------------------------------------------------- masonry

   Turns a grid's implicit rows into a four pixel ruler so a card can be given
   a row span matching its own height and stack straight up the column. The
   class is added by layoutMasonry() in ll-promo.js and by nothing else: if the
   script does not run, the host page's grid is untouched.

   align-items must be start, or an item stretches to its whole span and the
   next measurement reads the span back instead of the content.              */

.llp-masonry { grid-auto-rows: 4px !important; row-gap: 0 !important; align-items: start !important; }
#inventory-grid.llp-masonry > * { margin-bottom: 1.4rem; }
.llf-grid.llp-masonry > * { margin-bottom: 1rem; }
/* Nothing is stretching a card here, so it keeps its own natural height and
   the ceiling never comes into it. */
.llp-masonry .llp-card { max-height: none; }

/* --------------------------------------------------------------- lightbox */

.llp-lb {
  position: fixed; inset: 0; z-index: 2147483000;
  display: flex; align-items: flex-end; justify-content: center;
  opacity: 0; transition: opacity 0.19s ease;
  font: inherit;
}
.llp-lb.llp-on { opacity: 1; }
@media (min-width: 700px) { .llp-lb { align-items: center; } }

.llp-lb-back { position: absolute; inset: 0; background: rgba(8, 13, 24, 0.66); backdrop-filter: blur(2px); }

.llp-lb-panel {
  position: relative;
  width: 100%; max-width: 470px;
  max-height: 92vh; max-height: 92dvh;
  display: flex; flex-direction: column;
  background: #fff;
  border-radius: 20px 20px 0 0;
  box-shadow: 0 -8px 50px rgba(8, 13, 24, 0.4);
  transform: translateY(22px);
  transition: transform 0.22s cubic-bezier(0.22, 1, 0.36, 1);
  overflow: hidden;
}
.llp-lb.llp-on .llp-lb-panel { transform: translateY(0); }
@media (min-width: 700px) {
  .llp-lb-panel { border-radius: 18px; transform: translateY(10px) scale(0.985); }
  .llp-lb.llp-on .llp-lb-panel { transform: none; }
}

.llp-lb-close {
  position: absolute; top: 10px; right: 10px; z-index: 3;
  width: 34px; height: 34px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(255, 255, 255, 0.9); color: #0f172a;
  box-shadow: 0 1px 6px rgba(15, 23, 42, 0.2);
}
.llp-lb-close:hover { background: #fff; }

/* The offer restated at the top of the form. A shopper who taps a card and
   then sees a generic contact form assumes they tapped the wrong thing. */
.llp-lb-head {
  position: relative;
  padding: 1.25rem 3.2rem 1.15rem 1.25rem;
  color: #fff;
  background: linear-gradient(140deg, var(--llp-primary, #005c90) 0%, var(--llp-primary-far, #004466) 100%);
}
.llp-lb-head .llp-eyebrow { background: rgba(255, 255, 255, 0.2); color: #fff; margin-bottom: 0.5rem; }
/* [HOST-GLOBALS 2026-09-14] Explicit white. The LeadLocate CRM, which draws
   these same layers for its samples popup, carries a global h3 colour rule
   that beat the inherited white and left the offer title invisible on the
   dark head. Anything a host stylesheet could reach through an element
   selector is pinned here rather than inherited. */
.llp-lb-head h3 { margin: 0; font-size: 1.16rem; line-height: 1.25; font-weight: 800; letter-spacing: -0.012em; color: #fff; }
.llp-lb-head p { margin: 0.35rem 0 0; font-size: 0.82rem; line-height: 1.4; color: rgba(255, 255, 255, 0.85); padding: 0; }

.llp-lb-body { padding: 1.1rem 1.25rem 1.3rem; overflow-y: auto; -webkit-overflow-scrolling: touch; }

.llp-steps { display: flex; gap: 5px; margin-bottom: 1rem; }
.llp-step-pip { height: 4px; flex: 1; border-radius: 999px; background: #e2e8f0; transition: background 0.2s ease; }
.llp-step-pip.llp-pip-on { background: var(--llp-primary, #005c90); }

.llp-q { margin-bottom: 1.05rem; }
.llp-q-label { display: block; margin-bottom: 0.5rem; font-size: 0.9rem; font-weight: 700; color: #0f172a; line-height: 1.3; }

.llp-chips { display: flex; flex-wrap: wrap; gap: 0.45rem; }
.llp-chip {
  font: inherit; font-size: 0.85rem; font-weight: 650; margin: 0;
  padding: 0.58rem 0.85rem; border-radius: 10px; cursor: pointer;
  border: 1.5px solid #dfe5ec; background: #fff; color: #334155;
  transition: border-color 0.14s ease, background 0.14s ease, color 0.14s ease;
}
.llp-chip:hover { border-color: var(--llp-primary, #005c90); }
.llp-chip.llp-picked {
  border-color: var(--llp-primary, #005c90);
  background: var(--llp-primary, #005c90);
  color: #fff;
}

.llp-field { margin-bottom: 0.85rem; }
.llp-field label { display: block; margin-bottom: 0.32rem; font-size: 0.78rem; font-weight: 700; color: #475569; }
.llp-field input {
  font: inherit; font-size: 1rem; width: 100%; margin: 0; box-sizing: border-box;
  padding: 0.72rem 0.85rem; border-radius: 10px;
  border: 1.5px solid #dfe5ec; background: #fff; color: #0f172a;
  -webkit-appearance: none; appearance: none;
}
.llp-field input:focus { outline: none; border-color: var(--llp-primary, #005c90); box-shadow: 0 0 0 3px var(--llp-primary-soft, rgba(0, 92, 144, 0.16)); }
.llp-field.llp-bad input { border-color: #dc2626; background: #fff5f5; }
.llp-field .llp-err { display: none; margin-top: 0.3rem; font-size: 0.74rem; font-weight: 650; color: #dc2626; }
.llp-field.llp-bad .llp-err { display: block; }
.llp-money { position: relative; }
.llp-money input { padding-left: 1.85rem; }
.llp-money::before {
  content: '$'; position: absolute; left: 0.85rem; top: 50%;
  transform: translateY(-50%); font-size: 1rem; font-weight: 700; color: #94a3b8;
  pointer-events: none; z-index: 1;
}
.llp-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.6rem; }

.llp-hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

.llp-go {
  font: inherit; font-size: 0.98rem; font-weight: 800;
  width: 100%; padding: 0.9rem 1rem; margin: 0.35rem 0 0; box-sizing: border-box;
  border: 0; border-radius: 11px; cursor: pointer; color: #fff;
  background: var(--llp-primary, #005c90);
  box-shadow: 0 8px 20px -8px var(--llp-primary-glow, rgba(0, 92, 144, 0.8));
}
.llp-go:hover { filter: brightness(1.07); }
.llp-go:disabled { opacity: 0.6; cursor: default; filter: none; }
.llp-back {
  font: inherit; font-size: 0.84rem; font-weight: 700;
  display: block; margin: 0.7rem auto 0; padding: 0.35rem 0.6rem;
  border: 0; background: none; color: #64748b; cursor: pointer;
}
.llp-back:hover { color: #0f172a; }

.llp-alert {
  display: none; margin-bottom: 0.8rem; padding: 0.7rem 0.85rem;
  border-radius: 10px; font-size: 0.85rem; font-weight: 650;
  background: #fef2f2; color: #b91c1c; border: 1px solid #fecaca;
}
.llp-alert.llp-on { display: block; }

.llp-fine {
  margin: 0.85rem 0 0; font-size: 0.68rem; line-height: 1.45;
  color: #94a3b8; text-align: center;
}

/* The thank you. Short, warm, and it says what happens next, which is the
   only thing anybody wants to know at this point. */
.llp-done { padding: 2rem 1.5rem 2.2rem; text-align: center; }
.llp-done-mark {
  width: 58px; height: 58px; margin: 0 auto 1rem;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; background: #ecfdf5; color: #059669;
}
.llp-done-mark svg { width: 28px; height: 28px; }
.llp-done h4 { margin: 0 0 0.5rem; font-size: 1.2rem; font-weight: 800; color: #0f172a; }
.llp-done p { margin: 0 0 0.4rem; font-size: 0.9rem; line-height: 1.5; color: #475569; }
.llp-done a { color: var(--llp-primary, #005c90); font-weight: 800; text-decoration: none; }

/* ------------------------------------- the host page's financing bubble

   NOT OUR COMPONENT, AND FIXED HERE ANYWAY, because it is measurably the most
   expensive thing on a dealer page and this stylesheet is already on all of
   them.

   Every vehicle card carries an "as low as $269/m" bubble, and the page
   animates it with `financing-pulse`, an infinite keyframe on box-shadow. A
   box-shadow cannot be handed to the compositor, so each step repaints the
   element. Measured on a live page: 250 of them running at once, forever, on
   every dealer page, on every phone, for decoration nobody asked for.

   The look is kept exactly. The static shadow stays on the bubble, and a
   pseudo element carrying the larger shadow fades in and out over it. Opacity
   is composited, so the whole thing costs the main thread nothing.

   If the bubble's own styling is ever reworked in index.php, delete this
   block rather than fighting it.                                           */
.financing-bubble { animation: none !important; }
.financing-bubble::after {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  pointer-events: none;
  box-shadow: 0 6px 28px var(--llp-primary-glow, rgba(0, 92, 144, 0.7)), 0 3px 12px rgba(0, 0, 0, 0.2);
  opacity: 0;
  animation: llp-bubble-pulse 2s ease-in-out infinite;
  will-change: opacity;
}
@keyframes llp-bubble-pulse {
  0%, 100% { opacity: 0; }
  50% { opacity: 1; }
}
.financing-bubble:hover::after { animation: none; opacity: 1; }

/* SOMEBODY WHO ASKED FOR LESS MOTION GETS LESS MOTION, all of it, not the
   pieces that happened to be remembered. Vestibular disorders are common
   enough that a page full of pulsing badges and sliding panels is genuinely
   unusable for a real share of shoppers. */
@media (prefers-reduced-motion: reduce) {
  .llp-card,
  .llp-cta-arrow,
  .llp-lb,
  .llp-lb-panel,
  .llo-overlay,
  .llp-chip,
  .llp-field input,
  .llp-step-pip {
    transition: none !important;
  }
  .llp-off-live i::after,
  .llp-pulse-ring,
  .llo-skel,
  .llp-art svg * {
    animation: none !important;
  }
  .llp-card:hover { transform: none; }
  .llo-skel { background: #e6ebf1; }
  /* The host page declares no reduced motion support of its own anywhere, so
     its two decorative loops are covered from here as well. */
  .financing-bubble::after,
  .shop-by-payment-btn { animation: none !important; }
  .financing-bubble::after { opacity: 0; }
}

/* Narrow phones. The cards keep their shape, the type steps down a little so
   a five word headline never takes four lines. */
@media (max-width: 400px) {
  .llp-card { min-height: 356px; }
  .llp-title { font-size: 1.35rem; }
  .llp-has-shot .llp-title { font-size: 1.3rem; }
  .llp-shot { height: 164px; }
  .llp-inner { padding: 1.05rem 1.05rem 1rem; }
  .llp-row { grid-template-columns: 1fr; }
}

/* ==========================================================================
   [OFFER-FORMATS 2026-09-17, owner] EDITORIAL FOOTPRINTS ON THE OFFERS PAGE

   Every card on this page used to be the same rectangle, so the page read as
   one advert printed forty times and a shopper stopped looking after the
   third. The deck is now dealt into six footprints and the masonry packs them,
   which costs no vertical space and gives the eye a reason to keep going.

     tile       the original, one column. Still most of the page on purpose.
     feature    two columns, the photography down the left, the copy beside it.
     poster     one column, a deeper picture and a bigger headline.
     quote      one column, no picture at all, short. The change of rhythm.
     strip      two columns, a banner, the button beside the words.
     spotlight  two columns, a live manufacturer program with the money set
                at display size.

   The class is put on by ll-promo.js AFTER the grid is in the document, from
   the live column count, and it is taken straight back off under three
   columns. So everything in here is desktop only by construction, and the
   media query below is the belt to that pair of braces.

   WHY dense. A two column card that does not fit where it lands leaves a hole
   behind it. Dense backfills that hole with the next card that does fit, which
   is the whole reason mixed footprints can sit in a plain CSS grid at all.
   ========================================================================== */

.llo-grid { grid-auto-flow: row dense; }

@media (min-width: 901px) {

  .llo-grid .llp-fmt-feature,
  .llo-grid .llp-fmt-strip,
  .llo-grid .llp-fmt-spotlight { grid-column: span 2; }

  /* Two skins hold a rule across the top of the card with their own padding.
     A rule is a header on a tile and a white sliver above the photograph on a
     card whose picture runs down the side, so it comes off on those. */
  .llo-grid .llp-fmt-feature,
  .llo-grid .llp-fmt-spotlight { padding-top: 0; }

  /* ---------------------------------------------------------- feature ---- */

  .llo-grid .llp-fmt-feature {
    flex-direction: row;
    align-items: stretch;
    min-height: 322px;
  }
  /* The picture takes a fixed share of the width and whatever height the copy
     beside it ends up needing. The ceiling the tile layout puts on the collage
     would leave a band of card colour under it here. */
  .llo-grid .llp-fmt-feature > .llp-shot {
    flex: 0 0 44%;
    min-height: 0;
    max-height: none;
    align-self: stretch;
  }
  .llo-grid .llp-fmt-feature > .llp-face { flex: 1 1 auto; min-width: 0; }
  .llo-grid .llp-fmt-feature .llp-inner { padding: 1.55rem 1.7rem 1.4rem; justify-content: center; }
  /* [OFFERS-POLISH 2026-09-20] The copy is a block beside the picture, centred
     on it as a group, instead of a headline at the top and a void under the
     button on a tall row. */
  .llo-grid .llp-fmt-feature .llp-copy { padding: 0.55rem 0 1.2rem; flex: 0 0 auto; }
  .llo-grid .llp-fmt-feature .llp-title { font-size: 1.78rem; line-height: 1.12; }
  .llo-grid .llp-fmt-feature .llp-sub { font-size: 1.02rem; max-width: 44ch; }
  /* A button the width of half a page is not a button, it is a bar. */
  .llo-grid .llp-fmt-feature .llp-cta {
    width: auto;
    align-self: flex-start;
    padding: 0.9rem 1.5rem;
  }
  .llo-grid .llp-fmt-feature .llp-foot { text-align: left; }

  /* ----------------------------------------------------------- poster ---- */

  .llo-grid .llp-fmt-poster { min-height: 520px; }
  .llo-grid .llp-fmt-poster > .llp-shot {
    flex: 1 1 318px;
    min-height: 300px;
    max-height: 382px;
  }
  .llo-grid .llp-fmt-poster .llp-title { font-size: 1.56rem; }

  /* ------------------------------------------------------------ quote ---- */

  .llo-grid .llp-fmt-quote { min-height: 262px; }
  .llo-grid .llp-fmt-quote > .llp-shot { display: none; }
  .llo-grid .llp-fmt-quote .llp-inner { padding: 1.5rem 1.4rem 1.3rem; }
  .llo-grid .llp-fmt-quote .llp-copy { padding: 0.6rem 0 1.05rem; }
  .llo-grid .llp-fmt-quote .llp-title { font-size: 1.62rem; }
  /* The reassurance line under the button is what makes a tall card feel
     finished. On a card this short it is the thing making it taller. */
  .llo-grid .llp-fmt-quote .llp-foot { display: none; }

  /* ------------------------------------------------------------ strip ---- */

  .llo-grid .llp-fmt-strip { min-height: 0; }
  .llo-grid .llp-fmt-strip > .llp-shot { display: none; }
  /* Grid rather than flex, so the words can stack on the left while the button
     sits centred against both of them on the right, without wrapping either of
     them in a box the rest of the card does not have. */
  .llo-grid .llp-fmt-strip .llp-inner {
    display: grid;
    /* The words get the room. The button column is sized to the longest label
       these cards actually carry, not to a share of the card, because a wide
       button column on a banner leaves the headline wrapping to three lines
       and the banner stops being one. */
    grid-template-columns: minmax(0, 1fr) minmax(156px, 214px);
    /* [OFFERS-POLISH 2026-09-20] Two content rows packed in the middle. The
       Offers grid stretches a banner to the height of its row, and with the
       rows left to stretch as well the eyebrow sat at the top, the headline at
       the bottom and the button floated between them. */
    grid-template-rows: auto auto;
    align-content: center;
    column-gap: 1.5rem;
    row-gap: 0.3rem;
    align-items: center;
    padding: 1.4rem 1.6rem;
  }
  .llo-grid .llp-fmt-strip .llp-eyebrow { grid-column: 1; grid-row: 1; }
  .llo-grid .llp-fmt-strip .llp-copy {
    grid-column: 1;
    grid-row: 2;
    flex: 0 0 auto;
    justify-content: flex-start;
    padding: 0.15rem 0 0;
  }
  .llo-grid .llp-fmt-strip .llp-title { font-size: 1.34rem; }
  .llo-grid .llp-fmt-strip .llp-sub { font-size: 0.93rem; max-width: 64ch; }
  .llo-grid .llp-fmt-strip .llp-cta { padding-left: 0.9rem; padding-right: 0.9rem; font-size: 0.97rem; }
  .llo-grid .llp-fmt-strip .llp-cta {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: center;
  }
  .llo-grid .llp-fmt-strip .llp-foot { display: none; }
  /* THE DRAWN MOTIFS ARE PLACED FOR A CARD THAT IS TALLER THAN IT IS WIDE.
     The bottom band is 168 pixels of route lines and waves measured against a
     column of copy about 300 pixels tall. Beside a photograph the copy is half
     that, so the band runs straight through the sentence and the line under
     the button, which is the one thing artwork may never do. The seal is
     centred on the whole card, which on these is the middle of the
     photograph. The corner piece still reads on both, and it stays. */
  .llo-grid .llp-fmt-strip .llp-art svg.llp-a-bottom,
  .llo-grid .llp-fmt-strip .llp-art svg.llp-a-seal,
  .llo-grid .llp-fmt-strip .llp-art svg.llp-a-corner,
  .llo-grid .llp-fmt-feature .llp-art svg.llp-a-bottom,
  .llo-grid .llp-fmt-feature .llp-art svg.llp-a-seal { display: none; }

  /* -------------------------------------------------------- spotlight ---- */

  .llo-grid .llp-fmt-spotlight { min-height: 336px; }
  .llo-grid .llp-fmt-spotlight .llp-inner { flex-direction: row; align-items: stretch; }
  .llo-grid .llp-fmt-spotlight .llp-off-photo,
  .llo-grid .llp-fmt-spotlight .llp-off-panel {
    flex: 0 0 50%;
    min-height: 0;
    max-height: none;
  }
  .llo-grid .llp-fmt-spotlight .llp-off-body {
    flex: 1 1 auto;
    min-width: 0;
    justify-content: center;
    gap: 0.4rem;
    padding: 1.5rem 1.7rem;
  }
  .llo-grid .llp-fmt-spotlight .llp-off-figure { font-size: 3.05rem; flex-wrap: wrap; }
  /* The qualifier takes a line of its own rather than wrapping mid phrase. At
     tile size it sits beside the figure and fits; beside a photograph the
     figure is half again as big and a month for 36 months broke after the
     36, which reads as a typesetting accident. */
  .llo-grid .llp-fmt-spotlight .llp-off-figure small { font-size: 1.06rem; flex: 1 1 100%; margin-top: 0.12rem; }
  .llo-grid .llp-fmt-spotlight .llp-off-model { font-size: 1.14rem; }
  .llo-grid .llp-fmt-spotlight .llp-off-meta { margin-top: 0.15rem; }
  .llo-grid .llp-fmt-spotlight .llp-cta {
    width: auto;
    align-self: flex-start;
    padding: 0.9rem 1.5rem;
    margin-top: 0.55rem;
  }
  .llo-grid .llp-fmt-spotlight .llp-foot { text-align: left; }
}

/* A narrow desktop window carries three columns at most, so a two column card
   is two thirds of the page and the feature photograph gets cramped. It keeps
   a little more of the width. */
@media (min-width: 901px) and (max-width: 1180px) {
  .llo-grid .llp-fmt-feature > .llp-shot { flex: 0 0 40%; }
  .llo-grid .llp-fmt-feature .llp-title { font-size: 1.6rem; }
  .llo-grid .llp-fmt-spotlight .llp-off-figure { font-size: 2.7rem; }
}

/* ==========================================================================
   [CONFIRM 2026-09-17, owner] THE CONFIRMATION SCREEN

   What a shopper sees the moment a form goes out. It names the salesperson who
   is about to ring them, it names the store, and it puts the next step in
   front of them while they are still holding the phone.

   IT IS NOT A TOAST AND IT DOES NOT TIME OUT. The screen it replaced faded
   after seven seconds, which meant the most valuable ten seconds on the page
   were spent watching a bubble disappear.

   THE HOST PAGE SWITCHES ITS OWN CHROME OFF WITH body.modal-open, and that
   rule sets pointer-events: none on every button and link on the page. Our
   layer is never part of that bookkeeping, so it says so explicitly rather
   than relying on the page having tidied up first.
   ========================================================================== */

.llc-overlay {
  position: fixed;
  inset: 0;
  z-index: 2147483000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.1rem;
  background: rgba(8, 14, 24, 0.66);
  -webkit-backdrop-filter: saturate(140%) blur(5px);
  backdrop-filter: saturate(140%) blur(5px);
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 0;
  transition: opacity 0.22s ease;
}
.llc-overlay.llp-on { opacity: 1; }

body.modal-open .llc-overlay,
body.modal-open .llc-overlay * { pointer-events: auto; }

.llc-overlay,
.llc-overlay * { box-sizing: border-box; }

.llc-panel {
  position: relative;
  width: 100%;
  max-width: 520px;
  margin: auto;
  padding: 2.3rem 2rem 1.7rem;
  border-radius: 20px;
  background: #fff;
  color: #0f172a;
  font: inherit;
  text-align: center;
  box-shadow: 0 30px 80px -24px rgba(8, 14, 24, 0.6), 0 2px 10px rgba(8, 14, 24, 0.18);
  transform: translateY(14px) scale(0.985);
  transition: transform 0.26s cubic-bezier(0.2, 0.9, 0.3, 1);
}
.llc-overlay.llp-on .llc-panel { transform: none; }

.llc-close {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(15, 23, 42, 0.06);
  color: #475569;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.llc-close:hover { background: rgba(15, 23, 42, 0.12); }

/* ---- the tick -----------------------------------------------------------
   Drawn rather than animated with a GIF, and drawn in one green whatever the
   brand colour is. A tick in the dealership's own blue reads as part of the
   furniture. A tick in green reads as done. */

.llc-mark { width: 74px; height: 74px; margin: 0 auto 1.15rem; }
.llc-mark svg { width: 100%; height: 100%; display: block; }
.llc-mark-ring {
  stroke: #16a34a;
  stroke-dasharray: 145;
  stroke-dashoffset: 145;
  animation: llc-ring 0.62s cubic-bezier(0.65, 0, 0.45, 1) 0.06s forwards;
}
.llc-mark-tick {
  stroke: #16a34a;
  stroke-dasharray: 36;
  stroke-dashoffset: 36;
  animation: llc-tick 0.32s cubic-bezier(0.65, 0, 0.45, 1) 0.52s forwards;
}
@keyframes llc-ring { to { stroke-dashoffset: 0; } }
@keyframes llc-tick { to { stroke-dashoffset: 0; } }

.llc-head {
  margin: 0 0 0.7rem;
  font-size: 1.42rem;
  line-height: 1.24;
  font-weight: 800;
  letter-spacing: -0.016em;
  color: #0f172a;
}
.llc-sub {
  margin: 0 auto;
  max-width: 40ch;
  font-size: 0.96rem;
  line-height: 1.5;
  font-weight: 500;
  color: #475569;
}

/* ---- the next step ------------------------------------------------------ */

.llc-acts { margin-top: 1.5rem; text-align: left; }
.llc-acts-label {
  display: block;
  margin-bottom: 0.55rem;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  text-align: center;
  color: #7c8798;
}

.llc-act {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  margin: 0;
  padding: 0.92rem 1.05rem;
  border: 0;
  border-radius: 12px;
  font: inherit;
  font-size: 1rem;
  font-weight: 800;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.16s ease, box-shadow 0.16s ease, background 0.16s ease;
}
.llc-act-go {
  color: #fff;
  background: var(--llp-primary, #005c90);
  box-shadow: 0 10px 22px -10px var(--llp-primary-glow, rgba(0, 92, 144, 0.75));
}
.llc-act-alt {
  font-size: 0.93rem;
  padding: 0.8rem 0.9rem;
  color: var(--llp-primary-dark, #004466);
  background: #fff;
  border: 1.5px solid rgba(15, 23, 42, 0.14);
}
@media (hover: hover) and (pointer: fine) {
  .llc-act-go:hover { transform: translateY(-1px); box-shadow: 0 14px 26px -10px var(--llp-primary-glow, rgba(0, 92, 144, 0.8)); }
  .llc-act-alt:hover { background: var(--llp-primary-wash, #eef5fa); border-color: var(--llp-primary-line, rgba(0, 92, 144, 0.42)); }
}
.llc-act:focus-visible { outline: 3px solid var(--llp-primary, #005c90); outline-offset: 2px; }
.llc-act-text { display: block; }
.llc-act-arrow { display: block; flex: none; }
.llc-act-arrow svg { width: 16px; height: 16px; display: block; }
.llc-act-alt .llc-act-arrow { display: none; }

.llc-note {
  margin: 0.55rem 0 0;
  font-size: 0.79rem;
  line-height: 1.4;
  font-weight: 600;
  text-align: center;
  color: #64748b;
}

.llc-row { display: flex; gap: 0.6rem; margin-top: 0.85rem; }
.llc-row .llc-act { flex: 1 1 0; min-width: 0; }

.llc-phone {
  margin: 1.15rem 0 0;
  font-size: 0.86rem;
  font-weight: 600;
  color: #64748b;
}
.llc-phone strong { color: #0f172a; font-weight: 800; letter-spacing: 0.01em; }

.llc-skip {
  display: block;
  margin: 1.1rem auto 0;
  padding: 0.4rem 0.6rem;
  border: 0;
  background: none;
  font: inherit;
  font-size: 0.84rem;
  font-weight: 700;
  color: #7c8798;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.llc-skip:hover { color: #0f172a; }

/* ---- inside a panel that already has its own chrome ---------------------
   The promo card lightbox and the Vehicle Finder both call for the same body
   and both already carry the padding, the close button and a heading. */

.llc-tight { text-align: center; max-width: 560px; margin: 0 auto; padding-top: 0.35rem; }
.llc-tight .llc-mark { width: 62px; height: 62px; margin-bottom: 0.9rem; }
.llc-tight .llc-head { font-size: 1.26rem; }

/* ---- phone --------------------------------------------------------------
   The panel takes the screen. A card floating in the middle of a phone with a
   band of dimmed website above and below it reads as an advert, and this is
   the one screen that has to read as the website talking. */

/* The phone treatment for this panel now lives with every other pop up on the
   page, in the [SHEET 2026-09-18] block at the foot of this file. */

@media (prefers-reduced-motion: reduce) {
  .llc-overlay,
  .llc-panel,
  .llc-act { transition: none; }
  .llc-mark-ring,
  .llc-mark-tick { animation: none; stroke-dashoffset: 0; }
}

/* [OFFER-FORMATS 2026-09-17] A PHOTOGRAPH THAT HAS NOT ARRIVED YET IS STILL
   PART OF THE DESIGN.

   These bands were flat grey. On a page carrying ninety lazily loaded pictures
   that reads, for the second before each one paints, as a hole in the layout
   rather than as a picture on its way, and the bigger poster and feature
   footprints made the hole bigger. A soft wash in the dealership's own colour
   reads as a panel instead, and the photograph covers it completely the moment
   it lands. Deliberately not animated: sixty shimmering tiles is a compositor
   bill paid for half a second of loading, and this page can carry sixty. */
.llp-tile,
.llp-shot-one { background: linear-gradient(150deg, var(--llp-primary-wash, #eef5fa) 0%, #e4eaf1 100%); }
.llp-off-photo { background: linear-gradient(150deg, var(--llp-primary-wash, #eef5fa) 0%, #e8edf3 100%); }

/* ==========================================================================
   [SHEET 2026-09-18, owner] EVERY POP UP ON A DEALER PAGE RISES FROM THE
   BOTTOM

   The dealer pages carried two different ideas of what a pop up is. The promo
   card ask and the Vehicle Finder ask were already bottom sheets on a phone.
   The page's own eight modals (Ask a Question, Check Availability, Schedule a
   Visit, Trade In, Contact, Shop by Payment, Text Chat, Financing) were boxes
   pinned to the middle of the screen with a hard cut, no motion at all. So
   which button a shopper pressed decided what kind of software they were
   using.

   One pattern now, and it is the one the phone already taught them:

     under 700px   docked to the bottom edge, full width, rounded at the top,
                   a grab handle, and it slides up. 92dvh ceiling with its own
                   scroll, so a long form never pushes its button off screen
                   and the page behind never scrolls with it.
     700px and up  still centred, because a full width strip along the bottom
                   of a wide monitor is not a dialog, it is a cookie banner.
                   It rises into place from below, so the motion is the same
                   everywhere even though the resting place is not.

   EVERYTHING HERE IS SCOPED UNDER body.llp-sheeted, A CLASS ADDED BY THE SAME
   JAVASCRIPT THAT DRIVES THE MOTION. A browser that never ran ll-promo.js gets
   the page exactly as it was rather than eight modals parked off the bottom of
   the screen waiting for a class that is never coming.

   THE HOST PAGE PINS #financing-modal BY ID, so the overrides for it are
   written by id as well. An id beats any number of classes and a sheet rule
   that loses to `#financing-modal { top: 50% !important }` is a sheet nobody
   can read.
   ========================================================================== */

body.llp-sheeted .modal-center {
  will-change: transform;
}

body.llp-sheeted #modal-backdrop {
  background: rgba(8, 13, 24, 0.62) !important;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  opacity: 0;
  transition: opacity 0.24s ease;
}
body.llp-sheet-open #modal-backdrop { opacity: 1; }

/* ---------------------------------------------------------------- phone --- */

@media (max-width: 699px) {
  body.llp-sheeted .modal-center,
  body.llp-sheeted #financing-modal {
    top: auto !important;
    bottom: 0 !important;
    left: 0 !important;
    right: 0 !important;
    width: 100% !important;
    max-width: 100% !important;
    margin: 0 !important;
    transform: translateY(100%) !important;
    transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
    border-radius: 20px 20px 0 0 !important;
    /* The brand border stays on the three edges you can see. Carried along the
       bottom as well it draws a line under a panel that has no bottom. */
    border-bottom-width: 0 !important;
    max-height: 92vh;
    max-height: 92dvh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding-top: 1.1rem !important;
    /* The home indicator on a modern phone sits over the last 34 pixels. */
    padding-bottom: calc(0.85rem + env(safe-area-inset-bottom, 0px)) !important;
    box-shadow: 0 -10px 46px rgba(8, 13, 24, 0.42) !important;
  }
  /* THE ID HAS TO BE NAMED ON BOTH SIDES. Every selector in a list carries its
     own weight, so  parks that one panel
     with an id's worth of specificity and a class only rule can never bring it
     back. The financing sheet sat entirely below the fold until this line
     existed, and it is the one panel whose gate had not been written yet. */
  body.llp-sheeted .modal-center.llp-sheet-in,
  body.llp-sheeted #financing-modal.llp-sheet-in { transform: translateY(0) !important; }

  /* The grab handle. It is the one piece of furniture that tells somebody this
     panel belongs to the bottom of the screen and can be dismissed. */
  body.llp-sheeted .modal-center::before {
    content: '';
    position: absolute;
    top: 7px;
    left: 50%;
    width: 42px;
    height: 4px;
    margin-left: -21px;
    border-radius: 99px;
    background: rgba(15, 23, 42, 0.16);
    z-index: 12;
    pointer-events: none;
  }

  /* The financing application is an iframe that wants the whole screen. */
  body.llp-sheeted #financing-modal {
    height: 94dvh;
    max-height: 94dvh;
  }
  body.llp-sheeted #financing-modal #apply-for-financing-iframe,
  body.llp-sheeted #financing-modal #financing-loading-spinner {
    height: calc(94dvh - 96px) !important;
  }

  /* The close button moves down out of the handle's line. */
  body.llp-sheeted .modal-center .close-modal-btn { top: 14px !important; }

  /* THE BUTTON STAYS ON THE SCREEN WHILE THE TIMES SCROLL PAST IT. A store
     open twelve hours has twenty five slots, so on a phone the thing that
     tells a shopper what they have chosen and what happens next was always
     somewhere below the fold. It carries the appointment in its own label, so
     keeping it in view is the whole confirmation. */
  body.llp-sheeted #calendar-modal .schedule-visit-step-navigation {
    position: sticky;
    bottom: 0;
    z-index: 6;
    background: #fff;
    padding-bottom: 0.35rem;
    box-shadow: 0 -10px 18px -10px rgba(15, 23, 42, 0.22);
  }
}

/* -------------------------------------------------------------- desktop --- */

@media (min-width: 700px) {
  body.llp-sheeted .modal-center {
    /* Tailwind writes the centring as a transform, so the rise has to be part
       of the same declaration rather than a second one that replaces it. */
    transform: translate(-50%, -50%) translateY(18px) !important;
    transition: transform 0.26s cubic-bezier(0.22, 1, 0.36, 1);
    /* A CEILING, BECAUSE A CENTRED PANEL HAS NO FLOOR TO REST ON. The
       calendar panel is a month plus twenty five slots and it ran 1132 pixels
       tall, which on a laptop put its top edge 66 pixels above the top of the
       screen and its button below the bottom. There was no way to reach either
       of them: a centred element that outgrows the window does not scroll, it
       simply hangs off both ends. */
    max-height: 92vh;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  body.llp-sheeted .modal-center.llp-sheet-in {
    transform: translate(-50%, -50%) !important;
  }
  /* The one panel with two columns of content earns the extra width. */
  body.llp-sheeted #calendar-modal { max-width: 680px !important; }
  body.llp-sheeted #calendar-modal .schedule-visit-step-navigation {
    position: sticky;
    bottom: 0;
    z-index: 6;
    background: #fff;
    padding-bottom: 0.35rem;
    box-shadow: 0 -10px 18px -10px rgba(15, 23, 42, 0.22);
  }
}

@media (prefers-reduced-motion: reduce) {
  body.llp-sheeted .modal-center,
  body.llp-sheeted #modal-backdrop { transition: none; }
}

/* ---- the confirmation screen joins the pattern --------------------------
   It used to take the whole phone screen. That was right when it was the only
   thing of its kind on the page and wrong the moment everything else became a
   sheet, because the shopper's last impression of the page is the one that
   should feel most like the rest of it. */

@media (max-width: 699px) {
  .llc-overlay { align-items: flex-end; padding: 0; }
  .llc-panel {
    max-width: none;
    width: 100%;
    min-height: 0;
    margin: 0;
    padding: 2.1rem 1.3rem calc(1.5rem + env(safe-area-inset-bottom, 0px));
    border-radius: 20px 20px 0 0;
    max-height: 92vh;
    max-height: 92dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
    transform: translateY(100%);
    transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
    box-shadow: 0 -10px 46px rgba(8, 13, 24, 0.42);
  }
  .llc-overlay.llp-on .llc-panel { transform: translateY(0); }
  .llc-panel::before {
    content: '';
    position: absolute;
    top: 8px;
    left: 50%;
    width: 42px;
    height: 4px;
    margin-left: -21px;
    border-radius: 99px;
    background: rgba(15, 23, 42, 0.16);
  }
  .llc-head { font-size: 1.3rem; }
  .llc-row { flex-direction: column; gap: 0.55rem; }

  /* The promo card ask was a bottom sheet before any of this and it stays one.
     It only wanted the handle, so that every panel on the page carries the same
     piece of furniture. Its head is a colour band, so the handle is drawn in
     white rather than in ink. */
  .llp-lb-panel { border-radius: 20px 20px 0 0; }
  .llp-lb-head { padding-top: 1.55rem; }
  .llp-lb-head::before {
    content: '';
    position: absolute;
    top: 8px;
    left: 50%;
    width: 42px;
    height: 4px;
    margin-left: -21px;
    border-radius: 99px;
    background: rgba(255, 255, 255, 0.42);
    pointer-events: none;
  }
}

/* ==========================================================================
   [SCHEDULER 2026-09-18, owner] BOOKING A VISIT, BUILT FOR A THUMB

   What it replaced: a native date field and a select with twenty five options
   in it. On a phone that is two operating system pickers, one of them a
   spinning wheel, and no sense at any point of what you had chosen or what was
   left to do. Most appointments come from a phone, so that was the whole
   experience for most of the people booking one.

   What it is now: a real month calendar you tap, times grouped by the part of
   the day they belong to, a bar that fills as you go, and a line that
   assembles itself into the appointment you are about to make.

   THE ORIGINAL FIELDS ARE STILL THERE AND STILL WHAT GETS SENT. Everything
   here writes into #schedule-visit-date and #schedule-visit-time, so the
   page's own validation, its two step navigation, its collectFormData and the
   email that reaches the dealership all carry on exactly as they were. This is
   a surface over that form, never a replacement for it.
   ========================================================================== */

.llsv, .llsv * { box-sizing: border-box; }

.llsv-hid {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

.llsv {
  margin: 0.2rem 0 0.6rem;
  font: inherit;
  color: #0f172a;
}

/* [SCHED-SIMPLE 2026-09-20] One column: the calendar, then the times under
   it. The one tap shortcuts, the progress bar, the summary pill and the hours
   line all came out. Owner: the popup was overwhelming; a calendar and a set
   of times is the whole job. */

/* ---- the calendar ------------------------------------------------------- */

.llsv-cal {
  border: 1px solid rgba(15, 23, 42, 0.1);
  border-radius: 14px;
  padding: 0.7rem 0.7rem 0.55rem;
  background: #fff;
}
.llsv-cal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.55rem;
}
.llsv-month { font-size: 0.98rem; font-weight: 800; letter-spacing: -0.01em; }
.llsv-nav {
  width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%;
  background: rgba(15, 23, 42, 0.06);
  color: #334155;
  cursor: pointer;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
}
/* Colour rather than opacity, and background rather than filter, right across
   this panel. The host page walks every input and button inside an open modal
   setting style.opacity, style.filter and style.pointerEvents inline, so
   anything styled with those three loses the moment the modal opens. */
.llsv-nav:disabled { color: #cbd5e1; background: rgba(15, 23, 42, 0.03); cursor: default; }
.llsv-nav svg { width: 17px; height: 17px; display: block; }

.llsv-dow, .llsv-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.llsv-dow span {
  text-align: center;
  font-size: 0.66rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: #94a3b8;
  padding-bottom: 0.3rem;
}
.llsv-day {
  position: relative;
  aspect-ratio: 1 / 1;
  min-height: 40px;
  /* min-width: 0 IS LOAD BEARING. A grid item's automatic minimum size is its
     content, and an aspect ratio transfers a minimum height straight through
     to a minimum width. So min-height: 40px quietly made every column at least
     40px wide, seven of those plus the gaps came to more than the calendar
     box, and the last day of every row hung outside the card. */
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 11px;
  background: transparent;
  font: inherit;
  font-size: 0.95rem;
  font-weight: 700;
  color: #0f172a;
  cursor: pointer;
  padding: 0;
  transition: transform 0.16s cubic-bezier(0.22, 1, 0.36, 1), background 0.16s ease, color 0.16s ease;
  -webkit-tap-highlight-color: transparent;
}
.llsv-day.is-void { visibility: hidden; }
/* A day outside the booking window is shown rather than hidden, so the shape
   of the month stays readable and nobody wonders where the first week went. */
.llsv-day.is-off { color: #cbd5e1; cursor: default; font-weight: 600; }
.llsv-day.is-open { background: var(--llp-primary-wash, #eef5fa); }
.llsv-day.is-open:active { transform: scale(0.9); }
.llsv-day.is-on {
  background: var(--llp-primary, #005c90);
  color: #fff;
  box-shadow: 0 6px 14px -5px var(--llp-primary-glow, rgba(0, 92, 144, 0.75));
}
.llsv-day.is-on { animation: llsv-pop 0.34s cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes llsv-pop {
  0% { transform: scale(0.82); }
  60% { transform: scale(1.07); }
  100% { transform: scale(1); }
}
/* Today is marked but never bookable: the form takes tomorrow at the earliest,
   and a today nobody can tap needs to say which one it is. */
.llsv-day.is-today::after {
  content: '';
  position: absolute;
  bottom: 5px; left: 50%;
  width: 4px; height: 4px;
  margin-left: -2px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.55;
}
.llsv-day.is-on.is-today::after { background: #fff; opacity: 0.9; }

/* ---- the times ---------------------------------------------------------- */

.llsv-times { margin-top: 0.95rem; }
.llsv-ask {
  margin: 0 0 0.6rem;
  font-size: 0.95rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}
.llsv-band { margin-bottom: 0.7rem; }
.llsv-band-h {
  display: flex;
  align-items: center;
  gap: 0.38rem;
  margin-bottom: 0.4rem;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #7c8798;
}
.llsv-band-h svg { width: 14px; height: 14px; flex: none; }
.llsv-slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: 0.45rem; }
.llsv-slot {
  min-height: 42px;
  padding: 0.5rem 0.3rem;
  border: 1.5px solid rgba(15, 23, 42, 0.12);
  border-radius: 10px;
  background: #fff;
  font: inherit;
  font-size: 0.88rem;
  font-weight: 700;
  color: #0f172a;
  cursor: pointer;
  transition: transform 0.14s ease, background 0.16s ease, border-color 0.16s ease, color 0.16s ease;
  -webkit-tap-highlight-color: transparent;
}
.llsv-slot:active { transform: scale(0.94); }
.llsv-slot.is-on {
  background: var(--llp-primary, #005c90);
  border-color: var(--llp-primary, #005c90);
  color: #fff;
  animation: llsv-pop 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}
.llsv-none {
  margin: 0;
  padding: 0.7rem 0.2rem;
  font-size: 0.88rem;
  font-weight: 600;
  color: #64748b;
}

.llsv-nudge {
  margin: 0.7rem 0 0;
  padding: 0.6rem 0.8rem;
  border-radius: 10px;
  background: #fef2f2;
  color: #b91c1c;
  font-size: 0.86rem;
  font-weight: 700;
  display: none;
}
.llsv-nudge.is-on { display: block; }
.llsv-shake { animation: llsv-shake 0.4s ease; }
@keyframes llsv-shake {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(3px); }
  30%, 50%, 70% { transform: translateX(-5px); }
  40%, 60% { transform: translateX(5px); }
}

/* The page's own Next button, told what it is about to do. While the pick is
   incomplete it wears the theme colour as a wash rather than a grey, so it is
   still the same button and still reads as part of the same design. Not dimmed
   with opacity: the host page forces opacity 1 on every button in an open
   modal. */
.llsv-wait {
  background: var(--llp-primary-wash, #eef5fa) !important;
  color: var(--llp-primary-dark, #004466) !important;
  box-shadow: none !important;
}

/* The popup itself scrolls when a full day of times will not fit the screen.
   Its scrollbar is drawn as part of the panel: thin, rounded, on a clear
   track that stops short of the rounded corners, instead of the browser's
   grey gutter hanging off the edge of the card. */
#calendar-modal {
  max-height: 92vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(15, 23, 42, 0.26) transparent;
}
#calendar-modal::-webkit-scrollbar { width: 8px; }
#calendar-modal::-webkit-scrollbar-track { background: transparent; margin: 16px 0; }
#calendar-modal::-webkit-scrollbar-thumb { background: rgba(15, 23, 42, 0.22); border-radius: 99px; border: 2px solid #fff; }
#calendar-modal::-webkit-scrollbar-thumb:hover { background: rgba(15, 23, 42, 0.4); }
/* The Next button rides along the foot of the popup while the times scroll
   under it (the host makes it sticky). It gets a white footer that reaches
   the edge of the card and a soft shadow, so the row it covers is a row
   under a shelf rather than words showing through around a button. */
#calendar-modal #schedule-visit-step-1 .schedule-visit-step-navigation {
  position: sticky;
  bottom: -12px;
  margin: 0.4rem 0 -12px;
  padding: 0.55rem 0 12px;
  background: #fff;
  box-shadow: 0 -14px 16px -12px rgba(15, 23, 42, 0.16);
}
#calendar-modal #schedule-visit-step-1 .schedule-visit-step-navigation button { margin-top: 0; }

@media (prefers-reduced-motion: reduce) {
  .llsv-day, .llsv-slot { transition: none; animation: none; }
}

/* ==========================================================================
   [QUIET-ART 2026-09-20] The drawing steps back, the words step forward.

   Owner: the dot fields, rings and route lines behind the copy were dark
   enough to fight the offer itself ("Buying from out of state is routine
   here" over a field of near black dots). The art layer is now drawn at a
   third of its strength, and a frosted, translucent panel sits under the
   copy on every card, blurring whatever drawing is left so the pattern
   reads as texture rather than as a design element. Light skins frost
   white, dark skins frost near black, the colour skin frosts a shade
   darker. The live manufacturer offer card carries a photograph and no
   drawing, so it is left alone.
   ========================================================================== */
/* [QUIET-ART round 2, owner 2026-09-20] the first pass faded the drawing so
   far that light cards came out blank white. The art keeps most of its
   strength and colour; it is the veil in front of it that does the quieting. */
.llp-card .llp-art { opacity: 0.9; }
.llp-card:not(.llp-skin-offer) .llp-inner::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(255, 255, 255, 0.34);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  pointer-events: none;
}
/* The dark skins frost dark. Written with the card class as well, because
   the generic rule above carries :not() and would otherwise outrank these. */
.llp-card.llp-skin-midnight .llp-inner::before,
.llp-card.llp-skin-spotlight .llp-inner::before,
.llp-card.llp-skin-pulse .llp-inner::before,
.llp-card.llp-skin-glass .llp-inner::before { background: rgba(11, 17, 32, 0.34); }
.llp-card.llp-skin-wave .llp-inner::before { background: rgba(0, 0, 0, 0.14); }

/* ------------------------------------------------- store offers  [CUSTOM-OFFERS 2026-10-04]
   The store's own promotions from its Custom Offers. Same anatomy as the
   manufacturer offer card: the picture is the top of the card, the words and
   the button sit under it. A dealer graphic is shown WHOLE on a blurred copy
   of itself, because it carries its own words; it is never cropped and never
   stretched. Designed offers are drawn in the page's own colours. */
.llp-skin-store { background: #fff; border: 1px solid #e6e9ee; }
.llp-skin-store .llp-inner { padding: 0; gap: 0; }
.llp-st-media {
  position: relative;
  flex: 0 0 auto;
  width: 100%;
  max-height: 420px;
  overflow: hidden;
  background: #0f172a;
}
.llp-st-bg {
  position: absolute; inset: -8%;
  width: 116%; height: 116%; max-width: none;
  object-fit: cover;
  filter: blur(20px) brightness(0.62) saturate(1.1);
}
.llp-st-fg {
  position: absolute; inset: 0;
  width: 100%; height: 100%; max-width: none;
  object-fit: contain;
}
.llp-st-play {
  position: absolute; left: 50%; top: 50%; z-index: 2;
  width: 58px; height: 58px; margin: -29px 0 0 -29px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; padding-left: 3px;
  color: #fff; background: rgba(15, 23, 42, 0.55);
  border: 2px solid rgba(255, 255, 255, 0.92);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  transition: transform 0.18s ease;
}
@media (hover: hover) and (pointer: fine) {
  .llp-skin-store:hover .llp-st-play { transform: scale(1.07); }
}
.llp-st-dur {
  position: absolute; right: 0.6rem; bottom: 0.6rem; z-index: 2;
  padding: 0.18rem 0.45rem; border-radius: 6px;
  font-size: 0.72rem; font-weight: 800; color: #fff;
  background: rgba(15, 23, 42, 0.78);
}
.llp-st-frame { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; background: #000; object-fit: contain; }
.llp-st-flag {
  position: absolute; left: 0.75rem; top: 0.75rem; z-index: 3;
  display: inline-flex; align-items: center; gap: 0.36rem;
  padding: 0.36rem 0.62rem 0.36rem 0.5rem; border-radius: 999px;
  font-size: 0.66rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; line-height: 1;
  color: #0f172a; background: rgba(255, 255, 255, 0.95);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.22);
}
.llp-st-flag svg { color: var(--llp-primary, #005c90); }

/* Designed offers. */
.llp-st-panel {
  position: relative;
  flex: 0 0 auto;
  min-height: 205px;
  overflow: hidden;
  display: flex; flex-direction: column; justify-content: flex-end; gap: 0.2rem;
  padding: 3.1rem 1.15rem 1.15rem;
  color: #fff;
  background: linear-gradient(150deg, var(--llp-primary, #005c90) 0%, var(--llp-primary-far, #004466) 100%);
}
.llp-st-panel::before, .llp-st-panel::after {
  content: ''; position: absolute; border-radius: 50%; pointer-events: none;
  border: 18px solid rgba(255, 255, 255, 0.08);
}
.llp-st-panel::before { width: 200px; height: 200px; right: -72px; top: -84px; }
.llp-st-panel::after { width: 116px; height: 116px; right: 38px; bottom: -74px; border-width: 12px; }
.llp-st-type {
  position: absolute; left: 1.15rem; top: 2.85rem; z-index: 1;
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-size: 0.7rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.92;
}
.llp-st-fig { position: relative; z-index: 1; display: flex; align-items: baseline; gap: 0.2rem; line-height: 1; margin-top: 1.6rem; }
.llp-st-big { font-size: 3.1rem; font-weight: 900; letter-spacing: -0.04em; }
.llp-st-unit { font-size: 1.15rem; font-weight: 800; opacity: 0.94; }
.llp-st-small { position: relative; z-index: 1; font-size: 0.88rem; font-weight: 700; opacity: 0.94; }
.llp-st-hero { position: relative; z-index: 1; margin-top: 1.6rem; font-size: 1.55rem; line-height: 1.14; font-weight: 900; letter-spacing: -0.02em; }
.llp-st-when {
  position: relative; z-index: 1; align-self: flex-start; margin-top: 0.55rem;
  padding: 0.24rem 0.6rem; border-radius: 6px;
  font-size: 0.74rem; font-weight: 800; letter-spacing: 0.04em;
  color: #f1c76b; background: rgba(241, 199, 107, 0.16);
}
.llp-st-l-photo { background: #0f172a; min-height: 230px; isolation: isolate; }
.llp-st-l-photo::before { display: none; }
.llp-st-l-photo::after {
  content: ''; display: block; position: absolute; inset: 0; z-index: 1;
  width: auto; height: auto; border: 0; border-radius: 0;
  background: linear-gradient(0deg, rgba(8, 10, 16, 0.86) 0%, rgba(8, 10, 16, 0.3) 55%, rgba(8, 10, 16, 0) 80%);
}
.llp-st-photo { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; max-width: none; object-fit: cover; }
.llp-st-l-photo .llp-st-type {
  position: relative; z-index: 2; left: auto; top: auto; align-self: flex-start;
  margin-bottom: 0.45rem; padding: 0.3rem 0.6rem; border-radius: 999px; opacity: 1;
  background: var(--llp-primary, #005c90); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}
.llp-st-l-photo .llp-st-fig, .llp-st-l-photo .llp-st-small, .llp-st-l-photo .llp-st-hero {
  position: relative; z-index: 2; text-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
}
.llp-st-l-photo .llp-st-fig, .llp-st-l-photo .llp-st-hero { margin-top: 0; }
.llp-st-l-ticket {
  background: #fbf7ec; color: #3b2a06;
  border-bottom: 2px dashed #d9c79a;
}
.llp-st-l-ticket::before, .llp-st-l-ticket::after { display: none; }
.llp-st-l-ticket .llp-st-type { color: var(--llp-primary-dark, #004466); opacity: 1; }
.llp-st-l-ticket .llp-st-big { color: var(--llp-primary-dark, #004466); }
.llp-st-l-ticket .llp-st-unit, .llp-st-l-ticket .llp-st-small { color: #5b4513; }
.llp-st-l-ticket .llp-st-hero { color: #2b1e04; }
.llp-st-l-event { background: radial-gradient(90% 120% at 0% 100%, var(--llp-primary-glow, rgba(0, 92, 144, 0.55)), transparent 60%), #0b1120; }
.llp-st-l-event .llp-st-type { color: #f1c76b; opacity: 1; }
.llp-st-l-event .llp-st-big { color: #f1c76b; }
.llp-st-l-event .llp-st-hero { text-transform: uppercase; letter-spacing: 0.01em; }

.llp-st-body { gap: 0.32rem; }
.llp-st-title { font-size: 1.12rem; line-height: 1.25; font-weight: 800; color: #0f172a; letter-spacing: -0.008em; }
.llp-st-sub { margin: 0; font-size: 0.9rem; line-height: 1.42; font-weight: 500; color: #415167; }
.llp-skin-store .llp-cta { margin-top: 0.7rem; }
.llp-skin-store .llp-foot { flex: 0 0 auto; padding: 0.55rem 0 0; }

/* The ribbon: a store offer riding inside a vehicle card. Across the TOP of
   the photograph, because the price and payment bubbles own its foot. */
.llp-ribbon {
  position: absolute; left: 0.7rem; right: 0.7rem; top: 0.7rem; z-index: 4;
  display: flex; align-items: center; gap: 0.5rem;
  min-height: 2.6rem; margin: 0;
  padding: 0.38rem 0.55rem 0.38rem 0.42rem;
  border: 0; border-radius: 0.72rem;
  font: inherit; text-align: left; cursor: pointer;
  color: #fff;
  background: var(--llp-primary, #005c90);
  box-shadow: 0 8px 22px -6px rgba(0, 0, 0, 0.55), inset 0 0 0 1px rgba(255, 255, 255, 0.16);
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.16s ease;
}
@media (hover: hover) and (pointer: fine) { .llp-ribbon:hover { transform: translateY(-1px); } }
.llp-ribbon:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
.llp-rb-tag {
  width: 1.75rem; height: 1.75rem; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 0.5rem; background: rgba(255, 255, 255, 0.2);
}
.llp-rb-txt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; line-height: 1.18; }
.llp-rb-txt small { font-size: 0.6rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.86; }
.llp-rb-txt b { font-size: 0.86rem; font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.llp-rb-more { flex: none; font-size: 0.7rem; font-weight: 800; padding: 0.12rem 0.42rem; border-radius: 999px; background: rgba(255, 255, 255, 0.22); }
.llp-rb-go { flex: none; display: flex; opacity: 0.9; }

/* In the lead layer: the picture or film first, then the offer, then the form. */
.llp-lb-media { flex: 0 0 auto; max-height: 38vh; border-radius: inherit; border-bottom-left-radius: 0; border-bottom-right-radius: 0; cursor: default; }
.llp-lb-media[role="button"] { cursor: pointer; }
.llp-lb-media.llp-st-panel { min-height: 170px; max-height: none; }
.llp-st-details { margin: 0 0 0.9rem; font-size: 0.9rem; line-height: 1.5; color: #334155; white-space: pre-line; }
.llp-st-fine { margin: 0.6rem 0 0; font-size: 0.66rem; line-height: 1.45; color: #64748b; text-align: left; white-space: pre-line; }
/* The card is a column flex box that does not stretch its children (see the
   align-items note on .llp-off-photo), so the store card's own pieces claim
   the full width themselves. */
.llp-skin-store .llp-inner { width: 100%; align-self: stretch; }
.llp-skin-store .llp-st-media, .llp-skin-store .llp-st-panel, .llp-skin-store .llp-st-body { align-self: stretch; width: 100%; }

/* [CUSTOM-OFFERS] An empty lot showing the store's own offers: the "no
   vehicles" sentence is hidden, its Find It For Me button is kept. */
#no-results-message.llp-store-only { font-size: 0; padding-top: 0.25rem; }
#no-results-message.llp-store-only .llf-empty-cta { font-size: 1rem; }
