/*
  The welcome page's styles.

  Palette taken from the app: the ink is the launcher icon's ground and the
  splash's background, the gold is the mark's own. The page is deliberately
  single-theme — the ink IS the brand rather than a light-mode choice — so
  there is no prefers-color-scheme branch to get wrong.
*/

:root {
  --ink: #1E232E;
  --gold: #D8A22C;
  --gold-hot: #FFE9B0;
  --paper: #FFFFFF;
  --muted: rgba(255, 255, 255, 0.58);
  /* One step lighter than the ground, for the alternating bands and cards. */
  --ink-raised: #232936;
  --hairline: rgba(255, 255, 255, 0.09);
  --shell: 76rem;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--paper);
  font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  line-height: 1.5;
}

/*
  Each hero element starts hidden and is placed by its own keyframe, so the
  page assembles in the order it reads: mark, name, tagline, the rest.
  `forwards` is repeated in every shorthand below — the shorthand resets
  fill-mode, so setting it here alone would be silently overridden.

  Scoped to the hero. Everything further down the page is present from the
  first paint: an element that starts at zero opacity and waits for a keyframe
  is an element that stays invisible if anything about the animation goes
  wrong, and that is not a risk worth taking with the catalogue.
*/
.hero .mark,
.hero h1,
.hero .tagline,
.hero .lede,
.hero .cta,
.hero .stats { opacity: 0; }

/*
  The mark, plain.

  It had a breathing halo, an expanding ring, a `drop-shadow` glow and then a
  lit wire running under it. All of them are gone. Anything that pulses beneath
  a logo reads as a status indicator — something loading, something syncing —
  and a front page that looks like it is still fetching itself is a front page
  nobody trusts. It arrives once and then holds still.

  Scoped to the hero: the brand strip further down marks its tiles `.mark` too,
  and unscoped this rule sizes them to 132px and animates them.
*/
.hero .mark {
  display: block;
  width: 132px;
  height: 132px;
  margin: 0 auto 1.6rem;
  animation: settle 0.6s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}

/* Without the wire to draw there is nothing to wait for, so the words follow
   the mark closely rather than after it. */
.hero h1 {
  margin: 0 0 0.7rem;
  font-size: clamp(2.1rem, 6vw, 3.4rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.05;
  animation: rise 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) 0.28s forwards;
}

.hero .tagline {
  margin: 0;
  color: var(--gold);
  font-size: 0.82rem;
  line-height: 1.6;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  font-weight: 600;
  animation: rise 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) 0.4s forwards;
}

@keyframes settle {
  from { opacity: 0; transform: scale(1.06); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/*
  # The page below the fold

  One column of full-bleed bands, each holding a centred shell. Bands rather
  than a single container because the alternating ground is what separates the
  sections on a phone, where the horizontal margin that would do it on a laptop
  has been spent on the content.

  Every grid is `auto-fit` over a `minmax`, so there are no width breakpoints
  to keep in step with the markup: the number of columns follows from how many
  fit, which is also what happens when a card is added or removed.
*/
.skip {
  position: absolute;
  left: -999px;
  top: 0;
  padding: 0.7rem 1rem;
  background: var(--gold);
  color: var(--ink);
  font-weight: 700;
  border-radius: 0 0 8px 0;
}
.skip:focus { left: 0; z-index: 10; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem clamp(1rem, 4vw, 2.5rem);
  background: rgba(30, 35, 46, 0.86);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--hairline);
}

.wordmark {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  color: inherit;
  text-decoration: none;
}
.glyph { width: 34px; height: 34px; display: block; }
.wordmark-text {
  font-weight: 800;
  letter-spacing: -0.01em;
  font-size: 1.02rem;
}

/*
  # The three bars

  `#menu:target` is the open state and the two bar-links are the control, so
  the page still holds no script. The one that opens points at the panel; the
  one that closes points at `#top`, which is the browser's own name for the
  start of the document and matches no element here, so targeting it shuts the
  panel. Every entry inside does the same on the way to its section, which is
  the whole point: the menu cannot be left covering the thing it scrolled to.

  Both the bars and the panel are laid out here and only *shown* in the narrow
  query below, so the laptop keeps its row of links untouched.
*/
.burger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 40px;
  padding: 0 10px;
  border: 1px solid var(--hairline);
  border-radius: 10px;
}
.burger span {
  display: block;
  height: 2px;
  border-radius: 2px;
  background: var(--paper);
}
.burger:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
/* The close control is the same bars crossed rather than a second icon, so
   there is one shape in that corner and only its state changes. */
