/* =========================================================================
   Likchat home — AI video generation
   Self-contained: the old creator-monetisation stylesheets are not loaded on
   this page, so nothing here has to fight them. Light theme, Inter, the same
   pill buttons and soft-shadow cards the rest of the site uses.
   ========================================================================= */

:root {
  --ink: #0b0b0f;
  --ink-2: #111827;
  --muted: #6b7280;
  --line: #eef2f7;
  --brand: #6d28d9;
  --brand-2: #a855f7;
  --brand-soft: #f5f3ff;
  --radius: 24px;
  --shadow: 0 8px 24px rgba(15, 23, 42, 0.05), 0 1px 2px rgba(15, 23, 42, 0.06);
}

* { box-sizing: border-box; }

body {
  font-family: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  color: var(--muted);
  background: #fff;
  overflow-x: hidden;
  margin: 0;
}

img, video { max-width: 100%; display: block; }

/* ================= ICONS ================= */
/* Inline SVG, defined once as a sprite at the top of <body>. Sized in `em`
   and painted with currentColor, so every rule that used to colour or size a
   Font Awesome <i> keeps working with no change. */
.ic {
  width: 1em;
  height: 1em;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* <svg> is inline by default, so it sits on the text baseline and rides a
     few px low next to a label. This centres it against the cap height. */
  vertical-align: -0.135em;
}

/* Brand marks are solid shapes, not line drawings. */
.ic-fill { fill: currentColor; stroke: none; }

/* The sprite is a definitions block — it must occupy no space. `display:none`
   would be enough for <use> in modern browsers, but this survives it being
   moved into a flex or grid parent by mistake. */
.ic-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

a { text-decoration: none; }

.wrap {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 20px;
}

/* ================= BUTTONS ================= */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 13px 24px;
  border-radius: 999px;
  font-size: 15px;
  font-weight: 600;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.15s, box-shadow 0.15s, background 0.15s;
  white-space: nowrap;
}

.btn-primary {
  background: linear-gradient(135deg, var(--brand), var(--brand-2));
  color: #fff;
  box-shadow: 0 8px 20px rgba(109, 40, 217, 0.24);
}

.btn-primary:hover { transform: translateY(-1px); color: #fff; }

.btn-ghost {
  background: #fff;
  color: var(--ink-2);
  border-color: #e5e7eb;
}

.btn-ghost:hover { border-color: var(--brand); color: var(--brand); }

.btn-sm { padding: 9px 18px; font-size: 14px; }

/* ================= SECTION FURNITURE ================= */
section { padding: 84px 0; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 15px;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand);
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 16px;
}

h1, h2, h3 { color: var(--ink-2); margin: 0; }

h1 {
  font-size: 58px;
  line-height: 1.05;
  font-weight: 800;
  letter-spacing: -0.03em;
  margin-bottom: 18px;
}

h1 .grad {
  background: linear-gradient(120deg, var(--brand), var(--brand-2));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

h2 {
  font-size: 40px;
  line-height: 1.15;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin-bottom: 14px;
}

.sec-head { text-align: center; max-width: 660px; margin: 0 auto 48px; }
.sec-head p { font-size: 16px; margin: 0; }

.lead { font-size: 17px; line-height: 1.6; max-width: 520px; }

/* ================= HERO ================= */
.hero {
  padding: 72px 0 84px;
  position: relative;
  overflow: hidden;
}

/* Soft brand glow behind the hero, echoing the logo's purple bloom. */
.hero::before {
  content: "";
  position: absolute;
  top: -220px;
  right: -140px;
  width: 620px;
  height: 620px;
  background: radial-gradient(circle, rgba(168, 85, 247, 0.16), transparent 68%);
  pointer-events: none;
}

.hero-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 56px;
  align-items: center;
  position: relative;
}

.hero-cta { display: flex; gap: 12px; margin: 30px 0 34px; flex-wrap: wrap; }

.stats { display: flex; gap: 34px; flex-wrap: wrap; }
.stats b { display: block; font-size: 27px; font-weight: 800; color: var(--ink-2); line-height: 1; }
.stats span { font-size: 13px; }