.burger-close span:nth-child(1) { transform: translateY(3.5px) rotate(45deg); }
.burger-close span:nth-child(2) { transform: translateY(-3.5px) rotate(-45deg); }

.topnav { display: flex; gap: clamp(0.75rem, 2.5vw, 1.75rem); }
.topnav a {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.86rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  padding: 0.25rem 0;
  border-bottom: 1px solid transparent;
  transition: color 0.25s ease, border-color 0.25s ease;
}
.topnav a:hover,
.topnav a:focus-visible { color: var(--paper); border-bottom-color: var(--gold); }

/* The ranges strip is the first thing worth reading, so the hero stops short
   of the viewport height rather than filling it. */
.hero {
  position: relative;
  max-width: 44rem;
  margin: 0 auto;
  padding: clamp(3rem, 9vw, 6rem) 1.5rem clamp(2.5rem, 7vw, 4.5rem);
  text-align: center;
}

/*
  A light source behind the mark.

  Flat ink reads as an unstyled dark page rather than a chosen one, and the top
  of the page is where that judgement is made. Two gradients: a warm one where
  the logo sits, and a cooler, wider one under it so the glow has somewhere to
  fall away to instead of stopping.

  Both are radial and both reach zero well inside the box, which is the whole
  reason there is no repeating texture layer here — a tiled pattern would end
  in a visible rectangle at the edge of this 44rem column on a wide screen.

  `z-index: -1` puts it behind the text: a positioned pseudo-element without it
  paints over the words. It costs no request and cannot shift the layout.
*/
.hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(58% 40% at 50% 20%, rgba(216, 162, 44, 0.15), rgba(216, 162, 44, 0) 72%),
    radial-gradient(75% 55% at 50% 42%, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0) 70%);
}

.hero .lede {
  margin: 1.4rem auto 0;
  max-width: 34rem;
  color: rgba(255, 255, 255, 0.74);
  font-size: clamp(0.98rem, 2.4vw, 1.08rem);
  line-height: 1.7;
  animation: rise 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) 0.52s forwards;
}

.cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem;
  margin-top: 1.9rem;
  animation: rise 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) 0.64s forwards;
}

.btn {
  display: inline-block;
  padding: 0.8rem 1.5rem;
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.92rem;
  text-decoration: none;
  border: 1px solid transparent;
  transition: transform 0.25s ease, background 0.25s ease, border-color 0.25s ease, color 0.25s ease;
}
.btn-primary { background: var(--gold); color: var(--ink); }
.btn-primary:hover { background: var(--gold-hot); }
/*
  The store badge.

  Google's artwork carries its own margin and its own corner radius, so this
  adds neither — `line-height: 0` only removes the baseline gap an inline image
  otherwise leaves under itself, which is what makes a badge sit a few pixels
  low beside a pill. The lift on hover is the same one the buttons use, so the
  row behaves as one row.
*/
.store-badge {
  display: inline-block;
  line-height: 0;
  border-radius: 8px;
  transition: transform 0.25s ease, filter 0.25s ease;
}
.store-badge img { display: block; width: 181px; height: auto; }
.store-badge:hover { transform: translateY(-2px); filter: brightness(1.08); }
.store-badge:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.store-badge-sm img { width: 155px; }

/* Counted from the catalogue, so the numbers are true or the strip is absent
   — a "500+ products" that nobody maintains is worse than no claim at all. */
.stats {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(1.5rem, 6vw, 3.5rem);
  margin-top: clamp(2.2rem, 6vw, 3.2rem);
  padding-top: 1.8rem;
  border-top: 1px solid var(--hairline);
  animation: rise 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) 0.76s forwards;
}
.stat-value {
  display: block;
  font-size: clamp(1.5rem, 4.5vw, 2rem);
  font-weight: 800;
  color: var(--gold);
  line-height: 1.1;
}
.stat-label {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
}

/* The lower bound is what a phone gets, and it is deliberately tight: six
   bands at laptop padding is most of a screen spent on nothing. */
.section { padding: clamp(2.25rem, 8vw, 5.5rem) clamp(1rem, 4vw, 2.5rem); }
/* Every other band a step lighter, counted rather than classed: the offers and
   the brands only exist when the store has them, and a hand-placed alternation
   would put two grounds of the same shade together the day one is empty. */
main > section:nth-of-type(even) {
  background: var(--ink-raised);
  border-block: 1px solid var(--hairline);
}

.section-head {
  max-width: var(--shell);
  margin: 0 auto clamp(1.8rem, 4vw, 2.6rem);
}
/* The slides and the About panel have carried a gold kicker over their heading
   from the start; the bands between them were the only places without one, so
   the page changed its mind about its own headings halfway down. Same size and
   tracking as `.about-eyebrow`, because it is the same thing. */
.section-eyebrow {
  margin: 0 0 0.6rem;
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
  font-weight: 700;
}
.section-head h2 {
  margin: 0 0 0.5rem;
  font-size: clamp(1.4rem, 4vw, 2rem);
  font-weight: 800;
  letter-spacing: -0.02em;
}
.section-head p {
  margin: 0;
  max-width: 44rem;
  color: var(--muted);
  font-size: 0.96rem;
}

.grid {
  max-width: var(--shell);
  margin: 0 auto;
  display: grid;
  gap: clamp(0.85rem, 2vw, 1.25rem);
}
/* `min(track, 100%)` in every one of these: a bare `minmax(19rem, 1fr)` is a
   floor the grid will not go under, so on a 320px phone the track is wider
   than the screen and the whole page scrolls sideways. */
.grid-tiles { grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr)); }
.grid-cards { grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr)); }
.grid-slides { grid-template-columns: repeat(auto-fit, minmax(min(19rem, 100%), 1fr)); }

/* The store's own boards. The artwork carries the message, so the copy sits on
   a gradient over its foot rather than beside it — the same way it reads in
   the app the images were made for. */
.slide {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid var(--hairline);
  isolation: isolate;
}
.slide img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.slide:hover img { transform: scale(1.04); }
.slide-copy {
  position: absolute;
  inset: auto 0 0 0;
  padding: 1.6rem 1.2rem 1.1rem;
  background: linear-gradient(to top, rgba(20, 24, 32, 0.92), rgba(20, 24, 32, 0));
}
.slide-eyebrow {
  margin: 0 0 0.25rem;
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  font-weight: 700;
}
.slide-title { margin: 0; font-size: 1.15rem; font-weight: 800; letter-spacing: -0.01em; }

/* Maker logos are drawn for white paper, so each gets its own light tile
   instead of being knocked out against the ink. */
.marks {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0;
  list-style: none;
  display: grid;
  gap: clamp(0.85rem, 2vw, 1.25rem);
  grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr));
}
/* Scoped to the strip: the hero logo is a `.mark` too, and unscoped these
   rules put the brand tile's white panel and border behind it. */
.marks .mark {
  display: grid;
  place-items: center;
  padding: 1.1rem;
  min-height: 6.5rem;
  background: var(--paper);
  border-radius: 14px;
  border: 1px solid var(--hairline);
  transition: transform 0.3s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.marks .mark:hover { transform: translateY(-4px); }
.marks .mark img { max-width: 100%; max-height: 4rem; object-fit: contain; display: block; }

.tile,
.card {
  background: rgba(255, 255, 255, 0.035);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  transition: transform 0.3s cubic-bezier(0.2, 0.7, 0.3, 1), border-color 0.3s ease, background 0.3s ease;
}
.tile:hover,
.card:hover {
  transform: translateY(-4px);
  border-color: rgba(216, 162, 44, 0.45);
  background: rgba(255, 255, 255, 0.06);
}

.tile {
  padding: 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  align-items: flex-start;
}
.tile-media {
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 10px;
  object-fit: cover;
  background: rgba(216, 162, 44, 0.12);
}
.tile-name { margin: 0; font-size: 0.98rem; font-weight: 700; }
.tile-note {
  margin: 0;
  color: var(--muted);
  font-size: 0.82rem;
  line-height: 1.5;
}

.card { overflow: hidden; display: flex; flex-direction: column; }
.card-media {
  position: relative;
  aspect-ratio: 4 / 3;
  background: rgba(255, 255, 255, 0.04);
  display: grid;
  place-items: center;
}
.card-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.card-body { padding: 1rem 1.1rem 1.2rem; display: flex; flex-direction: column; gap: 0.4rem; flex: 1; }
.card-eyebrow {
  margin: 0;
  font-size: 0.7rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--gold);
  font-weight: 700;
}
.card-title { margin: 0; font-size: 1rem; font-weight: 700; line-height: 1.35; }
.card-note {
  margin: 0;
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1.55;
}