/* Hero video collage — two columns drifting in opposite directions */
.collage {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  height: 540px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 88%, transparent);
}

.collage-col { display: flex; flex-direction: column; gap: 14px; }
.collage-col.up   { animation: drift-up 46s linear infinite; }
.collage-col.down { animation: drift-down 46s linear infinite; }

@keyframes drift-up   { from { transform: translateY(0); }    to { transform: translateY(-50%); } }
@keyframes drift-down { from { transform: translateY(-50%); } to { transform: translateY(0); } }

@media (prefers-reduced-motion: reduce) {
  .collage-col.up, .collage-col.down { animation: none; }
}

.tile {
  border-radius: 18px;
  overflow: hidden;
  background: #f3f4f6;
  box-shadow: var(--shadow);
  aspect-ratio: 9 / 16;
  flex: none;
}

.tile video, .tile img { width: 100%; height: 100%; object-fit: cover; }

/* ================= CARD GRIDS ================= */
.grid { display: grid; gap: 20px; }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }

.card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 30px;
  box-shadow: var(--shadow);
  height: 100%;
}

.card h3 { font-size: 19px; font-weight: 700; margin-bottom: 8px; }
.card p { font-size: 14.5px; line-height: 1.6; margin: 0; }

.icon {
  width: 48px;
  height: 48px;
  border-radius: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  background: var(--brand-soft);
  color: var(--brand);
  margin-bottom: 18px;
}

/* ---- roadmap (how it works) ---- */
/* One geometry, two directions. Desktop lays the road out left to right with
   the stops on top of the cards; below 768px the same rules rotate it into a
   rail down the left. The connector is drawn by each step reaching toward the
   NEXT one, never by a line under the whole row — that version always ran
   past the first and last stops and had to be masked back. */
.roadmap {
  /* Kept on the component, not :root — the connector measures itself as
     "my width plus one gap", so these two must stay in step with the grid
     gap below, and that is easiest to see when they sit next to it. */
  --rm-node: 52px;
  --rm-gap: 28px;

  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--rm-gap);
}

.rm-step {
  position: relative;
  padding-top: calc(var(--rm-node) + 26px);
}

/* The road itself: a dashed centre line, like lane markings. */
.rm-step::before {
  content: "";
  position: absolute;
  top: calc(var(--rm-node) / 2 - 1.5px);
  left: 50%;
  width: calc(100% + var(--rm-gap));
  height: 3px;
  background-image: linear-gradient(90deg, var(--brand) 55%, transparent 0);
  background-size: 15px 3px;
  background-repeat: repeat-x;
  opacity: 0.32;
  animation: rm-run 0.9s linear infinite;
}

/* The last stop is the destination — no road leaves it. */
.rm-end::before { display: none; }

@keyframes rm-run { to { background-position: 15px 0; } }

.rm-node {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: var(--rm-node);
  height: var(--rm-node);
  border-radius: 50%;
  background: linear-gradient(135deg, var(--brand), var(--brand-2));
  color: #fff;
  font-weight: 800;
  font-size: 18px;
  display: grid;
  place-items: center;
  /* Lifts the stop above the road so the dashes pass behind it, and the white
     ring keeps the line from appearing to touch the circle. */
  z-index: 1;
  box-shadow: 0 0 0 6px #fff, 0 8px 18px rgba(109, 40, 217, 0.28);
  transition: transform 0.18s, box-shadow 0.18s;
}

/* Deliberately no icon inside the stop. Font Awesome 404s on this site, so
   an icon here would render as an empty circle — the number is the one thing
   guaranteed to draw. Hover grows the stop instead. */
.rm-step:hover .rm-node {
  transform: translateX(-50%) scale(1.1);
  box-shadow: 0 0 0 6px #fff, 0 10px 24px rgba(109, 40, 217, 0.42);
}

/* Must stay position:static. The stop lives inside this card but positions
   itself against .rm-step; making this positioned would re-anchor it and
   drop the desktop stop into the card's top-left corner. */