/*
  # About

  One panel rather than a row of equal boxes: the prose is the section and the
  short claims run beside it. `27rem` is about the narrowest the paragraph
  column stays readable at, so the second column appears only when both fit —
  under that the list falls beneath the text on its own, with no width
  breakpoint to keep in step with the markup.
*/
.about {
  max-width: var(--shell);
  margin: 0 auto;
  display: grid;
  gap: clamp(1.5rem, 4vw, 3rem);
  grid-template-columns: repeat(auto-fit, minmax(min(27rem, 100%), 1fr));
  align-items: start;
  padding: clamp(1.4rem, 4vw, 2.6rem);
  border: 1px solid var(--hairline);
  border-radius: 20px;
  background: rgba(255, 255, 255, 0.035);
}
.about-eyebrow {
  margin: 0 0 0.6rem;
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
  font-weight: 700;
}
.about-copy h2 {
  margin: 0 0 1rem;
  font-size: clamp(1.5rem, 4vw, 2.1rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.about-copy p {
  margin: 0 0 0.9rem;
  color: rgba(255, 255, 255, 0.74);
  font-size: clamp(0.95rem, 2.2vw, 1.02rem);
  line-height: 1.75;
}
.about-copy .about-sign {
  margin-bottom: 0;
  color: var(--gold);
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
}
.about-cta { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.5rem; }

/* The scanning half: hairlines between the claims rather than a card each, so
   they read as one list belonging to the paragraph beside them. */
.about-facts { margin: 0; padding: 0; list-style: none; }
.about-facts li { padding: 1.1rem 0; border-top: 1px solid var(--hairline); }
.about-facts li:first-child { border-top: 0; padding-top: 0; }
.about-facts li:last-child { padding-bottom: 0; }
.about-facts strong {
  display: block;
  margin-bottom: 0.3rem;
  font-size: 0.98rem;
  font-weight: 700;
}
.about-facts span {
  display: block;
  color: var(--muted);
  font-size: 0.88rem;
  line-height: 1.6;
}

.empty {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 1.4rem;
  border: 1px dashed var(--hairline);
  border-radius: 14px;
  color: var(--muted);
  text-align: center;
}

/*
  # The footer, which is also the contact section

  How to reach us used to be a band of bordered cards in the middle of the
  page. On a laptop that was a row; on a phone it was six boxes to scroll past
  before the page ended. It is a footer now, because that is where a visitor
  looks for it on any other site and because plain lines under a heading say
  the same thing in a third of the height.

  Flex rather than grid: the brand column wants to be wider than the link
  columns, and `repeat(auto-fit, …)` cannot be mixed with a differently-sized
  track. Each column states the width below which it would rather wrap.
*/
.footer {
  padding: clamp(2.5rem, 6vw, 4rem) clamp(1rem, 4vw, 2.5rem) 2rem;
  border-top: 1px solid var(--hairline);
}
.footer-grid {
  max-width: var(--shell);
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.6rem, 4vw, 3rem);
}
.footer-brand { flex: 1 1 20rem; max-width: 32rem; }
.footer-col { flex: 1 1 11rem; }

.footer-name { margin: 0; font-size: 1.15rem; font-weight: 800; letter-spacing: -0.01em; }
.footer-tag {
  margin: 0.35rem 0 0;
  color: var(--gold);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
}
.footer-blurb {
  margin: 0.9rem 0 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.65;
}
/* Smaller here than in the hero: this is the second offer of the same thing,
   and the ways to reach us in the column beside are what the footer is for. */
.footer-brand .store-badge { margin-top: 1.2rem; }

.footer-col h2 {
  margin: 0 0 0.9rem;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  font-weight: 700;
}
.footer-col ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 0.55rem; }
.footer-col li {
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.footer-col li span { color: rgba(255, 255, 255, 0.38); }
.footer-col a {
  color: var(--muted);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 0.25s ease, border-color 0.25s ease;
}
.footer-col a:hover { color: var(--paper); border-bottom-color: var(--gold); }
.footer-note { margin: 0; color: var(--muted); font-size: 0.9rem; line-height: 1.6; }

.footer-base {
  max-width: var(--shell);
  margin: clamp(1.8rem, 4vw, 2.6rem) auto 0;
  padding-top: 1.3rem;
  border-top: 1px solid var(--hairline);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0.8rem;
}
.footer-legal { margin: 0; color: rgba(255, 255, 255, 0.4); font-size: 0.78rem; }
.footer-policies { display: flex; flex-wrap: wrap; gap: 1.2rem; }
.footer-policies a {
  color: rgba(255, 255, 255, 0.45);
  font-size: 0.78rem;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 0.25s ease, border-color 0.25s ease;
}
.footer-policies a:hover { color: var(--paper); border-bottom-color: var(--gold); }

/*
  The nav is the only thing that has to give way on a narrow screen: six labels
  and a wordmark do not fit on one line, and shrinking them to fit puts the
  whole menu below the size a thumb can hit.

  So under 48rem the row becomes a panel that hangs off the bar. It is laid
  over the page rather than wedged into the header: a drawer that grows the bar
  pushes the hero — logo and all — down the screen while it is open, and the
  page appears to jump twice for one tap. Absolute against the sticky bar, so
  it finds the bar's own height instead of a number written here that would go
  stale the day the wordmark changes size.
*/
@media (max-width: 48rem) {
  .burger { display: flex; }
  /* Only the state that is not showing is hidden, so the corner always holds
     exactly one control. */
  #menu:target ~ .burger-open { display: none; }
  .burger-close { display: none; }
  #menu:target ~ .burger-close { display: flex; }

  .topnav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 0;
    padding: 0.25rem clamp(1rem, 4vw, 2.5rem) 0.75rem;
    background: rgba(30, 35, 46, 0.97);
    backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--hairline);
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.45);
    /* `visibility` as well as opacity: a panel that is merely transparent is
       still in the tab order and still swallows the tap meant for the hero. */
    opacity: 0;
    visibility: hidden;
    transform: translateY(-0.5rem);
    transition: opacity 0.22s ease, transform 0.22s ease, visibility 0.22s;
  }
  #menu:target { opacity: 1; visibility: visible; transform: none; }
  .topnav a {
    padding: 0.8rem 0.25rem;
    font-size: 0.95rem;
    border-bottom: 1px solid var(--hairline);
  }
  .topnav a:last-child { border-bottom: 0; }
  .topnav a:hover,
  .topnav a:focus-visible { border-bottom-color: var(--gold); }

  /*
    # Rails, not stacks

    Eight product cards and three banners in a single column is roughly four
    screens of thumb-work before the page moves on, and the visitor has to
    scroll all of it whether or not they wanted to look. Sideways they occupy
    one screen and are opted into.

    `78%` rather than a whole one: a card cut off at the edge is the only
    honest signal that there is more, now that the scrollbar is hidden. Snap
    so a flick lands on a card rather than between two.
  */
  .grid-cards,
  .grid-slides {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 78%;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }
  .grid-cards > *,
  .grid-slides > * { scroll-snap-align: start; }
  .grid-cards::-webkit-scrollbar,
  .grid-slides::-webkit-scrollbar { display: none; }
}

/*
  The phone. Buttons stop sitting side by side — two half-width pills on a
  360px screen are two targets a thumb misses — and the panels give back the
  padding the content needs. The hero is not listed: it is one badge now, and
  the badge is artwork with a fixed size rather than a pill that can stretch.
*/
@media (max-width: 30rem) {
  .about-cta .btn {
    flex: 1 1 100%;
    text-align: center;
    justify-content: center;
  }
  .hero { padding-top: clamp(2rem, 8vw, 3rem); }
  .hero .mark { width: 104px; height: 104px; }
  .about { padding: 1.2rem; border-radius: 16px; }
  /* Three brand tiles a row instead of two: they are logos, and at this size
     the extra row buys nothing but scroll. */
  .marks { grid-template-columns: repeat(auto-fit, minmax(min(6.5rem, 100%), 1fr)); }
  .marks .mark { min-height: 5rem; padding: 0.7rem; }
  .marks .mark img { max-height: 3rem; }
}


/*
  # Reduced motion — the setting that made this page look broken

  This block is why the animation appeared dead during review, and it is worth
  being precise about rather than deleting.

  "Reduce motion" is an accessibility preference: Windows puts it under
  Settings → Accessibility → Visual effects → Animation effects, macOS under
  Accessibility → Display. People enable it because movement makes them ill —
  vestibular disorders, migraine, motion sensitivity. A machine with it on was
  matching this block, which used to be `display: none` on everything that
  moved, so the page assembled and then sat perfectly still. Correct behaviour,
  and indistinguishable from a bug.

  Deleting the query is the wrong fix: it would push sliding motion onto
  exactly the people who asked not to receive it. The right one is to hand them
  the finished page instead of the assembly of it — everything the hero
  animates into place is simply already there, and nothing further down the
  page moves on its own.
*/
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .hero .mark,
  .hero h1,
  .hero .tagline,
  .hero .lede,
  .hero .cta,
  .hero .stats {
    animation: none;
    opacity: 1;
    transform: none;
  }
  /* The card lift, the logo lift and the banner's slow zoom are travel too, so
     they go with the rest. The drawer still opens; it just stops sliding. */
  .card:hover,
  .tile:hover,
  .marks .mark:hover,
  .store-badge:hover,
  .slide:hover img { transform: none; }
  .topnav { transition: none; }
  /* A snapped rail is motion the visitor asked for, but let it come to rest
     where they let go rather than being pulled to the next card. */
  .grid-cards,
  .grid-slides { scroll-snap-type: none; }
}