.rm-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 30px;
  box-shadow: var(--shadow);
  height: 100%;
  transition: transform 0.18s, border-color 0.18s, box-shadow 0.18s;
}

.rm-step:hover .rm-card {
  transform: translateY(-3px);
  border-color: var(--brand-2);
  box-shadow: 0 14px 30px rgba(24, 16, 48, 0.09);
}

.rm-card h3 { font-size: 19px; font-weight: 700; margin-bottom: 8px; }
.rm-card p { font-size: 14.5px; line-height: 1.6; margin: 0; }

/* ---- models ---- */
.models { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }

/* Duplicate cards exist only to close the mobile marquee loop. */
.model-clone { display: none; }

.model {
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 26px;
  background: #fff;
  box-shadow: var(--shadow);
  transition: border-color 0.15s, transform 0.15s;
}

.model:hover { border-color: var(--brand-2); transform: translateY(-2px); }

.model-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }

.model h3 { font-size: 18px; font-weight: 700; }

.chip {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand);
}

.chip-alt { background: #ecfdf5; color: #047857; }

.model p { font-size: 14.5px; line-height: 1.6; margin: 0 0 14px; }

.model ul { list-style: none; margin: 0; padding: 0; }

.model li {
  font-size: 13.5px;
  padding: 6px 0;
  border-top: 1px solid #f3f4f6;
  display: flex;
  gap: 8px;
}

.model li:first-child { border-top: 0; }
/* The tick beside each feature. In a flex row, so vertical-align does nothing
   here — the margin is what lines it up with the first line of text. */
.model li .ic { color: var(--brand); margin-top: 3px; font-size: 13px; stroke-width: 2.6; }

/* ---- categories ---- */
.cats { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }

/* Mobile: rows of pills that scroll past continuously. Wrapping 17 categories
   on a phone produced a tall block of near-identical pills; rows read faster
   and hint that the list keeps going. Built by JS only under 768px. */
.cat-rows { display: none; }

.cat-row {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}

.cat-row + .cat-row { margin-top: 10px; }

/* Spacing is a per-item margin, not `gap`: with `gap` the final item has no
   trailing space, so half the track width lands mid-gap and the loop visibly
   jumps. A uniform margin makes every item exactly (width + margin) wide, so
   -50% is precisely one full set. */
.cat-track {
  display: flex;
  width: max-content;
  animation: marquee-l var(--dur, 34s) linear infinite;
}

.cat-track .cat { margin-right: 10px; }

.cat-row.rev .cat-track { animation-name: marquee-r; }

@keyframes marquee-l { to { transform: translateX(-50%); } }
@keyframes marquee-r { from { transform: translateX(-50%); } }

.cat {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 20px;
  border-radius: 999px;
  border: 1px solid #e5e7eb;
  background: #fff;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--ink-2);
  transition: border-color 0.15s, background 0.15s;
}

.cat:hover { border-color: var(--brand); background: var(--brand-soft); color: var(--brand); }
.cat b { font-weight: 700; color: var(--brand); }

.cat-skeleton {
  width: 120px;
  height: 44px;
  border-radius: 999px;
  background: linear-gradient(90deg, #f3f4f6, #e9eaee, #f3f4f6);
  background-size: 200% 100%;
  animation: shimmer 1.4s linear infinite;
}

@keyframes shimmer { to { background-position: -200% 0; } }

/* ---- template gallery ---- */
.gallery { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }

.g-item {
  position: relative;
  border-radius: 18px;
  overflow: hidden;
  aspect-ratio: 9 / 16;
  background: #f3f4f6;
  box-shadow: var(--shadow);
}

.g-item video { width: 100%; height: 100%; object-fit: cover; }

/* The phone-only conveyor belt (see rotateGallery). The dip is a crossfade,
   not a slide: the tiles are grid items being reordered, so any transform
   would animate from the wrong cell. */
.g-item { transition: opacity 0.24s ease; }
.gallery.g-fade .g-item { opacity: 0.18; }

/* Template titles are user-written and run long (emoji, full sentences), so the
   caption is pinned to a single line — a wrapping one covered the video. */
.g-cap {
  position: absolute;
  inset: auto 0 0 0;
  padding: 26px 12px 11px;
  background: linear-gradient(transparent, rgba(0, 0, 0, 0.78));
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ================= STATUS TEMPLATES ================= */
/* Ready-made greeting posts, as opposed to the AI gallery above. Two things
   make this section different from .gallery and neither is cosmetic:

   1. These are mostly stills, and their designs run at whatever ratio the
      artist drew — 1080x1350 and 736x1308 both turn up in the same feed.
      A fixed aspect-ratio tile would crop the greeting text off the top or
      bottom of half of them, which is precisely what the section exists to
      show. So: CSS columns, each post at its own height, nothing cropped.
   2. The tiles are smaller and denser. The point here is "there are hundreds
      of these, for every occasion", not "look closely at one". */
.st-grid {
  columns: 5;
  column-gap: 14px;
}

/* Its own class rather than .cats: that one is hidden below 768px in favour
   of the scrolling .cat-rows marquee, and six pills do not need a marquee. */
.st-cats { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }

/* Duplicate pills exist only to close the phone marquee loop — on desktop
   they would just be the same six categories listed twice. */
.st-clone { display: none; }

/* "Showing now · Hartalika Teej in 3 days · morning picks" */
.st-note {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  margin-top: 22px;
  font-size: 13.5px;
  color: var(--muted);
}

.st-note b { color: var(--ink-2); font-weight: 700; }

.st-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #16a34a;
  box-shadow: 0 0 0 4px rgba(22, 163, 74, 0.15);
}

.st-item {
  break-inside: avoid;
  margin-bottom: 14px;
  border-radius: 14px;
  overflow: hidden;
  background: #f3f4f6;
  box-shadow: var(--shadow);
  /* Without this, Chrome occasionally splits a tile across a column break. */
  display: inline-block;
  width: 100%;
  position: relative;
}

.st-item img,
.st-item video { display: block; width: 100%; height: auto; }

/* A play badge only on the handful of status posts that are video, so the
   still ones don't advertise something that will not happen. */
.st-play {
  position: absolute;
  top: 9px;
  right: 9px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(2px);
}

/* The three "how a status works" lines. Deliberately lighter than .card —
   this is a caption to the grid, not a second Three Steps section. */
.st-steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
  margin: 0 0 40px;
}

.st-step {
  display: flex;
  gap: 13px;
  align-items: flex-start;
  text-align: left;
}

/* A number, not an icon: Font Awesome 404s on this site, so an <i> here drew
   an empty lilac square — visible as three blank boxes above the pills. */
.st-step em {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 11px;
  background: var(--brand-soft);
  color: var(--brand);
  display: grid;
  place-items: center;
  font-style: normal;
  font-weight: 800;
  font-size: 15px;
}

.st-step b { display: block; font-size: 15px; margin-bottom: 3px; }
.st-step span { font-size: 14.5px; color: var(--muted, #6b7280); line-height: 1.5; }

/* ================= CTA BAND ================= */
.band {
  background: linear-gradient(135deg, #1a0b2e, #2f1f50 55%, #4c1d95);
  border-radius: 32px;
  padding: 64px 48px;
  text-align: center;
  position: relative;
  overflow: hidden;
}

.band::after {
  content: "";
  position: absolute;
  bottom: -180px;
  left: 50%;
  transform: translateX(-50%);
  width: 520px;
  height: 380px;
  background: radial-gradient(ellipse, rgba(168, 85, 247, 0.45), transparent 70%);
}

.band h2, .band p { color: #fff; position: relative; z-index: 1; }
.band p { opacity: 0.78; max-width: 520px; margin: 0 auto 30px; }
.band .btn { position: relative; z-index: 1; }
.band .btn-ghost { background: rgba(255, 255, 255, 0.1); color: #fff; border-color: rgba(255, 255, 255, 0.28); }

/* ================= FAQ ================= */
.faq { max-width: 780px; margin: 0 auto; }

.faq details {
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 20px 24px;
  margin-bottom: 12px;
  background: #fff;
}

.faq details[open] { border-color: #ddd6fe; }

.faq summary {
  font-size: 16px;
  font-weight: 650;
  color: var(--ink-2);
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: 16px;
}

.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; font-size: 22px; color: var(--brand); line-height: 1; }
.faq details[open] summary::after { content: "\2212"; }
.faq p { font-size: 15px; line-height: 1.65; margin: 14px 0 0; }

/* ================= RESPONSIVE ================= */
@media (max-width: 991px) {
  section { padding: 60px 0; }
  h1 { font-size: 42px; }
  h2 { font-size: 31px; }

  .hero-grid { grid-template-columns: 1fr; gap: 40px; }
  .hero-left { text-align: center; }
  .lead { margin-left: auto; margin-right: auto; }
  .hero-cta, .stats { justify-content: center; }

  .collage { height: 420px; }

  .grid-3, .grid-4, .models { grid-template-columns: repeat(2, 1fr); }
  .gallery { grid-template-columns: repeat(3, 1fr); }
  .st-grid { columns: 4; }
  .st-steps { grid-template-columns: 1fr; gap: 20px; max-width: 520px; margin-inline: auto; }

  .hd-nav { display: none; }
}

/* A range, not a max-width: the 767px blocks sit BELOW the 575px one in this
   file, so a plain max-width:767px rule would win at phone widths too and
   quietly undo the two-column grid set there. */
@media (min-width: 576px) and (max-width: 767px) {
  .st-grid { columns: 3; }
}

@media (max-width: 575px) {
  .wrap { padding: 0 16px; }
  section { padding: 46px 0; }

  h1 { font-size: 33px; }
  h2 { font-size: 25px; }
  .lead { font-size: 15.5px; }

  .hero { padding: 40px 0 56px; }
  .collage { height: 330px; gap: 10px; }
  .collage-col { gap: 10px; }

  .stats { gap: 22px; }
  .stats b { font-size: 22px; }

  /* Full-width buttons beat two cramped pills on a phone */
  .hero-cta { flex-direction: column; }
  .hero-cta .btn { width: 100%; }

  .grid-3, .grid-4 { grid-template-columns: 1fr; }
  /* 2x2 — the four slots the belt rotates the eight templates through.
     Scoped to this width on purpose: JS clears .g-hide when it leaves phone
     size, and this makes a missed cleanup impossible to see anyway. */
  .gallery { grid-template-columns: repeat(2, 1fr); gap: 12px; }
  .g-item.g-hide { display: none; }
  /* Two columns, not three. On a 360px screen three masonry columns leave
     ~110px tiles, and these posts ARE their greeting text — at that size the
     words stop being readable and the grid turns into coloured rectangles. */
  .st-grid { columns: 2; column-gap: 10px; }
  .st-item { margin-bottom: 10px; border-radius: 11px; }

  .st-cats .cat { padding: 10px 17px; font-size: 14px; }

  /* Wider tiles are also taller ones, so 15 of them ran on for screens. Eight
     still reads as "there are lots"; the button below goes and gets the rest. */
  .st-item:nth-child(n + 9) { display: none; }

  .card, .model { padding: 22px; }
  .band { padding: 44px 22px; border-radius: 24px; }
  .sec-head { margin-bottom: 32px; }
  .ft-cols { gap: 36px; }
}

/* ================= ROADMAP, TURNED VERTICAL ================= */
/* The first version of this ran the stops down a rail on the left with the
   cards beside it. It read as a road, but the rail cost every card ~74px of
   an already narrow screen and the body copy wrapped to six lines.
   So the stop moves INSIDE the card, the cards go full width, and the road
   becomes a short dashed hop between one card and the next. Same route, and
   the text gets back about a third of its width. */
@media (max-width: 767px) {
  .roadmap { --rm-node: 40px; grid-template-columns: 1fr; gap: 0; }

  /* The bottom padding is the hop; the connector below measures itself
     against it, so the two must stay equal. */
  .rm-step { padding: 0 0 30px; }

  .rm-step::before {
    top: calc(100% - 30px);
    height: 30px;
    /* Under the badge, not under the card's centre: the eye follows the
       numbers down the left edge. 20px is the card's own padding. */
    left: calc(20px + var(--rm-node) / 2 - 1.5px);
    width: 3px;
    background-image: linear-gradient(180deg, var(--brand) 55%, transparent 0);
    background-size: 3px 15px;
    background-repeat: repeat-y;
    animation-name: rm-run-y;
  }

  /* In the flow now, sitting above the heading inside the card. */
  .rm-node {
    position: static;
    transform: none;
    margin-bottom: 14px;
    font-size: 16px;
    /* The white ring existed to punch the stop out of the road behind it.
       Nothing runs behind it here, and against the card it read as a halo. */
    box-shadow: 0 6px 14px rgba(109, 40, 217, 0.3);
  }

  .rm-step:hover .rm-node { transform: scale(1.06); }

  .rm-card { padding: 22px 20px; }
  .rm-card h3 { font-size: 17.5px; }

  /* Nothing follows the last card, so its hop is dead space. */
  .rm-end { padding-bottom: 0; }
}

@keyframes rm-run-y { to { background-position: 0 15px; } }

/* ================= MOBILE MARQUEES ================= */
/* Stacked one-per-row, the six model cards made the section endlessly long.
   Below 768px they become a single looping row instead. */
@media (max-width: 767px) {
  .models-mq {
    overflow: hidden;
    /* Bleed past .wrap's padding so cards run to both screen edges. */
    margin: 0 -16px;
    padding: 4px 0;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
    mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  }

  .models {
    display: flex;
    width: max-content;
    /* Cards are cloned once, so -50% lands exactly on the duplicate.
       Spacing is a per-card margin rather than `gap` — see .cat-track. */
    animation: marquee-l 48s linear infinite;
  }

  .models:active { animation-play-state: paused; }

  .model {
    width: 80vw;
    max-width: 330px;
    margin-right: 14px;
    flex: none;
  }

  .model-clone { display: block; }

  /* Swap the wrapped pill cloud for scrolling rows. */
  .cats { display: none; }
  .cat-rows { display: block; }
  .cat { padding: 10px 17px; font-size: 14px; }

  /* Status categories: six pills wrapped to three stacked rows here and
     pushed the grid below the fold. One looping strip instead. */
  .st-cats-mq {
    overflow: hidden;
    /* Bleed past .wrap's padding so the strip runs to both screen edges. */
    margin: 0 -16px;
    padding: 2px 0;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
    mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  }

  .st-cats {
    flex-wrap: nowrap;
    justify-content: flex-start;
    width: max-content;
    /* Spacing is a per-pill margin, NOT `gap`. The pills are cloned once and
       the loop translates -50%; a gap would add one more space between the
       two sets than within them, and the loop would visibly jump. */
    gap: 0;
    animation: marquee-l 30s linear infinite;
  }

  /* Held down to tap a pill, the strip stops — these are real links, and a
     moving target is hard to hit. */
  .st-cats:active { animation-play-state: paused; }

  .st-cats .cat { flex: none; margin-right: 10px; }
  .st-clone { display: inline-flex; }
}

/* Anyone who asked for less motion gets the plain, static layouts. */
@media (prefers-reduced-motion: reduce) {
  /* The road stays drawn; only the lane markings stop flowing. */
  .models, .cat-track, .st-cats, .rm-step::before { animation: none; }

  @media (max-width: 767px) {
    .models-mq { overflow-x: auto; -webkit-overflow-scrolling: touch; }
    .cat-row { overflow-x: auto; }
    /* A stopped strip is still wider than the screen, so it has to become
       swipeable or the later pills are simply unreachable. The mask would
       fade the pill under the reader's thumb, so it goes too. */
    .st-cats-mq {
      overflow-x: auto;
      -webkit-overflow-scrolling: touch;
      -webkit-mask-image: none;
      mask-image: none;
    }
  }
}
